如何使用 CMake execute_process() 正确调用 MSYS2 Bash 命令?
How do I properly invoke MSYS2 Bash commands using CMake execute_process()?
问题描述
我在设置执行 MSYS2 bash 命令的 CMake external_process() 命令时遇到问题。当我在 MSYS2 shell 中时,如果我 运行 命令 $ bash -v ./bootstrap.sh
命令工作正常。但是,如果我 运行 MSYS2 shell 中的 CMake 脚本使用 $ cmake -P Run_bash_command.cmake
命令会在整个过程中出错。我在 CMake Documentation 中发现的一条重要信息让我认为我没有正确调用 bash 或缺少环境变量:
CMake executes the child process using operating system APIs directly. All arguments are passed VERBATIM to the child process. No intermediate shell is used, so shell operators such as > are treated as normal arguments.
如果可能的话,我希望能够使用 CMake 执行此命令,因为这个问题是一个更大的 CMake 超级构建项目的一部分。如果有另一种解决问题的方法,我愿意接受建议,只要我可以将它包含在 superbuild 项目的自动化中。任何帮助将不胜感激。
Run_bash_command.cmake内容:
SET( ENV{MSYSTEM} MINGW64 )
SET( DIR_CONTAINING_BOOTSTRAP_SH C:/bash_test )
SET( BASH_COMMAND_TO_RUN bash -v ./bootstrap.sh )
EXECUTE_PROCESS( COMMAND ${BASH_COMMAND_TO_RUN}
WORKING_DIRECTORY ${DIR_CONTAINING_BOOTSTRAP_SH} RESULT_VARIABLE command_result )
IF( NOT "${command_result}" STREQUAL "0" )
MESSAGE( FATAL_ERROR "Error: command_result='${command_result}'" )
ENDIF()
环境设置
- 我按照 setup MSYS2 64 位的说明进行操作,并使用命令
pacman -S base-devel git mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain
添加了 mingw-w64 工具链和 cmake
- 为了运行我使用的命令是 MinGW-w64 Win64 Shell 与 MSYS2
一起安装
- 文件 bootstrap.sh 来自 libusb github repository 和文件夹 c:/bash_test 包含主分支的克隆
输出
$ bash -v ./bootstrap.sh
输出:
$ bash -v ./bootstrap.sh
#!/bin/sh
if ! test -d m4 ; then
mkdir m4
fi
autoreconf -ivf || exit 1
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
autoreconf: configure.ac: tracing
autoreconf: running: libtoolize --copy --force
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './ltmain.sh''
...<clipped output due to length>...
configure.ac:29: installing './install-sh'
configure.ac:29: installing './missing'
examples/Makefile.am: installing './depcomp'
autoreconf: Leaving directory `.'
$ cmake -P Run_bash_command.cmake
输出:
$ cmake -P Run_bash_command.cmake
#!/bin/sh
if ! test -d m4 ; then
mkdir m4
fi
autoreconf -ivf || exit 1
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
aclocal-1.15: error: aclocal: file '/msys64/usr/share/aclocal/xsize.m4' does not exist
autoreconf: aclocal failed with exit status: 1
CMake Error at Run_bash_command.cmake:10 (MESSAGE):
Error: command_result='1'
我尝试过的事情:
- 替换
bash -l -c
但这会导致 shell 默认为主目录,然后无法找到文件 bootstrap.sh
- 通过检查我的环境 PATH 变量
验证 bash 的正确版本
- 已验证 MSYS2 及其软件包是最新的
- 使用
sh
代替 bash
- 直接调用
autoreconf -ivf
,出现同样的问题
- 使用 Unix 风格路径而不是 Windows 风格
我能够使用下面的代码解决问题。
Run_bash_command.cmake内容:
SET( DIR_CONTAINING_BOOTSTRAP_SH /C/bash_test )
SET( BASH_COMMAND_TO_RUN bash -l -c "cd ${DIR_CONTAINING_BOOTSTRAP_SH} && sh ./bootstrap.sh" )
EXECUTE_PROCESS( COMMAND ${BASH_COMMAND_TO_RUN}
WORKING_DIRECTORY ${DIR_CONTAINING_BOOTSTRAP_SH} RESULT_VARIABLE command_result )
IF( NOT "${command_result}" STREQUAL "0" )
MESSAGE( FATAL_ERROR "Error: command_result='${command_result}'" )
ENDIF()
重要提示:
- 使用
bash -l
导致 shell 默认为主目录,为了解决这个问题,我添加了一个更改目录 cd <path>
命令来让我们回到我们想要的目录发出 bash 命令。
- 使用
-c
会导致 bash 从字符串中读取命令。由于我们要发出两个命令,一个用于更改目录,一个用于 运行 shell 脚本,我们需要使用 &&
将命令链接在一起并使用 "quotation marks" 以确保将整个命令正确读取为字符串。
问题描述
我在设置执行 MSYS2 bash 命令的 CMake external_process() 命令时遇到问题。当我在 MSYS2 shell 中时,如果我 运行 命令 $ bash -v ./bootstrap.sh
命令工作正常。但是,如果我 运行 MSYS2 shell 中的 CMake 脚本使用 $ cmake -P Run_bash_command.cmake
命令会在整个过程中出错。我在 CMake Documentation 中发现的一条重要信息让我认为我没有正确调用 bash 或缺少环境变量:
CMake executes the child process using operating system APIs directly. All arguments are passed VERBATIM to the child process. No intermediate shell is used, so shell operators such as > are treated as normal arguments.
如果可能的话,我希望能够使用 CMake 执行此命令,因为这个问题是一个更大的 CMake 超级构建项目的一部分。如果有另一种解决问题的方法,我愿意接受建议,只要我可以将它包含在 superbuild 项目的自动化中。任何帮助将不胜感激。
Run_bash_command.cmake内容:
SET( ENV{MSYSTEM} MINGW64 )
SET( DIR_CONTAINING_BOOTSTRAP_SH C:/bash_test )
SET( BASH_COMMAND_TO_RUN bash -v ./bootstrap.sh )
EXECUTE_PROCESS( COMMAND ${BASH_COMMAND_TO_RUN}
WORKING_DIRECTORY ${DIR_CONTAINING_BOOTSTRAP_SH} RESULT_VARIABLE command_result )
IF( NOT "${command_result}" STREQUAL "0" )
MESSAGE( FATAL_ERROR "Error: command_result='${command_result}'" )
ENDIF()
环境设置
- 我按照 setup MSYS2 64 位的说明进行操作,并使用命令
pacman -S base-devel git mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain
添加了 mingw-w64 工具链和 cmake
- 为了运行我使用的命令是 MinGW-w64 Win64 Shell 与 MSYS2 一起安装
- 文件 bootstrap.sh 来自 libusb github repository 和文件夹 c:/bash_test 包含主分支的克隆
输出
$ bash -v ./bootstrap.sh
输出:
$ bash -v ./bootstrap.sh
#!/bin/sh
if ! test -d m4 ; then
mkdir m4
fi
autoreconf -ivf || exit 1
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
autoreconf: configure.ac: tracing
autoreconf: running: libtoolize --copy --force
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './ltmain.sh''
...<clipped output due to length>...
configure.ac:29: installing './install-sh'
configure.ac:29: installing './missing'
examples/Makefile.am: installing './depcomp'
autoreconf: Leaving directory `.'
$ cmake -P Run_bash_command.cmake
输出:
$ cmake -P Run_bash_command.cmake
#!/bin/sh
if ! test -d m4 ; then
mkdir m4
fi
autoreconf -ivf || exit 1
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
aclocal-1.15: error: aclocal: file '/msys64/usr/share/aclocal/xsize.m4' does not exist
autoreconf: aclocal failed with exit status: 1
CMake Error at Run_bash_command.cmake:10 (MESSAGE):
Error: command_result='1'
我尝试过的事情:
- 替换
bash -l -c
但这会导致 shell 默认为主目录,然后无法找到文件 bootstrap.sh - 通过检查我的环境 PATH 变量 验证 bash 的正确版本
- 已验证 MSYS2 及其软件包是最新的
- 使用
sh
代替bash
- 直接调用
autoreconf -ivf
,出现同样的问题 - 使用 Unix 风格路径而不是 Windows 风格
我能够使用下面的代码解决问题。
Run_bash_command.cmake内容:
SET( DIR_CONTAINING_BOOTSTRAP_SH /C/bash_test )
SET( BASH_COMMAND_TO_RUN bash -l -c "cd ${DIR_CONTAINING_BOOTSTRAP_SH} && sh ./bootstrap.sh" )
EXECUTE_PROCESS( COMMAND ${BASH_COMMAND_TO_RUN}
WORKING_DIRECTORY ${DIR_CONTAINING_BOOTSTRAP_SH} RESULT_VARIABLE command_result )
IF( NOT "${command_result}" STREQUAL "0" )
MESSAGE( FATAL_ERROR "Error: command_result='${command_result}'" )
ENDIF()
重要提示:
- 使用
bash -l
导致 shell 默认为主目录,为了解决这个问题,我添加了一个更改目录cd <path>
命令来让我们回到我们想要的目录发出 bash 命令。 - 使用
-c
会导致 bash 从字符串中读取命令。由于我们要发出两个命令,一个用于更改目录,一个用于 运行 shell 脚本,我们需要使用&&
将命令链接在一起并使用 "quotation marks" 以确保将整个命令正确读取为字符串。