如何将CMake自定义命令的输出重定向到文件?

23

我需要使用add_custom_command执行一个命令并捕获它的标准输出,但将 shell 重定向到文件>无法工作,并且add_custom_command没有任何相关选项。我怎么能做到呢?

3个回答

10
请注意,由于Florian的评论,我在调查问题后更改了我的答案。有关编辑的详细信息请参见下文。
execute_process的文档明确说明它不使用中间shell,因此重定向运算符在其中不起作用。
但是对于add_custom_command,则不是这样。重定向应该按预期工作。编辑后,有时似乎不起作用的原因是CMake生成器、VERBATIM限定符和缺少>与文件名之间的空格的不幸组合。
事实证明,如果您确保>与文件名之间有一个空格,在大多数情况下,即使使用VERBATIM,它也可以正常工作。
add_custom_command(OUTPUT ${some-file}
    COMMAND cmake --version > ${some-file}
    VERBATIM # optional
)

关于另一种解决方案的说明: 之前我认为add_custom_commandexecute_process一样不使用中间 shell,所以建议调用包含一个execute_process命令并使用OUTPUT_FILE选项重定向其输出的CMake脚本来运行实际命令。

如果由于某种原因上述解决方案仍然无法解决问题,请尝试使用ExecuteProcessWrapper.cmake进行替代解决。


4
我认为CMake中的自定义命令实现可能与平台相关。能否提供一个示例,其中自定义命令不使用中间的shell?我已经成功地在Ninja和Visual Studio生成器中使用了stdout/stderr重定向。这些生成器会在Windows上为自定义命令加前缀cmd.exe /c。并且管道命令已在CMake的自定义命令单元测试中进行了测试。 - Florian
3
我在CMake开发者论坛上找到了这个帖子:http://cmake.3232098.n2.nabble.com/Redirect-output-from-add-custom-target-td7583901.html。他们写道,在`add_custom_target()`中进行重定向可能在某些情况下不起作用。另一方面,`add_custom_command()`和`add_custom_target()`都接受`VERBATIM`选项,但在没有涉及shell的情况下没有意义。相反,`execute_process()`不接受该选项,并明确指出了有关重定向的说明。那么,真相究竟是什么? - Tsyvarev
1
嗯,对我来说VERBATIM不能防止重定向。例如,可以看看这个答案:https://dev59.com/JY3da4cB1Zd3GeqPxUI1#31558761。 - Tsyvarev
1
@Tsyvarev 看起来这个重定向问题在不同平台和生成器上非常不稳定。对我来说:mingw或window-cmd提示符+msvc生成器,VERBATIM会破坏重定向。 - tamas.kenez
1
问题实际上是这些引号来自哪里。请在 > 后尝试添加一个空格,因为我认为管道命令会以特殊方式处理。参见 BUG: Do not escape shell operators when generating command linesCMAKE add_custom_command: How to use my raw commands - Florian
显示剩余6条评论

3
find_program(BASH bash HINTS /bin)
...
add_custom_command(
  OUTPUT
    ${some-file}
  COMMAND
    ${CMAKE_COMMAND} -E env ${BASH} -c "cmake --version > ${some-file} 2>&1"
  VERBATIM
)

0
作为备选方案,一种解决方法是将要运行的脚本放在一个单独的.sh文件中并运行该文件。这样,您就不必费心思考如何在cmake中编写这样的脚本。它还使得维护和其他程序员帮助脚本变得更加容易。对于一行命令可能不那么重要,但它经常从一行开始,最终成为一个2,000行的脚本...
add_custom_command(
  OUTPUT
    ${some-file}
  COMMAND
    ${CMAKE_SOURCE_DIR}/my-script.sh ${some-file}
  WORKING_DIRECTORY
    ${CMAKE_BINARY_DIR}
)

我也喜欢使用WORKING_DIRECTORY,以便在执行脚本时清楚地知道我们从哪里开始。

P.S. 脚本需要可执行:

chmod 755 my-script.sh

然而,在您的特定情况下,您也可以考虑执行命令并将结果保存在文件中,如下所示:

execute_process(
  COMMAND
    cmake --version
  OUTPUT_FILE
    ${some-file}
)

这样做可能会更加清晰。

在这种情况下需要记住的一件事是:执行顺序将会不同。 execute_process() 在语句解析时发生。 add_custom_command() 在其输出被要求时执行,通常是通过 add_custom_target() 实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接