有时候我们希望在构建时能够在命令行添加一些宏定义,改变程序行为。一个典型应用示例是代码里通过检查是否定义了 DEBUG
宏,来决定是否输出调试信息。编译器一般提供命令行选项支持这种做法,例如使用 gcc 时可以在命令行添加 -D
选项,定义一些宏:
gcc -DDEBUG=1 a.c
不过,大型项目一般都需要自动化构建工具,如 GNU Autotools 或者 CMake。使用它们后,我们无法直接修改编译命令,但它们提供了替代方案。对于 Autotools,它可以识别 CPPFLAGS
等环境变量,从而我们可以在命令行上添加宏定义,例如:
CPPFLAGS="-DDEBUG=1" ./configure
此外,我们还可以先 export CPPFLAGS="-DDEBUG=1"
,再用 ./configure
命令。注意这里 CPPFLAGS
的 CPP 指的是 C 预处理器 (C Preprocessor),不是 C++,其中只应该设置 -I
、-D
、-U
等影响预处理器的选项。Autotools 支持 CFLAGS
、CXXFLAGS
、LDFLAGS
环境变量,分别用来指定 C 编译链接时、C++ 编译链接时、以及仅在链接时有效的选项。
目前许多项目已经使用 CMake 来构建。CMake 支持 CFLAGS
、CXXFLAGS
、LDFLAGS
等,但遗憾的是唯独不支持 CPPFLAGS
。也就是说,CMake 会无视 CPPFLAGS
环境变量的值。Aron Xu 为此报了一个 BUG,不过因为没人志愿去做,所以一直没有修复。许多人可能会以为,可以用类似 cmake .. -DVAR=VALUE
的方式来添加宏定义,但这是无效的。这样一来,如果想在命令行上指定宏定义,只能复用 CFLAGS
或者 CXXFLAGS
变量。这基本可以工作,因为一般情况下预处理和编译是同一个命令进行的。
CMake 中标准的添加宏定义方法是使用 ADD_DEFINITIONS(-DMACRO)
(参考文档),不过这需要修改 CMakeLists.txt
文件。如果想要在命令行上定制宏的开关或取值,那么可以像这里一样,定义一个 CMake 选项:
OPTION(DEFINE_MACRO "Option description" ON) # Enabled by default
然后做一个条件判断:
IF(DEFINE_MACRO)
ADD_DEFINITIONS(-DMACRO)
ENDIF(DEFINE_MACRO)
之后,就可以用 cmake -DDEFINE_MACRO=OFF ..
调整宏的开关或取值了。
最后值得一提的是,如果代码里已经有了宏定义语句,那么通过命令行修改其取值是不可能的。编译器会警告宏被重复定义,而且生效的是源文件中的定义。想要重新定义,只能随后 #undef
再 #define
。这将不得不通过修改代码来实现。