在CMake语义中,"目标"与命令"之间存在某种区别",令我感到困惑.在Makefile中,没有这样的区别:
targetname:dependency
command
Run Code Online (Sandbox Code Playgroud)
即,目标对应于生成的同名文件.
在CMake中,您有"add_custom_command"和"add_custom_target"等具有重叠功能的命令,即使在官方文档中,语义也会混淆,即在"掌握CMake,第5版",第110页"添加自定义目标"下:
DEPENDS参数设置自定义目标和自定义命令之间的依赖关系.
我的理解是目标(生成的文件)具有依赖性(其他文件,生成或不生成),以及实际生成的命令.说目标取决于命令是没有意义的.更糟糕的是,有两种"add_custom_command"可以将附加命令附加到现有目标,或者将命令吐出到以太网中.
有人可以解释为什么这种区别甚至存在?
Fra*_*ser 43
通常,目标包括可执行文件或库,这些可执行文件或库通过调用add_executable或add_library可以设置许多属性来定义.
它们可以彼此依赖,对于诸如这些目标之类的目标只意味着依赖它们将在它们的依赖之后构建.
但是,您也可以通过定义"自定义目标" add_custom_target.来自文档:
添加具有执行给定命令的给定名称的目标.目标没有输出文件,即使命令尝试创建具有目标名称的文件,也始终在日期之后考虑.使用ADD_CUSTOM_COMMAND生成具有依赖项的文件.默认情况下,不依赖于自定义目标.使用ADD_DEPENDENCIES向其他目标添加依赖项或从其他目标添加依赖项.
所以这些与"普通"目标的不同之处在于它们不代表会产生exe或lib的东西,但是它们仍然可以从目标可以具有的所有属性中受益,包括具有或具有依赖性.它们看起来像是可以构建的目标(例如make MyCustomTarget或msbuild MyCustomTarget.vcxproj).在构建它们时,您只需调用为它们设置的命令.如果它们依赖于其他目标(普通或自定义),那么将首先构建这些目标.
定义via的自定义命令add_custom_command是完全不同的,因为它不是一个"可构建"的对象,并且没有像目标那样具有可设置的属性 - 它不是一个命名对象,可以在添加到目标之后再次明确引用它.的CMakeLists.txt.
它基本上是在构建依赖目标之前将调用的命令(或命令集).这就是"依赖"真的意味着在这里(至少我是如何看待它) - 它只是说如果A依赖于B,那么B将在A构建之前构建/执行.
可以使用add_custom_command(TARGET target ...表单显式设置自定义命令的依赖项,也可以通过创建包含通过add_custom_command(OUTPUT output1 ...表单生成的文件的目标来隐式设置.
在第一种情况下,每次target构建时,首先执行自定义命令.
在第二种情况下,它有点复杂.如果自定义命令具有依赖于其输出文件的目标(并且输出文件尚不存在),则在构建这些依赖对象之前调用它.当您执行例如通过其生成的文件的add_library(MyLib output1.h ... )位置时,将隐式创建依赖项.output1.hadd_custom_command(OUTPUT output1.h ... )
add_custom_command 添加一个可调用函数,该函数可以定义输出(使用 OUTPUT 和 BYPRODUCTS 参数)。它还可以具有将在调用函数之前运行的依赖项。
请注意,由于奇怪的文档(makefile 示例非常具有误导性),它不会执行您可能认为它会做的事情。特别是,它对执行的次数没有任何保证。例如,想象一下:
add_custom_command(OUTPUT /tmp/touched COMMAND echo touch COMMAND touch /tmp/touched)
add_custom_target(touched-one ALL DEPENDS /tmp/touched)
add_custom_target(touched-two ALL DEPENDS /tmp/touched)
Run Code Online (Sandbox Code Playgroud)
“触摸”会打印多少次?你不知道,因为它没有在任何地方指定;make -j2 可能会打印两次,但它与时间有关:
Scanning dependencies of target touched-two
Scanning dependencies of target touched-one
[ 50%] Generating touched
touch
[100%] Generating touched
touch
[100%] Built target touched-two
[100%] Built target touched-one
Run Code Online (Sandbox Code Playgroud)
但是 Ninja 只会打印一次,大概是:
# rm -rf * && cmake -GNinja ../c ; cmake --build . -- -j 5
[1/1] Generating touched
touch
Run Code Online (Sandbox Code Playgroud)
通常,您将执行 add_custom_command 来完成一些工作并定义一个 OUTPUT,然后您将拥有一个依赖于自定义命令输出的 add_custom_target。任何想要输出的人都取决于目标,这确实为您提供了所需的保证。
警告:查看这个 bug的一个很好的例子,说明为什么构建跨平台元构建工具真的很难。
| 归档时间: |
|
| 查看次数: |
30483 次 |
| 最近记录: |