FlowEQ变换:融合光流与轮廓增强的视频行为识别技术解析
2026/5/27 0:08:50
本课程将学习如何:
add_subdirectory()组织多个子目录06-多目录构建网络/ ├── CMakeLists.txt # 主CMakeLists.txt(根配置) ├── core/ # 核心库模块 │ ├── CMakeLists.txt │ ├── core_lib.h │ └── core_lib.cpp ├── utils/ # 工具库模块(可选) │ ├── CMakeLists.txt │ ├── utils_lib.h │ └── utils_lib.cpp ├── app/ # 主应用程序 │ ├── CMakeLists.txt │ └── main.cpp ├── examples/ # 示例程序(可选) │ ├── CMakeLists.txt │ ├── example1.cpp │ └── example2.cpp └── tests/ # 测试程序(可选) ├── CMakeLists.txt └── test_core.cpp作用:将子目录添加到构建系统中,CMake会处理子目录中的CMakeLists.txt。
语法:
add_subdirectory(子目录路径)示例:
# 添加核心库子目录 add_subdirectory(core) # 条件添加工具库子目录 if(BUILD_UTILS) add_subdirectory(utils) endif()要点:
add_subdirectory()的顺序处理子目录重要规则:
set(... PARENT_SCOPE)可以修改父目录的变量示例:
# 父目录 CMakeLists.txt set(PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) set(BUILD_TESTS ON) add_subdirectory(core) # 子目录可以使用 PROJECT_ROOT 和 BUILD_TESTS # 子目录 core/CMakeLists.txt message(STATUS "项目根目录: ${PROJECT_ROOT}") # ✓ 可以使用 message(STATUS "构建测试: ${BUILD_TESTS}") # ✓ 可以使用 set(LOCAL_VAR "只在core目录中可见") # 父目录看不到这个变量# 子目录中 set(MY_VAR "新值" PARENT_SCOPE) # 修改父目录的变量关键点:
add_library(),add_executable())在父目录和其他子目录中自动可见target_link_libraries()链接这些目标示例:
# core/CMakeLists.txt add_library(core_lib STATIC core_lib.cpp) # 创建目标 # utils/CMakeLists.txt add_library(utils_lib STATIC utils_lib.cpp) target_link_libraries(utils_lib PUBLIC core_lib) # ✓ 可以链接core_lib # app/CMakeLists.txt add_executable(main_app main.cpp) target_link_libraries(main_app core_lib utils_lib) # ✓ 可以链接两个库PUBLIC 的传递性:
# core/CMakeLists.txt target_include_directories(core_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) # PUBLIC 表示:core_lib需要这个目录,链接core_lib的目标也需要 # utils/CMakeLists.txt target_link_libraries(utils_lib PUBLIC core_lib) # 因为core_lib使用了PUBLIC包含目录,utils_lib会自动获得这个包含目录 # app/CMakeLists.txt target_link_libraries(main_app core_lib) # main_app也会自动获得core_lib的PUBLIC包含目录依赖链:
core_lib (PUBLIC包含目录) ↓ utils_lib (链接core_lib) ↓ main_app (链接core_lib和utils_lib)# 主CMakeLists.txt option(BUILD_TESTS "构建测试程序" OFF) option(BUILD_EXAMPLES "构建示例程序" ON) option(BUILD_UTILS "构建工具库" ON)# 根据选项决定是否添加子目录 if(BUILD_TESTS) enable_testing() add_subdirectory(tests) endif() if(BUILD_EXAMPLES) add_subdirectory(examples) endif()# app/CMakeLists.txt target_link_libraries(main_app core_lib) # 如果工具库被构建,则链接它 if(BUILD_UTILS) target_link_libraries(main_app utils_lib) target_compile_definitions(main_app PRIVATE BUILD_UTILS_LIB) endif()项目根目录/ ├── CMakeLists.txt # 主配置 ├── include/ # 公共头文件(可选) ├── src/ # 源代码(可选,或直接在子目录) ├── libs/ # 第三方库(可选) │ ├── lib1/ │ └── lib2/ ├── apps/ # 应用程序 │ ├── app1/ │ └── app2/ ├── tests/ # 测试 └── docs/ # 文档# 1. 收集源文件 set(MODULE_SOURCES file1.cpp file2.cpp ) # 2. 创建目标(库或可执行文件) add_library(module_name STATIC ${MODULE_SOURCES}) # 3. 设置包含目录 target_include_directories(module_name PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) # 4. 链接依赖 target_link_libraries(module_name PUBLIC dependency1 dependency2 ) # 5. 安装规则(可选) install(TARGETS module_name ...)cd06-多目录构建网络 tree /F# Windows# 或tree# Linux/Macmkdirbuildcdbuild cmake..观察输出:
cmake --build.观察:
# Windows.\Debug\main_app.exe# 或.\main_app.exe# Linux/Mac./main_appcd..rm-rf build# 或 rmdir /s /q build (Windows)mkdirbuildcdbuild cmake -DBUILD_UTILS=OFF..cmake --build..\main_app.exe观察:
cmake -DBUILD_UTILS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF..cmake --build.cmake -DBUILD_UTILS=ON -DBUILD_EXAMPLES=ON -DBUILD_TESTS=ON..cmake --build.# 生成依赖关系图(需要安装Graphviz)cmake --graphviz=graph.dot..dot -Tpng graph.dot -o graph.png# 第1-2行:版本要求 cmake_minimum_required(VERSION 3.10) # 第5行:项目定义 project(MultiDirectoryProject VERSION 1.0.0 LANGUAGES CXX) # 第8-9行:全局C++标准设置 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 这些设置会传递给所有子目录 # 第12-15行:定义全局选项 option(BUILD_TESTS "构建测试程序" OFF) option(BUILD_EXAMPLES "构建示例程序" ON) option(BUILD_UTILS "构建工具库" ON) # 这些选项可以在命令行通过 -D 参数修改 # 第18行:定义全局变量 set(PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) # 子目录可以使用这个变量 # 第32行:无条件添加核心库 add_subdirectory(core) # core目录必须被构建 # 第35-38行:条件添加工具库 if(BUILD_UTILS) add_subdirectory(utils) endif() # 第41行:添加应用程序 add_subdirectory(app) # 第44-47行:条件添加示例程序 if(BUILD_EXAMPLES) add_subdirectory(examples) endif() # 第50-54行:条件添加测试 if(BUILD_TESTS) enable_testing() # 启用CTest add_subdirectory(tests) endif()# 第7-9行:收集源文件 set(CORE_SOURCES core_lib.cpp ) # 第12行:创建静态库 add_library(core_lib STATIC ${CORE_SOURCES}) # 这个目标在整个项目中可见 # 第15-18行:设置包含目录(PUBLIC) target_include_directories(core_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} # core目录 ${PROJECT_ROOT}/include # 使用父目录定义的变量 ) # PUBLIC表示:链接core_lib的目标也会自动获得这些包含目录 # 第20-24行:设置目标属性 set_target_properties(core_lib PROPERTIES VERSION ${PROJECT_VERSION} # 使用父目录定义的版本 SOVERSION 1 )# 第12行:创建工具库 add_library(utils_lib STATIC ${UTILS_SOURCES}) # 第20行:链接核心库 target_link_libraries(utils_lib PUBLIC core_lib) # PUBLIC表示:链接utils_lib的目标也会自动链接core_lib # 并且会自动获得core_lib的PUBLIC包含目录# 第29行:创建可执行文件 add_executable(main_app ${APP_SOURCES}) # 第37-40行:条件链接工具库 if(BUILD_UTILS) target_link_libraries(main_app utils_lib) target_compile_definitions(main_app PRIVATE BUILD_UTILS_LIB) # 定义宏,让代码知道工具库可用 endif()| 位置 | 父目录变量 | 子目录变量 |
|---|---|---|
| 父目录 | ✓ 可见 | ✗ 不可见 |
| 子目录 | ✓ 可见 | ✓ 可见 |
target_link_libraries()链接# 1. 定义选项 option(BUILD_MODULE "描述" ON) # 2. 条件添加子目录 if(BUILD_MODULE) add_subdirectory(module) endif() # 3. 条件链接(在需要的地方) if(BUILD_MODULE) target_link_libraries(my_target module_lib) endif()尝试添加一个新模块network/,包含:
network/CMakeLists.txtnetwork/network_lib.h和network/network_lib.cppBUILD_NETWORK将项目重构为:
项目/ ├── CMakeLists.txt ├── libs/ │ ├── core/ │ ├── utils/ │ └── network/ ├── apps/ │ ├── app1/ │ └── app2/ └── tests/创建一个函数来简化库的创建:
function(create_library lib_name) add_library(${lib_name} STATIC ${ARGN}) target_include_directories(${lib_name} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) endfunction() # 使用 create_library(core_lib core_lib.cpp)添加依赖检查,确保必需的模块被构建:
if(NOT BUILD_UTILS AND BUILD_EXAMPLES) message(FATAL_ERROR "示例程序需要工具库,请启用BUILD_UTILS") endif()A: 使用set(... PARENT_SCOPE):
# 子目录中 set(MY_VAR "值" PARENT_SCOPE)A: CMake会根据依赖关系自动确定编译顺序。如果A依赖B,B会先编译。
A: 可以,但不推荐。最好在根CMakeLists.txt中统一管理选项。
A: 在CMakeLists.txt中添加:
get_property(_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS) foreach(_target ${_targets}) message(STATUS "目标: ${_target}") endforeach()A: 使用条件判断:
if(NOT SKIP_MODULE) add_subdirectory(module) endif()A: 不一定。子目录可以只设置变量、定义函数等,不一定要创建目标。
项目/ ├── CMakeLists.txt ├── src/ # 源代码 │ ├── core/ │ ├── gui/ │ └── network/ ├── tests/ # 测试 ├── examples/ # 示例 └── tools/ # 工具if(WIN32) add_subdirectory(platform/windows) elseif(UNIX) add_subdirectory(platform/linux) endif()option(BUILD_PLUGIN_A "构建插件A" ON) option(BUILD_PLUGIN_B "构建插件B" OFF) if(BUILD_PLUGIN_A) add_subdirectory(plugins/plugin_a) endif()掌握了多目录构建后,你可以继续学习:
通过本课程,你学会了:
✅ 使用add_subdirectory()组织多个CMakeLists.txt
✅ 理解变量作用域和传递机制
✅ 管理模块间的依赖关系
✅ 实现条件构建和可选模块
✅ 构建可扩展的、模块化的项目结构
现在你已经掌握了将几十个小CMakeLists.txt组织成可控构建网络的核心技能!🎉
祝你学习愉快!🚀