Передача аргументов для "make 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

Спасибо!

Ответ 1

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

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

Тогда:

make ARGS="asdf" run

Ответ 2

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

Если вы используете 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

Ответ 3

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

make run arg1=asdf

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

run: ./prog $(arg1)
   etc

Ссылки для make Microsoft NMake

Ответ 4

Вы можете передать переменную в 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

Ответ 5

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

Ответ 6

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

test-%:
    $(PYTHON) run-tests.py [email protected]

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

Ответ 7

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

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

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

Ответ 8

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

second_argument := $(word 2, $(MAKECMDGOALS) )

Ответ 9

anon, run: ./prog выглядит немного странно, поскольку правая часть должна быть целью, поэтому run: prog выглядит лучше.

Я бы предложил просто:

.PHONY: run

run:
        prog $(arg1)

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

  • в качестве аргумента: make arg1="asdf" run
  • или определяется как среда: arg1="asdf" make run

Ответ 10

Вот мой пример. Обратите внимание, что я пишу под 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

Ответ 11

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

run:
    @echo command-you-want

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

$(make run) args to my command

Ответ 12

Другой трюк, который я использую, это флаг -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