添加自定义命令

将自定义构建规则添加到生成的构建系统。

add_custom_command 有两个主要签名。

生成文件

第一个签名用于添加自定义命令以生成输出:

add_custom_command(OUTPUT output1 [output2 ...]
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [MAIN_DEPENDENCY depend]
                   [DEPENDS [depends...]]
                   [BYPRODUCTS [files...]]
                   [IMPLICIT_DEPENDS <lang1> depend1
                                    [<lang2> depend2] ...]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [DEPFILE depfile]
                   [JOB_POOL job_pool]
                   [VERBATIM] [APPEND] [USES_TERMINAL]
                   [COMMAND_EXPAND_LISTS])

这定义了一个命令来生成指定的 OUTPUT 文件。在同一目录(CMakeLists.txt 文件)中创建的将自定义命令的任何输出指定为源文件的目标被赋予规则以在构建时使用命令生成文件。

不要在多个可能并行构建的独立目标中列出输出,否则规则的实例可能会发生冲突。相反,使用 add_custom_target() 命令来驱动命令并使其他目标依赖于该命令。请参阅下面的“示例:为多个目标生成文件”。

选项是:

追加

COMMANDDEPENDS 选项值附加到指定第一个输出的自定义命令。之前必须已经调用过具有相同输出的此命令。

如果前一个调用通过生成器表达式指定了输出,则当前调用指定的输出必须在评估生成器表达式后至少在一个配置中匹配。在这种情况下,附加的命令和依赖项适用于所有配置。

COMMENTMAIN_DEPENDENCYWORKING_DIRECTORY 选项当前在给出 APPEND 时被忽略,但将来可能会被使用。

副产品

在 3.2 版本加入.

指定命令预期生成的文件,但其修改时间可能比依赖项更新,也可能不更新。如果副产品名称是相对路径,它将相对于与当前源目录相对应的构建树目录进行解释。每个副产品文件将自动标有 GENERATED 源文件属性。

查看政策 CMP0058 了解此功能背后的动机。

Ninja 生成器支持副产品的显式规范,以告诉 ninja 构建工具如何在副产品丢失时重新生成它们。当其他构建规则(例如自定义命令)依赖于副产品时,它也很有用。 Ninja 需要为任何生成的文件建立规则,而另一个规则所依赖的文件即使存在仅顺序依赖项,以确保副产品在其依赖项构建之前可用。

Makefile 生成器 将在 make clean 期间删除 BYPRODUCTS 和其他 GENERATED 文件。

在 3.20 版本加入: BYPRODUCTS 的参数可以使用一组受限的 generator expressionsTarget-dependent expressions 是不允许的。

命令

指定要在构建时执行的命令行。如果指定了多个 COMMAND,它们将按顺序执行,但 不一定 必须组合成有状态的 shell 或批处理脚本。 (要运行完整脚本,请使用 configure_file() 命令或 file(GENERATE) 命令创建它,然后指定一个 COMMAND 来启动它。)可选的 `` ARGS`` 参数是为了向后兼容,将被忽略。

如果 COMMAND 指定了可执行目标名称(由 add_executable() 命令创建),如果满足以下任一条件,它将自动替换为构建时创建的可执行文件的位置:

  • 目标未被交叉编译(即 CMAKE_CROSSCOMPILING 变量未设置为 true)。

  • 在 3.6 版本加入: 正在交叉编译目标并提供模拟器(即设置其 CROSSCOMPILING_EMULATOR 目标属性)。在这种情况下,CROSSCOMPILING_EMULATOR 的内容将添加到目标可执行文件位置之前的命令中。

如果以上条件都不满足,则假定命令名称是在构建时在 PATH 上找到的程序。

COMMAND 的参数可以使用 generator expressions。使用 TARGET_FILE 生成器表达式稍后在命令行中引用目标的位置(即作为命令参数而不是作为要执行的命令)。

每当以下基于目标的生成器表达式之一用作要执行的命令或在命令参数中提及时,将自动添加目标级依赖项,以便在使用此自定义命令的任何目标之前构建提及的目标(请参阅政策:policy:CMP0112)。

  • TARGET_FILE

  • TARGET_LINKER_FILE

  • TARGET_SONAME_FILE

  • TARGET_PDB_FILE

此目标级依赖性不会添加文件级依赖性,该文件级依赖性会导致自定义命令在可执行文件重新编译时重新运行。使用 DEPENDS 选项列出目标名称以添加此类文件级依赖项。

评论

在构建时执行命令之前显示给定的消息。

在 3.26 版本加入: COMMENT 的参数可以使用 generator expressions

取决于

指定命令所依赖的文件。每个参数都转换为依赖项,如下所示:

  1. 如果参数是目标的名称(由 add_custom_target()add_executable()add_library() 命令创建),则创建目标级依赖项以确保构建目标在使用此自定义命令的任何目标之前。此外,如果目标是可执行文件或库,则会创建文件级依赖性,以便在重新编译目标时重新运行自定义命令。

  2. 如果参数是绝对路径,则会在该路径上创建文件级依赖项。

  3. 如果参数是已添加到目标或已设置源文件属性的源文件的名称,则会在该源文件上创建文件级依赖项。

  4. 如果参数是相对路径并且它存在于当前源目录中,则会在当前源目录中的该文件上创建文件级依赖项。

  5. 否则,将在相对于当前二进制目录的该路径上创建文件级依赖项。

如果任何依赖项是同一目录中另一个自定义命令的“输出”(“CMakeLists.txt”文件),CMake 会自动将其他自定义命令引入构建此命令的目标中。

在 3.16 版本加入: 如果任何依赖项被列为目标的“BYPRODUCTS”或其在同一目录中的任何构建事件,则会添加目标级依赖项,以确保副产品可用。

如果未指定“DEPENDS”,则只要缺少“OUTPUT”,该命令就会运行;如果该命令实际上并未创建 OUTPUT,则该规则将始终运行。

在 3.1 版本加入: DEPENDS 的参数可以使用 generator expressions

COMMAND_EXPAND_LISTS

在 3.8 版本加入.

COMMAND 参数中的列表将被扩展,包括使用 generator expressions 创建的列表,允许 COMMAND 参数,例如 ${CC} -I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc 被正确扩展。

IMPLICIT_DEPENDS

请求扫描输入文件的隐式依赖项。给定的语言指定应使用其相应依赖扫描器的编程语言。目前仅支持``C`` 和``CXX`` 语言扫描器。必须为“IMPLICIT_DEPENDS”列表中的每个文件指定语言。从扫描中发现的依赖项会在构建时添加到自定义命令的依赖项中。请注意,IMPLICIT_DEPENDS 选项目前仅支持 Makefile 生成器,其他生成器将忽略该选项。

备注

此选项不能与 DEPFILE 选项同时指定。

作业池

在 3.15 版本加入.

Ninja 生成器指定一个 pool。与 USES_TERMINAL 不兼容,这意味着 console 池。使用 JOB_POOLS 未定义的池会导致 ninja 在构建时出错。

MAIN_DEPENDENCY

指定命令的主要输入源文件。这就像赋予“DEPENDS”选项的任何值一样对待,但也会向 Visual Studio 生成器建议将自定义命令挂在何处。每个源文件最多可以有一个命令将其指定为其主要依赖项。编译命令(即用于库或可执行文件)算作隐式主要依赖项,它会被自定义命令规范悄悄覆盖。

输出

指定命令预期生成的输出文件。每个输出文件将自动标有 GENERATED 源文件属性。如果自定义命令的输出实际上并未创建为磁盘上的文件,则应使用 SYMBOLIC 源文件属性进行标记。

如果输出文件名是相对路径,则其绝对路径是通过相对于以下各项解释它来确定的:

  1. 与当前源目录对应的构建目录( CMAKE_CURRENT_BINARY_DIR),或

  2. 当前源目录( CMAKE_CURRENT_SOURCE_DIR)。

构建目录中的路径是首选,除非源树中的路径被提及为当前目录中其他地方的绝对源文件路径。

在 3.20 版本加入: OUTPUT 的参数可以使用一组受限的 generator expressionsTarget-dependent expressions 是不允许的。

USES_TERMINAL

在 3.2 版本加入.

如果可能,该命令将被授予直接访问终端的权限。使用 Ninja 生成器,这会将命令放在 console pool 中。

逐字

命令的所有参数都将为构建工具正确转义,以便调用的命令接收每个参数不变。请注意,在 add_custom_command 甚至看到参数之前,CMake 语言处理器仍然使用一级转义。建议使用“VERBATIM”,因为它可以实现正确的行为。当未给出 VERBATIM 时,行为是特定于平台的,因为没有对特定于工具的特殊字符的保护。

工作目录

使用给定的当前工作目录执行命令。如果它是相对路径,它将被解释为相对于当前源目录对应的构建树目录。

在 3.13 版本加入: WORKING_DIRECTORY 的参数可以使用 generator expressions

DEPFILE

在 3.7 版本加入.

指定一个包含自定义命令依赖项的 depfile。它通常由自定义命令本身发出。这个关键字只能在生成器支持的情况下使用,如下所述。

预期格式与带有选项“-M”的“gcc”生成的内容兼容,与生成器或平台无关。

使用带有常规扩展名的`BNF <https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form>`_ 符号指定的正式语法如下:

depfile       ::=  rule*
rule          ::=  targets (':' (separator dependencies?)?)? eol
targets       ::=  target (separator target)* separator*
target        ::=  pathname
dependencies  ::=  dependency (separator dependency)* separator*
dependency    ::=  pathname
separator     ::=  (space | line_continue)+
line_continue ::=  '\' eol
space         ::=  ' ' | '\t'
pathname      ::=  character+
character     ::=  std_character | dollar | hash | whitespace
std_character ::=  <any character except '$', '#' or ' '>
dollar        ::=  '$$'
hash          ::=  '\#'
whitespace    ::=  '\ '
eol           ::=  '\r'? '\n'

备注

作为“路径名”的一部分,任何斜杠和反斜杠都被解释为目录分隔符。

在 3.7 版本加入: Ninja 生成器支持 DEPFILE 因为关键字是第一次添加的。

在 3.17 版本加入: 添加了 Ninja Multi-Config 生成器,其中包括对 DEPFILE 关键字的支持。

在 3.20 版本加入: 添加了对 Makefile 生成器 的支持。

备注

DEPFILE 不能与 Makefile 生成器IMPLICIT_DEPENDS 选项同时指定。

在 3.21 版本加入: 添加了对 VS 2012 及更高版本的 Visual Studio Generators 和 Xcode 生成器的支持。还添加了对 generator expressions 的支持。

DEPFILE 与上面列出的生成器以外的生成器一起使用是错误的。

如果``DEPFILE`` 参数是相对的,它应该是相对于 CMAKE_CURRENT_BINARY_DIR,并且``DEPFILE`` 中的任何相对路径也应该是相对于 CMAKE_CURRENT_BINARY_DIR。请参阅策略:policy:CMP0116,对于:ref:Makefile GeneratorsVisual Studio 生成器 和:generator:Xcode 生成器,它始终是 NEW

示例:生成文件

自定义命令可用于生成源文件。例如,代码:

add_custom_command(
  OUTPUT out.c
  COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
                   -o out.c
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
  VERBATIM)
add_library(myLib out.c)

添加自定义命令以运行“someTool”以生成“out.c”,然后将生成的源代码编译为库的一部分。只要 in.txt 发生变化,生成规则就会重新运行。

在 3.20 版本加入: 可以使用生成器表达式来指定每个配置的输出。例如,代码:

add_custom_command(
  OUTPUT "out-$<CONFIG>.c"
  COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
                   -o "out-$<CONFIG>.c"
                   -c "$<CONFIG>"
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
  VERBATIM)
add_library(myLib "out-$<CONFIG>.c")

添加一个自定义命令来运行 someTool 以生成 out-<config>.c,其中 <config> 是构建配置,然后将生成的源代码编译为库的一部分。

示例:为多个目标生成文件

如果多个独立目标需要相同的自定义命令输出,则它必须附加到它们都依赖的单个自定义目标。考虑以下示例:

add_custom_command(
  OUTPUT table.csv
  COMMAND makeTable -i ${CMAKE_CURRENT_SOURCE_DIR}/input.dat
                    -o table.csv
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.dat
  VERBATIM)
add_custom_target(generate_table_csv DEPENDS table.csv)

add_custom_command(
  OUTPUT foo.cxx
  COMMAND genFromTable -i table.csv -case foo -o foo.cxx
  DEPENDS table.csv           # file-level dependency
          generate_table_csv  # target-level dependency
  VERBATIM)
add_library(foo foo.cxx)

add_custom_command(
  OUTPUT bar.cxx
  COMMAND genFromTable -i table.csv -case bar -o bar.cxx
  DEPENDS table.csv           # file-level dependency
          generate_table_csv  # target-level dependency
  VERBATIM)
add_library(bar bar.cxx)

只有目标“foo”需要输出“foo.cxx”,只有目标“bar”需要输出“bar.cxx”,但是*两个*目标都需要“table.csv” ,传递性。由于“foo”和“bar”是可以同时构建的独立目标,我们通过将其自定义命令放在单独的目标“generate_table_csv”中来防止它们竞相生成“table.csv”。生成 ``foo.cxx`bar.cxx 的自定义命令各自指定了对 generate_table_csv 的目标级依赖,因此使用它们的目标,foobar , 在构建目标 generate_table_csv 之前不会构建。

建立事件

第二个签名将自定义命令添加到目标,例如库或可执行文件。这对于在构建目标之前或之后执行操作很有用。该命令成为目标的一部分,并且只会在构建目标本身时执行。如果目标已经构建,命令将不会执行。

add_custom_command(TARGET <target>
                   PRE_BUILD | PRE_LINK | POST_BUILD
                   COMMAND command1 [ARGS] [args1...]
                   [COMMAND command2 [ARGS] [args2...] ...]
                   [BYPRODUCTS [files...]]
                   [WORKING_DIRECTORY dir]
                   [COMMENT comment]
                   [VERBATIM] [USES_TERMINAL]
                   [COMMAND_EXPAND_LISTS])

这定义了一个新命令,该命令将与构建指定的 <target> 相关联。 <target> 必须在当前目录中定义;可能未指定在其他目录中定义的目标。

该命令何时执行取决于指定了以下哪一项:

PRE_BUILD

Visual Studio 生成器 上,在目标内执行任何其他规则之前运行。在其他生成器上,在“PRE_LINK”命令之前运行。

PRE_LINK

在编译源之后但在链接二进制文件或运行静态库的库管理器或归档器工具之前运行。这不是为 add_custom_target 命令创建的目标定义的。

POST_BUILD

在执行完目标中的所有其他规则后运​​行。

使用“TARGET”形式时,项目应始终指定上述三个关键字之一。出于向后兼容性的原因,如果没有给出这样的关键字,则假定为“POST_BUILD”,但项目应明确提供关键字之一以明确他们期望的行为。

备注

因为生成器表达式可以在自定义命令中使用,所以可以定义 COMMAND 行或整个自定义命令,这些命令对某些配置求值为空字符串。对于 Visual Studio 11 2012(及更新版本) 生成器,这些命令行或自定义命令将针对特定配置省略,并且不会添加“空字符串命令”。

这允许为每个配置添加单独的构建事件。

在 3.21 版本加入: 支持目标相关的生成器表达式。

示例:构建事件

POST_BUILD 事件可用于在链接后对二进制文件进行后处理。例如,代码:

add_executable(myExe myExe.c)
add_custom_command(
  TARGET myExe POST_BUILD
  COMMAND someHasher -i "$<TARGET_FILE:myExe>"
                     -o "$<TARGET_FILE:myExe>.hash"
  VERBATIM)

将在链接后运行 someHasher 以在可执行文件旁边生成一个 .hash 文件。

在 3.20 版本加入: 可以使用生成器表达式来指定每个配置的副产品。例如,代码:

add_library(myPlugin MODULE myPlugin.c)
add_custom_command(
  TARGET myPlugin POST_BUILD
  COMMAND someHasher -i "$<TARGET_FILE:myPlugin>"
                     --as-code "myPlugin-hash-$<CONFIG>.c"
  BYPRODUCTS "myPlugin-hash-$<CONFIG>.c"
  VERBATIM)
add_executable(myExe myExe.c "myPlugin-hash-$<CONFIG>.c")

将在链接 myPlugin 后运行 someHasher,例如生成一个 .c 文件,其中包含用于检查 myExe 可执行文件可以在加载之前验证它的 myPlugin 散列的代码。

忍者多配置

在 3.20 版本加入: add_custom_command 支持 Ninja Multi-Config 生成器的交叉配置功能。有关详细信息,请参阅生成器文档。

也可以看看