【问题标题】:Best practice to run a prebuild step with CMake使用 CMake 运行预构建步骤的最佳实践
【发布时间】:2021-07-05 13:34:00
【问题描述】:

假设您有一个存储库,其中包含一个文件夹(名为 dataset),其中包含多个 .csv 文件和一个 python 脚本(名为 csvcut.py),该脚本获取数据集中的所有 .csv 并生成相应的 .h 文件。

这些 .h 文件包含在一些 .cpp 文件中以构建用于测试的可执行文件 (add_executable(testlib...)。

假设您使用 add_custom_target(test_pattern... 创建一个运行 csvcut.py 的目标(名为 test_pattern),并使用 add_dependencies(testlib test_pattern) 在构建 testlib 之前运行脚本。

这行得通,但最好是:

  • 脚本仅在数据集文件夹中的文件或脚本本身发生更改时运行(而不是在 .cpp 更改时);
  • .h 文件在构建文件夹的子文件夹(即 build/tests/dataset/)中生成,并包含在 .cpp 文件中,如 #include <tests/dataset/generated.h>

您对进行这些改进/优化有什么建议吗?

谢谢,阿尔贝托

【问题讨论】:

  • 第一个任务似乎很难,但第二个任务似乎很容易。您可以将${CMAKE_CURRENT_BINARY_DIR} 传递给gererator 脚本,以便它可以将生成的文件放到build 文件夹中。然后将${CMAKE_CURRENT_BINARY_DIR} 作为包含目录添加到相关目标(可执行文件或库)与target_include_directories

标签: c++ cmake prebuild


【解决方案1】:

这需要多个步骤,但都可以使用标准 CMake 处理。首先,我们将使用add_custom_command 来实际生成文件。我还添加了一个自定义目标,但只是因为我无法弄清楚如何在没有它的情况下使 INTERFACE 库工作。

add_custom_command(
    OUTPUT
        "${CMAKE_CURRENT_BINARY_DIR}/include/foo.h"
    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/gen.py"
    DEPENDS
        gen.py
        foo.h.in
    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include"
)
add_custom_target(gen_files
    DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/include/foo.h"
)

就我而言,gen.py 只是吐出一个基本的头文件,但这并不重要。列出你需要的任何文件作为输出,你的 csv 文件应该在DEPENDS 下(对我来说,foo.h.in 试图模拟这个)。

由于您只提到了生成头文件,我创建了一个依赖于gen_files 目标的INTERFACE 库。我还添加了适当的包含目录。

add_library(foo INTERFACE)
target_include_directories(foo
    INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/include"
)
add_dependencies(foo
    gen_files
)

如果构建 STATIC/SHARED 库,我可以直接添加生成的文件,因为源和依赖项工作,但 INTERFACE 库需要额外的目标(即使我尝试在 @ 下列出文件987654333@)。由于您已经有一个自定义目标,我认为这不会是一个大问题。

最后,我有一个链接到foo 的可执行文件。

add_executable(main
    main.c
)
target_link_libraries(main
    PRIVATE
        foo
)

演示:

$ make clean 
$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  include  Makefile
$ make
[ 33%] Generating include/foo.h
[ 33%] Built target gen_files
[ 66%] Building C object CMakeFiles/main.dir/main.c.o
[100%] Linking C executable main
[100%] Built target main
$ make clean
$ make main
[ 33%] Generating include/foo.h
[ 33%] Built target gen_files
[ 66%] Building C object CMakeFiles/main.dir/main.c.o
[100%] Linking C executable main
[100%] Built target main
$ make
[ 33%] Built target gen_files
[100%] Built target main
$ touch ../foo.h.in 
$ make
[ 33%] Generating include/foo.h
[ 33%] Built target gen_files
[100%] Built target main
$ touch ../gen.py 
$ make
[ 33%] Generating include/foo.h
[ 33%] Built target gen_files
[100%] Built target main
$ ls include/
foo.h

如果输入 (foo.h.in) 或生成脚本 (gen.py) 发生更改,则重新构建目标。

【讨论】:

  • 太棒了!您的示例对解决我的问题非常有帮助。我第一次使用 add_custom_command 和 add_custom_target 的组合,这在许多其他场景中可能对我有用。谢谢!
猜你喜欢
  • 2018-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-06
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
相关资源
最近更新 更多