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
循环。
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 也不能正确处理所有情况。
我无法在 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
循环。
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 也不能正确处理所有情况。