CMake具体示例
目录结构
project0702/
├── CMakeLists.txt # 主目录的 CMake 配置文件
├── build/ # 构建输出目录
│ └── Debug/ # Debug 模式下的输出目录
├── lib/ # 存放动态库的目录
│ ├── practice01.dll
│ ├── practice02.dll
│ └── practice03.dll
├── practice01/ # practice01 模块
│ ├── CMakeLists.txt # practice01 模块的 CMake 配置文件
│ ├── include/ # 存放 practice01 模块的头文件
│ │ └── practice01.h
│ └── src/ # 存放 practice01 模块的源代码
│ └── practice01.cpp
├── practice02/ # practice02 模块
│ ├── CMakeLists.txt # practice02 模块的 CMake 配置文件
│ ├── include/ # 存放 practice02 模块的头文件
│ │ └── practice02.h
│ └── src/ # 存放 practice02 模块的源代码
│ └── practice02.cpp
├── practice03/ # practice03 模块
│ ├── CMakeLists.txt # practice03 模块的 CMake 配置文件
│ ├── include/ # 存放 practice03 模块的头文件
│ │ └── practice03.h
│ └── src/ # 存放 practice03 模块的源代码
│ └── practice03.cpp
└── main.cpp # 主程序的入口文件
主项目 CMakeLists.txt
代码
cmake_minimum_required(VERSION 3.10)
project(project0702)
# 包含子模块的头文件路径
include_directories(${CMAKE_SOURCE_DIR}/practice01/include)
include_directories(${CMAKE_SOURCE_DIR}/practice02/include)
include_directories(${CMAKE_SOURCE_DIR}/practice03/include)
# 查找主目录下的所有源文件,在这里也就是找到main.cpp
file(GLOB SRC_LISTS ${CMAKE_SOURCE_DIR}/*.cpp)
# 设置可执行文件的输出目录
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/build)
# 添加子模块
add_subdirectory(practice01)
add_subdirectory(practice02)
add_subdirectory(practice03)
# 创建可执行文件
add_executable(project0702 ${SRC_LISTS})
# 链接子模块库
target_link_libraries(project0702 practice01 practice02 practice03)
# 自定义命令:构建后将动态库复制到输出目录
add_custom_command(TARGET project0702 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/lib/practice01.dll ${CMAKE_SOURCE_DIR}/build/Debug/
)
add_custom_command(TARGET project0702 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/lib/practice02.dll ${CMAKE_SOURCE_DIR}/build/Debug/
)
add_custom_command(TARGET project0702 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/lib/practice03.dll ${CMAKE_SOURCE_DIR}/build/Debug/
)
解释
include_directories():
为主项目添加子模块的头文件路径,以便主项目中的源文件能够找到模块的头文件。file(GLOB SRC_LISTS ...):
查找主目录下的所有源文件(如 main.cpp),并将其用于构建可执行文件。set(EXECUTABLE_OUTPUT_PATH ...)
:设置可执行文件的输出目录为 build/add_subdirectory()
:将子模块(practice01、practice02、practice03)添加到项目中,使得这些模块可以被构建。add_executable()
:为项目创建可执行文件 project0702。target_link_libraries()
:将生成的动态库 practice01、practice02、practice03链接到可执行文件。add_custom_command()
:在构建后,使用 cmake -E copy 将生成的 .dll文件复制到可执行文件所在的目录,以确保在运行时可以找到并加载动态库。
practice01 的 CMakeLists.txt
代码
cmake_minimum_required(VERSION 3.10)
project(practice01)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
file(GLOB_RECURSE SRC_LISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_library(practice01 SHARED ${SRC_LISTS})
解释
include_directories()
:添加 practice01 的头文件路径,使得其他项目可以引用 practice01的头文件file(GLOB_RECURSE ...)
:递归查找 practice01 模块中的所有 .cpp文件,并将这些文件用于构建动态库set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ...)
:设置 .dll文件的输出目录set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
:自动导出动态库中的所有符号add_library()
:创建 practice01 的动态库。
其余同理
总结
- 子模块的 CMakeLists.txt 文件生成动态库:
每个子模块(如 practice01、practice02、practice03)的 CMakeLists.txt 文件负责将各自的源代码编译成动态链接库(.dll 或 .so 文件)。这些动态库封装了子模块的功能,并可以在项目的其他部分中使用。 - 主项目的 CMakeLists.txt 文件整合这些动态链接库:
主项目的 CMakeLists.txt 文件负责将这些生成的动态链接库链接到主程序的可执行文件中(如 project0702.exe)。它通过target_link_libraries()
命令,将子模块的动态库链接到主程序的主函数(如 main.cpp 中的 main() 函数)。
同时,主项目的 CMakeLists.txt 还可以通过自定义命令(add_custom_command())
确保在运行时,这些动态库(.dll 文件)被复制到可执行文件所在的目录,使得主程序能够加载这些动态库并使用其中的功能。 - 如果是静态链接库就不用移到exe文件的文件夹内了,在把静态的.lib文件链接到main.cpp当中后,
main.exe
就可以之间执行,不需要在运行时进行动态加载。