CMakeLists.txt 是 CMake 构建系统的核心配置文件,用于描述如何编译和构建 C/C++ 项目。它类似于传统的 Makefile,但更高级、跨平台且易于维护。
一、CMake 核心作用和使用方式的详细说明
1. CMake 是什么?
CMake 是一个跨平台的构建工具生成器,它本身不直接编译代码,而是生成特定平台的构建文件(如 Makefile、Visual Studio 项目文件等)。
优势:一次编写配置,跨平台生成对应构建文件,避免为不同平台维护多套 Makefile。
2. CMakeLists.txt 的核心作用
(1) 定义项目基本信息
cmake_minimum_required(VERSION 3.10) # 最低 CMake 版本要求
project(MyProject VERSION 1.0.0) # 项目名称和版本
(2) 设置编译选项和变量
set(CMAKE_CXX_STANDARD 17) # C++ 标准
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") # 编译选项
set(SOURCE_DIR "${CMAKE_SOURCE_DIR}/src") # 自定义变量
(3) 添加源文件和头文件路径
# 自动收集 src 目录下的所有 .cpp 文件
file(GLOB_RECURSE SOURCES "${SOURCE_DIR}/*.cpp")
# 添加头文件搜索路径
include_directories("${CMAKE_SOURCE_DIR}/include")
(4) 定义目标(可执行文件或库)
# 添加可执行文件
add_executable(myapp ${SOURCES})
# 添加库(STATIC=静态库,SHARED=动态库)
add_library(mylib SHARED ${LIB_SOURCES})
(5) 链接外部库
# 查找系统库(如 pthread)
find_package(Threads REQUIRED)
target_link_libraries(myapp PRIVATE Threads::Threads)
# 链接自定义库
target_link_libraries(myapp PRIVATE mylib)
(6) 控制构建过程
# 设置输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
# 添加自定义构建步骤
add_custom_command(TARGET myapp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/assets" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/assets"
)
- 项目结构示例
myproject/
├── CMakeLists.txt # 主配置文件
├── src/ # 源文件
│ ├── main.cpp
│ └── ...
├── include/ # 头文件
│ └── mylib/
│ └── myheader.h
├── lib/ # 第三方库
└── build/ # 构建目录(建议外部构建)
- 典型工作流程
(1)编写 CMakeLists.txt:定义项目结构和编译规则。
(2)创建构建目录(建议):
mkdir build && cd build
(3)运行CMake生成构建文件:
cmake .. # 生成 Makefile(Linux/macOS)或 VS 项目文件(Windows)
(4) 执行构建:
make # Linux/macOS
# 或双击 .sln 文件(Windows)
- 高级特性
(1) 条件编译
option(BUILD_TESTS "Build tests" ON) # 可通过 cmake -DBUILD_TESTS=OFF 关闭
if(BUILD_TESTS)
add_subdirectory(tests)
endif()
(2) 模块化设计
通过 add_subdirectory() 包含子目录的 CMakeLists.txt,实现模块化管理:
# 主 CMakeLists.txt
add_subdirectory(src)
add_subdirectory(lib)
# src/CMakeLists.txt
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE mylib)
# lib/CMakeLists.txt
add_library(mylib STATIC lib.cpp)
(3) 查找第三方库
# 查找 OpenCV
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(myapp PRIVATE ${OpenCV_LIBS})
-
常见命令速查表
命令 作用
project() 定义项目名称和版本
add_executable() 添加可执行文件目标
add_library() 添加库目标(STATIC/SHARED/MODULE)
target_link_libraries() 链接库到目标
include_directories() 添加头文件搜索路径
set() 设置变量(如编译选项、路径)
find_package() 查找并导入第三方库或工具
add_subdirectory() 添加子目录,处理其中的 CMakeLists.txt
file() 文件操作(如收集源文件、复制文件)
option() 定义可配置选项(通过 cmake -D 传递) -
推荐学习资源
官方文档:CMake Documentation
CMake 实践教程:Modern CMake Tutorial
CMake 最佳实践:Effective CMake
通过合理使用 CMakeLists.txt,你可以高效管理复杂项目的构建过程,提升跨平台开发体验。
二、CMakeLists模板
新朋友构建新的CPP项目,都会觉得CMakeLists.txt难写,尤其是构建大型项目时,容易写错,如果有个CMake模板就好了,下面是我简单总结的常见模板:我将详细解释 QXlsx 项目的 CMakeLists.txt 文件的结构和各个部分的作用作为例子:
# 1. 基本项目设置
cmake_minimum_required(VERSION 3.16) # 指定最低 CMake 版本要求
project(QXlsx # 定义项目名称
VERSION 1.5.0 # 项目版本号
LANGUAGES CXX # 使用的编程语言(C++)
)
# 2. 基本配置
set(CMAKE_INCLUDE_CURRENT_DIR ON) # 将当前目录添加到包含路径
set(CMAKE_AUTOMOC ON) # 启用 Qt 的 MOC 自动处理
include(GNUInstallDirs) # 包含 GNU 标准安装目录定义
# 3. Qt 依赖配置
if(NOT DEFINED QT_VERSION_MAJOR) # 如果没有指定 Qt 版本
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui REQUIRED) # 查找 Qt6 或 Qt5
endif()
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui REQUIRED) # 查找具体版本的 Qt
set(EXPORT_NAME QXlsxQt${QT_VERSION_MAJOR}) # 设置导出名称
# 4. C++ 标准设置
if (QT_VERSION_MAJOR EQUAL 6) # 如果是 Qt6
set(CMAKE_CXX_STANDARD 17) # 使用 C++17
else()
set(CMAKE_CXX_STANDARD 11) # 使用 C++11
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON) # 强制要求使用指定的 C++ 标准
# 5. 路径设置
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) # 设置 CMake 模块路径
# 设置各种路径变量
if(NOT DEFINED QXLSX_PARENTPATH)
set(QXLSX_PARENTPATH ${CMAKE_CURRENT_SOURCE_DIR}/../)
endif()
if(NOT DEFINED QXLSX_HEADERPATH)
set(QXLSX_HEADERPATH ${CMAKE_CURRENT_SOURCE_DIR}/../QXlsx/header/)
endif()
if(NOT DEFINED QXLSX_SOURCEPATH)
set(QXLSX_SOURCEPATH ${CMAKE_CURRENT_SOURCE_DIR}/../QXlsx/source/)
endif()
# 6. 构建选项
option(BUILD_SHARED_LIBS "Build in shared lib mode" OFF) # 设置是否构建动态库
# 7. 源文件列表
set(SRC_FILES ...) # 设置源文件列表
set(QXLSX_PUBLIC_HEADERS ...) # 设置公共头文件列表
# 8. 创建库目标
add_library(QXlsx # 创建库目标
${SRC_FILES} # 源文件
${QXLSX_PUBLIC_HEADERS} # 公共头文件
)
add_library(QXlsx::QXlsx ALIAS QXlsx) # 创建别名目标
# 9. 编译定义
target_compile_definitions(QXlsx PRIVATE # 添加编译定义
QT_NO_KEYWORDS
QT_NO_CAST_TO_ASCII
# ... 其他 Qt 相关的编译定义
)
# 10. 平台特定设置
if (NOT WIN32) # 非 Windows 平台特定设置
target_compile_definitions(QXlsx PRIVATE QT_STRICT_ITERATORS)
endif()
# 11. 编译特性设置
target_compile_features(QXlsx INTERFACE cxx_std_11) # 设置 C++ 标准特性
# 12. 动态库特定设置
if (BUILD_SHARED_LIBS)
target_compile_definitions(QXlsx PUBLIC QXlsx_SHAREDLIB)
endif()
# 13. 链接依赖
target_link_libraries(${PROJECT_NAME} # 链接 Qt 库
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::GuiPrivate
)
# 14. 包含目录设置
target_include_directories(QXlsx # 设置包含目录
PRIVATE
${QXLSX_HEADERPATH} # 私有包含目录
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/header> # 公共包含目录
$<INSTALL_INTERFACE:include/QXlsxQt${QT_VERSION_MAJOR}>
)
# 15. 目标属性设置
set_target_properties(QXlsx PROPERTIES # 设置目标属性
OUTPUT_NAME ${EXPORT_NAME} # 输出文件名
VERSION ${PROJECT_VERSION} # 版本号
SOVERSION ${PROJECT_VERSION_MAJOR} # 主版本号
PUBLIC_HEADER "${QXLSX_PUBLIC_HEADERS}" # 公共头文件
)