CMP0058¶
在版本 3.3 中添加。
Ninja 要求自定义命令副产品是显式的。
当在构建期间生成的中间文件被一个耗时的操作或一个巨大的依赖关系树使用时,可以通过仅在其内容发生变化时更新文件时间戳来减少增量重建所需的工作。使用此方法,生成规则必须有一个单独的输出文件,该文件始终使用比规则的任何依赖项都新的新时间戳进行更新,以便构建工具仅在输入更改时重新运行规则。我们称单独的输出文件为规则的见证,将生成的文件称为规则的副产品。
副产品不可作为输出列出,因为允许它们的时间戳早于输入的时间戳。CMake 在设计时存在的没有任何构建工具(比如 make
) 可以表达副产品。因此,3.2 之前的 CMake 版本没有指定它们的方法。项目通常会将副产品留在生成它们的规则中不声明。例如
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 抱怨无法满足依赖关系,并停止构建,即使有只保证顺序的依赖关系确保在使用者需要之前 byproduct.txt
将存在。请参阅 Ninja 问题 760 中对此问题的讨论,了解更多有关 Ninja 如此工作的原因的详细信息。
不要在生成它们规则中保留未声明的副产品,Ninja 期望副产品与其他输出一起列出。此类规则可以用 restat
选项进行标记,该选项告诉 Ninja 在规则运行后检查输出的时间戳。这可以防止时间戳不变的副产品导致其依赖项不必要地重建。
由于以上方法没有告诉 CMake 哪个自定义命令生成了 byproduct.txt
,所以 Ninja 生成器没有足够的信息将副产品作为任何规则的输出添加。CMake 2.8.12 及更高版本解决了此问题,并允许使用上述方法构建的项目生成 phony
构建规则来告诉 Ninja 容忍此类丢失的文件。然而,此解决方法阻止了 Ninja 诊断真正丢失的依赖关系。它在源内构建中也运行不佳,其中每个自定义命令依赖关系(即使在源文件上)都需要这样处理,因为 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
。
此策略在 CMake 3.3 版中引入。它可通过 cmake_policy()
或 cmake_minimum_required()
进行设置。如果未进行设置,当 CMake 在外部构建树中看到未知的依赖项时会发出警告,并使用 OLD
行为。
策略设置必须在该项目的顶级 CMakeLists.txt
文件的末尾处于作用域内,并且具有全局效果。
注意
一个策略的 OLD
行为 根据定义已弃用 并且可能在未来版本的 CMake 中被移除。