Passing arguments to “make run”
我使用makefiles。
我有一个名为
1 2 3 4 5 | prog: .... ... run: prog ./prog |
坐下来。我知道这很巧妙,但不需要起立鼓掌。
现在,我的问题是——有什么方法可以传递论点吗?以便
1 2 | make run asdf --> ./prog asdf make run the dog kicked the cat --> ./prog the dog kicked the cat |
谢谢!
我不知道做你想做的事情的具体方法,但解决方法可能是:
1 2 | run: ./prog ./prog ${ARGS} |
然后:
1 | make ARGS="asdf" run |
这个问题已经快三岁了,但无论如何…
如果您使用的是GNU make,这很容易做到。唯一的问题是,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # 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) |
运行此命令将提供:
1 2 | $ make run foo bar baz prog foo bar baz |
对于标准make,可以通过定义这样的宏来传递参数
1 | make run arg1=asdf |
然后像这样使用它们
1 2 | run: ./prog $(arg1) etc |
制造参考微软的nmake
您可以将变量传递到makefile,如下所示:
1 2 | run: @echo ./prog $$FOO |
用途:
1 2 | $ make run FOO="the dog kicked the cat" ./prog the dog kicked the cat |
或:
1 2 | $ FOO="the dog kicked the cat" make run ./prog the dog kicked the cat |
或者使用beta提供的解决方案:
1 2 3 4 | run: @echo ./prog $(filter-out $@,$(MAKECMDGOALS)) %: @: |
%: - rule which match any task name;
@: - empty recipe = do nothing
用途:
1 2 | $ make run the dog kicked the cat ./prog the dog kicked the cat |
医生不要这样做好的。
1 | $ make run arg |
而是创建脚本:好的。
1 2 3 4 5 | #! /bin/sh # rebuild prog if necessary make prog # run prog with some arguments ./prog"$@" |
这样做:好的。
1 | $ ./buildandrunprog.sh arg |
回答上述问题:好的。
您可以在配方中使用变量好的。
1 2 | run: prog ./prog $(var) |
然后将变量赋值作为参数传递给好的。
1 | $ make run var=arg |
这将执行
但要小心陷阱。我将详细说明这个方法和其他方法的缺陷。好的。
回答问题背后的假设意图:好的。
假设:您希望使用一些参数运行
答案是:创建一个脚本,在必要时重建,然后用参数运行prog好的。
1 2 3 4 5 | #! /bin/sh # rebuild prog if necessary make prog # run prog with some arguments ./prog"$@" |
这个剧本使意图非常清楚。它用make来做它有益的事情:建筑。它使用一个shell脚本来完成它所擅长的工作:批处理。好的。
另外,调用语法现在几乎是相同的:好的。
1 | $ ./buildandrunprog.sh foo"bar baz" |
比较:好的。
1 | $ ./prog foo"bar baz" |
另外,您可以用shell脚本的完全灵活性和表现力来做您可能需要的任何其他事情,而不需要makefile的所有警告。好的。
背景:好的。
make不用于运行目标并向该目标传递参数。命令行上的所有参数都被解释为目标(a.k.a.目标)、选项或变量分配。好的。
所以如果你运行这个:好的。
1 | $ make run foo bar --wat var=arg |
make将把
有关更多详细信息,请参阅: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好的。
关于变量赋值方法以及我为什么不推荐它好的。
1 | $ make run var=arg |
配方中的变量好的。
1 2 | run: prog ./prog $(var) |
这是向配方传递参数的最"正确"和最直接的方法。但是,虽然它可以用来运行带有参数的程序,但它的设计显然不是这样的。参见https://www.gnu.org/software/make/manual/html_node/overriding.html_overriding好的。
在我看来,这有一个很大的缺点:你想做的是用
1 | $ ./prog arg |
你在写:好的。
1 | $ make run var=arg |
当试图传递多个参数或包含空格的参数时,这会变得更加尴尬:好的。
1 2 3 4 5 | $ make run var="foo bar\ baz" ./prog foo bar\ baz argcount: 2 arg: foo arg: bar baz |
比较:好的。
1 2 3 4 | $ ./prog foo"bar baz" argcount: 2 arg: foo arg: bar baz |
据记载,这就是我的
1 2 3 4 5 | #! /bin/sh echo"argcount: $#" for arg in"$@"; do echo"arg: $arg" done |
请注意,当您在makefile中将
1 2 | run: prog ./prog"$(var)" |
那么,
1 2 3 4 | $ make run var="foo bar\ baz" ./prog"foo bar\ baz" argcount: 1 arg: foo bar\ baz |
这就是我反对这条路线的原因。好的。
为了完整性,这里还有一些其他的方法来"传递参数使其运行"。好的。
方法1:好的。
1 2 3 4 5 | run: prog ./prog $(filter-out $@, $(MAKECMDGOALS)) %: @true |
超短解释:从目标列表中过滤出当前目标。创建catch all目标(
方法2:好的。
1 2 3 4 5 6 7 | ifeq (run, $(firstword $(MAKECMDGOALS))) runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS)) $(eval $(runargs):;@true) endif run: ./prog $(runargs) |
超短解释:如果目标是
为了更深入的解释,请学习make手册:https://www.gnu.org/software/make/manual/html_node/index.html好的。
方法1的问题:好的。
以破折号开头的参数将由make解释,而不是作为目标传递。好的。
1$ make run --foo --bar解决办法好的。
1$ make run -- --foo --bar如果一个参数恰好是
run (等于目标),它也将被删除。好的。1$ make run foo bar run将运行
./prog foo bar ,而不是./prog foo bar run 好的。方法2可能的解决方法好的。
如果一个参数是合法的目标,它也将运行。好的。
1$ make run foo bar clean将运行
./prog foo bar clean ,但也将运行目标clean 的配方(假设存在)。好的。方法2可能的解决方法好的。
用空格传递参数很难好的。
1$ make run foo"bar\ baz"没有解决办法好的。
当您错误地输入合法的目标时,它将被静默忽略,因为会捕获所有目标。好的。
1$ make celan只会默默地忽略
celan 。好的。解决方法是使所有事情都变得冗长。你看会发生什么。但这对合法的输出产生了很大的干扰。好的。
方法2的问题:好的。
如果某个参数与现有目标同名,则make将打印一条警告,说明正在覆盖该参数。好的。
我不知道有什么解决办法好的。
用空格来传递论点仍然很难。好的。
没有解决办法好的。
带有空格的论点破坏了cx1〔2〕试图创建什么都不做的目标。好的。
解决方法:创建全局捕获所有目标,不执行上述任何操作。由于上述问题,它将再次默默地忽略输入错误的合法目标。好的。
它使用
eval 在运行时修改makefile。在可读性和可调试性以及最小惊异原则方面,你能做得更糟。好的。解决方法:不要这样做!!1改为编写一个运行make然后运行
prog 的shell脚本。好的。
我只测试了使用GNU制造。其他品牌可能有不同的行为。好的。
医生不要这样做好的。
1 | $ make run arg |
而是创建脚本:好的。
1 2 3 4 5 | #! /bin/sh # rebuild prog if necessary make prog # run prog with some arguments ./prog"$@" |
这样做:好的。
1 | $ ./buildandrunprog.sh arg |
好啊。
下面是另一个解决方案,可以帮助处理其中一些用例:
1 2 | test-%: $(PYTHON) run-tests.py $@ |
换句话说,选择一些前缀(本例中为
不。从gnu make的手册页查看语法
make [ -f makefile ] [ options ] ... [ targets ] ...
可以指定多个目标,因此为"否"(至少按指定的方式为"否")。
可以在命令行中显式提取每个n个参数。要做到这一点,您可以使用变量makeCmdGoals,它保存给"make"的命令行参数列表,并将其解释为目标列表。如果要提取第n个参数,可以将该变量与"word"函数结合使用,例如,如果需要第二个参数,可以将其存储在变量中,如下所示:
1 | second_argument := $(word 2, $(MAKECMDGOALS) ) |
对此并不太自豪,但我不想传递环境变量,因此我颠倒了运行屏蔽命令的方式:
1 2 | run: @echo command-you-want |
这将打印要运行的命令,因此只需在子shell中对其进行计算:
1 | $(make run) args to my command |
这是我的例子。注意,我是在Windows7下编写的,使用dev cpp附带的mingw32-make.exe。(我有C:windowssystem32make.bat,所以该命令仍然称为"make"。)
1 2 3 4 | clean: $(RM) $(OBJ) $(BIN) @echo off if"${backup}" NEQ"" ( mkdir ${backup} 2> nul && copy * ${backup} ) |
定期清洁的用途:
1 | make clean |
在mydir/中清理和创建备份的用法:
1 | make clean backup=mydir |
不,
我建议简单地:
1 2 3 4 | .PHONY: run run: prog $(arg1) |
我想补充一点,这些参数可以传递:
我使用的另一个技巧是
1 2 3 4 | $ 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 |