Как правильно вызвать команды MSYS2 Bash с помощью CMake execute_process()?
описание проблемы
У меня проблемы с настройкой команды CMake external_process(), которая выполняет команду MSYS2 bash. Когда я нахожусь в оболочке MSYS2, если я запускаю команду $ bash -v ./bootstrap.sh
команда работает правильно. Но если я запускаю сценарий CMake в оболочке MSYS2, используя $ cmake -P Run_bash_command.cmake
команда выдает ошибку во время процесса. Важная часть информации, которую я нашел в документации CMake, заставляет меня думать, что я неправильно вызываю bash или пропускаю переменную среды:
CMake напрямую выполняет дочерний процесс, используя API операционной системы. Все аргументы передаются VERBATIM дочернему процессу. Промежуточная оболочка не используется, поэтому операторы оболочки, такие как>, рассматриваются как обычные аргументы.
Я хотел бы быть в состоянии сделать эту команду, используя CMake, если это возможно, так как эта проблема является частью гораздо более крупного проекта CMake superbuild. Если есть другой подход к решению проблемы, я открыт для предложений, если я могу включить его в автоматизацию проекта 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()
Настройка среды
- Я следовал инструкциям по установке MSYS2 64bit и добавил команду mingw-w64, а также cmake, используя команду
pacman -S base-devel git mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain
- Для запуска команд я использую MinGW-w64 Win64 Shell, который устанавливается вместе с MSYS2
- Файл bootstrap.sh поставляется из репозитория libusb github, а папка 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
но это заставляет оболочку по умолчанию использовать домашний каталог, а затем он не может найти файл bootstrap.sh - Проверена правильная версия bash, найденная при проверке моей переменной PATH
- Проверенный MSYS2 и его пакеты обновлены
- С помощью
sh
вместоbash
- призвание
autoreconf -ivf
напрямую, но возникает та же проблема - Использование путей в стиле Unix вместо стиля Windows
1 ответ
Я смог решить проблему, используя код ниже.
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
вызывает оболочку по умолчанию для домашнего каталога, чтобы обойти это, я добавил изменение каталогаcd <path>
команда, чтобы вернуть нас в каталог, где мы хотим выполнить команду bash. - С помощью
-c
заставляет bash прочитать команду из строки. Поскольку мы хотим выполнить две команды, одну для смены каталога и одну для запуска сценария оболочки, нам нужно использовать&&
чтобы объединить команды вместе, а также использовать "кавычки", чтобы убедиться, что вся команда правильно прочитана как строка.