【问题标题】:When should I rerun cmake?我应该什么时候重新运行 cmake?
【发布时间】:2015-03-30 18:23:41
【问题描述】:

在运行一次cmake 命令以生成构建系统后,我应该在什么时候重新运行cmake 命令?

生成的构建系统可以检测相关CMakeLists.txt 文件中的更改并做出相应的行为。您可以在生成的 Makefile 中看到这样做的逻辑。什么时候会成功发生的确切规则对我来说是个谜。

我应该什么时候重新运行cmake?答案是否取决于使用的生成器?

This blog post(在标题下:“多次调用 CMake”)指出了对这个问题的困惑,并指出答案实际上是“从不”,无论生成器如何,但我发现这令人惊讶。是真的吗?

【问题讨论】:

  • 如果您的新代码需要链接一个新库怎么办?我认为你应该重新运行 cmake。
  • @GuyL 实际上,在这种情况下,我认为你很适合。
  • 因为 CMakeLists.txt 中检测到的更改?我不是 cMake 专家(我只将它用于 cLion 项目)
  • 是的,生成的构建系统知道 CMakeLists.txt 文件,并且可以参考它们以检查更改并相应地修改构建。

标签: cmake


【解决方案1】:

答案很简单: cmake 二进制文件当然需要在您每次更改任何构建设置时重新运行,但不需要按设计这样做;因此,对于您必须发出的命令,“从不”是正确的。

cmake 创建的构建目标自动包含检查随后 [=从主 CMakeLists.txt 文件开始] 涉及或包含生成当前 Makefiles/VS 项目/任何文件集的每个文件。当调用make(假设这里是unix)时,如果需要,这会自动触发cmake的先前执行;因此您生成的项目包含调用 cmake 本身的逻辑!由于最初传递的所有命令行参数(例如cmake -DCMAKE_BUILD_TYPE=RELEASE .. 将存储在CMakeCache.txt 中,您不需要在后续调用中重新指定任何这些参数,这就是为什么项目也可以只运行cmake 并知道它仍然按照您的意愿行事。

更多细节: CMake 生成簿记文件,其中包含 Makefile/Project 生成中涉及的所有文件,参见例如我的<binary-dir>/CMakeFiles/Makefile.cmake 文件的这些示例内容使用 MSYS 生成文件:

# The top level Makefile was generated from the following files:
set(CMAKE_MAKEFILE_DEPENDS
  "CMakeCache.txt"
  "C:/Program Files (x86)/CMake/share/cmake-3.1/Modules/CMakeCCompiler.cmake.in"
  "C:/Program Files (x86)/CMake/share/cmake-3.1/Modules/RepositoryInfo.txt.in"
  "<my external project bin dir>/release/ep_tmp/IRON-cfgcmd.txt.in" 
  "../CMakeFindModuleWrappers/FindBLAS.cmake"
  "../CMakeFindModuleWrappers/FindLAPACK.cmake"
  "../CMakeLists.txt"
  "../CMakeScripts/CreateLocalConfig.cmake"
  "../Config/Variables.cmake"
  "../Dependencies.cmake"
  "CMakeFiles/3.1.0/CMakeCCompiler.cmake"
  "CMakeFiles/3.1.0/CMakeRCCompiler.cmake")

对任何这些文件的任何修改都会触发另一个 cmake 运行只要您选择开始构建目标。老实说,我不知道这些依赖项跟踪在 CMake 中的精细程度如何,即如果其他地方的任何更改不会影响目标的编译,是否只会构建目标。我没想到它会很快变得混乱,而且重复的 CMake 运行(正确使用缓存功能)无论如何都非常快。

唯一需要重新运行cmake 的情况是在启动project(MyProject) 后更改编译器;但即使这种情况现在也由较新的 CMake 版本自动处理(有些大喊大叫:-))。

回复 cmets 的附加评论:

在某些情况下,您需要手动重新运行 cmake,也就是说,每当您编写配置脚本时,cmake 可能无法检测到您正在创建的文件/依赖项。一个典型的场景是您的第一次 cmake 运行使用例如创建文件。 execute_process 然后您将使用file(GLOB ..) 将它们包括在内。这是糟糕的风格,CMake Docs for file 明确表示

注意:我们不建议使用 GLOB 从源代码树中收集源文件列表。如果在添加或删除源时没有 CMakeLists.txt 文件发生更改,则生成的构建系统无法知道何时要求 CMake 重新生成。

顺便说一句,这条评论也阐明了上面解释的生成的构建系统的自我调用:-)

处理在配置期间创建源文件的这种情况的“正确”方法是使用add_custom_command(OUTPUT ...),以便 CMake 能够“感知”正在生成的文件并正确跟踪更改。如果由于某种原因您不能/不会使用add_custom_command,您仍然可以使用源文件属性GENERATED 让CMake 知道您的文件生成。任何带有此标志集的源文件都可以硬编码到目标源文件中,并且 CMake 不会在配置时抱怨缺少文件(并希望在(第一次!)cmake 运行期间生成该文件。

【讨论】:

  • you change the compiler after you started a project(MyProject) 根本不这样做:) 在项目之前/在工具链中/显式设置编译器作为 cmake '-D' 参数
  • 请考虑该问题的上下文。我希望每个人都清楚你不应该那样改变编译器!当你这样做时,甚至 cmake 都会对你大喊大叫。
  • 嗯,是的,我不确定我是否正确理解了最后一部分。通过“重新运行 cmake”,我的意思是使用旧的构建目录调用它。因此,当您更改编译器时,您必须创建 new 构建目录。所以我不同意它是“重新运行”——你是从头开始运行新项目。 tl;dr 你永远不需要重新运行 cmake,没有例外:)
  • 这个答案将通过解决文件通配和类似情况得到改善。如果您认为这些是不应该做的事情,请随意提出反对意见,但它们仍然是完整答案的一部分。当使用文件通配符需要手动重新运行cmake 时,我很清楚。我不清楚其他外部命令何时会导致需要手动重新运行 cmake
  • @ruslo 是的,如果您正确使用 cmake,这正是您应该做的。但是,如果您编码错误并从您的配置脚本中发出更改编译器的命令(在 project() 命令之后),那么 cmake 将自动重新运行。
【解决方案2】:

查看此主题以从 debian/changelog 文件(生成阶段)读取版本信息,我在主题中运行 cmake 执行应在 debian/changelog 被修改时触发。所以我需要将 debian/changelog 添加到 CMAKE_MAKEFILE_DEPENDS。

在我的例子中,debian/changelog 是通过 execute_process 读取的。不幸的是,Execute_process 无法将处理过的文件添加到 CMAKE_MAKEFILE_DEPENDS。但我发现运行 configure_file 就可以了。实际上,我在 execute_process 中确实缺少像 DEPENDENCIES 这样的东西。

但是,由于我需要根据自己的需要配置 debian/changelog 文件,因此我隐含地找到了解决方案。

其实我在configure_file的官方文档中也发现了一个提示:

“如果输入文件被修改,构建系统将重新运行CMake重新配置文件并再次生成构建系统。”

所以使用configure_file触发cmake的重新运行应该是安全的。

从用户的角度来看,我希望其他命令也可以扩展 CMAKE_MAKEFILE_DEPENDS。例如。 execute_process(按需)还有文件(READ)(隐含地像 configure_file)。也许还有其他人。每个读取文件都可能影响生成阶段。作为替代方案,最好有一个命令来扩展依赖项列表(提示 cmake 开发人员,也许会出现)。

【讨论】:

    猜你喜欢
    • 2021-08-21
    • 2016-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多