CMake进阶: 配置文件(configure_file)
目录
1.简介
2.核心作用
3.常用场景与示例
3.1.场景 1:生成头文件(嵌入版本号、路径等信息)
3.2.场景 2:生成跨平台脚本(替换路径分隔符)
3.3.仅复制文件(不替换变量)
4.完整示例
5.注意事项
相关链接
1.简介
configure_file
是 CMake 中用于生成配置文件的核心命令,主要功能是将模板文件(含 CMake 变量占位符)中的变量替换为实际值,生成最终可用的文件(如头文件、配置脚本等)。它是连接 CMake 构建配置与源代码 / 脚本的重要桥梁。
基本语法:
configure_file(<input> # 输入模板文件路径(通常在源目录,如 ${CMAKE_SOURCE_DIR}/config.h.in)<output> # 输出文件路径(通常在构建目录,如 ${CMAKE_BINARY_DIR}/config.h)[COPYONLY] # 仅复制文件,不替换变量(禁用变量替换)[ESCAPE_QUOTES] # 对输出中的引号进行转义(如将 " 转为 \")[@ONLY] # 仅替换 @VAR@ 形式的变量,不替换 ${VAR} 形式(避免与其他模板冲突)[NEWLINE_STYLE <style>] # 指定换行符风格(UNIX/DOS/WINDOWS,跨平台适配)
)
- < input>:输入文件路径,通常是一个 .in 文件,里面包含变量和 CMake 语法。
- < output>:输出文件路径,生成的文件将被写入该路径。
- COPYONLY:可选参数,指示只复制输入文件而不进行替换。
- ESCAPE_QUOTES:可选参数,将替换时的引号进行转义。将输出文件中的双引号
"
转为转义形式\"
,适合生成 JSON、脚本等需要转义引号的文件。 - @ONLY:可选参数,只替换 @ 开头的变量。仅替换
@VAR@
形式的变量,不替换${VAR}
。避免与 C++ 宏(${...}
)或其他模板系统冲突,是生成头文件时的常用参数。 - NEWLINE_STYLE:可选参数,指定换行符风格,可以是 UNIX、DOS 或 WIN32。指定输出文件的换行符风格(
UNIX
为\n
,DOS
/WINDOWS
为\r\n
),跨平台脚本生成时必备。
2.核心作用
1.变量替换:将模板文件中 @变量名@
或 ${变量名}
形式的占位符,替换为 CMake 中定义的实际变量值(如项目版本、安装路径、编译选项等)。
2.跨平台适配:自动处理路径分隔符(如 Windows 的 \
与 Unix 的 /
)、换行符风格等平台差异。
3.动态生成配置:根据构建配置(如 Debug/Release、是否启用某功能)动态生成符合当前环境的文件。
3.常用场景与示例
3.1.场景 1:生成头文件(嵌入版本号、路径等信息)
在源代码中需要使用 CMake 中定义的变量(如项目版本、安装路径)时,可通过 configure_file
生成头文件。
1.模板文件(src/config.h.in
,源目录中):
// 由 CMake 自动生成,不要手动修改
#ifndef CONFIG_H
#define CONFIG_H// 项目版本(来自 CMakeLists.txt 中的 project 命令)
#define PROJECT_VERSION "@PROJECT_VERSION@"// 安装路径(来自 CMAKE_INSTALL_PREFIX)
#define INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"// 是否启用调试模式(来自 CMake 选项)
#cmakedefine ENABLE_DEBUG @ENABLE_DEBUG@#endif
2.CMake 配置(CMakeLists.txt
中):
cmake_minimum_required(VERSION 3.14)
project(MyProject VERSION 1.2.3) # 定义 PROJECT_VERSION# 定义选项(供模板文件使用)
option(ENABLE_DEBUG "Enable debug mode" ON)# 生成 config.h(输入为模板,输出到构建目录)
configure_file(${CMAKE_SOURCE_DIR}/src/config.h.in # 输入模板路径${CMAKE_BINARY_DIR}/src/config.h # 输出文件路径(构建目录,避免污染源文件)@ONLY # 仅替换 @VAR@ 形式,不替换 ${VAR}(避免与 C++ 宏冲突)
)# 让编译器能找到生成的 config.h
add_executable(myapp src/main.cpp)
target_include_directories(myapp PRIVATE ${CMAKE_BINARY_DIR}/src)
3.源代码使用(src/main.cpp
):
#include "config.h"
#include <iostream>int main() {std::cout << "Version: " << PROJECT_VERSION << std::endl;std::cout << "Install path: " << INSTALL_PREFIX << std::endl;
#ifdef ENABLE_DEBUGstd::cout << "Debug mode enabled" << std::endl;
#endifreturn 0;
}
构建后,config.h
中的占位符会被替换为实际值,例如:
#define PROJECT_VERSION "1.2.3"
#define INSTALL_PREFIX "/usr/local"
#define ENABLE_DEBUG 1
3.2.场景 2:生成跨平台脚本(替换路径分隔符)
在需要生成脚本文件(如 .sh
或 .bat
)时,configure_file
可自动处理路径分隔符(如将 CMake 中的 /
转为 Windows 的 \
)。
1.模板脚本(scripts/run.sh.in
):
#!/bin/sh
# 自动生成的运行脚本
EXE_PATH="@CMAKE_BINARY_DIR@/myapp" # CMake 路径会自动适配平台分隔符
"$EXE_PATH" "$@"
2.CMake 配置:
configure_file(${CMAKE_SOURCE_DIR}/scripts/run.sh.in${CMAKE_BINARY_DIR}/scripts/run.sh@ONLYNEWLINE_STYLE UNIX # 强制 Unix 换行符(适合 .sh 脚本)
)# 为脚本添加可执行权限(可选)
file(COPY_FILE${CMAKE_BINARY_DIR}/scripts/run.sh${CMAKE_BINARY_DIR}/scripts/run.shFILE_PERMISSIONS OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ
)
在 Windows 上若生成 .bat
脚本,可指定 NEWLINE_STYLE DOS
确保换行符正确。
3.3.仅复制文件(不替换变量)
使用 COPYONLY
参数可禁用变量替换,仅实现文件复制(类似 file(COPY ...)
,但会在输入文件变化时自动更新)。
# 复制数据文件到构建目录(不替换变量)
configure_file(${CMAKE_SOURCE_DIR}/data/config.ini${CMAKE_BINARY_DIR}/data/config.iniCOPYONLY # 仅复制,不处理变量
)
4.完整示例
下面通过一个生成版本信息头文件的例子,展示 configure_file
的具体用法。这个例子会将 CMake 中定义的项目版本、编译日期等信息,自动嵌入到源代码可访问的头文件中。
1.项目结构
version_demo/
├── CMakeLists.txt # CMake 配置文件
├── src/
│ ├── main.cpp # 主程序(使用生成的头文件)
│ └── version.h.in # 头文件模板(含 CMake 变量占位符)
2.头文件模板(src/version.h.in
)
这是一个包含 CMake 变量占位符的模板文件,其中 @变量名@
会被 CMake 替换为实际值:
// 由 CMake 自动生成,请勿手动修改
#ifndef VERSION_H
#define VERSION_H// 项目版本信息(来自 CMakeLists.txt 中的 project 命令)
#define PROJECT_NAME "@PROJECT_NAME@"
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define PROJECT_VERSION "@PROJECT_VERSION@"// 编译时间(由 CMake 变量提供)
#define BUILD_DATE "@CMAKE_BUILD_DATE@"
#define BUILD_TIME "@CMAKE_BUILD_TIME@"// 条件编译示例(根据 CMake 选项决定是否启用)
#cmakedefine ENABLE_LOG // 若 ENABLE_LOG 为 ON,则生成 #define ENABLE_LOG#endif // VERSION_H
- 模板中使用
@变量名@
作为占位符(如@PROJECT_NAME@
)。 #cmakedefine ENABLE_LOG
是特殊语法:若 CMake 中ENABLE_LOG
为ON
,则生成#define ENABLE_LOG
;否则生成/* #undef ENABLE_LOG */
。
3.CMake 配置(CMakeLists.txt
)
在 CMake 中定义变量,并通过 configure_file
生成最终的头文件:
cmake_minimum_required(VERSION 3.14)# 定义项目名称和版本(会自动生成 PROJECT_NAME、PROJECT_VERSION 等变量)
project(MyApp VERSION 2.3.4)# 定义编译日期和时间(使用 CMake 的内置命令)
string(TIMESTAMP CMAKE_BUILD_DATE "%Y-%m-%d") # 格式:年-月-日
string(TIMESTAMP CMAKE_BUILD_TIME "%H:%M:%S") # 格式:时:分:秒# 定义一个可选功能(用于演示条件编译)
option(ENABLE_LOG "Enable logging feature" ON) # 默认启用# 核心:使用 configure_file 生成头文件
configure_file(${CMAKE_SOURCE_DIR}/src/version.h.in # 输入:模板文件路径(源目录)${CMAKE_BINARY_DIR}/src/version.h # 输出:生成的头文件路径(构建目录)@ONLY # 仅替换 @VAR@ 形式的变量,不替换 ${VAR}(避免与 C++ 语法冲突)
)# 生成可执行文件
add_executable(myapp src/main.cpp)# 让编译器能找到生成的 version.h(构建目录下的 src 文件夹)
target_include_directories(myapp PRIVATE ${CMAKE_BINARY_DIR}/src)
PROJECT_NAME
、PROJECT_VERSION_MAJOR
等是project
命令自动生成的变量。string(TIMESTAMP ...)
用于生成编译时间戳,存储到CMAKE_BUILD_DATE
和CMAKE_BUILD_TIME
变量中。option(ENABLE_LOG ...)
定义一个可选功能开关,控制模板中#cmakedefine
的生成结果。
4.源代码使用(src/main.cpp
)
在代码中包含生成的 version.h
,使用其中的宏定义:
#include <iostream>
#include "version.h" // 包含 CMake 生成的头文件int main() {std::cout << "Project: " << PROJECT_NAME << std::endl;std::cout << "Version: " << PROJECT_VERSION_MAJOR << "."<< PROJECT_VERSION_MINOR << "."<< PROJECT_VERSION_PATCH << std::endl;std::cout << "Built on: " << BUILD_DATE << " " << BUILD_TIME << std::endl;#ifdef ENABLE_LOGstd::cout << "Logging is enabled" << std::endl;
#elsestd::cout << "Logging is disabled" << std::endl;
#endifreturn 0;
}
5.构建与运行
# 创建构建目录并配置
mkdir build && cd build
cmake ..# 编译
make # 或 cmake --build .# 运行程序
./myapp
6.输出结果
Project: MyApp
Version: 2.3.4
Built on: 2024-05-20 15:30:45
Logging is enabled
5.注意事项
1.路径处理:输入文件通常放在源目录(CMAKE_SOURCE_DIR
),输出文件放在构建目录(CMAKE_BINARY_DIR
),避免污染源文件。
2.变量可见性:模板中引用的变量必须在 configure_file
调用之前定义(否则替换为空)。
3.自动更新:若输入模板文件被修改,CMake 会自动重新运行 configure_file
生成新的输出文件(无需手动触发)。
4.#cmakedefine
语法:在模板中使用 #cmakedefine VAR [VALUE]
可根据变量是否定义生成 #define VAR VALUE
或 /* #undef VAR */
(适合条件编译),例如:
#cmakedefine ENABLE_FEATURE # 若 ENABLE_FEATURE 为 ON,则生成 #define ENABLE_FEATURE;否则生成 /* #undef ENABLE_FEATURE */
#cmakedefine MAX_SIZE @MAX_SIZE@ # 若 MAX_SIZE 定义,生成 #define MAX_SIZE 100;否则生成 /* #undef MAX_SIZE */
configure_file
是 CMake 中连接 “构建配置” 与 “源代码 / 脚本” 的核心工具,通过变量替换实现动态文件生成,广泛用于嵌入版本信息、适配跨平台路径、生成条件编译头文件等场景。掌握它可以大幅提升项目的灵活性和跨平台兼容性。
相关链接
- CMake 官网 CMake - Upgrade Your Software Build System
- CMake 官方文档:CMake Tutorial — CMake 4.1.0 Documentation
- CMake 源码:https://github.com/Kitware/CMake
- CMake 源码:https://gitlab.kitware.com/cmake/
- 中文版基础介绍: CMake 入门实战 | HaHack
- wiki: https://gitlab.kitware.com/cmake/community/-/wikis/Home
- Modern CMake 简体中文版: Introduction · Modern CMake