TL; DR не пытайтесь сделать это
$ make run arg
вместо этого создайте скрипт:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
и сделайте это:
$ ./buildandrunprog.sh arg
ответ на поставленный вопрос:
Вы можете использовать переменную в рецепте
run: prog
./prog $(var)
затем передайте переменную в качестве аргумента, чтобы сделать
$ make run var=arg
это выполнит ./prog arg
.
но остерегайтесь ловушек. я расскажу о подводных камнях этого метода и других методов далее.
ответ на предполагаемое намерение, стоящее за вопросом:
предположение: вы хотите запустить prog
с некоторыми аргументами, но перестроить его перед запуском при необходимости.
ответ: создайте скрипт, который при необходимости пересобирает, затем запускает прогу с аргументами
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
этот скрипт проясняет намерение. он использует make, чтобы делать то, для чего он хорош: building. он использует скрипт оболочки, чтобы делать то, для чего он хорош: пакетная обработка.
также синтаксис вызова теперь практически идентичен:
$ ./buildandrunprog.sh foo "bar baz"
сравнить с:
$ ./prog foo "bar baz"
плюс вы можете делать все, что вам может понадобиться, с полной гибкостью и выразительностью сценария оболочки без всех предостережений make-файла.
фон:
make не предназначен для запуска цели и передачи аргументов этой цели. Все аргументы в командной строке интерпретируются как цель (a.k.a. target), как опция или как присвоение переменной.
так что если вы запустите это:
$ make run foo bar --wat var=arg
make будет интерпретировать run
, foo
и bar
как цели (цели) для обновления в соответствии с их рецептами. --wat
как опция для изготовления. и var=arg
в качестве присваивания переменной.
для более подробной информации см .: https://www.gnu.org/software/make/manual/html_node/Goals.html#Goals
для терминологии см .: https://www.gnu.org/software/make/manual/html_node/Rule-Introduction.html#Rule-Introduction
о методе присвоения переменных и почему я рекомендую против него
$ make run var=arg
и переменная в рецепте
run: prog
./prog $(var)
это самый «правильный» и простой способ передачи аргументов в рецепт. но хотя он может использоваться для запуска программы с аргументами, он определенно не предназначен для такого использования. см https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
по моему мнению, у этого есть один большой недостаток: вы хотите запустить prog
с аргументом arg
. но вместо того, чтобы писать:
$ ./prog arg
вы пишете:
$ make run var=arg
это становится еще более неловко при попытке передать несколько аргументов или аргументов, содержащих пробелы:
$ make run var="foo bar\ baz"
./prog foo bar\ baz
argcount: 2
arg: foo
arg: bar baz
сравнить с:
$ ./prog foo "bar baz"
argcount: 2
arg: foo
arg: bar baz
для записи вот как выглядит мой prog
:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
обратите внимание, что когда вы помещаете $(var)
в кавычки в make-файле:
run: prog
./prog "$(var)"
тогда prog
всегда получит только один аргумент:
$ make run var="foo bar\ baz"
./prog "foo bar\ baz"
argcount: 1
arg: foo bar\ baz
Вот почему я рекомендую этот маршрут.
для полноты здесь приведены некоторые другие методы «передачи аргументов для запуска».
метод 1:
run: prog
./prog $(filter-out $@, $(MAKECMDGOALS))
%:
@true
супер краткое объяснение: отфильтровать текущую цель из списка целей. create catch all target (%
), которая ничего не делает, чтобы игнорировать другие цели.
метод 2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
супер короткое объяснение: если целью является run
, тогда удалите первую цель и создайте ничего не делайте цели для оставшихся целей, используя eval
.
для более глубокого объяснения изучите руководство по изготовлению: https://www.gnu.org/software/make/manual/html_node/index.html
проблемы метода 1:
аргументы, начинающиеся с тире, будут интерпретироваться make и не будут передаваться как цель.
$ make run --foo --bar
Обойти
$ make run -- --foo --bar
если аргумент окажется run
(равным цели), он также будет удален
$ make run foo bar run
будет работать ./prog foo bar
вместо ./prog foo bar run
Обходной путь возможен по методу 2
если аргумент является допустимой целью, он также будет запущен.
$ make run foo bar clean
будет запускать ./prog foo bar clean
, а также рецепт для цели clean
(при условии, что она существует).
Обходной путь возможен по методу 2
неловко передавать аргументы с пробелами
$ make run foo "bar\ baz"
без обходного пути
когда вы неправильно наберете легитимную цель, она будет беззвучно проигнорирована из-за захвата всей цели.
$ make celan
просто тихо проигнорирует celan
.
Обходной путь - сделать все многословным. так что вы видите, что происходит. но это создает много шума для законного вывода.
проблемы метода 2:
если аргумент имеет то же имя, что и существующая цель, make выдает предупреждение о том, что он перезаписывается.
нет обходного пути, о котором я знаю
передача аргументов с пробелом все еще неуклюжа.
обходного пути нет
аргументы с пробелами eval
попытки создать ничего не делать цели.
Обходной путь: создайте глобальную цель catch all, ничего не делая, как описано выше с проблемой, как указано выше, что он снова будет молча игнорировать опечатки законных целей.
он использует eval
для изменения make-файла во время выполнения. насколько хуже вы можете стать с точки зрения читабельности и отладки, а также принципа наименьшего удивления .
обходной путь: не делайте этого !! 1 Вместо этого напишите сценарий оболочки, который запускает make, а затем запускает prog
.
Я тестировал только с использованием GNU Make. другие марки могут иметь другое поведение.
TL; DR не пытайтесь сделать это
$ make run arg
вместо этого создайте скрипт:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
и сделайте это:
$ ./buildandrunprog.sh arg