Как правильно вызвать команды 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 прочитать команду из строки. Поскольку мы хотим выполнить две команды, одну для смены каталога и одну для запуска сценария оболочки, нам нужно использовать && чтобы объединить команды вместе, а также использовать "кавычки", чтобы убедиться, что вся команда правильно прочитана как строка.
Другие вопросы по тегам