CMake 核心知识点总结——从基础语法到现代 CMake 的常用命令与最佳实践
目录CMake 知识点总结1. CMake 是什么2. CMake 工作流程配置Configure构建Build清理3. 基本语法注释定义变量使用变量输出信息4. 常用内置变量项目目录当前目录编译器操作系统5. 项目管理project()cmake_minimum_required()add_subdirectory()6. 源文件管理aux_source_directory()file()推荐方式7. 生成目标Target可执行程序静态库动态库OBJECT库INTERFACE库8. 头文件管理传统写法现代写法三种作用域PRIVATEPUBLICINTERFACE9. 链接库传统写法现代写法链接多个库10. 编译选项添加编译参数指定标准全局推荐11. 宏定义添加宏推荐12. 输出目录可执行程序库现代写法13. 条件判断if判断变量字符串比较判断文件存在判断系统14. 循环foreachwhile15. 自定义函数与宏functionmacro区别16. 查找第三方库find_package()17. 安装规则install()18. 构建类型DebugRelease查看当前类型现代 CMake 最重要的理念CMake 知识点总结1. CMake 是什么CMake 是一个跨平台构建系统生成工具Build System Generator。它本身不负责编译代码而是根据CMakeLists.txt生成MakefileNinjaVisual Studio 工程Xcode 工程然后再由对应构建工具完成编译和链接。2. CMake 工作流程配置Configurecmake-S.-Bbuild作用读取所有CMakeLists.txt解析变量检查编译器生成构建系统文件例如Makefile build.ninja Visual Studio Solution构建Buildcmake--buildbuild作用编译源文件生成目标文件生成库生成可执行程序清理删除构建目录即可rm-rfbuild3. 基本语法注释# 单行注释定义变量set(VAR_NAME value)例如set(APP_NAME demo)使用变量${VAR_NAME}例如message(${APP_NAME})输出信息message(Hello CMake)message(STATUS Build Start)常见等级STATUS WARNING FATAL_ERROR例如message(FATAL_ERROR Compiler Not Found)4. 常用内置变量项目目录当前项目根目录PROJECT_SOURCE_DIR当前构建目录PROJECT_BINARY_DIR当前目录当前CMakeLists.txt所在目录CMAKE_CURRENT_SOURCE_DIR当前目录对应的构建目录CMAKE_CURRENT_BINARY_DIR编译器C 编译器CMAKE_CXX_COMPILERC 编译器CMAKE_C_COMPILER操作系统WIN32 UNIX APPLE示例if(WIN32) message(Windows) endif()5. 项目管理project()定义项目project(MyProject)指定语言project( MyProject LANGUAGES C CXX )cmake_minimum_required()指定最低版本cmake_minimum_required(VERSION 3.15)add_subdirectory()添加子模块add_subdirectory(src) add_subdirectory(test)作用进入子目录执行子目录中的CMakeLists.txt6. 源文件管理aux_source_directory()收集目录下源文件aux_source_directory(. SRC)等价于SRC a.cpp b.cpp c.cppfile()现代项目更常用file(GLOB SRC *.cpp)递归搜索file(GLOB_RECURSE SRC *.cpp)推荐方式显式列出源文件set(SRC main.cpp test.cpp util.cpp )优点可读性好IDE 支持更完善文件变化不会漏掉7. 生成目标TargetCMake 的核心思想一切围绕 Target目标进行。目标主要分两类可执行程序add_executable(app main.cpp)生成app静态库add_library(math STATIC math.cpp)Linuxlibmath.aWindowsmath.lib动态库add_library(math SHARED math.cpp)Linuxlibmath.soWindowsmath.dllOBJECT库只编译不打包add_library(core OBJECT a.cpp b.cpp)常用于大型项目。INTERFACE库纯接口库add_library(common INTERFACE)不生成实际文件。仅传播头文件路径编译选项宏定义8. 头文件管理传统写法include_directories(include)全局生效。现代写法target_include_directories( app PRIVATE include )三种作用域PRIVATE仅当前目标使用PRIVATEPUBLIC自己使用且传播给依赖者PUBLICINTERFACE自己不用只给依赖者INTERFACE9. 链接库传统写法link_directories(lib) link_libraries(math)现代写法target_link_libraries( app PRIVATE math )推荐使用。链接多个库target_link_libraries( app PRIVATE math network database )10. 编译选项添加编译参数target_compile_options( app PRIVATE -Wall -Wextra )指定标准全局set(CMAKE_CXX_STANDARD 17)推荐target_compile_features( app PRIVATE cxx_std_17 )11. 宏定义添加宏add_definitions(-DDEBUG)推荐target_compile_definitions( app PRIVATE DEBUG )代码中#ifdefDEBUG#endif12. 输出目录可执行程序set(EXECUTABLE_OUTPUT_PATH bin)库set(LIBRARY_OUTPUT_PATH lib)现代写法set_target_properties( app PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin )13. 条件判断ifif(condition) endif()判断变量if(VAR) endif()字符串比较if(VAR STREQUAL Debug) endif()判断文件存在if(EXISTS file.txt) endif()判断系统if(WIN32) endif() if(UNIX) endif() if(APPLE) endif()14. 循环foreachforeach(item a b c) message(${item}) endforeach()whilewhile(VAR LESS 10) endwhile()15. 自定义函数与宏function有作用域function(print_name name) message(${name}) endfunction()调用print_name(Tom)macro无独立作用域macro(print_name name) message(${name}) endmacro()区别项目functionmacro独立作用域✔✘修改外部变量✘✔推荐程度✔一般16. 查找第三方库find_package()现代项目最重要命令之一。例如find_package(Threads REQUIRED)使用target_link_libraries( app PRIVATE Threads::Threads )查找 Boostfind_package(Boost REQUIRED)查找 Protobuffind_package(Protobuf REQUIRED)17. 安装规则install()安装可执行程序install( TARGETS app DESTINATION bin )安装头文件install( DIRECTORY include/ DESTINATION include )执行cmake--installbuild18. 构建类型Debugcmake-DCMAKE_BUILD_TYPEDebug..特点调试信息无优化Releasecmake-DCMAKE_BUILD_TYPERelease..特点开启优化去除调试信息查看当前类型message(${CMAKE_BUILD_TYPE})现代 CMake 最重要的理念现代 CMake 推荐add_library(calc ...) target_include_directories(calc PUBLIC include) add_executable(app main.cpp) target_link_libraries(app PRIVATE calc)避免include_directories(...) link_directories(...) link_libraries(...)核心思想不再配置“全局环境”而是配置“目标(Target)”。