蔚淦丞
发布于 2026-09-22 / 2 阅读
0
0

cmake语法清单

基础模板

cmake_minimum_required(VERSION 3.14)   # 最低cmake版本,必须放最开头
project(demo LANGUAGES CXX C)          # 项目名,指定语言
set(CMAKE_CXX_STANDARD 17)              # c++标准
set(CMAKE_CXX_STANDARD_REQUIRED ON)    # 强制要求,不回退
set(CMAKE_CXX_EXTENSIONS OFF)          # 关闭编译器扩展(-std=c++17而不是gnu++17)

set 变量

set(VAR "hello")                       #普通变量
set(SRC_LIST src/a.cpp src/b.cpp)      #源文件列表,空格分割
set(VAR ${VAR} "append")               #追加内容
message(STATUS "打印变量: ${VAR}")      #打印日志
# 布尔变量 ON/OFF
set(ENABLE_TEST ON CACHE BOOL "是否开启单元测试")

路径相关

${PROJECT_SOURCE_DIR}     #项目根目录(CMakeLists.txt所在顶层)
${CMAKE_SOURCE_DIR}       #最顶层项目目录,submodule也不变
${CMAKE_CURRENT_SOURCE_DIR} #当前CMakeLists.txt所在目录
${CMAKE_BINARY_DIR}       #构建输出目录build/
${PROJECT_BINARY_DIR}

#头文件路径,只是告诉编译器-I,不会编译文件
include_directories(include)

#推荐现代写法 target_include_directories,作用域绑定目标
target_include_directories(target_name
    PUBLIC include
    PRIVATE src
    INTERFACE public_api
)

PUBLIC:自己用,依赖我的项目也会继承该头文件路径 PRIVATE:仅当前目标内部使用,对外不暴露 INTERFACE:我不用,依赖我的目标需要

编译目标 add_executable /add_library

#可执行程序
add_executable(main src/main.cpp)

#静态库 *.a
add_library(mylib STATIC ${SRC_LIST})
#动态库 *.so
add_library(mylib SHARED ${SRC_LIST})
#对象库,只编译不归档,多个目标复用编译产物
add_library(objlib OBJECT src/x.cpp)
target_link_libraries(main
    PRIVATE mylib pthread
)
#系统库直接写名字,pthread dl rt

Git Submodule 引入外部库

#如果submodule没拉取,提示
find_git_submodules()
add_subdirectory(extern/mempool-cpp) #把子项目加入构建
#然后直接链接
target_link_libraries(main PRIVATE mempool)

子项目内部必须自己写 CMakeLists.txt 对外暴露库目标。

条件判断 if‑else

if(ENABLE_TEST)
    message(STATUS "编译测试")
else()
    message(STATUS "关闭测试")
endif()

if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
endif()

#逻辑运算符 AND OR NOT
if(WIN32)
elseif(UNIX AND NOT APPLE) #Linux
endif()

常用平台变量:WIN32UNIXAPPLE

编译选项 flags

#全局,不推荐
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")

#现代:仅给单个目标设置编译选项
target_compile_options(mytarget
    PRIVATE
        -Wall
        -Wextra
)

#定义宏,代码里#ifdef使用
target_compile_definitions(mytarget
    PRIVATE
        DEBUG_LOG=1
)

单元测试 enable_testing

enable_testing() #必须放在顶层

add_executable(test_demo tests/test.cpp)
target_link_libraries(test_demo PRIVATE mylib)
add_test(NAME test_demo COMMAND test_demo)

构建后执行:ctest

文件查找

#递归搜集所有cpp,简单项目用,大项目不推荐
file(GLOB_RECURSE SRC_FILES src/*.cpp)

install 安装

install(TARGETS mylib main
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)
install(DIRECTORY include/ DESTINATION include)

常用构建类型

cmake -DCMAKE_BUILD_TYPE=Debug ..
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo .. #release + g调试符号,开发最推荐

作用域重点(高频踩坑)

  1. include_directories / add_definitions 全局,影响之后所有目标,旧写法。

  2. target_xxx系列:target_include_directories / target_link_libraries / target_compile_options,绑定具体 target,有 PUBLIC/PRIVATE/INTERFACE,优先使用。

常用命令行

mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -j$(nproc)
ctest

子目录 add_subdirectory

project/
├── CMakeLists.txt
└── src/
    └── CMakeLists.txt

顶层:add_subdirectory(src),子目录 CMakeLists 构建库。子目录定义的 target 可以在上层直接链接。

简单完整示例模板

cmake_minimum_required(VERSION 3.14)
namespace(file‑vault‑cpp LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(extern/mempool‑cpp)

file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
add_library(vault_lib STATIC ${LIB_SOURCES})
target_include_directories(vault_lib PUBLIC include)
target_link_libraries(vault_lib PUBLIC mempool pthread)

add_executable(server src/main_server.cpp)
target_link_libraries(server PRIVATE vault_lib)

option(BUILD_TEST "build test" ON)
if(BUILD_TEST)
  enable_testing()
  add_executable(test_app tests/test.cpp)
  target_link_libraries(test_app PRIVATE vault_lib)
  add_test(NAME all_test COMMAND test_app)
endif()

踩坑清单

  1. ${}取值,不加 ${} 代表变量名本身。

  2. add_subdirectory(submodule)前要 git submodule update 拉取代码,否则目录为空报错。

  3. CMAKE_CXX_STANDARD 只对目标生效,旧编译器不要写-std=c++17放到 flags,优先 set 标准变量。

  4. GLOB 不会监控文件新增删除,新增源文件需要重新执行 cmake。

  5. PUBLIC/PRIVATE 搞反会出现头文件找不到,链接外部库一般 PRIVATE。

  6. 字符串比较要用STREQUALif(VAR == "xxx")是旧 cmake 扩展。

  7. 不要混用全局 include_directories,尽量全部 target_include_directories。


评论