运行 使用 CMake 进行预构建步骤的最佳实践
Best practice to run a prebuild step with CMake
假设您有一个存储库,其中包含一个包含多个 .csv 文件的文件夹(名为数据集)和一个 python 脚本(名为 csvcut.py),该脚本获取数据集中的所有 .csv 并生成相应的 . h 个文件。
这些 .h 文件包含在一些 .cpp 文件中以构建用于测试的可执行文件 (add_executable(testlib...
)。
假设您使用 add_custom_target(test_pattern...
创建一个目标(名为 test_pattern)运行 到 csvcut.py,并且 add_dependencies(testlib test_pattern)
到 运行构建测试库之前的脚本。
这可行,但如果:
会更好
- 仅当数据集文件夹中的文件或脚本本身更改时(不是 .cpp 更改时),脚本才 运行;
- .h 文件是在构建文件夹(即 build/tests/dataset/)的子文件夹中生成的,并包含在 .cpp 文件中,如
#include <tests/dataset/generated.h>
.
您对进行这些改进/优化有什么建议吗?
谢谢,阿尔贝托
这需要多个步骤,但都可以使用标准 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
库需要额外的目标(甚至当我尝试在 add_dependencies
下列出文件时)。由于您已经有一个自定义目标,我认为这不会是一个大问题。
最后,我有一个链接到 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
) 发生变化,目标将被重建。
假设您有一个存储库,其中包含一个包含多个 .csv 文件的文件夹(名为数据集)和一个 python 脚本(名为 csvcut.py),该脚本获取数据集中的所有 .csv 并生成相应的 . h 个文件。
这些 .h 文件包含在一些 .cpp 文件中以构建用于测试的可执行文件 (add_executable(testlib...
)。
假设您使用 add_custom_target(test_pattern...
创建一个目标(名为 test_pattern)运行 到 csvcut.py,并且 add_dependencies(testlib test_pattern)
到 运行构建测试库之前的脚本。
这可行,但如果:
会更好- 仅当数据集文件夹中的文件或脚本本身更改时(不是 .cpp 更改时),脚本才 运行;
- .h 文件是在构建文件夹(即 build/tests/dataset/)的子文件夹中生成的,并包含在 .cpp 文件中,如
#include <tests/dataset/generated.h>
.
您对进行这些改进/优化有什么建议吗?
谢谢,阿尔贝托
这需要多个步骤,但都可以使用标准 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
库需要额外的目标(甚至当我尝试在 add_dependencies
下列出文件时)。由于您已经有一个自定义目标,我认为这不会是一个大问题。
最后,我有一个链接到 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
) 发生变化,目标将被重建。