我使用Makefiles。
我有一个名为run的目标,它运行构建目标。简化后,如下图所示:
prog: ....
...
run: prog
./prog
有传递参数的方法吗?这
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
我使用Makefiles。
我有一个名为run的目标,它运行构建目标。简化后,如下图所示:
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
# or
make run ARGS="asdf"
其他回答
建立在理想答案的基础上。 你可以创建一个通用的“函数”来获取参数 使用以下方法:
define fetch_parameter
$(eval target_name:= $(firstword $(MAKECMDGOALS)))
$(eval varname := $(target_name)_value)
$(eval $(varname) := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)))
$(eval $($(varname))::;@:)
endef
然后你可以像这样在你的目标中使用它:
my-target: res := $(call fetch_parameter)
my-target: ## Example target. Usage: make my-target <value>
echo The value: $($@_value)
这样你就可以在任何你想检索值的目标上使用res:= $(调用fetch_parameter)。
注意:我在这段代码中添加了额外的:$(eval $($(varname))::;@:),因为如果你有多个调用fetch_parameter的目标,它也会被触发。 如果你有:
my-target: res := $(call fetch_parameter)
my-target: ## Example target. Usage: make my-target <value>
echo The value: $($@_value)
my-target2: res := $(call fetch_parameter)
my-target2: ## Example target. Usage: make my-target2 <value>
echo The value: $($@_value)
并且你调用make my-target2 hello, make的工作方式,$(call fetch_parameter)都将被触发,导致创建2个伪hello目标,但额外的:(hello::) make不会抱怨你覆盖了一个目标。
Run: ./prog看起来有点奇怪,因为正确的部分应该是一个先决条件,所以Run: prog看起来更好。
我的建议很简单:
.PHONY: run
run:
prog $(arg1)
我想补充一点,可以传递参数:
作为参数:使arg1="asdf"运行 或者定义为environment: arg1="asdf" make run
它已经有一段时间了,但我将提供我在生产中使用的版本。
我希望有人会觉得它有用。
例子:
.PHONY: greeting
greeting:
echo $(if $s,$s,)
命令:
使问候s="hello world"
输出:
你好世界
不要尝试这样做
$ make run arg
相反,创建脚本build_and_run_prog.sh:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
然后这样做:
$ ./build_and_run_prog.sh arg
继续往下读,你会明白为什么这是最合理的选择,为什么最好避免其他选择
回答上述问题:如何将参数传递给make目标
您可以在配方中使用变量
run: prog
./prog $(var)
然后传递一个变量赋值作为make的参数
$ make run var=arg
这将执行。/prog arg。
但要小心陷阱。
最明显的是用空格传递参数时的尴尬。你必须这样做:
$ make run var="foo bar\ baz"
这将执行。/prog foo "bar baz"。
我将在下面详细说明这种方法的缺陷和其他缺陷。
回答您的问题背后的假定意图:您希望带一些参数运行prog,但在必要时运行之前重新构建它。
创建一个脚本,在必要时重新构建,然后运行prog和args
build_and_run_prog.sh:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
这个脚本的意图非常明确。它使用make来做它擅长的事情:构建。它使用一个shell脚本来做它擅长的事情:批处理。
此外,您可以使用shell脚本的完全灵活性和表现力来完成其他任何您可能需要的事情,而不需要makefile的所有警告。
而且调用语法现在实际上是相同的:
$ ./build_and_run_prog.sh foo "bar baz"
相比:
$ ./prog foo "bar baz"
对比
$ make run var="foo bar\ baz"
make如何处理参数的背景说明:
Make不是设计用来将参数传递给目标的。命令行上的所有参数都被解释为目标(也称为目标)、选项或变量赋值。
如果你运行这个:
$ make run foo --wat var=arg
Make将run和foo解释为目标(目标),根据它们的食谱进行更新。作为制作的一个选项。var=arg作为make的变量赋值。
从命令行传递信息以在配方中使用的唯一机会是通过变量赋值。
有关如何运行make的更多细节,请参阅gnu手册
为什么我不推荐变量赋值
$ make run var=arg
以及配方中的变量
run: prog
./prog $(var)
这是将参数传递给配方的最“正确”和最直接的方式。但是,虽然它可以用来运行带参数的程序,但它肯定不是被设计成这样使用的。关于重写,请参阅gnu手册
在我看来,这有一个很大的缺点:你想做的是用参数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
为了记录,这是我的项目的样子:
#! /bin/sh
echo "argcount: $#"
for arg in "$@"; do
echo "arg: $arg"
done
还要注意,你不应该在makefile中把$(var)放在引号中:
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
从目标列表中过滤出当前目标。创建catch all target(%),它不做任何事情来默默地忽略其他目标。
方法2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
如果目标正在运行,则删除第一个目标,并使用eval为其余目标创建什么都不做的目标。
这两种方法都可以写成这样
$ make run arg1 arg2
方法一的问题:
Arguments that start with a dash will be interpreted by make and not passed as a goal. $ make run --foo --bar workaround $ make run -- --foo --bar Arguments with an equal sign will be interpreted by make and not passed $ make run foo=bar no workaround Arguments with spaces is awkward $ make run foo "bar\ baz" no workaround If an argument happens to be run (equal to the target) it will also be removed $ make run foo bar run will run ./prog foo bar instead of ./prog foo bar run workaround possible with method 2 If an argument is a legitimate target it will also be run. $ make run foo bar clean will run ./prog foo bar clean but also the recipe for the target clean (assuming it exists). workaround possible with method 2 When you mistype a legitimate target it will be silently ignored because of the catch all target. $ make celan will just silently ignore celan. workaround is to make everything verbose. so you see what happens. but that creates a lot of noise for the legitimate output.
方法二的问题:
If an argument has same name as an existing target then make will print a warning that it is being overwritten. no workaround that I know of Arguments with an equal sign will still be interpreted by make and not passed no workaround Arguments with spaces is still awkward no workaround Arguments with space breaks eval trying to create do nothing targets. workaround: create the global catch all target doing nothing as above. with the problem as above that it will again silently ignore mistyped legitimate targets. it uses eval to modify the makefile at runtime. how much worse can you go in terms of readability and debugability and the Principle of least astonishment. workaround: don't!
我只使用gnu make进行了测试。其他品牌可能有不同的行为。
Gnu制作手册
https://www.gnu.org/software/make/manual/html_node/index.html
你可以像下面这样将变量传递给Makefile:
run:
@echo ./prog $$FOO
用法:
$ make run FOO="the dog kicked the cat"
./prog the dog kicked the cat
or:
$ 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