0

我正在使用 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
4

0 回答 0