CMP0058¶
警告
此策略的 OLD 行为已在 CMake 4.0 版本中移除。此策略必须通过调用 cmake_minimum_required() 或 cmake_policy() 来设置为 NEW。
3.3 版本中新增。
Ninja 要求自定义命令的副产品(byproducts)必须显式声明。
当构建过程中生成的中间文件被一个耗时操作或一个大型依赖树所消费时,可以通过仅在文件内容更改时才更新文件时间戳来减少增量重建所需的工作量。使用此方法,生成规则必须有一个单独的输出文件,该文件始终使用比规则的任何依赖项都新的时间戳进行更新,以便构建工具仅在输入更改时才重新运行规则。我们将这个单独的输出文件称为规则的见证文件 (witness),将生成的文件称为规则的副产品 (byproduct)。
副产品不能被列为输出,因为它们的时间戳允许比输入旧。当 CMake 被设计出来时,已有的构建工具(如 make)都没有表达副产品的方式。因此,CMake 3.2 之前的版本无法指定它们。项目通常会将副产品留给生成它们的规则 undeclared。例如:
add_custom_command(
OUTPUT witness.txt
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/input.txt
byproduct.txt # timestamp may not change
COMMAND ${CMAKE_COMMAND} -E touch witness.txt
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.txt
)
add_custom_target(Provider DEPENDS witness.txt)
add_custom_command(
OUTPUT generated.c
COMMAND expensive-task -i byproduct.txt -o generated.c
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/byproduct.txt
)
add_library(Consumer generated.c)
add_dependencies(Consumer Provider)
这种方式对除了 Ninja 之外的所有生成器都工作良好。Ninja 构建工具将 byproduct.txt 列为依赖项,但没有规则将其列为输出。然后 Ninja 会抱怨没有办法满足这个依赖,并停止构建,即使有顺序依赖(order-only dependencies)确保 byproduct.txt 在其消费者需要它之前就会存在。有关 Ninja 为何如此工作的更多细节,请参阅 Ninja Issue 760 中对这个问题的讨论。
Ninja 希望副产品与其它输出一起被列出,而不是留给生成它们的规则 undeclared。这样的规则可以被标记为 restat 选项,该选项告诉 Ninja 在规则运行后检查输出的时间戳。这可以防止那些时间戳没有改变的副产品不必要地导致它们的依赖项重新构建。
由于上述方法没有告诉 CMake 是哪个自定义命令生成了 byproduct.txt,Ninja 生成器没有足够的信息将副产品添加为任何规则的输出。CMake 2.8.12 及以上版本通过生成 phony 构建规则来容忍这些丢失的文件,从而解决了这个问题,并允许使用上述方法的项目进行构建。然而,这个变通方法阻止了 Ninja 诊断真正缺失的依赖项。它在 in-source 构建中也效果不佳,因为在这种情况下,每个自定义命令的依赖项,即使是源文件,都需要以这种方式处理,因为 CMake 没有足够的信息来知道哪些文件是自定义命令生成的副产品。
引入副产品¶
CMake 3.2 在 add_custom_command() 和 add_custom_target() 命令中引入了 BYPRODUCTS 选项。此选项允许显式指定副产品。
add_custom_command(
OUTPUT witness.txt
BYPRODUCTS byproduct.txt # explicit byproduct specification
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/input.txt
byproduct.txt # timestamp may not change
...
BYPRODUCTS 选项被 Ninja 生成器用来将副产品列在生成它们的自定义命令的输出中,并被其他生成器忽略。
CMake 3.3 及以上版本倾向于要求项目显式指定自定义命令的副产品,以便能够完全避免使用 phony 规则的变通方法。策略 CMP0058 被引入,以提供与仍然需要变通方法的现有项目兼容。
此策略对 Ninja 之外的生成器没有影响。此策略的 OLD 行为是为构建树中未知的依赖项生成 Ninja phony 规则。此策略的 NEW 行为是不生成这些规则,而是要求项目显式指定自定义命令的 BYPRODUCTS。
策略设置必须在项目的顶层 CMakeLists.txt 文件结束时处于作用域内,并且具有全局影响。
此策略在 CMake 版本 3.3 中引入。在 CMake 版本 4.0 移除之前,可以通过 cmake_policy() 或 cmake_minimum_required() 设置。如果未设置,CMake 会在看到 out-of-source 构建树中的未知依赖项时发出警告,并使用 OLD 行为。