Подстановка процессов в GNU Makefiles

11

В командной строке bash можно выполнить diff, используя псевдо-файлы:

diff <(echo test) <(echo test)

Добавление этого как есть в Makefile завершается неудачно:

all:
        diff <(echo test) <(echo test)

Ошибка (подсказка: / bin / sh указывает на / bin / bash в этой системе):

/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `diff <(echo test) <(echo test)'

Что это значит, и есть ли способ по-прежнему различать два вывода без использования временных файлов?

Johannes
источник

Ответы:

20

/bin/shможет быть bashв вашей системе, но при вызове как sh, bashбудет работать в режиме POSIX (как если бы он POSIXLY_CORRECTбыл определен, или он был запущен с --posix).

В этом режиме замены процесса не существуют.

Решения:

all:
    command1 >file1
    command2 >file2
    diff file1 file2
    rm -f file1 file2

Альтернатива:

all:
    bash -c "diff <(command1) <(command2)"

Или просто определите переменную Makefile SHELLкак /bin/bash:

SHELL=/bin/bash

Если вам нужна мобильность, воспользуйтесь первым решением. Если у вас все в порядке с зависимостью bash, выберите второе. Если вам дополнительно не нужно заботиться о реализациях не-GNU make, используйте третий.


Что касается настройки SHELL: Стандарт POSIX говорит , что исполняемые файлы в Makefiles должны вызываться с system()библиотечной функцией C помощи make. Эта функция не гарантирует использование SHELLпеременной окружения (на самом деле, это не рекомендуется стандартом). Стандарт также говорит о том, что установка переменной Makefile SHELLне должна влиять на переменную окружения SHELL . Однако в большинстве makeизвестных мне реализаций переменная Makefile SHELLбудет использоваться для выполнения команд.

Предложение в обосновании makeутилиты заключается в использовании bash -c:

Исторический MAKESHELLпризнак и связанные с ним функции, предоставляемые другими makeреализациями, были опущены. В некоторых реализациях он используется, чтобы позволить пользователю переопределить оболочку, которая будет использоваться для запуска makeкоманд. Это сбивало с толку; для портативного компьютера makeоболочка должна быть выбрана автором make-файла. Кроме того, средство записи make-файла не может требовать использования альтернативной оболочки и все же считает, что make-файл является переносимым. Хотя было бы возможно стандартизировать механизм указания альтернативной оболочки, существующие реализации не согласны с таким механизмом, и разработчики make-файлов уже могут вызывать альтернативную оболочку, указав имя оболочки в правиле для цели; например:

python -c "foo"

Кусалананда
источник
Есть ли способ вызвать bashв Makefile или любом другом решении проблемы diff без использования временных файлов?
Йоханнес
Просто используйте два временных файла, это более или менее то, что метод подстановки процесса сделал бы в любом случае под капотом.
Кусалананда
3
Кроме того, можно установить , SHELLчтобы /bin/bashв Makefile.
Стивен Китт
1
@Johannes Kusalananda добавил информацию в свой ответ, и это здорово, поскольку в нем представлен ряд вариантов и обстоятельства, при которых они могут быть использованы. Я бы предпочел, чтобы вы приняли этот ответ ... (Но я ценю это чувство!)
Стивен Китт
2
Информация о том, что использование переменной SHELL не соответствует POSIX, была очень полезной. Может быть, все еще лучше использовать bash -c.
Йоханнес