必须用CMake在配置阶段生成Config.h:通过configure_file()将Config.h.in模板中的@VAR@替换为实际值,输出到构建目录,并自动纳入依赖链,确保编译期确定性。

编译期自动生成 Config.h 的核心思路
不能靠手写,也不能靠运行时生成——必须让构建系统在 cmake 配置阶段(或 make 构建初期)就产出 Config.h,且内容由当前编译环境、选项、版本等决定。CMake 是最现实的选择,它原生支持 configure_file() 和 write_file(),能可靠完成这件事。
用 CMake configure_file 生成 Config.h(推荐方案)
这是最稳定、可读性最强的方式。你写一个模板 Config.h.in,CMake 把其中的 @VAR@ 替换成实际值,输出为 Config.h,并自动加入构建依赖链——只要 CMakeLists.txt 里改了变量,下次 cmake 或 make 就会重生成。
常见做法:
- 在源码目录放
Config.h.in,内容类似:#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@ #define HAVE_OPENSSL @HAVE_OPENSSL@ #define BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@
- 在
CMakeLists.txt中添加:set(PROJECT_VERSION_MAJOR 1) set(PROJECT_VERSION_MINOR 4) option(ENABLE_SSL "Enable OpenSSL support" ON) find_package(OpenSSL QUIET) set(HAVE_OPENSSL ${OpenSSL_FOUND}) configure_file(Config.h.in ${CMAKE_BINARY_DIR}/include/Config.h) - 确保头文件搜索路径包含生成目录:
include_directories(${CMAKE_BINARY_DIR}/include)
注意:生成的 Config.h 在构建目录下,不是源码目录;configure_file() 默认只在 cmake 阶段运行一次,但若你修改了 .in 模板或相关 set() 变量,CMake 会检测到并触发重配置。
立即学习“C++免费学习笔记(深入)”;
避免用 add_custom_command 生成 Config.h
有人想用 add_custom_command() + echo 或脚本生成,这容易出问题:
- 生成时机不可控——可能晚于某些 target 的编译,导致
#include "Config.h"失败 - 依赖声明难写全,比如漏掉对
CMakeLists.txt中某个set()的追踪,就会“改了配置但没重生成” - 跨平台脚本(如 PowerShell vs bash)增加维护成本
- CMake 3.20+ 虽支持
write_file()直接写字符串,但依然不如configure_file()自带变量替换和依赖管理
如何让 Config.h 参与编译期检查(比如 static_assert)
生成后,直接在代码里 #include "Config.h" 即可。但要注意:
- 确保所有需要它的
.cpp文件都通过target_include_directories()正确设置了生成路径,例如:target_include_directories(mylib PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include>) - 如果想做编译期校验,可以加
static_assert:#include "Config.h" static_assert(PROJECT_VERSION_MAJOR >= 1, "Minimum major version required");
- 不要在
Config.h里写复杂逻辑(比如条件宏嵌套太多),它只是配置快照;逻辑判断应留在 CMake 层,生成确定的宏定义
真正的难点不在生成动作本身,而在于把哪些信息放进 Config.h —— 版本号、第三方库是否找到、编译器特性开关(如 __cpp_concepts)、目标架构标识(__x86_64__)这些都该由 CMake 决定并固化,而不是让头文件自己探测。否则就失去了“编译期确定性”这个前提。


















