Shell 在 Linux 上使用 Cmake add_custom_command 命令

Shell commands using Cmake add_custom_command on Linux

我无法在 Linux 上的 Cmake 中的 post 构建步骤中找到 运行 shell 命令的正确语法。我可以做一个简单的 echo 工作,但是当我想,例如遍历所有文件和 echo 那些,我收到一个错误。

以下作品:

add_custom_command(TARGET ${MY_LIBRARY_NAME}
                   POST_BUILD
                   COMMAND echo Hello world!
                   USES_TERMINAL)

这会正确打印 Hello world!

但现在我想遍历所有 .obj 文件并打印它们。我认为我应该这样做:

add_custom_command(TARGET ${MY_LIBRARY_NAME} 
                   POST_BUILD
                   COMMAND for file in *.obj; do echo @file ; done 
                   VERBATIM
                   USES_TERMINAL)

但是会出现以下错误:

/bin/sh: 1: Syntax error: end of file unexpected

我尝试了各种带引号或以 sh 开头的组合,但其中 none 似乎有效。我怎样才能正确地做到这一点?

add_custom_command(以及所有其他执行 COMMAND 的 CMake 函数)不 运行 shell 脚本,但只允许执行单个命令. USES_TERMINAL 不会导致命令在实际终端中变为 运行 或允许使用 shell 内置函数,如 for 循环。

来自documentation

To run a full script, use the configure_file() command or the file(GENERATE) command to create it, and then specify a COMMAND to launch it.

或者,对于非常简单的脚本,您可以按照@lojza 在对您的问题的评论中建议的操作和 运行 bash 命令以实际脚本内容作为参数。

add_custom_command(
  TARGET ${MY_LIBRARY_NAME}
  POST_BUILD 
  COMMAND bash -c [[for file in *.obj; do echo ${file}; done]]
  VERBATIM
)

请注意,我在这里故意使用了 CMake 原始字符串文字,这样 ${file} 就不会扩展为 CMake 变量。您还可以将 bash -c "for file in *obj; do echo $file; done" 与常规字符串文字一起使用,在这种情况下,由于缺少大括号,$file 也不会展开。在我知道在此类脚本中追踪由 CMake 变量的意外扩展引起的错误是多么困难之前,我已经将其他来源的 bash 代码复制并粘贴到 CMake 中,所以我总是建议使用 [[]] 除非你真的想扩展一个 CMake 变量。

但是,对于您对所有匹配模式的文件执行某些操作的具体示例,还有一个更简单的替代方法:使用 find 命令而不是 bash 循环:

add_custom_command(
  TARGET ${MY_LIBRARY_NAME}
  POST_BUILD 
  COMMAND find
    -maxdepth 1 
    -name *.obj 
    -printf "%P\n"
  VERBATIM
)

有时,可以使用调试来执行 COMMAND 的正确脚本编写。 在 错误消息 下面有一个点指向导致它的行。像

/bin/sh: 1: Syntax error: end of file unexpected
make[2]: *** [CMakeFiles/my_target.dir/build.make:57: CMakeFiles/my_target] Error 2

因此,您可以查看文件 CMakeFiles/my_target.dir/build.make 的第 57 行,找出实际放入 Makefile 的命令:

CMakeFiles/my_target:
    for file in "*.obj" do echo @file done

如您所见,CMake 删除了所有分号 (;):这是因为此符号是 CMake 的分隔符。

在 VERBATIM 模式下引用分号没有帮助:

命令

COMMAND for file in *.obj ";" do echo @file ";" done

转型

CMakeFiles/my_target:
    for file in "*.obj" ";" do echo @file ";" done

但是 shell 不会将引号中的分号 (";") 视为命令分隔符!

省略 VERBATIM 可提供更好的转换:

CMakeFiles/my_target:
    for file in *.obj ; do echo @file ; done

下一步是在脚本中正确引用file变量(@肯定是错误的方式)。脚本应该看到 $file${file},但是 both CMake 和 Make 有处理美元的特殊方式 ($)。 (VERBATIM 可以自动转义 Make 的内容,但由于分号,我们不能使用它。)

结果命令可以是

COMMAND for file in *.obj ";" do echo $$file ";" done

COMMAND for file in "CMake*" ";" do echo $${file} ";" done

如您所见,即使是 VERBATIM 也不能正确处理所有情况。