跳到主要内容

CmakeLists.txt常用命令介绍

· 阅读需 16 分钟
XingHunm
Tech Enthusiast

本文档介绍 CMake 构建系统中最常用的命令和最佳实践,适合初学者和进阶开发者参考。

1. 基础配置

1.1 cmake_minimum_required

指定项目所需的最低 CMake 版本。虽然不是强制要求,但建议始终显式声明,以确保构建环境兼容并避免因版本差异导致的问题。

语法:

cmake_minimum_required(VERSION x.y)

示例:

cmake_minimum_required(VERSION 3.20)

版本选择原则:

  1. 基于项目使用的 CMake 特性

    • target_link_options 需要 CMake 3.13+
    • CMAKE_CXX_STANDARDCMAKE_CXX_STANDARD_REQUIRED 需要 CMake 3.1+
    • qt_add_executable 需要 CMake 3.16+
  2. 基于第三方库要求

    • Qt 6 官方要求 CMake 3.16+
    • OpenCV 4.5+ 推荐 CMake 3.10+

1.2 project

定义项目名称、版本号和编程语言。

语法:

project(ProjectName VERSION major.minor.patch [LANGUAGES ...])

示例:

project(MyAwesomeApp VERSION 1.2.3 LANGUAGES CXX)

参数说明:

  • ProjectName: 项目名称,用于生成工程文件名和变量 PROJECT_NAME
  • VERSION: 版本号(主版本.次版本.补丁版本),自动生成以下变量:
    • PROJECT_VERSION
    • PROJECT_VERSION_MAJOR
    • PROJECT_VERSION_MINOR
    • PROJECT_VERSION_PATCH
  • LANGUAGES: 支持的编程语言,可选值:
    • C: C 语言
    • CXX: C++ 语言
    • Fortran: Fortran 语言
    • ASM: 汇编语言

注意事项:

  • 如果不指定 LANGUAGES,默认启用 C 和 CXX
  • 建议明确指定所需语言以避免不必要的编译器检测

2. 目标管理

2.1 add_executable

定义并创建一个可执行文件目标,将指定的源文件编译链接成可运行的程序(如 Windows 的 .exe 文件)。

语法:

add_executable(TargetName [WIN32] [MACOSX_BUNDLE] source1 source2 ...)

参数说明:

  • TargetName: 目标名称
  • WIN32: Windows 平台上创建 GUI 程序(无控制台窗口)
  • MACOSX_BUNDLE: macOS 平台上创建 .app 应用包
  • source1 source2 ...: 源文件列表

基础示例:

add_executable(MyApp
src/main.cpp
src/app.cpp
)

跨平台示例:

# 收集源文件
file(GLOB_RECURSE SOURCES "src/*.cpp")

# 根据平台添加不同选项
if(WIN32)
add_executable(MyApp WIN32 ${SOURCES})
elseif(APPLE)
add_executable(MyApp MACOSX_BUNDLE ${SOURCES})
else()
add_executable(MyApp ${SOURCES})
endif()

注意事项:

  • 头文件无需添加到源文件列表中
  • 必须包含所有参与编译的 .cpp 文件
  • Qt 项目推荐使用 qt_add_executable

2.2 add_library

定义并创建一个库目标,将指定的源文件编译成可重用的库文件(如静态库 .a/.lib 或动态库 .so/.dll)。

语法:

add_library(targetName [STATIC|SHARED|MODULE|INTERFACE|OBJECT] [sources...])

库类型说明:

  • STATIC: 静态库(.a / .lib)
  • SHARED: 动态库(.so / .dll)
  • MODULE: 模块库(插件,运行时加载)
  • INTERFACE: 接口库(纯头文件库)
  • OBJECT: 对象文件库(.o 文件集合)

示例:

# 静态库
add_library(mylib STATIC
src/foo.cpp
src/bar.cpp
)

# 动态库
add_library(mylib_shared SHARED
src/foo.cpp
src/bar.cpp
)

# 接口库(仅头文件)
add_library(header_only_lib INTERFACE)

常见配套命令:

  • target_include_directories() - 设置头文件路径
  • target_link_libraries() - 链接依赖库
  • target_compile_options() - 编译选项
  • target_sources() - 管理源文件

2.3 target_sources

为已存在的目标添加源文件。相比 add_library 在创建目标时一次性添加源文件,target_sources 的优势在于目标创建后可以分多次、分条件地动态添加源文件。

语法:

target_sources(targetName [PRIVATE | PUBLIC | INTERFACE] sources...)

可见性说明:

  • PRIVATE: 源文件仅用于该目标本身
  • PUBLIC: 目标本身使用,依赖者也可见(很少用于源文件)
  • INTERFACE: 目标本身不用,仅对依赖者可见

示例:

# 先创建空库
add_library(mylib STATIC)

# 根据平台添加不同源文件
if(WIN32)
target_sources(mylib PRIVATE src/windows.cpp)
elseif(APPLE)
target_sources(mylib PRIVATE src/macos.cpp)
else()
target_sources(mylib PRIVATE src/linux.cpp)
endif()

使用场景:

  • 模块化管理源文件
  • 条件性添加源文件
  • 提高 CMakeLists.txt 可读性

3. 依赖管理

3.1 target_include_directories

为目标设置头文件搜索路径,控制编译器在何处查找 #include 的头文件;若未设置,编译器只会在源文件目录和系统默认路径中查找头文件,其他目录下的头文件将无法找到。

语法:

target_include_directories(targetName [PUBLIC|PRIVATE|INTERFACE] dirs...)

可见性说明:

  • PRIVATE: 路径仅用于该目标编译
  • PUBLIC: 该目标及其依赖者都使用此路径
  • INTERFACE: 仅依赖者使用此路径

示例:

# 为可执行程序添加私有头文件路径
add_executable(myapp main.cpp)
target_include_directories(myapp
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)

# 为库添加公共头文件路径
add_library(mylib src/foo.cpp)
target_include_directories(mylib
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)

目录结构示例:

project_root/
├── include/
│ ├── foo.h
│ └── utils/
│ └── helper.h
├── src/
│ └── main.cpp
└── CMakeLists.txt

代码中的使用:

// main.cpp
#include "foo.h" // 正确
#include "utils/helper.h" // 正确
#include "helper.h" // 错误:需要包含完整路径

重要提示:

  • CMake 不会递归搜索子目录
  • 需在代码中提供相对于 include(target_include_directories 指定的目录)目录的完整路径

为目标链接库依赖。也就是告诉 CMake:在编译 target 时,需要额外链接哪些库(依赖的库),才能正常运行。

语法:

target_link_libraries(targetName [PUBLIC|PRIVATE|INTERFACE] libraries...)

可见性说明:

  • PRIVATE: 仅该目标使用
  • PUBLIC: 该目标及其依赖者都链接
  • INTERFACE: 仅依赖者链接

库类型:

  • CMake 目标(如自定义库)
  • 系统库(如 pthread)
  • 第三方库的导入目标(如 Qt6::Core)

示例:

# 链接自定义库
add_library(mylib STATIC foo.cpp)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE mylib)

# 链接第三方库
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
target_link_libraries(myapp
PRIVATE
Qt6::Core
Qt6::Widgets
)

# 链接系统库
target_link_libraries(myapp PRIVATE pthread)

4. 库和包查找

4.1 find_package

用来自动查找和配置外部依赖库或包,当你的项目依赖第三方库或系统库时就需要。

语法:

find_package(PackageName [Version] [REQUIRED] [COMPONENTS components...])

参数说明:

  • PackageName: 包名称(如 Qt6、OpenCV、Boost)
  • Version: 最低版本要求
  • REQUIRED: 找不到时停止构建
  • COMPONENTS: 指定所需子模块

示例:

find_package(Qt6 6.6 REQUIRED COMPONENTS Core Widgets Gui)

4.2 查找机制详解

CMake 使用严格的优先级顺序查找包,找到第一个匹配项就立即停止搜索。

4.2.1 完整查找流程

  1. 检查缓存变量:如果 <PackageName>_DIR 已经在缓存中,直接使用
  2. 模块模式(Module Mode):搜索 Find<PackageName>.cmake 文件
  3. 配置模式(Config Mode):搜索 <PackageName>Config.cmake<lowercase-name>-config.cmake 文件

重要: 一旦在模块模式中找到 Find<PackageName>.cmake,CMake 就会停止搜索,不会继续尝试配置模式

4.2.2 模块模式(Module Mode)

按以下顺序搜索 Find<PackageName>.cmake 文件:

  1. CMAKE_MODULE_PATH 指定路径(按添加顺序)
  2. CMake 内置模块路径(如 /usr/share/cmake/Modules

示例:

# 如果存在 FindQt6.cmake(不太可能),就会使用模块模式
find_package(Qt6 REQUIRED)

4.2.3 配置模式(Config Mode)

只有在模块模式失败后才会尝试配置模式,搜索 <PackageName>Config.cmake 文件:

  1. <PackageName>_DIR 变量指定路径
  2. CMAKE_PREFIX_PATH 路径(最重要):
    • <prefix>/
    • <prefix>/cmake/
    • <prefix>/lib/cmake/<PackageName>/
    • <prefix>/lib/<PackageName>/
    • <prefix>/lib/<PackageName>/cmake/
    • <prefix>/share/<PackageName>/
    • <prefix>/share/<PackageName>/cmake/
  3. CMAKE_FRAMEWORK_PATH(macOS 框架)
  4. CMAKE_APPBUNDLE_PATH(macOS App Bundle)
  5. CMAKE_FIND_ROOT_PATH(交叉编译)
  6. 系统默认路径:
    • /usr/lib/cmake/<PackageName>/
    • /usr/local/lib/cmake/<PackageName>/
    • /opt/local/lib/cmake/<PackageName>/
    • Windows: C:/Program Files/<PackageName>/
  7. 环境变量 PATH 路径
  8. 平台注册表(Windows)

4.2.4 强制使用配置模式

可以通过 CONFIG 关键字强制跳过模块模式:

# 强制使用配置模式,跳过 FindQt6.cmake 查找
find_package(Qt6 CONFIG REQUIRED)

# 等价写法
find_package(Qt6 CONFIG REQUIRED COMPONENTS Core Widgets)

4.2.5 Windows 查找 Qt6 实例

假设在 Windows 上安装了 Qt6 到 C:/Qt/6.7.0/msvc2022_64/,执行以下查找:

find_package(Qt6 REQUIRED COMPONENTS Core Widgets)

查找流程:

  1. 检查缓存变量

    检查 CMakeCache.txt 中是否有 Qt6_DIR
    如果有:Qt6_DIR:PATH=C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6
  2. 模块模式(通常 Qt6 不使用此模式)

    查找 FindQt6.cmake:
    - CMAKE_MODULE_PATH 路径
    - C:/Program Files/CMake/share/cmake-3.x/Modules/FindQt6.cmake(不存在)
  3. 配置模式(Qt6 的标准方式)

    查找 Qt6Config.cmake,按以下顺序:

    a) Qt6_DIR 变量指定路径:
    - C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6/Qt6Config.cmake ✓

    b) CMAKE_PREFIX_PATH 路径(如果设置了):
    假设设置了 CMAKE_PREFIX_PATH=C:/Qt/6.7.0/msvc2022_64
    - C:/Qt/6.7.0/msvc2022_64/Qt6Config.cmake
    - C:/Qt/6.7.0/msvc2022_64/cmake/Qt6Config.cmake
    - C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6/Qt6Config.cmake ✓
    - C:/Qt/6.7.0/msvc2022_64/lib/Qt6/Qt6Config.cmake
    - C:/Qt/6.7.0/msvc2022_64/share/Qt6/Qt6Config.cmake

    c) 系统默认路径:
    - C:/Program Files/Qt6/lib/cmake/Qt6/Qt6Config.cmake
    - C:/Program Files (x86)/Qt6/lib/cmake/Qt6/Qt6Config.cmake
    - C:/Qt6/lib/cmake/Qt6/Qt6Config.cmake

    d) 注册表查找:
    - HKEY_CURRENT_USER\Software\Kitware\CMake\Packages\Qt6
    - HKEY_LOCAL_MACHINE\Software\Kitware\CMake\Packages\Qt6

4.2.6 默认搜索的局限性

重要: 如果 Qt 安装在 C:/Qt/ 下(如 C:/Qt/6.7.0/msvc2022_64/),不设置 CMAKE_PREFIX_PATH 通常找不到

原因分析:

  1. CMake 默认搜索路径

    C:/Program Files/Qt6/lib/cmake/Qt6/
    C:/Program Files (x86)/Qt6/lib/cmake/Qt6/
    C:/Qt6/lib/cmake/Qt6/ # 注意:只查找 C:/Qt6,不查找 C:/Qt/
  2. Qt 实际安装路径

    C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6/Qt6Config.cmake # 不在默认搜索路径中
  3. 路径不匹配

    • 默认搜索:C:/Qt6/lib/cmake/Qt6/
    • 实际路径:C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6/
    • 两者不匹配!

测试验证:

# 清除所有前缀路径,仅使用默认搜索
unset(CMAKE_PREFIX_PATH)
unset(CMAKE_PREFIX_PATH CACHE)
unset(Qt6_DIR CACHE)

# 尝试查找 Qt6
find_package(Qt6 COMPONENTS Core)

if(Qt6_FOUND)
message(STATUS "✓ 在默认路径找到 Qt6: ${Qt6_DIR}")
else()
message(WARNING "✗ 默认路径未找到 Qt6")
message(STATUS "需要设置 CMAKE_PREFIX_PATH 或 Qt6_DIR")
endif()

可能的例外情况:

  1. 注册表信息

    如果 Qt 安装程序向注册表写入了路径信息:
    HKEY_LOCAL_MACHINE\Software\Kitware\CMake\Packages\Qt6
  2. 符号链接

    如果存在符号链接:C:/Qt6 -> C:/Qt/6.7.0/msvc2022_64
  3. 环境变量

    如果系统环境变量中设置了相关路径(不常见)

解决方案(按推荐程度排序):

# 方案1:设置前缀路径(推荐)
set(CMAKE_PREFIX_PATH "C:/Qt/6.7.0/msvc2022_64")

# 方案2:直接指定 Qt6 路径
set(Qt6_DIR "C:/Qt/6.7.0/msvc2022_64/lib/cmake/Qt6")

# 方案3:环境变量
# set CMAKE_PREFIX_PATH=C:\Qt\6.7.0\msvc2022_64

# 方案4:命令行参数
# cmake -DCMAKE_PREFIX_PATH="C:/Qt/6.7.0/msvc2022_64" ..

总结: C:/Qt/ 路径下的 Qt 安装需要手动配置路径,CMake 默认搜索机制无法自动找到。

重要提示:

  • CMAKE_PREFIX_PATH 是最常用的配置变量
  • 添加 NO_DEFAULT_PATH 可限制搜索范围
  • CMAKE_FIND_ROOT_PATH 主要用于交叉编译

4.2.7 默认搜索路径(不设置前缀路径时)

如果不手动设置 CMAKE_PREFIX_PATH,CMake 会使用系统默认路径进行搜索:

Linux/Unix 系统:

/usr/
/usr/local/
/opt/
/usr/lib/x86_64-linux-gnu/ (架构相关)
/usr/share/
/usr/local/share/

macOS 系统:

/usr/
/usr/local/
/opt/
/opt/local/ (MacPorts)
/usr/local/Cellar/ (Homebrew)
/Applications/ (应用程序)
/System/Library/Frameworks/ (系统框架)
/Library/Frameworks/ (用户框架)

Windows 系统:

C:/Program Files/
C:/Program Files (x86)/
C:/
注册表路径 (Registry)

常见问题:

  1. 找不到包:如果库安装在非标准路径(如 /opt/Qt6),CMake 在默认路径中找不到,需要设置 CMAKE_PREFIX_PATH

  2. 找到错误版本:系统中安装多个版本时,CMake 可能找到旧版本而不是期望的版本。

验证默认搜索:

# 查看系统默认前缀路径
message(STATUS "CMAKE_SYSTEM_PREFIX_PATH: ${CMAKE_SYSTEM_PREFIX_PATH}")

# 测试不设置前缀路径的查找
unset(CMAKE_PREFIX_PATH)
find_package(Qt6)
if(Qt6_FOUND)
message(STATUS "Found Qt6 in system default paths: ${Qt6_DIR}")
else()
message(WARNING "Qt6 not found in system default paths")
endif()

4.3 find_library

查找指定库文件的路径,当库没有 CMake 配置文件或你只想手动指定库路径时使用。

语法:

find_library(variable_name library_name [PATHS path_list] [REQUIRED] [NO_DEFAULT_PATH])

示例:

find_library(MYLIB_PATH mylib
PATHS /usr/local/lib
REQUIRED
)
target_link_libraries(myapp PRIVATE ${MYLIB_PATH})

4.4 find_path

查找指定文件的目录,返回包含该文件的完整目录路径,可以用于 target_include_directories。

语法:

find_path(variable_name file_name [PATHS path_list] [REQUIRED] [NO_DEFAULT_PATH])

示例:

find_path(MYLIB_INCLUDE_DIR mylib.h
PATHS /usr/local/include
REQUIRED
)
target_include_directories(myapp PRIVATE ${MYLIB_INCLUDE_DIR})

5. 编译配置

5.1 set

设置变量值。

语法:

set(VAR value)

常用预定义变量:

# C++ 标准配置
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 构建类型
set(CMAKE_BUILD_TYPE Release)

# 输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

5.2 target_compile_definitions

target_compile_definitions 用来给目标添加编译宏,在需要条件编译、传递特性标记或调试开关时使用

语法:

target_compile_definitions(target_name [PUBLIC|PRIVATE|INTERFACE] <definition>...)

示例:

# 编译 app 时会定义 USE_FEATURE_X,启用条件代码
target_compile_definitions(app PRIVATE USE_FEATURE_X)

条件编译:

#ifdef USE_FEATURE_X
void featureX() { ... }
#endif

5.3 target_compile_options

用来为目标添加编译器选项。

语法:

target_compile_options(targetName [PUBLIC|PRIVATE|INTERFACE] options...)

示例:

# GCC/Clang 编译选项, -Wall启用一组常用的编译器警告
target_compile_options(myapp
PRIVATE
-Wall
)

6. 安装和导出

6.1 install(TARGETS)

编译生成的可执行文件或库安装到指定目录或打包中,当你需要发布、共享或正式部署目标文件时使用

语法:

install(TARGETS target1 target2 ...
[RUNTIME DESTINATION <dir>]
[LIBRARY DESTINATION <dir>]
[ARCHIVE DESTINATION <dir>]
[BUNDLE DESTINATION <dir>]
)

参数说明:

  • RUNTIME DESTINATION: 可执行文件安装路径
  • LIBRARY DESTINATION: 动态库安装路径
  • ARCHIVE DESTINATION: 静态库安装路径
  • BUNDLE DESTINATION: macOS 应用包安装路径

示例:

install(TARGETS myapp
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

6.2 install(FILES)

用来把指定的文件直接安装到目标目录,和 install(TARGETS ...) 不同,它不是安装编译生成的目标,而是安装已有文件(比如头文件、配置文件、资源文件等)。

语法:

install(FILES file1 file2 ... DESTINATION path)

示例:

install(FILES
${CMAKE_SOURCE_DIR}/config/config.json
${CMAKE_SOURCE_DIR}/README.md
DESTINATION share/myapp
)

7. 控制流程

7.1 if/elseif/else/endif

条件控制语句。

语法:

if(condition)
# commands
elseif(condition)
# commands
else()
# commands
endif()

常用条件:

# 平台检测
if(WIN32)
message("Building on Windows")
elseif(APPLE)
message("Building on macOS")
elseif(UNIX)
message("Building on Linux/Unix")
endif()

# 变量检测
if(DEFINED MY_VARIABLE)
message("MY_VARIABLE is defined")
endif()

# 字符串比较
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DDEBUG_BUILD)
endif()

7.2 option

用来定义布尔开关,让用户选择开启或关闭某个功能,编译流程可根据这个开关灵活控制。

语法:

option(OptionName "description" [ON|OFF])

示例:

option(BUILD_TESTS "Build unit tests" ON)

if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
#CMake 的 option() 定义的开关,用户可以 在命令行配置项目时指定 ON 或 OFF,从而控制编译流程
cmake -S . -B build -DBUILD_TESTS=OFF

8. 实用工具

8.1 add_subdirectory

用来将另一个子目录加入到当前构建中,并处理该子目录下的 CMakeLists.txt。 换句话说,它让你可以组织项目为多个模块或子项目,并把它们编译到同一个构建中。

语法:

add_subdirectory(path)

示例:

假设项目结构:

project_root/
├── CMakeLists.txt
├── src/
│ └── main.cpp
└── tests/
└── CMakeLists.txt
└── test_main.cpp

主 CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
project(MyApp)

add_executable(myapp src/main.cpp)

option(BUILD_TESTS "Build unit tests" ON)

if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif()

8.2 include

包含外部 CMake 脚本文件。

语法:

include(path/to/file.cmake)

8.3 message

输出信息到控制台。

语法:

message([level] "text")

级别说明:

  • STATUS: 状态信息(绿色)
  • WARNING: 警告信息(黄色)
  • FATAL_ERROR: 致命错误(红色,停止构建)

示例:

message(STATUS "Configuring project ${PROJECT_NAME}")
message(WARNING "This feature is deprecated")
message(FATAL_ERROR "Required dependency not found")

9. Qt 特有配置

9.1 自动化工具

set(CMAKE_AUTOMOC ON) # 自动处理 MOC(Meta-Object Compiler)
set(CMAKE_AUTORCC ON) # 自动处理资源文件(.qrc)
set(CMAKE_AUTOUIC ON) # 自动处理界面文件(.ui)

功能说明:

  • CMAKE_AUTOMOC: 自动为包含 Q_OBJECT 宏的类生成 moc 文件
  • CMAKE_AUTORCC: 自动编译 .qrc 资源文件为 C++ 代码
  • CMAKE_AUTOUIC: 自动将 .ui 界面文件转换为头文件

9.2 qt_standard_project_setup()

Qt 6 推荐的项目设置函数,内部已包含上述自动化配置。

语法:

qt_standard_project_setup(REQUIRES 6.5)

10. 完整示例

10.1 Python 扩展模块(.pyd)

cmake_minimum_required(VERSION 3.16)
project(QComposer VERSION 0.1 LANGUAGES CXX)

# C++ 标准配置
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 项目路径配置
set(PROJECT_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/..)

# Conda 环境配置
if(DEFINED ENV{CONDA_PREFIX})
list(PREPEND CMAKE_PREFIX_PATH "$ENV{CONDA_PREFIX}")
endif()

# 常见的前缀路径自动检测
if(DEFINED ENV{VCPKG_ROOT})
list(APPEND CMAKE_PREFIX_PATH "$ENV{VCPKG_ROOT}/installed/${VCPKG_TARGET_TRIPLET}")
endif()

if(DEFINED ENV{Qt6_DIR})
list(APPEND CMAKE_PREFIX_PATH "$ENV{Qt6_DIR}")
endif()

# 查找依赖
find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)
find_package(Qt6 REQUIRED COMPONENTS Quick QuickControls2)
find_package(pybind11 REQUIRED)

# Qt 标准配置
qt_standard_project_setup(REQUIRES 6.5)

# 收集源文件
file(GLOB_RECURSE SOURCES ${PROJECT_ROOT_DIR}/src/*.cpp)

# 添加资源
qt_add_resources(RESOURCES ${PROJECT_ROOT_DIR}/src/resources.qrc)

# 创建 Python 模块
pybind11_add_module(QComposer
${PROJECT_ROOT_DIR}/python-module/binding.cpp
${SOURCES}
${RESOURCES}
)

# 配置包含目录
target_include_directories(QComposer
PRIVATE ${PROJECT_ROOT_DIR}
)

# 链接库
target_link_libraries(QComposer
PRIVATE
Qt6::Quick
Qt6::Gui
Qt6::QuickControls2
)

# 设置输出属性
set_target_properties(QComposer PROPERTIES
OUTPUT_NAME "QComposer"
PREFIX ""
SUFFIX ".pyd"
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}
)

10.2 Qt 桌面应用程序

cmake_minimum_required(VERSION 3.16)
project(QComposer VERSION 0.1 LANGUAGES CXX)

# C++ 标准配置
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 查找 Qt6
find_package(Qt6 REQUIRED COMPONENTS Quick QuickControls2)

# Qt 标准配置
qt_standard_project_setup(REQUIRES 6.5)

# 收集源文件
file(GLOB_RECURSE SOURCES src/*.cpp src/*.h)

# 创建可执行程序
qt_add_executable(QComposer
src/app/main.cpp
${CMAKE_SOURCE_DIR}/Resources/icon.png
)

# 添加 QML 模块
qt_add_qml_module(QComposer
URI QComposer
VERSION 1.0
SOURCES ${SOURCES}
RESOURCES src/resources.qrc
)

# 设置程序属性
set_target_properties(QComposer PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE_ICON_FILE icon.png
WIN32_EXECUTABLE TRUE
)

# 配置资源文件位置(macOS)
set_source_files_properties(${CMAKE_SOURCE_DIR}/Resources/icon.png
PROPERTIES MACOSX_PACKAGE_LOCATION "Resources"
)

# 链接库
target_link_libraries(QComposer
PRIVATE
Qt6::Quick
Qt6::Gui
Qt6::QuickControls2
)

# 安装规则
install(TARGETS QComposer BUNDLE DESTINATION .)

11. 总结

本文档涵盖了 CMake 的核心命令和最佳实践。在实际使用中,建议:

  1. 从简单开始: 先掌握基础命令,再学习高级特性
  2. 使用现代 CMake: 优先使用 target_* 系列命令
  3. 保持一致性: 统一代码风格和项目结构
  4. 合理组织: 将复杂项目拆分为多个 CMakeLists.txt
  5. 版本管理: 明确指定最低 CMake 版本和依赖版本

通过掌握这些命令,你可以构建从简单到复杂的各种项目。