CMP0058

警告

此策略的 OLD 行为已在 CMake 4.0 版本中移除。此策略必须通过调用 cmake_minimum_required()cmake_policy() 来设置为 NEW

3.3 版本中新增。

Ninja 要求必须显式指定自定义命令的副产品(byproducts)。

当构建过程中生成的中间文件被昂贵的操作或大型依赖树所消耗时,可以通过仅在文件内容发生变化时更新文件时间戳来减少增量重构所需的工作量。采用这种方法时,生成规则必须有一个单独的输出文件,该文件始终更新为比规则的任何依赖项都新的时间戳,以便构建工具仅在输入发生变化时才重新运行该规则。我们将这个单独的输出文件称为规则的“见证文件”(witness),将生成的文件称为规则的“副产品”(byproduct)。

副产品不能被列为输出,因为允许它们的时间戳早于输入文件。在 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 列为依赖项,却没有任何规则将其列为输出。即使存在“仅顺序依赖”(order-only dependencies)以确保 byproduct.txt 在其使用者需要之前存在,Ninja 仍会报错称无法满足依赖关系并停止构建。有关 Ninja 为何以这种方式工作的更多详细信息,请参阅 Ninja Issue 760 的讨论。

Ninja 不希望将副产品留在生成它们的规则中保持未声明状态,而是期望将副产品与其他输出一起列出。此类规则可以标记 restat 选项,该选项告诉 Ninja 在规则运行后检查输出的时间戳。这可以防止时间戳未改变的副产品导致其依赖项进行不必要的重新构建。

由于上述方法没有告诉 CMake 是哪个自定义命令生成了 byproduct.txt,因此 Ninja 生成器没有足够的信息将副产品添加为任何规则的输出。CMake 2.8.12 及更高版本通过生成 phony 构建规则来解决这个问题,允许使用上述方法的项目进行构建,从而告诉 Ninja 容忍此类缺失文件。然而,这种变通方法阻止了 Ninja 诊断真正缺失的依赖项。它在源内构建(in-source builds)中表现也很差,因为每一个自定义命令依赖(即使是对源文件的依赖)都需要以这种方式处理,因为 CMake 没有足够的信息来确定哪些文件是作为自定义命令的副产品生成的。

引入副产品(Byproducts)

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 在源外构建树中发现未知依赖项时会发出警告,并使用 OLD 行为。