【问题标题】:CMake add_custom_command not being runCMake add_custom_command 未运行
【发布时间】:2011-02-25 14:22:41
【问题描述】:

我正在尝试使用add_custom_command 在构建期间生成文件。该命令似乎从未运行过,所以我制作了这个测试文件。

cmake_minimum_required( VERSION 2.6 )

add_custom_command(
  OUTPUT hello.txt
  COMMAND touch hello.txt
  DEPENDS hello.txt
)

我试过跑步:

cmake .  
make

并且没有生成 hello.txt。我做错了什么?

【问题讨论】:

  • add_custom_target could 是 add_custom_command 的替代品

标签: cmake cmake-custom-command


【解决方案1】:

add_custom_target(run ALL ... 解决方案适用于只有一个目标正在构建的简单情况,但当您有多个顶级目标时会崩溃,例如应用和测试。

当我试图将一些测试数据文件打包到一个目标文件中时,我遇到了同样的问题,这样我的单元测试就不会依赖于任何外部。我使用add_custom_command 解决了它,并使用set_property 解决了一些额外的依赖魔法。

add_custom_command(
  OUTPUT testData.cpp
  COMMAND reswrap 
  ARGS    testData.src > testData.cpp
  DEPENDS testData.src 
)
set_property(SOURCE unit-tests.cpp APPEND PROPERTY OBJECT_DEPENDS testData.cpp)

add_executable(app main.cpp)
add_executable(tests unit-tests.cpp)

所以现在 testData.cpp 将在 unit-tests.cpp 编译之前生成,并且任何时候 testData.src 更改。如果您调用的命令真的很慢,您将获得额外的好处,即当您仅构建应用程序目标时,您不必等待该命令(只有测试可执行文件需要)完成。

上面没有显示,但仔细应用${PROJECT_BINARY_DIR}, ${PROJECT_SOURCE_DIR} and include_directories() 将使您的源代码树中生成的文件保持干净。

【讨论】:

  • 这个尴尬的时刻,最好的答案不是带有绿色复选图标的那个:) 谢谢 Rian!
  • 不应该add_dependencies 能够完成set_property(... 行的工作吗?
  • cmake 还有很多其他的好处。我真正喜欢的主要内容之一是生成器(Makefile、ninja 文件、Visual Studio、Eclipse 等)。 CMake 的语言不像任何常规的高级编程语言那样进化,但是一旦你在几个小时内掌握了它就非常容易。 Autotools 很好,过去很流行。想一想:为什么有这么多人使用 cmake 而不是 autotools?它更容易学习并提供更多好处。
  • @dom0,你可以用add_dependencies 来做,但它有点棘手。您不能直接在add_custom_command 和其他东西之间添加依赖关系,您首先必须创建一个add_custom_target(它是空的,它只是用于提供一个您可以稍后命名的目标)。原因是add_dependencies 只能将目标作为参数,而不是文件。有关更多信息,请参阅此博客:samthursfield.wordpress.com/2015/11/21/…
  • 当两个答案低于公认答案是最好的答案时,更加尴尬的时刻是最好的答案,而对应该是答案的第一个评论是专业的声音而不是尖刻的。跨度>
【解决方案2】:

添加以下内容:

add_custom_target(run ALL
    DEPENDS hello.txt)

如果您熟悉 makefile,这意味着:

all: run
run: hello.txt

【讨论】:

  • 这对我来说不起作用,CMake 3.6.1,OSX。我在我的 CMakeLists.txt add_custom_command( OUTPUT hello.txt COMMAND touch ARGS hello.txt DEPENDS hello.txt ) 中做了以下操作并添加了 add_custom_target(run ALL DEPENDS hello.txt )
  • add_custom_target每次都运行,改用Rian提倡的add_custom_command
  • @linello 从你的add_custom_command() 调用中删除 DEPENDS,它会创建一个循环依赖。只有add_custom_target() 应该在此处具有 DEPENDS 参数。当你修复它时,它在 OS X 上对我有用(用 CMake 3.8.0 测试)。
【解决方案3】:

两个现有答案的问题是,它们要么使依赖项全局化 (add_custom_target(name ALL ...)),要么将其分配给特定的单个文件 (set_property(...)),如果您有许多文件需要它作为一个依赖。相反,我们想要的是一个可以依赖另一个目标的目标。

这样做的方法是使用add_custom_command 定义规则,然后add_custom_target 根据该规则定义一个新目标。然后您可以通过add_dependencies将该目标添加为另一个目标的依赖项。

# this defines the build rule for some_file
add_custom_command(
  OUTPUT some_file
  COMMAND ...
)
# create a target that includes some_file, this gives us a name that we can use later
add_custom_target(
  some_target
  DEPENDS some_file
)
# then let's suppose we're creating a library
add_library(some_library some_other_file.c)
# we can add the target as a dependency, and it will affect only this library
add_dependencies(some_library some_target)

这种方法的优点:

  • some_target 不是 ALL 的依赖项,这意味着您仅在特定目标需要时才构建它。 (而add_custom_target(name ALL ...) 将无条件地为所有目标构建它。)
  • 因为some_target 是整个库的依赖项,所以它将在该库中的所有文件之前构建。这意味着如果库中有很多文件,我们不必对每个文件都执行set_property
  • 如果我们将DEPENDS 添加到add_custom_command,那么它只会在其输入发生变化时重建。 (将此与使用 add_custom_target(name ALL ...) 的方法进行比较,在该方法中,无论是否需要,命令都会在每个构建上运行。)

有关为什么会这样工作的更多信息,请参阅这篇博文:https://samthursfield.wordpress.com/2015/11/21/cmake-dependencies-between-targets-and-files-and-custom-commands/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多