Передача аргументов в «make run» - PullRequest
308 голосов
/ 06 февраля 2010

Я использую Makefiles.

У меня есть цель с именем run, которая выполняет цель сборки. Упрощенно это выглядит следующим образом:

prog: ....
  ...

run: prog
  ./prog

Сядь обратно. Я знаю, что это гениально, но не нужно оваций.

Теперь мой вопрос - есть ли способ передать аргументы? Так что

make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat

Спасибо!

Ответы [ 12 ]

214 голосов
/ 06 февраля 2010

Я не знаю, как сделать то, что вы хотите, но обходной путь может быть:

run: ./prog
    ./prog ${ARGS}

Тогда:

make ARGS="asdf" run
174 голосов
/ 28 декабря 2012

Этому вопросу почти три года, но все равно ...

Если вы используете 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
42 голосов
/ 06 февраля 2010

для стандартного make вы можете передавать аргументы, определяя макросы как этот

make run arg1=asdf

тогда используйте их вот так

run: ./prog $(arg1)
   etc

Рекомендации для Марка Microsoft NMake

28 голосов
/ 10 сентября 2015

Вы можете передать переменную в 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 $@,$(MAKECMDGOALS))
%:
    @:

%: - правило, соответствующее любому имени задачи;@: - пустой рецепт = ничего не делать

Использование:

$ make run the dog kicked the cat
./prog the dog kicked the cat
14 голосов
/ 10 июля 2017

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
11 голосов
/ 29 июля 2015

Вот еще одно решение, которое может помочь с некоторыми из этих вариантов использования:

test-%:
    $(PYTHON) run-tests.py $@

Другими словами, выберите некоторый префикс (test- в данном случае), а затем передайте имя цели непосредственно программе / исполнителю. Я предполагаю, что это в основном полезно, если есть какой-то сценарий запуска, который может развернуть целевое имя во что-то полезное для основной программы.

9 голосов
/ 06 февраля 2010

Нет. Глядя на синтаксис man-страницы для GNU make

make [-f makefile] [опции] ... [цели] ...

Вы можете указать несколько целей, следовательно, «нет» (по крайней мере, нет точно так, как вы указали).

4 голосов
/ 03 февраля 2016

Вы можете явно извлечь каждый n-й аргумент в командной строке. Для этого вы можете использовать переменную MAKECMDGOALS, в которой содержится список аргументов командной строки, заданных для make, который он интерпретирует как список целей. Если вы хотите извлечь n-й аргумент, вы можете использовать эту переменную в сочетании с функцией «word», например, если вам нужен второй аргумент, вы можете сохранить его в переменной следующим образом:

second_argument := $(word 2, $(MAKECMDGOALS) )
3 голосов
/ 28 июля 2016

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

run:
    @echo command-you-want

это напечатает команду, которую вы хотите запустить, поэтому просто оцените ее в подоболочке:

$(make run) args to my command
2 голосов
/ 03 июля 2013

Вот мой пример. Обратите внимание, что я пишу под 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...