Answers:
我不知道完全按照自己的意愿做事的方法,但是一种解决方法可能是:
run: ./prog
./prog $(ARGS)
然后:
make ARGS="asdf" run
# or
make run ARGS="asdf"
$(foo)' or
$ {foo}'是对变量“ foo”。” 并继续给出仅使用$()的示例。呃,好吧。
这个问题已经快三年了,但无论如何...
如果您使用的是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
prog foo bar --baz
make
不要将其解释--baz
为命令行选项:make -- prog foo bar --baz
。的--
意思是“在这之后一切都是一个说法,不是一种选择”。
RUN_ARGS
使用它的默认值?
else
分支ifeq
并在RUN_ARGS
那里设置?
$(eval $(RUN_ARGS):dummy;@:)
,而未定义虚拟目标。
您可以将变量传递给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 $@,$(MAKECMDGOALS))
%:
@:
用法:
$ make run the dog kicked the cat
./prog the dog kicked the cat
TL; DR不要尝试这样做
$ make run arg
而是创建脚本:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
并执行以下操作:
$ ./buildandrunprog.sh arg
回答所述问题:
您可以在配方中使用变量
run: prog
./prog $(var)
然后将变量赋值作为参数传递给make
$ make run var=arg
这将执行./prog arg
。
但是要当心陷阱。我将详细介绍该方法以及其他方法的陷阱。
回答问题背后的预期意图:
假设:您想prog
使用一些参数来运行,但是在必要时在运行之前对其进行重建。
答案:创建一个脚本,该脚本在必要时进行重建,然后使用args运行prog
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
该脚本使意图非常明确。它使用make来完成其擅长的工作:构建。它使用Shell脚本执行其擅长的功能:批处理。
另外,您可以在没有makefile的所有警告的情况下,利用shell脚本的完全灵活性和表现力来完成任何您可能需要做的事情。
现在调用语法实际上是相同的:
$ ./buildandrunprog.sh foo "bar baz"
相比于:
$ ./prog foo "bar baz"
相比较
$ make run var="foo bar\ baz"
背景:
make并非旨在将参数传递给目标。命令行上的所有参数都被解释为目标(也称为目标),选项或变量赋值。
因此,如果运行此命令:
$ make run foo --wat var=arg
make将根据其配方来解释run
和foo
作为目标(目标)进行更新。--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
使用arguments 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 "$@"; 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
这就是为什么我建议您反对这条路线。
为了完整性,这里有一些其他方法“传递参数以使运行”。
方法1:
run: prog
./prog $(filter-out $@, $(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
在运行时修改makefile。就可读性和可调试性以及最小惊讶原理而言,您能差多少?
解决方法:不要这样做!1而是编写一个运行make然后运行的shell脚本prog
。
我只测试了使用gnu make。其他品牌可能会有不同的行为。
TL; DR不要尝试这样做
$ make run arg
而是创建脚本:
#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
并执行以下操作:
$ ./buildandrunprog.sh arg
这是另一个可以帮助解决其中一些用例的解决方案:
test-%:
$(PYTHON) run-tests.py $@
换句话说,选择一些前缀(test-
在这种情况下),然后将目标名称直接传递给程序/运行程序。我猜想,如果涉及到一些运行程序脚本,这些脚本可以将目标名称解包为对基础程序有用的内容,那么这最有用。
$*
来传递仅与匹配的目标部分%
。
您可以在命令行中显式提取每个第n个参数。为此,您可以使用变量MAKECMDGOALS,该变量包含提供给'make'的命令行参数列表,它将其解释为目标列表。如果要提取第n个参数,则可以将该变量与“ word”函数结合使用,例如,如果要第二个参数,则可以将其存储在变量中,如下所示:
second_argument := $(word 2, $(MAKECMDGOALS) )
make: *** No rule to make target 'arg'. Stop.
对此并不感到骄傲,但是我不想传入环境变量,因此我改变了运行固定命令的方式:
run:
@echo command-you-want
这将打印您要运行的命令,因此只需在子shell中对其进行评估:
$(make run) args to my command
我找到了一种方法来获取带有等号(=)的参数!答案尤其是对@lesmana答案的补充(因为这是最完整的说明),但是将其写为注释太大了。再次,我重复他的信息:TL; DR不要尝试这样做!
我需要一种方法来处理我的参数--xyz-enabled=false
(因为默认值是true),到现在我们都知道这不是make目标,因此也不是的一部分$(MAKECMDGOALS)
。
通过回显i 查看所有make变量时,$(.VARIABLES)
得到了这些有趣的输出:
[...] -*-command-variables-*- --xyz-enabled [...]
这使我们可以采用两种方式:要么全部以一个--
(如果适用于您的情况)开始,要么研究GNU make specific(可能不打算供我们使用)变量-*-command-variables-*-
。**有关其他选项,请参见页脚**在我的情况下,此变量为:
--xyz-enabled=false
使用此变量,我们可以将其与现有解决方案结合使用$(MAKECMDGOALS)
,从而定义:
# the other technique to invalidate other targets is still required, see linked post
run:
@echo ./prog $(-*-command-variables-*-) $(filter-out $@,$(MAKECMDGOALS))`
并将其与(明确混合参数的顺序)一起使用:
make run -- config --xyz-enabled=false over=9000 --foo=bar show isit=alwaysreversed? --help
回:
./prog isit=alwaysreversed? --foo=bar over=9000 --xyz-enabled=false config show --help
如您所见,我们放宽了args的总顺序。带有“赋值” -args的部分似乎已颠倒,“目标” -args的顺序得以保留。我在一开始就放置了“ assignment” -args,希望您的程序不在乎参数的放置位置。
更新:以下使变量看起来也很有希望:
MAKEFLAGS = -- isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false
MAKEOVERRIDES = isit=alwaysreverse? --foo=bar over=9000 --xyz-enabled=false