将parameter passing给“make run”
我使用Makefiles。
我有一个运行构build目标的运行目标。 简化,看起来如下所示:
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
会将命令行中的非选项参数解释为目标。 解决办法是把它们变成无所作为的目标,所以不要抱怨:
# 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
对于标准,可以通过像这样定义macros来传递参数
make run arg1=asdf
然后像这样使用它们
run: ./prog $(arg1) etc
使微软的NMake的参考
你可以像下面那样把variables传递给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提供的解决scheme:
run: @echo ./prog $(filter-out $@,$(MAKECMDGOALS)) %: @:
%:
– 匹配任何任务名称的规则;@:
– 空配方=什么也不做
用法:
$ make run the dog kicked the cat ./prog the dog kicked the cat
不,从GNU make的手册页查看语法
make [-f makefile] [options] … [targets] …
你可以指定多个目标,因此'不'(至less没有以你指定的方式)。
这是另一个可以帮助解决这些用例的解决scheme:
test-%: $(PYTHON) run-tests.py $@
换句话说,select一些前缀(在这种情况下是test-
),然后直接将目标名称传递给程序/ runner。 我想这是最有用的,如果有一些亚军脚本参与,可以解开目标名称为底层程序有用的东西。
anon , run: ./prog
看起来有点奇怪,因为右边的部分应该是目标,所以run: prog
看起来更好。
我会build议简单的:
.PHONY: run run: prog $(arg1)
我想补充一点,可以传递参数:
- 作为参数:
make arg1="asdf" run
- 或者定义为环境:
arg1="asdf" make run
这是我的例子。 请注意,我正在使用Dev-Cpp附带的mingw32-make.exe在Windows 7下编写代码。 (我有c:\ Windows \ System32 \ make.bat,所以命令仍然被称为“make”。)
clean: $(RM) $(OBJ) $(BIN) @echo off if "${backup}" NEQ "" ( mkdir ${backup} 2> nul && copy * ${backup} )
定期清洁的用法:
make clean
在mydir /中清理和创build备份的用法
make clean backup=mydir
您可以在命令行中显式提取每个第n个参数。 要做到这一点,你可以使用variablesMAKECMDGOALS,它包含了赋予“make”的命令行参数列表,它被解释为一个目标列表。 如果要提取第n个参数,可以将该variables与“word”函数结合使用,例如,如果需要第二个参数,则可以将其存储在variables中,如下所示:
second_argument := $(word 2, $(MAKECMDGOALS) )
不要太自豪,但我不想传递环境variables,所以我倒过来运行一个canned命令的方式:
run: @echo command-you-want
这将打印你想运行的命令,所以只需在一个子shell中进行评估:
$(make run) args to my command
回答所述问题:
你可以在配方中使用一个variables
run: prog ./prog $(var)
然后传递一个variables赋值作为参数
$ make run var=arg
这将执行./prog arg
。
但要小心陷阱。 我将详细说明这种方法和其他方法的陷阱。
回答问题背后的可能意图:
你想用一些参数来运行prog
,但如果需要的话,在运行之前重新prog
它。
创build脚本:
#! /bin/sh # rebuild prog if necessary make prog # run prog with some arguments ./prog "$@"
使用脚本构build和运行:
$ ./buildandrunprog.sh arg
背景:
make并不是为了运行一个目标而devise的,并且将parameter passing给目标。 命令行上的所有参数都被解释为目标(或目标),作为选项或作为variables赋值。
所以如果你运行这个:
$ make run foo bar --wat var=arg
make将把--wat
作为一个选项来解释, var=arg
作为一个variables赋值, run
foo
和bar
作为目标或者目标来根据他们的配方进行更新。
有关更多详细信息,请参阅: 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
关于variables赋值方法
$ make run var=arg
和配方中的variables
run: prog ./prog $(var)
这是向食谱传递参数的最“正确”和直接的方式。 “正确”的意思是,它实际上是要用这种方式。 请参阅https://www.gnu.org/software/make/manual/html_node/Overriding.html#Overriding
在我看来,这有一个很大的缺点:你想要做的是用参数arg
运行prog
。 但不是写作:
$ ./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
为logging这是我prog
样子:
#! /bin/sh echo "argcount: $#" for arg in "$@"; do echo "arg: $arg" done
请注意,当您将$(var)
放在makefile中的引号中时:
run: prog ./prog "$(var)"
那么prog
将总是只有一个参数:
$ make run var="foo bar\ baz" ./prog "foo bar\ baz" argcount: 1 arg: foo bar\ baz
所有这些都是为什么我build议不要这样做。
问题是:你想达到什么目的? 正如我上面所说的,我假设你想用一些参数来运行prog
,但是如果需要的话在运行之前重新prog
它。
我build议的shell脚本就是这么做的
#! /bin/sh # rebuild prog if necessary make prog # run prog with some arguments ./prog "$@"
这个剧本意图非常清楚。 它使用make来做什么:building。 它使用一个shell脚本来做它擅长的事情:批处理。
调用语法现在几乎是相同的:
$ ./buildandrunprog.sh foo "bar baz"
相比于:
$ ./prog foo "bar baz"
另外你可以做任何你可能需要的东西,而且没有所有makefile文件的注意事项。
为了完整性,这里还有一些其他的方法来“传递参数来运行”。
方法1:
run: prog ./prog $(filter-out $@, $(MAKECMDGOALS)) %: @true
超级简短的解释:从目标列表中滤除当前目标。 创造捕捉所有的目标( %
),没有任何东西默默地忽略其他目标。
方法2:
ifeq (run, $(firstword $(MAKECMDGOALS))) runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS)) $(eval $(runargs):;@true) endif run: ./prog $(runargs)
超级简短的解释:如果目标run
则删除第一个目标,并使用eval
为剩余的目标创build无所作为的目标。
为了更深入地讲解make的手册: 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"
没有解决方法
-
当你错误地input一个合法的目标时,由于捕获所有目标,它将被默默地忽略。
$ make celan
只会默默地忽略
celan
。解决方法是使一切都冗长。 所以你看看会发生什么 但是这会为合法的输出创造大量的噪音。
第二种方法的问题:
-
如果参数与现有目标名称相同,那么make将会打印一条警告信息,说明它正在被覆盖。
没有我知道的解决方法
-
与空间传递争论仍然尴尬。
没有解决方法
-
争论空间rest
eval
试图创造无所作为的目标。解决方法:创build一个全局的全局目标,如上所述。 面对上述问题,它将再次默默地忽略错误的合法目标。
-
它使用
eval
在运行时修改makefile。 在可读性和可debugging性以及最less的惊讶原则方面,你能走多less?解决方法:不要这样做!! 1而是编写一个运行make的shell脚本,然后运行
prog
。
我只用gnu make进行了testing。 其他制造可能会有不同的行为。