Ответ 1
Я не знаю, как сделать то, что вы хотите точно, но обходным решением может быть:
run: ./prog
./prog ${ARGS}
Тогда:
make ARGS="asdf" run
Я использую Makefile.
У меня есть цель с именем run
, которая запускает цель сборки. Упрощенный, он выглядит следующим образом:
prog: ....
...
run: prog
./prog
Сядьте обратно. Я знаю, что это гениально, но не нужно стоять овациями.
Теперь, мой вопрос: есть ли способ передать аргументы? Так что
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
Спасибо!
Я не знаю, как сделать то, что вы хотите точно, но обходным решением может быть:
run: ./prog
./prog ${ARGS}
Тогда:
make ARGS="asdf" run
Этот вопрос почти три года, но в любом случае...
Если вы используете GNU make, это легко сделать. Единственная проблема заключается в том, что make
интерпретирует необязательные аргументы в командной строке как цели. Решение состоит в том, чтобы превратить их в цели без цели, поэтому make
не будет жаловаться:
# If the first argument is "run"...
ifeq (run,$(firstword $(MAKECMDGOALS)))
# use the rest as arguments for "run"
RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
# ...and turn them into do-nothing targets
$(eval $(RUN_ARGS):;@:)
endif
prog: # ...
# ...
.PHONY: run
run : prog
@echo prog $(RUN_ARGS)
Запуск этого дает:
$ make run foo bar baz
prog foo bar baz
для стандартного make вы можете передавать аргументы, определяя такие макросы как
make run arg1=asdf
тогда используйте их как
run: ./prog $(arg1)
etc
Вы можете передать переменную в Makefile, как показано ниже:
run:
@echo ./prog $$FOO
Использование:
$ make run FOO="the dog kicked the cat"
./prog the dog kicked the cat
или
$ FOO="the dog kicked the cat" make run
./prog the dog kicked the cat
В качестве альтернативы используйте решение Beta:
run:
@echo ./prog $(filter-out [email protected],$(MAKECMDGOALS))
%:
@:
%:
- правило, которое соответствует любому имени задачи;@:
- пустой рецепт = ничего не делать
Использование:
$ make run the dog kicked the cat
./prog the dog kicked the cat
TL; DR не пытайтесь сделать это
$ make run arg
вместо этого создайте скрипт:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "[email protected]"
и сделай это:
$ ./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 "[email protected]"
этот сценарий делает намерение очень ясным. он использует 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 "[email protected]"; 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 [email protected], $(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
.
оба позволят вам написать что-то вроде этого
$ make run arg1 arg2
для более глубокого объяснения изучите руководство по make: https://www.gnu.org/software/make/manual/html_node/index.html
проблемы метода 1:
аргументы, начинающиеся с тире, будут интерпретироваться make и не будут передаваться как цель.
$ make run --foo --bar
обходной
$ make run -- --foo --bar
аргументы со знаком равенства будут интерпретированы make и не будут переданы
$ make run foo=bar
нет обходного пути
аргументы с пробелами неудобны
$ make run foo "bar\ baz"
нет обходного пути
если аргумент окажется 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 celan
просто тихо проигнорирует celan
.
Обходной путь должен сделать все многословным. так что вы видите, что происходит. но это создает много шума для законного выхода.
проблемы метода 2:
если аргумент имеет то же имя, что и существующая цель, make выдаст предупреждение о его перезаписи.
нет обходного пути, который я знаю о
аргументы со знаком равенства будут по-прежнему интерпретироваться make и не передаваться
нет обходного пути
аргументы с пробелами все еще неудобны
нет обходного пути
аргументы с пробелами eval
, пытающиеся создать цели без цели.
Обходной путь: создайте глобальный перехват цели, ничего не делая, как описано выше. с проблемой, как указано выше, что он снова будет молча игнорировать опечатки законных целей.
он использует 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 "[email protected]"
и сделай это:
$ ./buildandrunprog.sh arg
Вот еще одно решение, которое может помочь в некоторых из этих случаев использования:
test-%:
$(PYTHON) run-tests.py [email protected]
Другими словами, выберите в этом случае префикс (test-
), а затем передайте целевое имя непосредственно программе/бегун. Я думаю, что это в основном полезно, если задействован какой-то бегун script, который может развернуть имя цели во что-то полезное для базовой программы.
Нет. Глядя на синтаксис с man-страницы для GNU make
make [-f makefile] [опции]... [цели]...
вы можете указать несколько целей, следовательно, "нет" (по крайней мере, не так точно, как вы указали).
Вы можете явно извлечь каждый n-й аргумент в командной строке. Для этого вы можете использовать переменную MAKECMDGOALS, она содержит список аргументов командной строки, заданных для "make", который он интерпретирует как список целей. Если вы хотите извлечь n-й аргумент, вы можете использовать эту переменную в сочетании с функцией "word", например, если вы хотите использовать второй аргумент, вы можете сохранить его в переменной следующим образом:
second_argument := $(word 2, $(MAKECMDGOALS) )
anon, run: ./prog
выглядит немного странно, поскольку правая часть должна быть целью, поэтому run: prog
выглядит лучше.
Я бы предложил просто:
.PHONY: run
run:
prog $(arg1)
и я хотел бы добавить, что аргументы могут быть переданы:
make arg1="asdf" run
arg1="asdf" make run
Вот мой пример. Обратите внимание, что я пишу под Windows 7, используя mingw32-make.exe, который поставляется с Dev-Cpp. (У меня есть c:\Windows\System32\make.bat, поэтому команда по-прежнему называется "make".)
clean:
$(RM) $(OBJ) $(BIN)
@echo off
if "${backup}" NEQ "" ( mkdir ${backup} 2> nul && copy * ${backup} )
Использование для регулярной очистки:
make clean
Использование для очистки и создания резервной копии в mydir/:
make clean backup=mydir
Не слишком горжусь этим, но я не хотел передавать переменные окружения, поэтому я перевернул способ запуска консервной команды:
run:
@echo command-you-want
это выведет команду, которую вы хотите запустить, поэтому просто оцените ее в подоболочке:
$(make run) args to my command
Другой трюк, который я использую, это флаг -n
, который говорит make
выполнить пробный прогон. Например,
$ make install -n
# Outputs the string: helm install stable/airflow --name airflow -f values.yaml
$ eval $(make install -n) --dry-run --debug
# Runs: helm install stable/airflow --name airflow -f values.yaml --dry-run --debug