Łuk*_*Lew 33 build-process cmake pre-compilation
我想将一些选项传递给编译器.该选项必须在编译时计算 - 每次调用'make'时,而不是'cmake',因此execute_process命令不会删除它.(可以?)
例如,将日期传递给g ++编译器,如下所示:
g++ prog.cpp -o prog -DDATETIME="17:09:2009,14:25"
Run Code Online (Sandbox Code Playgroud)
但是在编译时计算DATETIME.
知道如何在CMake中做到这一点吗?
赏金编辑:
最不受欢迎的解决方案将被接受.
请注意,我希望能够在编译时执行任意命令,而不仅仅是'date'.
编辑2:
它必须适用于Linux,Windows(VS),Mingw,Cygwin和OS X.您不能假设Ruby,Perl或Python,因为它们在Windows上是非标准的.你可以假设BOOST,但我想这没用.
目标是强制cmake生成Makefile(在Linux的情况下),当make执行时,将完成工作.
创建自定义*.h文件是可以的,但它必须由make的Makefile(或其他操作系统上的等效文件)启动.*.h的创建不必(也不应该)使用cmake.
Jes*_*erE 45
您将遗漏一些信息,例如您需要在哪些平台上运行此信息,以及是否有任何其他工具可供使用.如果你可以使用Python的Ruby,Perl,事情会变得简单得多.我假设你想在Unix和Windows pqlatform上运行,并且没有额外的工具可用.
如果您希望在预处理程序符号中输出命令,则最简单的方法是生成头文件,而不是摆弄命令行参数.请记住,CMake有一个脚本模式(-P),它只处理文件中的脚本命令,所以你可以这样做:
的CMakeLists.txt:
project(foo)
cmake_minimum_required(VERSION 2.6)
add_executable(foo main.c custom.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_custom_command(OUTPUT custom.h
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/custom.cmake)
Run Code Online (Sandbox Code Playgroud)
文件"custom.h"在编译时由命令"cmake -P custom.cmake"生成.custom.cmake看起来像这样:
execute_process(COMMAND uname -a
OUTPUT_VARIABLE _output OUTPUT_STRIP_TRAILING_WHITESPACE)
file(WRITE custom.h "#define COMPILE_TIME_VALUE \"${_output}\"")
Run Code Online (Sandbox Code Playgroud)
它执行命令(在本例中为"uname -a",您将用您希望的任何命令替换它),并将输出放在变量_output中,然后将其写入custom.h.请注意,这仅在命令输出单行时才有效.(如果您需要多行输出,则必须编写更复杂的custom.cmake,具体取决于您希望多行数据进入程序的方式.)
主程序如下所示:
#include <stdio.h>
#include "custom.h"
int main()
{
printf("COMPILE_TIME_VALUE: %s\n", COMPILE_TIME_VALUE);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果你真的想在编译时计算编译器选项,事情变得更加棘手.对于Bourne-shell生成器,您只需将命令插入反引号即可.如果您在搞清楚引用时生气,请将命令的所有逻辑移到shell脚本中,这样您只需要输入mycommand.shadd_definitions():
if(UNIX)
add_definitions(`${CMAKE_CURRENT_SOURCE_DIR}/custom-options.sh`)
endif()
Run Code Online (Sandbox Code Playgroud)
对于基于Windows批处理文件的生成器来说,事情很棘手,我没有一个好的解决方案.问题是PRE_BUILD命令不是作为与实际编译器调用相同的批处理文件的一部分执行(详细研究BuildLog.htm),所以我最初的想法不起作用(在一个PRE_BUILD步骤中生成custom.bat 然后执行在其上"调用custom.bat"以获取一个变量集,稍后可以在编译器命令行中引用该变量集.如果批处理文件中有相同的反引号,则可以解决问题.
希望这能给出一些想法和起点.
(现在到了不可避免的反问:你真的 想做什么?)
编辑:我不知道为什么你不想让CMake用于生成头文件.使用$ {CMAKE_COMMAND}将扩展为用于生成Makefile/.vcproj文件的CMake,并且由于CMake不支持可移植的Makefile/.vcproj文件,因此您需要在目标计算机上重新运行CMake.
由于这个明确的原因,CMake还有一堆实用程序命令(为列表运行"cmake -E").你可以这样做
add_custom_command(OUTPUT custom.h COMMAND ${CMAKE_COMMAND} -E copy file1.h file2.h)
Run Code Online (Sandbox Code Playgroud)
将file1.h复制到file2.h.
无论如何,如果你不想使用CMake生成头文件,你需要调用单独的.bat/.sh脚本来生成头文件,或者使用echo来执行:
add_custom_command(OUTPUT custom.h COMMAND echo #define SOMETHING 1 > custom.h)
Run Code Online (Sandbox Code Playgroud)
根据需要调整报价.
上面的解决方案(使用单独的 CMake 脚本文件来生成头文件)看起来非常灵活,但对于示例中所做的事情来说有点复杂。
另一种方法是在单个源文件和/或目标上设置 COMPILE_DEFINITIONS 属性,在这种情况下,定义的预处理器变量将只为源文件或目标中的文件被编译设置。
COMPILE_DEFINITIONS 属性的格式与 add_definitions 命令中使用的格式不同,其优点是您无需担心“-D”或“\D”语法,并且它们可以跨平台工作。
示例代码
-- CMakeLists.txt --
execute_process(COMMAND svnversion
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE SVN_REV)
string(STRIP ${SVN_REV} SVN_REV)
execute_process(COMMAND date "+%Y-%m-%d-%H:%M"
OUTPUT_VARIABLE BUILD_TIME)
string(STRIP ${BUILD_TIME} BUILD_TIME)
set_source_files_properties(./VersionInfo.cpp
PROPERTIES COMPILE_DEFINITIONS SVN_REV=\"${SVN_REV}\";BUILD_TIME=\"${BUILD_TIME}\"")
Run Code Online (Sandbox Code Playgroud)
第一行运行一个 shell 命令svnversion并将结果放在变量中SVN_REV。string(STRIP ...)需要该命令从输出中删除尾随换行符。
请注意,这是假设正在运行的命令是跨平台的。如果不是,您可能需要为不同的平台提供替代方案。例如,我使用 Unixdate命令的 cygwin 实现,并且有:
if(WIN32)
execute_process(COMMAND cmd /C win_date.bat
OUTPUT_VARIABLE BUILD_TIME)
else(WIN32)
execute_process(COMMAND date "+%Y-%m-%d-%H:%M"
OUTPUT_VARIABLE BUILD_TIME)
endif(WIN32)
string(STRIP ${BUILD_TIME} BUILD_TIME)
Run Code Online (Sandbox Code Playgroud)
对于日期命令,其中win_date.bat是以所需格式输出日期的 bat 文件。
这两个预处理器变量在文件中不可用,./VersionInfo.cpp但未在任何其他文件中设置。然后你可以有
-- 版本信息.cpp --
std::string version_build_time=BUILD_TIME;
std::string version_svn_rev=SVN_REV;
Run Code Online (Sandbox Code Playgroud)
这似乎可以很好地跨平台工作,并最大限度地减少了特定于平台的代码量。