我想通过一些选项的编译器。 该选项必须在编译时进行计算 - 每次当调用“化妆”,“cmake的”不能当,所以execute_process命令不剪。 (可以?)
例如通过一个日期到克++编译器那样:
g++ prog.cpp -o prog -DDATETIME="17:09:2009,14:25"
但随着DATETIME在编译时计算。
任何想法如何做到这一点的CMake的?
赏金编辑:
甲至少hackish的解决方案将被接受。
请注意,我希望能够在编译时exectue任意命令,不仅是“日期”。
编辑2:
它必须在Linux,Windows(VS),MinGW的,Cygwin和OS X的工作,你不能假设的Ruby,Perl或Python,因为它们是在Windows非标准。 你可以假设提升,但我想这是没有用的。
我们的目标是迫使CMake的生成Makefile文件(在Linux中的情况下)被执行时化妆,会做的工作。
创建自定义的* .h文件是好的,但它必须由一个Makefile发起(或等值其它OS)的补充。 .H的*创建不必(也不应该有)使用的cmake。
你留下了一些信息,比如哪些平台,您需要在运行此,如果有任何额外的工具,你可以使用。 如果你能使用Ruby,Perl和Python中的,事情就变得简单多了。 我假设你想在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)
文件“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}\"")
它执行该命令(在这种情况下,“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;
}
如果你真的想计算在编译时编译器选项,事情变得更加棘手。 对于Bourne壳发电机你可以插入反引号里面的命令。 如果你生气,同时搞清楚报价,移动你的命令的所有逻辑shell脚本里面,所以你只需要把mycommand.sh
你add_definitions():
if(UNIX)
add_definitions(`${CMAKE_CURRENT_SOURCE_DIR}/custom-options.sh`)
endif()
对于Windows批处理文件基于发电机东西太多tricker,我没有一个很好的解决方案。 问题是, PRE_BUILD
命令不一样的批处理文件的实际编译器调用(研究BuildLog.htm了解详细信息)的一部分执行的,所以我最初的想法没有工作(产生在一个custom.bat PRE_BUILD
一步,然后做“呼叫custom.bat”就可以得到一个变量集合,可以在后面的编译器命令行中引用)。 如果反引号的批处理文件等效,这将解决这个问题。
希望这给一些想法和出发点。
(现在不可避免的反问:什么是你真正想要做什么?)
编辑:我不知道为什么你不想让CMake的被用来生成头文件。 使用$ {} CMAKE_COMMAND将扩大到CMake的用于生成的Makefile /的.vcproj-文件,因为CMake的真的不支持便携的Makefile /的.vcproj-文件,你需要重新运行CMake的在目标计算机上。
CMake的也有一堆实用程序命令(运行“cmake的-E”的列表)这个明确的原因。 例如,你可以做
add_custom_command(OUTPUT custom.h COMMAND ${CMAKE_COMMAND} -E copy file1.h file2.h)
复制file1.h到file2.h。
无论如何,如果你不想使用生成C进行报头文件,你要么需要调用单独的.bat / .SH脚本生成的头文件,或做它用回声:
add_custom_command(OUTPUT custom.h COMMAND echo #define SOMETHING 1 > custom.h)
根据需要调整报价。
上述解决方案(使用单独的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}\"")
所述第一线延伸外壳命令svnversion
,并将结果在变量SVN_REV
。 的string(STRIP ...)
需要命令删除从输出尾随换行符。
请注意,这是假设正在运行的命令是跨平台的。 如果没有,你可能需要为不同的平台的替代品。 比如我使用Unix的cygwin的实施date
的命令,并且有:
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)
的日期的命令,其中win_date.bat
是bat文件输出在所期望的格式的日期。
这两个预处理器变量不是在文件中提供./VersionInfo.cpp
但在任何其它文件中未设置。 然后,您可以有
- VersionInfo.cpp -
std::string version_build_time=BUILD_TIME;
std::string version_svn_rev=SVN_REV;
这似乎是跨平台很好地工作,最大限度地减少的特定于平台的代码量。
我会用下面的办法:
- 创建打印当前日期到stdout一个可执行文件(CMake的缺乏此功能)
- 补充一点,一直被人们视为过时的目标
- 让目标调用另一个CMake的脚本
- 让调用CMake的脚本生成一个头文件
对于此示例的代码:
--- ---的CMakeLists.txt
PROJECT(Foo)
ADD_EXECUTABLE(RetreiveDateTime ${CMAKE_CURRENT_SOURCE_DIR}/datetime.cpp)
ADD_CUSTOM_TARGET(GenerateFooHeader
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/Generate.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS RetreiveDateTime)
ADD_EXECUTABLE(Foo "test.cpp" "${CMAKE_CURRENT_BINARY_DIR}/generated.h")
ADD_DEPENDENCIES(Foo GenerateFooHeader)
--- Generate.cmake ---
EXECUTE_PROCESS(COMMAND ${CMAKE_BINARY_DIR}/RetreiveDateTime OUTPUT_VARIABLE DATETIMESTRING)
MESSAGE(STATUS "DATETIME=\"${DATETIMESTRING}\"")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated.h @ONLY)
--- generate.h.in ---
#pragma once
#define DATETIMESTRING "@DATETIMESTRING@"
--- datetime.cpp ---
#include <iostream>
#include <ctime>
#include <cstring>
int main(int, char*[])
{
time_t now;
time(&now);
tm * timeinfo = localtime(&now);
char * asstring = asctime(timeinfo);
asstring[strlen(asstring) - 1] = '\0'; // Remove trailing \n
std::cout << asstring;
return 0;
}
--- TEST.CPP ---
#include "generated.h"
#include <iostream>
int main(int, char*[])
{
std::cout << DATETIMESTRING << std::endl;
return 0;
}
这导致在处理每个构建再生的标题“generated.h”。 如果你不需要DATETIME这个例子可以大大简化为CMake的缺乏这种功能和程序必须建立模拟功能。
不过,我倒觉得两次以上在此之前。 请记住,头文件将会重新生成每次化妆运行,使你的目标在任何时候都无效。 你将永远不会有被认为是跟上时代的二进制。
工作的呢?
d=`perl -e"print qq(Whatever calculated at runtime);"`; g++ prog.cpp -o prog -DDATETIME=$$d