CMP0058

警告

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

3.3 版本中新增。

Ninja 要求自定义命令副产品是显式的。

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

副产品不能被列为输出,因为它们的时间戳可能比输入旧。在 CMake 设计时存在的构建工具(如 make)都没有表达副产品的方式。因此,CMake 3.2 之前的版本无法指定它们。项目通常将副产品在其生成规则中声明为未声明。例如

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 这种工作方式的更多详细信息,请参阅 Ninja 问题 760 中对此问题的讨论。

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

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

引入副产品

CMake 3.2 引入了 BYPRODUCTS 选项到 add_custom_command()add_custom_target() 命令。此选项允许显式指定副产品

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 行为。