我使用Makefile。
我有一个名为run
的目标,它运行构建目标。简化后,它看起来如下:
prog: ....
...
run: prog
./prog
坐下来。我知道这是巧妙的,但不需要起立鼓掌。
现在,我的问题是 - 有没有办法传递参数?那么
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
谢谢!
答案 0 :(得分:210)
我不知道如何完全按照您的意愿行事,但解决方法可能是:
run: ./prog
./prog ${ARGS}
然后:
make ARGS="asdf" run
答案 1 :(得分:170)
这个问题已经快三年了,但无论如何......
如果你正在使用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
答案 2 :(得分:42)
答案 3 :(得分:14)
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 run var=arg
这将执行./prog arg
。
但要注意陷阱。我将详细阐述这种方法的缺陷以及其他方法。
回答问题背后的假设意图:
假设:您希望使用某些参数运行prog
,但必须在运行之前重建它。
答案:创建一个脚本,必要时重建然后用args
运行prog#! /bin/sh
# rebuild prog if necessary
make prog
# run prog with some arguments
./prog "$@"
这个脚本非常明确。它使用make来做它有用的东西:建筑。它使用shell脚本来完成它的优点:批处理。
现在调用语法几乎完全相同:
$ ./buildandrunprog.sh foo "bar baz"
比较:
$ ./prog foo "bar baz"
此外,您可以使用shell脚本的完全灵活性和表现力来执行您可能需要的任何其他操作,而无需makefile的所有注意事项。
背景:
make不是为运行目标而设计的,而是将参数传递给该目标。命令行中的所有参数都被解释为目标(a.k.a.target),选项或变量赋值。
所以如果你运行这个:
$ make run foo bar --wat var=arg
make会将run
,foo
和bar
解释为目标(目标),以根据其食谱进行更新。 --wat
作为make的选项。和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
运行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
请注意,当您在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
超短解释:从目标列表中筛选出当前目标。创建捕获所有目标(%
),它不会无声地忽略其他目标。
方法2:
ifeq (run, $(firstword $(MAKECMDGOALS)))
runargs := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(runargs):;@true)
endif
run:
./prog $(runargs)
超短解释:如果目标是run
,则删除第一个目标,并使用eval
为剩余目标创建不执行任何目标。
有关深入解释的研究手册: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"
没有解决方法
当您错误输入合法目标时,由于捕获所有目标,它将被默默忽略。
$ make celan
会默默地忽略celan
。
解决方法是让一切都变得冗长。所以你看看会发生什么。但这会给合法输出带来很多噪音。
方法2的问题:
如果参数与现有目标具有相同的名称,则make将打印一条警告,表明它已被覆盖。
我不知道
用空格传递参数仍然很尴尬。
没有解决方法
空格分隔eval
试图创建无任何目标的参数。
解决方法:创建全局捕获所有目标,如上所述不执行任何操作。如上所述,它将再次默默地忽略错误的合法目标。
它使用eval
在运行时修改makefile。在可读性和可调试性以及Principle of least astonishment方面你能走多远。
解决方法:不要这样做!! 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
答案 4 :(得分:10)
这是另一个可以帮助解决其中一些用例的解决方案:
test-%:
$(PYTHON) run-tests.py $@
换句话说,选择一些前缀(在这种情况下为test-
),然后将目标名称直接传递给程序/运行程序。我想如果涉及一些可以将目标名称解包为对底层程序有用的东西,那么这个程序非常有用。
答案 5 :(得分:9)
没有。查看GNU make的手册页中的语法
make [-f makefile] [options] ... [targets] ...
你可以指定多个目标,因此'不'(至少没有你指定的确切方式)。
答案 6 :(得分:4)
您可以在命令行中显式提取每个第n个参数。为此,您可以使用变量MAKECMDGOALS,它保存给予'make'的命令行参数列表,它将其解释为目标列表。如果要提取第n个参数,可以将该变量与“word”函数结合使用,例如,如果需要第二个参数,可以将其存储在变量中,如下所示:
second_argument := $(word 2, $(MAKECMDGOALS) )
答案 7 :(得分:3)
对此并不感到骄傲,但我并不想传递环境变量,所以我颠倒了运行固定命令的方式:
run:
@echo command-you-want
这将打印您要运行的命令,因此只需在子shell中进行评估:
$(make run) args to my command
答案 8 :(得分:2)
anon ,run: ./prog
看起来有点奇怪,因为正确的部分应该是目标,所以run: prog
看起来更好。
我建议简单地说:
.PHONY: run
run:
prog $(arg1)
我想补充说,可以传递参数:
make arg1="asdf" run
arg1="asdf" make run
答案 9 :(得分:2)
这是我的例子。请注意,我使用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 /中使用清理和创建备份:
make clean backup=mydir
答案 10 :(得分:0)
我使用的另一个技巧是-n
标志,它告诉make
进行空试。例如,
$ 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
答案 11 :(得分:0)
我找到了一种方法来获取带有等号(=)的参数!答案尤其是对@lesmana 's answer的补充(因为它是这里最完整和解释最清楚的一个),但是太大了,无法将其写为注释。再次,我重复他的信息:TL; DR不要尝试这样做!
我需要一种方法来处理我的参数--xyz-enabled=false
(因为默认值为true),我们现在都知道这不是make目标,因此也不是$(MAKECMDGOALS)
的一部分。
在回显$(.VARIABLES)
的情况下all variables of make时,我得到了这些有趣的输出:
[...] -*-command-variables-*- --xyz-enabled [...]
这使我们可以采用两种方式:要么全部以--
开始(如果适用于您的情况),要么查看GNU make specific (probably not intended for us to use)变量-*-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