Tianya
发布于 2026-07-24 / 1 阅读
0
0

CMake基本使用

1. CMake工程

1.1 基本CMake工程

  1. CMake
# CMake最低版本
cmake_minimum_required(VERSION 3.21)

# 工程名、版本号、工程描述
project(FlyShearSim
        VERSION 0.1
        DESCRIPTION "Test")

# C/C++ 标准版本
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)

# 指定在当前目录或以下目录下通过命令(如 add_executable() )链接稍后创建的任何目标时要使用的库或标志
LINK_LIBRARIES(m)

# 工程源文件
add_executable(${PROJECT_NAME}
               ./Src/main.c
               ./Src/FlyingShear.c)

# 工程包含目录
include_directories(./Inc)
  1. 工程目录结构
.
├── CMakeLists.txt
├── Inc
│   ├── FlyingShear.h
│   └── main.h
└── Src
    ├── FlyingShear.c
    └── main.c

1.2. 多模块CMake工程

1.3. CMakePresets.json

# ===== 基本系统信息 =====
set(CMAKE_SYSTEM_NAME               Generic)          # 设置目标系统名称为 "Generic"(裸机或无操作系统)
set(CMAKE_SYSTEM_PROCESSOR          arm)              # 设置目标处理器架构为 ARM

# ===== 编译器标识(可省略,此处手动声明) =====
set(CMAKE_C_COMPILER_ID GNU)                         # 声明 C 编译器 ID 为 GNU(GCC)
set(CMAKE_CXX_COMPILER_ID GNU)                       # 声明 C++ 编译器 ID 为 GNU(G++)

# ===== 工具链前缀与可执行文件路径 =====
# 注意:arm-none-eabi- 的 bin 目录必须在 PATH 环境变量中,或使用绝对路径
set(TOOLCHAIN_PREFIX                E:/sofeWare/GCC/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-)  # 定义工具链的可执行文件前缀(含完整路径)

set(CMAKE_C_COMPILER                ${TOOLCHAIN_PREFIX}gcc.exe)             # 指定 C 编译器
set(CMAKE_ASM_COMPILER              ${CMAKE_C_COMPILER})                    # 汇编编译器与 C 编译器相同(GCC 支持汇编)
set(CMAKE_CXX_COMPILER              ${TOOLCHAIN_PREFIX}g++.exe)             # 指定 C++ 编译器
set(CMAKE_LINKER                    ${TOOLCHAIN_PREFIX}g++.exe)             # 链接器使用 g++(可以链接 C++ 标准库,也可用 ld)
set(CMAKE_OBJCOPY                   ${TOOLCHAIN_PREFIX}objcopy.exe)         # 指定 objcopy 工具(用于格式转换,如生成 hex/bin)
set(CMAKE_SIZE                      ${TOOLCHAIN_PREFIX}size.exe)            # 指定 size 工具(查看段大小)
set(CMAKE_OBJDUMP                   ${TOOLCHAIN_PREFIX}objdump.exe)         # 指定 objdump 工具(反汇编等)
set(CMAKE_NM                        ${TOOLCHAIN_PREFIX}nm.exe)              # 指定 nm 工具(列出符号)

# ===== 可执行文件后缀 =====
set(CMAKE_EXECUTABLE_SUFFIX_ASM     ".elf")          # 汇编源文件构建的可执行文件后缀设为 .elf
set(CMAKE_EXECUTABLE_SUFFIX_C       ".elf")          # C 源文件构建的可执行文件后缀设为 .elf
set(CMAKE_EXECUTABLE_SUFFIX_CXX     ".elf")          # C++ 源文件构建的可执行文件后缀设为 .elf

# ===== 交叉编译检测设置 =====
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)    # 告诉 CMake 在探测编译器能力时,构建静态库而非可执行文件(因为裸机无法直接运行)

# ===== MCU 特定编译标志 =====
set(TARGET_FLAGS "-mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard ")  # 定义目标 MCU 的 CPU、FPU 和浮点 ABI 选项

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${TARGET_FLAGS}")                   # 将 MCU 标志追加到 C 编译标志
set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -MMD -MP")  # 汇编标志:继承 C 标志,并添加汇编预处理器支持和自动生成依赖文件
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fdata-sections -ffunction-sections")  # 添加警告和分节编译选项(便于链接时 --gc-sections 优化)

# ===== Debug 与 Release 模式标志 =====
set(CMAKE_C_FLAGS_DEBUG "-O0 -g3")                 # Debug 模式下:无优化,最高调试信息级别
set(CMAKE_C_FLAGS_RELEASE "-Os -g0")               # Release 模式下:体积优化,无调试信息
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g3")               # C++ Debug 标志
set(CMAKE_CXX_FLAGS_RELEASE "-Os -g0")             # C++ Release 标志

# ===== C++ 专用编译标志 =====
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics")  # C++ 标志:继承 C 标志,并禁用 RTTI、异常和线程安全的静态变量

# ===== 链接标志 =====
set(CMAKE_EXE_LINKER_FLAGS "${TARGET_FLAGS}")                                          # 设置链接器基础标志(与编译标志相同的 MCU 选项)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -T \"${CMAKE_SOURCE_DIR}/gd32h7xx_flash.ld\"")  # 指定链接脚本路径(注意:此处需要根据实际芯片更改链接脚本)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --specs=nano.specs")             # 使用 newlib-nano 库规格,减少库体积
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=${CMAKE_PROJECT_NAME}.map -Wl,--gc-sections")  # 生成 map 文件,并启用未用段的垃圾回收
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--print-memory-usage")       # 链接时打印内存使用信息

# ===== 链接库 =====
set(TOOLCHAIN_LINK_LIBRARIES "m")                  # 指定要链接的库(这里为数学库 libm)
{                                                    // 根对象开始:CMakePresets 的顶层结构
    "version": 3,                                    // 指定预设文件的架构版本(必须为 3)。版本 3 支持 buildPresets 和 testPresets
    "configurePresets": [                            // 定义配置预设数组,每个对象描述一套配置选项
        {
            "name": "default",                       // 该预设的名称(必须唯一)。这里命名为 "default"
            "hidden": true,                          // 标记此预设为隐藏,不会直接显示给用户(通常作为基础预设被其他预设继承)
            "generator": "Ninja",                    // 指定构建系统生成器(Ninja、Unix Makefiles 等)
            "binaryDir": "${sourceDir}/build/${presetName}", // 设置构建目录,宏变量支持:${sourceDir} 源码根目录,${presetName} 预设名称,最终为 "源码目录/build/default"
            "toolchainFile": "${sourceDir}/Configs/gcc-arm-none-eabi.cmake", // 指定工具链文件路径,用于交叉编译(这里是 ARM GCC 工具链)
            "cacheVariables": {                      // 定义 CMake 缓存变量(此处为空对象,未设置额外变量)
            }
        },
        {
            "name": "Debug",                         // 配置预设 "Debug"
            "inherits": "default",                   // 继承 "default" 预设的所有属性,可在此基础上覆盖或添加
            "cacheVariables": {                      // 该预设的缓存变量
                "CMAKE_BUILD_TYPE": "Debug"          // 设置构建类型为 Debug(包含调试符号,未优化)
            }
        },
        {
            "name": "Release",                       // 配置预设 "Release"
            "inherits": "default",                   // 同样继承 "default"
            "cacheVariables": {
                "CMAKE_BUILD_TYPE": "Release"        // 设置构建类型为 Release(优化,无调试符号)
            }
        }
    ],
    "buildPresets": [                                // 定义构建预设数组,与 configurePresets 关联
        {
            "name": "Debug",                         // 构建预设 "Debug"
            "configurePreset": "Debug"               // 关联到同名的配置预设 "Debug"
        },
        {
            "name": "Release",                       // 构建预设 "Release"
            "configurePreset": "Release"             // 关联到同名的配置预设 "Release"
        }
    ]
}                                                    // 根对象结束

2. CMake其他功能

2.1. CMake自定义指令

add_custom_command 是 CMake 中用来向构建系统添加自定义构建规则的命令。它主要有两种用法:生成文件(OUTPUT) 和 目标触发(TARGET)。

  1. 生成文件模式

用于描述如何生成一个或多个输出文件。它与其他构建规则一样,只有当输出文件被某个 target 依赖时才会执行。

add_custom_command(                            # 开始定义一条自定义命令(生成文件模式)
    OUTPUT  output1 [output2 ...]              # 【必需】指定命令要生成的一个或多个输出文件。构建系统以此文件名判断命令是否需要执行。
    COMMAND command1 [ARGS] [args1...]         # 【必需】定义要执行的第一条命令(可带参数)。方括号内 ARGS 是旧式占位符,直接写实际参数即可。
    [COMMAND command2 [ARGS] [args2...] ...]   # 【可选】定义后续命令,按书写顺序依次执行。支持多条 COMMAND。
    [MAIN_DEPENDENCY depend]                   # 【可选】为 IDE(如 Visual Studio)指定一个“主要依赖”文件,用于在工程树上定位源文件。
    [DEPENDS [depends...]]                     # 【可选】声明该命令的依赖文件或 CMake 目标。当任何依赖发生变化时,命令会重新执行。
    [BYPRODUCTS [files...]]                   # 【可选】声明命令产生的“副产品”文件。它们不是输出,但构建工具(Ninja)需要知道,以正确推断依赖。
    [IMPLICIT_DEPENDS <lang1> depend1 ...]     # 【可选】要求扫描指定语言文件的隐式依赖(如 C 文件的 #include),自动添加为依赖。
    [WORKING_DIRECTORY dir]                    # 【可选】设置命令执行时的工作目录。
    [COMMENT "comment"]                        # 【可选】构建期间显示的说明文字,会在执行命令前打印。
    [DEPFILE depfile]                          # 【可选】指定一个 .d 格式的依赖文件(通常由命令自身生成),用于动态发现依赖关系。
    [JOB_POOL pool]                            # 【可选】将该命令放入指定的作业池(与 Ninja 的 job pool 配合),控制并发执行数量。
    [VERBATIM] [APPEND] [USES_TERMINAL]        # 【可选标志】VERBATIM:对命令参数进行正确的跨平台转义(强烈推荐);APPEND:向已存在的 OUTPUT 自定义命令追加 COMMAND;USES_TERMINAL:命令需要连接到终端。
    [COMMAND_EXPAND_LISTS]                     # 【可选】若命令参数是列表变量,则将其展开为多个独立的参数,而非整体作为一个参数。
)                                              # 结束自定义命令的定义
  1. 目标触发模式

附加到一个现有 target(如可执行文件或库),在 target 构建的某个阶段执行额外命令。不产生输出文件,仅用于副作用。

add_custom_command(                            # 开始定义一条自定义命令(目标触发模式)
    TARGET <target>                            # 【必需】指定要挂载自定义命令的 CMake 目标名(如可执行文件、库)。
    PRE_BUILD | PRE_LINK | POST_BUILD         # 【必需】选择命令的触发阶段:PRE_BUILD(构建前)、PRE_LINK(编译后链接前)、POST_BUILD(链接后)。
    COMMAND command1 [ARGS] [args1...]         # 【必需】定义要执行的第一条命令。ARGS 是旧式占位符,实际使用时直接写命令和参数即可。
    [COMMAND command2 [ARGS] [args2...] ...]   # 【可选】定义后续命令,按书写顺序依次执行。支持多条。
    [BYPRODUCTS [files...]]                   # 【可选】声明命令产生的“副产品”文件,让构建工具(如 Ninja)正确处理依赖。
    [WORKING_DIRECTORY dir]                    # 【可选】设置命令执行时的工作目录。
    [COMMENT "comment"]                        # 【可选】构建时打印的说明信息。
    [VERBATIM] [USES_TERMINAL]                # 【可选标志】VERBATIM:跨平台正确转义参数(强烈推荐);USES_TERMINAL:命令需要与终端交互。
    [COMMAND_EXPAND_LISTS]                     # 【可选】若命令参数是列表变量,则将其展开为多个独立参数,而不是当做一个整体。
)                                              # 结束定义

2.1.1. 反汇编

# 构建后反汇编
add_custom_command(
  TARGET ${CMAKE_PROJECT_NAME}
  POST_BUILD
  COMMAND ${CMAKE_OBJDUMP} -d -S $<TARGET_FILE:${CMAKE_PROJECT_NAME}> > ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.asm
  COMMENT "反汇编中..."
  VERBATIM
)

2.1.2. elf转bin/Hex

# 构建后输出Hex和bin
add_custom_command(
  TARGET ${CMAKE_PROJECT_NAME}
  POST_BUILD
  COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.hex
  COMMENT "输出Hex文件..."
  VERBATIM
)
add_custom_command(
  TARGET ${CMAKE_PROJECT_NAME}
  POST_BUILD
  COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin
  COMMENT "输出Bin文件..."
  VERBATIM
)

2.1.3. 构建后导出符号表

# 构建后导出符号表
add_custom_command(
  TARGET ${CMAKE_PROJECT_NAME}
  POST_BUILD
  COMMAND ${CMAKE_NM} -n $<TARGET_FILE:${CMAKE_PROJECT_NAME}> > ${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}_symbol_table.txt
  COMMENT "导出符号表中..."
  VERBATIM
)

2.1.4. 编译着色器

cmake_minimum_required(VERSION 3.10)

project(Shader)

# 查找 glslc 编译器
set(GLSLC ${CMAKE_SOURCE_DIR}/glslc/bin/glslc.exe)

# 定义着色器文件列表
set(SHADER_FILES
    shader.vert
    shader.frag
)

if(WIN32)
    # Windows平台特定的设置
    set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}/BIN/$<CONFIGURATION>/WIN32")
elseif(APPLE)
    # Apple平台特定的设置
    set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}/BIN/$<CONFIGURATION>/APPLE")
elseif(UNIX) # 注意:Linux和macOS都满足UNIX为TRUE,所以通常先判断APPLE
    # Linux或其他类Unix系统的设置
    set(CMAKE_BINARY_DIR "${CMAKE_SOURCE_DIR}/BIN/$<CONFIGURATION>/UNIX")
endif()

# 遍历所有着色器,编译为 .spv 文件
foreach(SHADER ${SHADER_FILES})
    # 输出文件路径(放在 build/shaders 目录)
    set(SPIRV "${CMAKE_BINARY_DIR}/shaders/${SHADER}.spv")
    # 创建输出目录
    add_custom_command(
        OUTPUT ${SPIRV}
        COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/shaders/"
        # 调用 glslc 编译
        COMMAND ${GLSLC} ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER} -o ${SPIRV}
        DEPENDS ${SHADER}  # 依赖源文件,源文件修改后自动重新编译
        COMMENT "Compiling ${SHADER} to SPIR-V"
    )
    # 添加到构建目标
    list(APPEND SPIRV_FILES ${SPIRV})
endforeach()

# 创建一个目标,确保着色器在项目构建时被编译
add_custom_target(Shaders ALL DEPENDS ${SPIRV_FILES})

评论