我正在使用 cmake 构建一些库,所有这些库都会生成它们的一些文件。
我已经使用 add_custom_command() 创建了生成的文件,但是我发现了一些看起来像是错误依赖的东西。如果下游库有生成的文件并链接到上游库,则下游库源将不会开始编译,直到上游库完全构建。在我的项目中有许多库(超过 50 个),这种错误的依赖关系会导致构建中的序列化。
奇怪的是,我还注意到,如果生成文件的显式 add_custom_target() 与 add_dependencies() 一起使用,则错误依赖项不再存在,并且下游库中的文件将与上游库中的文件同时编译。所以我有一个解决方法,但这是预期的行为吗?
使用 Cmake 1.19、忍者 1.10.2。
以下是显示发生了什么的最小 CMakeLists.txt 文件。WORKS 选项有条件地添加 add_custom_target() 和 add_dependencies() 子句,使其工作(快速)。文件 foo.c 和 bar.c 是空的,我正在 CMakeLists.txt 目录的子目录中构建。
我放了一个名为 /tmp/x 的文件,它是 cc 的一个包装器,它休眠以显示序列化发生:
#!/bin/bash -e
echo "mycc" $(date)
sleep 4
exec /usr/bin/cc $*
这是 CMakeLists.txt:
cmake_minimum_required(VERSION 3.19)
project(test)
option(WORKS "false dependency gone if WORKS set to ON" OFF)
add_library(foo
foo.c
)
add_library(bar
bar.c
bargen.h
)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
add_custom_command(OUTPUT bargen.h
COMMAND touch bargen.h
)
if (${WORKS})
add_custom_target(generate_file
DEPENDS bargen.h
)
add_dependencies(bar generate_file)
endif()
target_link_libraries(bar PUBLIC foo)
像这样构建它,您将看到序列化:bar.c 直到 foo.c 完成编译后才开始编译(实际上,直到构建 foo 库之后)。(我明确选择“-j 4”以确保 Ninja 将尝试并行构建)。
cmake -DWORKS=OFF -G Ninja -DCMAKE_C_COMPILER=/tmp/x .. && ninja clean && ninja -j 4 -v | grep mycc
这显示了以下输出:
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/rhb/Downloads/cmake-anomaly/build
[1/1] Cleaning all built files...
Cleaning... 5 files.
mycc Sat Jan 2 15:15:25 EST 2021
mycc Sat Jan 2 15:15:29 EST 2021
现在像这样构建它,你会看到 bar.c 与 foo.c 并行编译:
cmake -DWORKS=ON -G Ninja -DCMAKE_C_COMPILER=/tmp/x .. && ninja clean && ninja -j 4 -v | grep mycc
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/rhb/Downloads/cmake-anomaly/build
[1/1] Cleaning all built files...
Cleaning... 5 files.
mycc Sat Jan 2 15:15:37 EST 2021
mycc Sat Jan 2 15:15:37 EST 2021