Ответ 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)
Мне нужно выполнить некоторые правила 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.
Любые предложения? Я мог бы использовать любое другое разумное решение для этого.
Используйте встроенную 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)
Завершение задания в 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)
Вот немного более сложный пример с трубопроводом и назначением переменной внутри рецепта:
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)
Я пишу ответ, чтобы увеличить видимость фактического синтаксиса, который решает проблему. К сожалению, то, что кто-то может видеть как тривиальное, может стать очень значительной головной болью для кого-то, кто ищет простой ответ на разумный вопрос.
Поместите в файл "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" на вкладку, и этот пример должен, надеюсь, работать для вас.
С 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)
Остерегайтесь таких рецептов
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;
Надеюсь, что это помогает кому-то.