如何在使用 CMake 编译之前替换源文件中的字符串?

Ben*_*uch 4 c++ cmake

我想在编译之前替换源代码文件中的a = statement;字符串。// something else这对应于一个预处理器#define,但是要替换的字符串不是一个简单的标识符。所以我想让 CMake 在编译之前执行此操作。

我的文件结构是:

main.cpp
CMakeLists.txt
build/
Run Code Online (Sandbox Code Playgroud)

的不可变内容main.cpp

main.cpp
CMakeLists.txt
build/
Run Code Online (Sandbox Code Playgroud)

当前内容CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(main)

file(READ main.cpp TEXT)
string(REPLACE "foo" "bar" TEXT "${TEXT}")
file(WRITE main.cpp "${TEXT}")

add_executable(main main.cpp)
Run Code Online (Sandbox Code Playgroud)

build/我调用cmake配置和构建我的项目:

#include <iostream>

int main() {
   std::cout << "foo\n";
}
Run Code Online (Sandbox Code Playgroud)

目前,在main.cpp文件中的配置过程中,该字符串foo被替换为bar. 然后将更改后的文件编译为可执行文件。

我希望 CMake 在构建期间读取main.cpp、替换字符串、写入文件CMAKE_BINARY_DIR,然后将这个新文件编译为可执行文件add_executable。这可能吗?

不应使用外部工具,因为我无法控制编译该项目的系统。configure_file似乎不起作用,因为这里不能替换任意字符串。

sta*_*all 6

是的,可以通过将字符串替换移动到单独的 CMake 脚本中来实现,然后在add_custom_command构建过程中调用该脚本。

如果您想要单个文件解决方案,则可以在配置期间写入此单独的文件。该文件的名称如replace.cmake以下示例所示。为了简化文件内容的定义并且不必进行大量转义以防止立即变量扩展,括号参数非常有用。

cmake_minimum_required(VERSION 3.12)

project(main)

file(WRITE "${CMAKE_BINARY_DIR}/replace.cmake"
[=[
file(READ "${SOURCE}" TEXT)
string(REPLACE "foo" "bar" TEXT "${TEXT}")
file(WRITE "${TARGET}" "${TEXT}")
]=])

add_custom_command(
    OUTPUT "${CMAKE_BINARY_DIR}/main.cpp"
    COMMAND "${CMAKE_COMMAND}"
        "-DSOURCE=${CMAKE_SOURCE_DIR}/main.cpp"
        "-DTARGET=${CMAKE_BINARY_DIR}/main.cpp"
        -P "${CMAKE_BINARY_DIR}/replace.cmake"
    DEPENDS "${CMAKE_SOURCE_DIR}/main.cpp" "${CMAKE_BINARY_DIR}/replace.cmake"
)

add_executable(main "${CMAKE_BINARY_DIR}/main.cpp")
Run Code Online (Sandbox Code Playgroud)

指定add_custom_command如果main.cpp自上次构建以来该文件发生更改,或者更准确地说,如果依赖文件具有比输出文件更新的时间戳,则处理该文件。

如果您选择将执行替换的脚本文件作为其自己的文件而不是生成它,您还应该将其列为自定义命令的依赖项,以便在更改脚本时它会重新运行。

您可以使用configure_file代替string(REPLACE),但是您必须遵循为该命令定义的模板/变量引用语法,并确保它不会扩展您不打算扩展的任何其他内容。

的目标定义add_executable必须引用新生成的版本main.cpp