Как назначить вывод команды переменной Makefile

Мне нужно выполнить некоторые правила make условно, только если установленный Python больше определенной версии (скажем, 2.5).

Я думал, что могу сделать что-то вроде выполнения:

python -c 'import sys; print int(sys.version_info >= (2,5))'

а затем используя вывод ('1', если ok, '0' в противном случае) в инструкции ifeq make.

В простой оболочке bash script это просто:

MY_VAR=`python -c 'import sys; print int(sys.version_info >= (2,5))'`

но это не работает в Makefile.

Любые предложения? Я мог бы использовать любое другое разумное решение для этого.

Ответ 1

Используйте встроенную shell Make, как в MY_VAR=$(shell echo whatever)

[email protected]:~$make
MY_VAR IS whatever

[email protected]:~$ cat Makefile 
MY_VAR := $(shell echo whatever)

all:
    @echo MY_VAR IS $(MY_VAR)

Ответ 2

Завершение задания в eval работает для меня.

# dependency on .PHONY prevents Make from 
# thinking there 'nothing to be done'
set_opts: .PHONY
  $(eval DOCKER_OPTS = -v $(shell mktemp -d -p /scratch):/output)

Ответ 3

Вот немного более сложный пример с трубопроводом и назначением переменной внутри рецепта:

getpodname:
    # Getting pod name
    @eval $$(minikube docker-env) ;\
    $(eval PODNAME=$(shell sh -c "kubectl get pods | grep profile-posts-api | grep Running" | awk '{print $$1}'))
    echo $(PODNAME)

Ответ 4

Я пишу ответ, чтобы увеличить видимость фактического синтаксиса, который решает проблему. К сожалению, то, что кто-то может видеть как тривиальное, может стать очень значительной головной болью для кого-то, кто ищет простой ответ на разумный вопрос.

Поместите в файл "Makefile" следующее.

MY_VAR := $(shell python -c 'import sys; print int(sys.version_info >= (2,5))')

all:
    @echo MY_VAR IS $(MY_VAR)

Поведение, которое вы хотели бы видеть, следующее (при условии, что у вас установлен последний python).

make
MY_VAR IS 1

Если вы скопируете и вставьте указанный выше текст в Makefile, вы получите это? Возможно нет. Вероятно, вы получите сообщение об ошибке, например:

makefile: 4: *** отсутствует разделитель. Стоп

Почему: потому что, хотя я лично использовал подлинную вкладку, Qaru (попытка быть полезной) превращает мою вкладку в несколько пробелов. Вы, разочарованный гражданин Интернета, теперь скопируйте это, думая, что у вас теперь есть тот же текст, который я использовал. Команда make теперь считывает пробелы и находит, что команда "все" некорректно отформатирована. Скопируйте приведенный выше текст, вставьте его, а затем преобразуйте пробел перед "@echo" на вкладку, и этот пример должен, надеюсь, работать для вас.

Ответ 5

С GNU Make вы можете использовать shell и eval для хранения, запуска и назначения вывода из произвольных вызовов командной строки. Разница между примером ниже и теми, которые используют := состоит в том, что := назначение происходит один раз (когда оно встречается) и для всех. Рекурсивно развернутые переменные, установленные с =, немного более "ленивы"; ссылки на другие переменные остаются до тех пор, пока не будет указана ссылка на саму переменную, и последующее рекурсивное расширение будет происходить каждый раз при обращении к переменной, что желательно для создания "согласованных, вызываемых фрагментов". См. Руководство по настройке переменных для получения дополнительной информации.

# Generate a random number.
# This is not run initially.
GENERATE_ID = $(shell od -vAn -N2 -tu2 < /dev/urandom)

# Generate a random number, and assign it to MY_ID
# This is not run initially.
SET_ID = $(eval MY_ID=$(GENERATE_ID))

# You can use .PHONY to tell make that we aren't building a target output file
.PHONY: mytarget
mytarget:
# This is empty when we begin
    @echo $(MY_ID)
# This recursively expands SET_ID, which calls the shell command and sets MY_ID
    $(SET_ID)
# This will now be a random number
    @echo $(MY_ID)
# Recursively expand SET_ID again, which calls the shell command (again) and sets MY_ID (again)
    $(SET_ID)
# This will now be a different random number
    @echo $(MY_ID)

Ответ 6

Остерегайтесь таких рецептов

target:
    MY_ID=$(GENERATE_ID);
    echo $MY_ID;

Он делает две вещи неправильно. Первая строка в рецепте выполняется в отдельном экземпляре оболочки от второй строки. Переменная тем временем теряется. Во-вторых, неправильно, что $ не сбежал.

target:
    MY_ID=$(GENERATE_ID); \
    echo $$MY_ID;

Обе проблемы были исправлены, и переменная может использоваться. Обратная косая черта объединяет обе строки в одну оболочку, поэтому установка переменной и чтение послесловия переменной работает.

Я понимаю, что в оригинальном сообщении говорилось, как получить результаты команды оболочки в переменную MAKE, и этот ответ показывает, как получить ее в переменную оболочки. Но другие читатели могут извлечь выгоду.

Одно из последних улучшений: если потребитель ожидает, что будет установлена "переменная среды", вам придется ее экспортировать.

my_shell_script
    echo $MY_ID

понадобится это в make файле

target:
    export MY_ID=$(GENERATE_ID); \
    ./my_shell_script;

Надеюсь, что это помогает кому-то.