将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。 我想这是最有用的,如果有一些亚军脚本参与,可以解开目标名称为底层程序有用的东西。

anonrun: ./prog看起来有点奇怪,因为右边的部分应该是目标,所以run: prog看起来更好。

我会build议简单的:

 .PHONY: run run: prog $(arg1) 

我想补充一点,可以传递参数:

  1. 作为参数: make arg1="asdf" run
  2. 或者定义为环境: 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 foobar作为目标或者目标来根据他们的配方进行更新。

有关更多详细信息,请参阅: 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将会打印一条警告信息,说明它正在被覆盖。

    没有我知道的解决方法

  • 与空间传递争论仍然尴尬。

    没有解决方法

  • 争论空间resteval试图创造无所作为的目标。

    解决方法:创build一个全局的全局目标,如上所述。 面对上述问题,它将再次默默地忽略错误的合法目标。

  • 它使用eval在运行时修改makefile。 在可读性和可debugging性以及最less的惊讶原则方面,你能走多less?

    解决方法:不要这样做!! 1而是编写一个运行make的shell脚本,然后运行prog


我只用gnu make进行了testing。 其他制造可能会有不同的行为。