【问题标题】:Shell commands using Cmake add_custom_command on Linux在 Linux 上使用 Cmake add_custom_command 的 Shell 命令
【发布时间】:2021-03-16 13:16:48
【问题描述】:

我不知道在 Linux 上的 Cmake 的构建后步骤中运行 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 开头的组合,但似乎都不起作用。我怎样才能正确地做到这一点?

【问题讨论】:

  • $filebash -c "$(for file in *.obj; do echo $file ; done)"

标签: linux shell cmake post-build


【解决方案1】:

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

来自documentation

要运行完整的脚本,请使用 configure_file() 命令或 file(GENERATE) 命令创建它,然后指定一个命令来启动它。

或者,或者,对于非常简单的脚本,您可以执行@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 中,所以我总是建议使用 [[ 和 @987654332 @ 除非你真的想扩展一个 CMake 变量。

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

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

【讨论】:

    【解决方案2】:

    有时,可以使用调试来执行正确的 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},但两者 CMake 和Make 都有一种特殊的方式来处理一美元($)。 (VERBATIM 可以自动转义 Make,但由于分号,我们不能使用它。)

    生成的命令可以是任一

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

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

    如您所见,即使 VERBATIM 也无法正确处理所有情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多