【CMake入门】

常用函数

  • cmake_minimum_required(VERSION 3.10):指定CMake的最小版本

  • project

    bash 复制代码
    cmake_minimum_required(VERSION 3.10)
    project(
        MyGame
        LANGUAGES CXX  # 仅支持 C++
        DESCRIPTION "3D open-world game engine"  # 项目描述
        VERSION 1.2.3  # 版本号:主版本1,次版本2,补丁3
    )
    
    # 引用自动定义的版本变量
    message(STATUS "Project version: ${PROJECT_VERSION}")  # 输出:Project version: 1.2.3
    add_executable(game main.cpp)
  • add_executable():用于在项目中添加一个可执行文件的目标

    cpp 复制代码
    add_executable(demo demo.cpp)
  • add_library(<静态库目标名> STATIC <源文件位置>):生成静态库

  • add_library(<动态库目标名> SHARED <源文件位置>):生成动态库

  • set:设置变量的值

    cpp 复制代码
    set(far "hello")
    ${far}
    
    set(CMAKE_CXX_STANDARD 11)
  • message:用于在cmake中打印相应的信息

    • mode 用于指定输出消息的模式,常用的模式如下
      • STATUS:以普通信息的形式输出。
      • WARNING:以警告信息的形式输出。
      • AUTHOR_WARNING:以作者警告信息的形式输出。
      • SEND_ERROR:以错误信息的形式输出,并停止构建过程,
      • FATAL_ERROR:以致命错误信息的形式输出,并立即终止构建过程。
    cpp 复制代码
    set(PROJECT_NAME "MyApp")
    
    # 打印项目名称和版本
    message(STATUS "Project Name: ${PROJECT_NAME}")  # 输出:-- Project Name: MyApp
    
    if(CMAKE_BUILD_TYPE STREQUAL "Debug")
        message(WARNING "Debug mode is enabled; performance may be reduced")
        # 输出:CMake Warning at CMakeLists.txt:5 (message): Debug mode is enabled; performance may be reduced
    endif()
    
    if(NOT CMAKE_CXX_STANDARD GREATER_EQUAL 11)
        message(SEND_ERROR "C++11 or higher is required")
        # 输出:CMake Error at CMakeLists.txt:8 (message): C++11 or higher is required
    endif()
    
    if(NOT EXISTS "${CMAKE_SOURCE_DIR}/src/main.cpp")
        message(FATAL_ERROR "Main source file not found: src/main.cpp")
        # 输出:CMake Error at CMakeLists.txt:11 (message): Main source file not found: src/main.cpp
        # 终止配置,后续命令不再执行
    endif()
  • get_filename_component:用于对文件路径解析,从而提取文件名、目录、扩展名等

    cpp 复制代码
    # 解析文件路径的目录部分
    get_filename_component(DIR_PATH "/home/user/project/src/main.cpp" PATH)
    message(STATUS "目录路径: ${DIR_PATH}")  # 输出:目录路径: /home/user/project/src
    
    # 提取包含扩展名的完整文件名
    get_filename_component(FILE_NAME "/home/user/project/src/main.cpp" NAME)
    message(STATUS "完整文件名: ${FILE_NAME}")  # 输出:完整文件名: main.cpp
    
    # 提取文件名(去除扩展名)
    get_filename_component(FILE_NAME_WE "/home/user/project/src/main.cpp" NAME_WE)
    message(STATUS "文件名(无扩展名): ${FILE_NAME_WE}")  # 输出:文件名(无扩展名): main
    
    # 提取文件扩展名(含点号)
    get_filename_component(FILE_EXT "/home/user/project/src/main.cpp" EXT)
    message(STATUS "扩展名: ${FILE_EXT}")  # 输出:扩展名: .cpp
    
    # 将相对路径转换为绝对路径
    get_filename_component(ABS_PATH "src/utils/helper.h" ABSOLUTE)
    message(STATUS "绝对路径: ${ABS_PATH}")  # 输出:绝对路径: /当前工作目录/src/utils/helper.h
  • aux_source_directory:发现目录中所以的文件

    bash 复制代码
    cmake_minimum_required(VERSION 3.28)
    project(firstproject)
    
    # 发现当前目录(.)下所有源文件,并存储到变量 SRCS 中
    aux_source_directory(. SRCS)
    
    # 打印发现的源文件列表(可选,用于调试)
    message(STATUS "发现的源文件: ${SRCS}")
    
    # 使用变量 SRCS 构建可执行文件
    add_executable(firstproject ${SRCS})
  • targe_sources:为CMake目标添加源文件

  • target_include_directories:指定要包含的头文件目录

    bash 复制代码
    project/
    ├── CMakeLists.txt
    ├── src/
    │   ├── core/
    │   │   ├── core.cpp
    │   │   └── core.h
    │   └── utils/
    │       ├── utils.cpp
    │       └── utils.h
    └── main.cpp
    cpp 复制代码
    add_executable(my_app main.cpp)
    
    # 分模块添加源文件
    target_sources(my_app 
      PRIVATE 
        src/core/core.cpp 
        src/utils/utils.cpp
    )
    
    # 配合 target_include_directories 添加头文件目录
    target_include_directories(my_app PRIVATE src)
  • add_subdirectory(source_dir):添加子工程

    cpp 复制代码
    #/top_project/CMakeLists.txt
    
    cmake_minimum_required(VERSION 3.0)
    project(YourProject)
    #添加子目录
    add_subdirectory(src)
    add_subdirectory(src/subdirectory)
  • CMake 内置的常用宏或变量

    cpp 复制代码
    cmake_minimum_required(VERSION 3.10)
    project(CMakeVariablesDemo LANGUAGES CXX)
    
    # ==============================================
    # 1. 操作系统判断 (CMAKE_SYSTEM_NAME)
    # ==============================================
    message(STATUS "=== 操作系统信息 ===")
    if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
        message(STATUS "当前系统: Windows")
        set(OS_SPECIFIC_DEFINE "-DWIN32")  # Windows 特定宏定义
    elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
        message(STATUS "当前系统: Linux")
        set(OS_SPECIFIC_DEFINE "-DLINUX")  # Linux 特定宏定义
    elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
        message(STATUS "当前系统: macOS")
        set(OS_SPECIFIC_DEFINE "-DMACOS")  # macOS 特定宏定义
    else()
        message(WARNING "未知系统: ${CMAKE_SYSTEM_NAME}")
    endif()
    
    # ==============================================
    # 2. 构建类型判断 (CMAKE_BUILD_TYPE)
    # ==============================================
    message(STATUS "\n=== 构建类型信息 ===")
    if(NOT CMAKE_BUILD_TYPE)
        set(CMAKE_BUILD_TYPE "Release" CACHE STRING "默认构建类型为 Release" FORCE)
    endif()
    message(STATUS "当前构建类型: ${CMAKE_BUILD_TYPE}")
    
    # 根据构建类型添加编译宏
    if(CMAKE_BUILD_TYPE STREQUAL "Debug")
        add_definitions(-DDEBUG_MODE)  # Debug 模式下定义 DEBUG_MODE 宏
        message(STATUS "已启用 Debug 模式宏定义")
    elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
        add_definitions(-DRELEASE_MODE)  # Release 模式下定义 RELEASE_MODE 宏
        message(STATUS "已启用 Release 模式宏定义")
    endif()
    
    # ==============================================
    # 3. 编译位数判断 (CMAKE_SIZEOF_VOID_P)
    # ==============================================
    message(STATUS "\n=== 编译位数信息 ===")
    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
        set(OS_BIT "64位")
        message(STATUS "当前编译架构: ${OS_BIT}")
    elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
        set(OS_BIT "32位")
        message(STATUS "当前编译架构: ${OS_BIT}")
    else()
        message(WARNING "无法识别的编译位数: ${CMAKE_SIZEOF_VOID_P}")
    endif()
    
    # ==============================================
    # 4. 项目路径变量 (PROJECT_SOURCE_DIR / PROJECT_BINARY_DIR)
    # ==============================================
    message(STATUS "\n=== 项目路径信息 ===")
    message(STATUS "源码目录 (PROJECT_SOURCE_DIR): ${PROJECT_SOURCE_DIR}")
    message(STATUS "构建目录 (PROJECT_BINARY_DIR): ${PROJECT_BINARY_DIR}")
    
    # ==============================================
    # 5. 生成可执行文件并应用上述配置
    # ==============================================
    add_executable(${PROJECT_NAME} main.cpp)
    
    # 添加系统特定编译选项
    target_compile_options(${PROJECT_NAME} PRIVATE ${OS_SPECIFIC_DEFINE})
    
    # 根据编译位数设置输出目录
    if(OS_BIT STREQUAL "64位")
        set_target_properties(${PROJECT_NAME} PROPERTIES
            RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/x64"
        )
    else()
        set_target_properties(${PROJECT_NAME} PROPERTIES
            RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/x86"
        )
    endif()
  • CMake Module 的作用:CMake Module(.cmake 文件)是用于封装可复用逻辑的模块文件,主要作用包括

    • 抽取公共逻辑:将重复使用的 CMake 代码(如函数、宏、配置检查)封装为模块,避免代码冗余。
    • 模块化管理:通过 include() 或 find_package() 加载模块,使项目结构更清晰,便于维护。
    • 跨项目复用:模块可在多个项目间共享,统一配置标准(如编译选项、依赖检查)。
    cpp 复制代码
    # cmake/toolchain.cmake
    # 宏:检查编译器类型并设置警告级别
    macro(setup_compiler_warnings target)
        if(MSVC)
            # MSVC 编译器:启用 /W4 警告级别
            target_compile_options(${target} PRIVATE /W4 /WX)
        else()
            # GCC/Clang 编译器:启用 -Wall -Wextra -Werror
            target_compile_options(${target} PRIVATE -Wall -Wextra -Werror)
        endif()
    endmacro()
    
    # 函数:检查 C++ 标准是否支持
    function(check_cxx_standard required_standard)
        if(CMAKE_CXX_STANDARD LESS ${required_standard})
            message(FATAL_ERROR "需要 C++${required_standard} 标准,当前配置为 C++${CMAKE_CXX_STANDARD}")
        endif()
        message(STATUS "C++ 标准检查通过:C++${CMAKE_CXX_STANDARD}")
    endfunction()
    cpp 复制代码
    # 主 CMakeLists.txt
    cmake_minimum_required(VERSION 3.10)
    project(MyProject LANGUAGES CXX)
    
    # 设置 C++ 标准
    set(CMAKE_CXX_STANDARD 17)
    
    # 加载自定义 Module
    include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/toolchain.cmake)
    
    # 调用 Module 中的函数检查 C++ 标准
    check_cxx_standard(17)
    
    # 创建可执行目标
    add_executable(my_app main.cpp)
    
    # 调用 Module 中的宏设置编译警告
    setup_compiler_warnings(my_app)

配置 与 构建

bash 复制代码
# 创建并进入构建目录(推荐用 Debug/Release 区分)
mkdir Debug && cd Debug

# 生成 VS2022 解决方案(64位 Debug)
cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Debug -S ../Coding -B .
  • 构建
bash 复制代码
# 加载 VS2022 编译环境(根据安装路径调整)
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"

# 编译解决方案(指定平台和配置)
msbuild MyProject.sln /p:Platform=x64 /p:Configuration=Debug /m
# 进入构建目录(如之前创建的 Debug 文件夹)
cd Debug

# 构建 Debug 配置(多线程编译)
cmake --build . --config Debug -j 8
cmake --build . --config Release --clean-first
相关推荐
糖猫猫cc2 小时前
Kite 实现逻辑删除
java·kotlin·orm·kite
Memory_荒年2 小时前
Dubbo调优实战:从QPS 1000到10000的惊险过山车之旅
java·后端·dubbo
Cosolar2 小时前
别再羡慕 Python 了!Java 开发者的 AI Agent 全指南:四大框架从选型到实战
java·人工智能·后端
色空大师2 小时前
网站搭建实操(三)后台管理-2-forum-core)
java·redis·网站·搭建网站
Memory_荒年2 小时前
Dubbo高级实战:从“能用”到“好用”的奇技淫巧
java·后端
Flittly2 小时前
【SpringAIAlibaba新手村系列】(4)流式输出与响应式编程
java·spring boot·spring·ai
酉鬼女又兒2 小时前
零基础快速入门前端蓝桥杯Web备考:BOM与定时器核心知识点详解(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·javascript·职场和发展·蓝桥杯
望眼欲穿的程序猿2 小时前
MacOS自定义安装Rust
开发语言·macos·rust