Как правильно вызывать команды 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. Если есть другой подход к решению проблемы, я открыт для предложений, пока я могу включить его в автоматизацию проекта суперсборки. Любая помощь будет оценена.

Содержимое 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 64-бит и добавил цепочку инструментов mingw-w64 как а также cmake с помощью команды pacman -S base-devel git mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain
  • Для запуска команд я использую оболочку MinGW-w64 Win64, которая устанавливается вместе с 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

person Chris Padgett    schedule 27.02.2016    source источник


Ответы (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 читать команду из строки. Поскольку мы хотим выполнить две команды, одну для изменения каталога и одну для запуска сценария оболочки, нам нужно использовать && для объединения команд, а также использовать «кавычки», чтобы убедиться, что вся команда правильно читается как строка. .
person Chris Padgett    schedule 01.04.2016