c++ - 预处理之后和使用 CMake 编译之前的自定义构建步骤

标签 c++ c cmake

我正在尝试使用 CMake 在预处理和编译之间添加自定义构建步骤。

在 C++ 预处理器步骤之后,我想在每个预处理的源文件上调用 python 脚本来修改它们。

这里有一个 Makefile 示例:

all : prog

# compilation step
prog: main.i
    gcc main.i -g -Wall -o prog 

# custom step
main.i: main.tmp
    ./my_script.py main.tmp > main.i

# only preprocessor step
main.tmp: main.c main.h
    gcc -E main.c > main.tmp

如何使用 CMake 来实现这一点?该步骤应应用于项目的每个 ccpp 文件。

最佳答案

使用the first signature of add_custom_command 运行命令来预处理文件,然后运行命令来执行自定义附加处理,并定义 OUTPUT作为自定义处理创建的文件,然后在定义该文件时将该文件列为相关目标的源文件(通过 add_library/add_executable ),或者在定义它之后执行此操作(通过 target_sources )。

如果您想采用我将展示的方法,那么在 CMake 中使用编译器标志和定义将变得非常棘手。一般来说,您需要确保预处理步骤命令具有与编译步骤命令完全相同的编译器定义和标志。如果预处理和编译之间的标志或定义不同,则可能会发生非常奇怪、微妙且可能危险的事情。您可能会遇到编译器错误,您可能会遇到链接器错误,您可能会遇到运行时错误 - 所有这些都可能难以理解 - 或者您可能没有收到任何错误,但仍然犯了错误。您需要极其小心,了解您的编译器并检查预处理器输出,以确保您正确完成操作。

也许有更好的方法,但我还没有想到。我从未在实际项目中这样做过。以下答案只是理论。将其视为起点。它不提供任何保证(<插入您在此处始终在开源许可证中看到的法律保证声明>)。虽然我会努力修复发现的错误并保持最新状态,但如果由于使用此功能而出现任何问题,我将不承担责任。

例如。对于 gcc(注意:有关 -E.ii 的文档,请参阅 here ):

list(APPEND my_target_sources "${CMAKE_CURRENT_SOURCE_DIR}/file.cpp")

# this is best placed immediately after the creation of the target so that it knows all the directory compile options and such that the target saw when it got created.
foreach(input_file ${my_target_sources})
  set(output_file "${CMAKE_CURRENT_BINARY_DIR}/src-$<CONFIG>/file.ii")
  get_target_property(target_compile_opts my_target COMPILE_OPTIONS)
  add_custom_command(
    OUTPUT "${output_file}"
    COMMAND "${CMAKE_CXX_COMPILER}" ${CMAKE_CXX_FLAGS}  ${target_compile_opts} -o "${output_file}" -E "${input_file}"
    COMMAND my_additional_custom_processing_script "${output_file}" my_arg1 my_arg2 my_arg3
    DEPENDS "${input_file}" "my_additional_custom_processing_script"
    VERBATIM COMMAND_EXPAND_LISTS # these two args are generally useful, but not actually required here.
  )
  target_sources(my_target PRIVATE "${output_file}")

  # this might be needed since I don't expect cmake to infer CXX from the .ii extension
  set_property(SOURCE "${output_file}" TARGET_DIRECTORY my_target PROPERTY LANGUAGE CXX)
endforeach()

虽然提问者使用的是 python 脚本,但为了对其他 future 的读者具有通用性,并尝试将其他非常相似的问题标记为重复,我尝试让该部分保持一点通用性,并将其编写为好像命令可以由主机系统在 PATH 上找到,并且可以自行运行(即,如果是脚本,则假设它具有适当的 shebang)。修改自定义预处理命令部分以适合您的用例。

如果您想在每个源文件的基础上设置任何编译器选项,您需要确保在该文件的自定义命令中设置它们,并在 COMPILE_OPTIONS 中设置它们。 preporty 用于后预处理源文件。

如果有关预处理输出的任何内容取决于 the general compiler flags that are config-specific ( CMAKE_<LANG>_FLAGS_<CONFIG> ) ,您需要将那些包含在正确生成器表达式中的变量添加到 COMMAND ,如"$<$<CONFIG:Debug>:${CMAKE_CXX_FLAGS_DEBUG}>" 。我不知道有什么更好的方法可以对所有配置执行此操作。

目前缺少此答案:

  • 设置INTERFACE预处理时来自目标依赖项的编译器选项。
  • 通过 compile definitions associated with the target到预处理器步骤命令。
    • 在我或某人找到实现此目的的好方法之前,当涉及 NDEBUG 的存在或不存在时,您可能会立即注意到这一点。宏。

我真的希望有人知道更好的方法来做到这一点,因为我在这里的答案已经成熟,有各种错误的机会。

关于c++ - 预处理之后和使用 CMake 编译之前的自定义构建步骤,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37587616/

相关文章:

c++ - 混合 C 和 C++ 库

c - pthread_created 后跟 pthread_join valgrind 可能损失 c

c++ - 英特尔® IPP 异步 C/C++ 库是否包含在标准 IPP 库中?

c++ - 如何在 CMake 文件中添加定义 QT_NO_DEBUG_OUTPUT?

c - 没有动态内存分配的自引用(递归)结构

c++ - 如何查看 cmake_automoc 正在运行的确切命令?

c++ - lambda tbb parallel reduce with a few arguments

c++ - 参数包模板元编程深度优先搜索

c# - 从 dll 调用 opencv Mat 到 Windows 窗体,图像出现故障

c++ - 使用QT进行XML解析