我想将一些选项传递给编译器。 该选项必须在编译时计算 - 每次调用'make'时,而不是'cmake',因此execute_process命令不会删除它。 (是吗?)

例如,将日期传递给g ++编译器,如:

g++ prog.cpp -o prog -DDATETIME="17:09:2009,14:25"

但是在编译时计算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。

有帮助吗?

解决方案

您遗漏了一些信息,例如您需要的平台 要运行它,如果有任何其他工具可以使用。如果 你可以使用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)

文件“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生成器,您可以 在反引号中插入命令。如果你在弄清楚的时候生气了 引用,将命令的所有逻辑移到shell脚本中 你只需要在add_definitions()中加入 mycommand.sh

if(UNIX)
  add_definitions(`${CMAKE_CURRENT_SOURCE_DIR}/custom-options.sh`)
endif()

对于基于Windows批处理文件的生成器,事情很多,而且我 没有一个好的解决方案。问题是 PRE_BUILD 命令 不会作为与实际编译器相同的批处理文件的一部分执行 调用(详细研究BuildLog.htm),所以我最初的想法 不起作用(在 PRE_BUILD 步骤中生成custom.bat然后执行 “call 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)

将file1.h复制到file2.h。

无论如何,如果你不想使用CMake生成头文件,你需要调用单独的.bat / .sh脚本来生成头文件,或者使用echo来执行:

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}\"")

第一行运行shell命令 svnversion ,并将结果放入变量 SVN_REV 。需要字符串(STRIP ...)命令从输出中删除尾随换行符。

请注意,这是假设正在运行的命令是跨平台的。如果没有,您可能需要为不同平台提供替代方案。例如,我使用Unix date 命令的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)

表示日期命令,其中 win_date.bat 是一个以所需格式输出日期的bat文件。

文件 ./ VersionInfo.cpp 中没有两个预处理器变量,但未在任何其他文件中设置。你可以拥有

- VersionInfo.cpp -

std::string version_build_time=BUILD_TIME;
std::string version_svn_rev=SVN_REV;

这似乎可以很好地跨平台工作,并最大限度地减少平台特定代码的数量。

我会使用以下方法:

  1. 创建一个可执行文件,将当前日期打印到stdout(CMake缺少此功能)
  2. 添加一个始终被视为过期的目标
  3. 让目标调用另一个CMake脚本
  4. 让调用的CMake脚本生成头文件
  5. 此示例代码:

    --- 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缺少这个功能,必须构建一个程序来模拟功能。

    然而,在这样做之前,我会考虑两次以上。请记住,每次运行make时都会重新生成头文件,使目标在所有次时无效。您永远不会拥有一个被认为是最新的二进制文件。

这有用吗?

d=`perl -e"print qq(Whatever calculated at runtime);"`; g++ prog.cpp -o prog -DDATETIME=$d
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top