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

问题描述 投票:0回答:2

我正在尝试使用 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 来实现这一点?该步骤应应用于项目的每个

c
cpp
文件。

c++ c cmake
2个回答
2
投票

使用

add_custom_command
的第一个签名运行命令来预处理文件,然后运行命令来执行自定义附加处理,并将
OUTPUT
定义为由自定义处理创建的文件,然后列出该文件在定义时将文件作为相关目标的源文件(通过
add_library
/
add_executable
),或者在定义它之后执行(通过
target_sources
)。

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

)。虽然我会努力修复发现的错误并保持最新状态,但如果由于使用此功能而出现任何问题,我将不承担责任。

例如。对于 gcc(注意:请参阅

here

有关 -E

.ii
的文档):
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 脚本,但为了对其他未来的读者具有通用性,并尝试将其他非常相似的问题标记为重复项,我尝试让该部分保持通用性,并将其编写为好像命令可以由主机系统在 PATH 上找到,并且可以自行运行(即,如果是脚本,则假设它具有适当的 shebang)。修改自定义预处理命令部分以适合您的用例。

如果您想在每个源文件的基础上设置任何编译器选项,您需要确保在该文件的自定义命令中设置它们,并在帖子的

COMPILE_OPTIONS

 预报告中设置它们-预处理的源文件。
如果有关预处理输出的任何内容取决于

特定于配置的通用编译器标志 (

CMAKE_<LANG>_FLAGS_<CONFIG>)

,则需要将那些包含在正确生成器表达式中的变量添加到 
COMMAND,例如
 "$<$<CONFIG:Debug>:${CMAKE_CXX_FLAGS_DEBUG}>"
。我不知道有什么更好的方法可以对所有配置执行此操作。

此答案目前缺失

在预处理时从目标的依赖项设置
    INTERFACE
  • 编译器选项。
    将与目标关联的
  • 编译定义
  • 传递给预处理器步骤命令。 在我或某人找到一个好方法来做到这一点之前,当涉及到
      NDEBUG
    • 宏的存在或不存在时,您可能会立即注意到这一点。
      
      
  • 我真的希望有人知道更好的方法来做到这一点,因为我在这里的答案已经成熟,有各种错误的机会。

您可能对 GCC 的

-no-integrated-cpp

 选项感兴趣。虽然我不确定具体如何使用它。


-1
投票

add_custom_target( start_preprocessor COMMAND make main.cpp.i .. )

使用另一个自定义目标,我备份 main.cpp,然后将 main.cpp.i 重命名为 main.cpp。然后我可以应用我的预处理过程。之后,我恢复源文件。

© www.soinside.com 2019 - 2024. All rights reserved.