将参数传递给“make run”
我使用 Makefile。
我有一个名为 run
的目标,它运行构建目标。简单来说,它看起来像下面这样:
prog: ....
...
run: prog
./prog
有什么方法可以传递参数吗?以便
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
I use Makefiles.
I have a target called run
which runs the build target. Simplified, it looks like the following:
prog: ....
...
run: prog
./prog
Is there any way to pass arguments? So that
make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
我不知道有什么方法可以准确地完成您想要的操作,但解决方法可能是:
然后:
I don't know a way to do what you want exactly, but a workaround might be:
Then:
如果您使用 GNU make,这很容易做到。唯一的问题是 make 会将命令行中的非选项参数解释为目标。解决方案是将它们变成不执行任何操作的目标,因此
make
不会抱怨:运行此命令会给出:
If you're using GNU make, this is easy to do. The only problem is that
make
will interpret non-option arguments in the command line as targets. The solution is to turn them into do-nothing targets, somake
won't complain:Running this gives:
TL;DR 不要尝试这样做,
而是创建脚本
build_and_run_prog.sh
:并执行以下操作:
继续阅读以了解为什么这是最合理的选择以及原因最好避免其他替代方案
回答所述问题:如何将参数传递给 make 目标
您可以在配方中使用变量
,然后传递变量赋值作为参数以使其
执行
./prog arg
.这是“将参数传递给菜谱”的最正确和最直接的方法。 gnu make 手册
请参阅 关于覆盖变量的 可以用于运行带有参数的程序,但它当然不应该这样使用。
让我详细说明一些问题,
您想要做的是使用参数
arg
运行prog
。但不是写:你需要写:
当尝试传递多个参数或包含空格的参数时,这会变得更加尴尬。
写而不是写
你需要
,否则
我希望你看到除了最简单的论点之外的任何事情都会变得非常尴尬。
另请注意,不应将
$(var)
放在 makefile 中的引号中:因为这样
prog
将始终只获得一个参数。回答您的问题背后的假定意图:您希望使用一些参数运行
prog
,但如果需要,请在运行之前重建它。创建一个脚本,必要时进行重建,然后使用参数运行 prog
build_and_run_prog.sh
:该脚本的意图非常明确。它使用 make 来做它擅长的事情:构建/编译。它使用 shell 脚本来做它擅长的事情:批处理。
另外,您可以利用 shell 脚本的完全灵活性和表现力来完成您可能需要的任何其他操作,而无需 makefile 的所有注意事项。
此外,调用语法现在实际上是相同的:
相比:
与
make 如何处理参数的背景说明相比:
Make 的设计目的不是将参数传递给目标。命令行上的所有参数都被解释为目标(也称为目标)、选项或变量赋值。
因此,如果您运行此命令:
make 会将
run
和foo
解释为目标(targets),以根据其配方进行更新。--wat
作为 make 的选项。以及var=arg
作为 make 的变量赋值。我希望您能看到从命令行传递信息以在配方中使用(无需黑客)的唯一方法是通过变量赋值。
更多详细信息,请参阅有关如何运行 make 的 gnu 手册
有关 完整性这里是一些“传递参数以运行”的技巧。
方法一:
超简短说明:从目标列表中过滤掉当前目标。然后将目标列表作为参数传递给
prog
。还创建一个捕获所有目标(%
),它不执行任何操作来默默地忽略所有其他“目标”。这将允许您编写类似
方法 1 的问题的内容:
以破折号开头的参数将由 make 解释,并且不会作为目标传递。
解决方法
带有等号的参数将由make解释并且不会被传递
没有解决办法
带有空格的参数很尴尬
没有解决办法
如果一个参数恰好被
运行
(等于目标),它也将被删除将运行
./prog foo bar
而不是./prog foo bar run
可以使用方法 2 来解决
如果参数是合法目标,它也将运行。
将运行
./prog foo bar clean
,但也会运行目标clean
的配方(假设它存在)。可以使用方法 2 来解决
当您错误输入合法目标时,由于捕获所有目标,该目标将被静默忽略。
<前><代码> $ make celan
只会默默地忽略
celan
。解决方法是让一切变得冗长。所以你看看会发生什么。但这会给合法输出带来很多噪音。
方法2:
超简短说明:如果目标是
run
,则处理目标列表并保存在变量中。还可以使用eval
为剩余的“目标”创建不执行任何操作的目标。稍后在运行prog
时将准备好的变量作为参数传递。方法 2 的问题:
如果参数与现有目标同名,那么 make 将打印一条警告,指出它正在被覆盖。
据我所知,没有解决方法
带有等号的参数仍将被 make 解释并且不会被传递
没有解决办法
带有空格的参数仍然很尴尬
没有解决办法
带空格的参数
eval
尝试创建不执行任何操作的目标。解决方法:创建全局捕获所有目标,如上所述,不执行任何操作。对于上述问题,它会再次默默地忽略输入错误的合法目标。
它使用
eval
在运行时修改makefile。在可读性和可调试性以及最小惊讶原则方面你还能差多少。解决方法:不要!
我只使用 gnu make 进行了测试。其他品牌可能有不同的行为。
gnu make 手册
https://www.gnu.org/software/make/手册/html_node/index.html
TL;DR don't try to do this
instead create script
build_and_run_prog.sh
:and do this:
Read on for some explanation of why this is the most reasonable choice and why the other alternatives are best avoided
Answer to the stated question: how to pass arguments to a make target
you can use a variable in the recipe
then pass a variable assignment as an argument to make
this will execute
./prog arg
.this is the most correct and straightforward way to "pass arguments to a recipe". see the gnu make manual on overriding variables
but while it can be used to run a program with arguments it is certainly not meant to be used that way.
Let me elaborate on some problems
what you want to do is run
prog
with argumentarg
. but instead of writing:you need to write:
this gets even more awkward when trying to pass multiple arguments or arguments containing spaces.
instead of writing
you need to write
or
i hope you see how this will get quite awkward for anything but the simplest arguments.
also note that you should not put
$(var)
in quotes in the makefile:because then
prog
will always get just one argument.Answer to the assumed intention behind your question: You want to run
prog
with some arguments but have it rebuild before running if necessary.Create a script which rebuilds if necessary then runs prog with args
build_and_run_prog.sh
:This script makes the intention very clear. It uses make to do what it is good for: building/compiling. It uses a shell script to do what it is good for: batch processing.
Plus you can do whatever else you might need with the full flexibility and expressiveness of a shell script without all the caveats of a makefile.
Also the calling syntax is now practically identical:
compared to:
contrast to
Background explanation of how make handles arguments:
Make is not designed to pass arguments to a target. All arguments on the command line are interpreted either as a goal (a.k.a. target), as an option, or as a variable assignment.
so if you run this:
make will interpret
run
andfoo
as goals (targets) to update according to their recipes.--wat
as an option for make. Andvar=arg
as a variable assignment for make.i hope you can see the only method you have to pass information from the command line to use inside a recipe (without hacks) is via variable assignment.
for more details see the gnu manual on how to run make
For completeness here are some of the hacks to "pass arguments to make run".
Method 1:
super short explanation: filter out current goal from list of goals. then pass list of goals as arguments to
prog
. also create a catch all target (%
) which does nothing to silently ignore all the other "goals".this will allow you to write something like this
problems of method 1:
Arguments that start with a dash will be interpreted by make and not passed as a goal.
workaround
Arguments with an equal sign will be interpreted by make and not passed
no workaround
Arguments with spaces is awkward
no workaround
If an argument happens to be
run
(equal to the target) it will also be removedwill 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.
will run
./prog foo bar clean
but also the recipe for the targetclean
(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.
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.
Method 2:
super short explanation: if the target is
run
then process the goal list and save in variable. also create do nothing targets for the remaining "goals" usingeval
. later when runningprog
pass the prepared variable as arguments.problems of method 2:
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!
I have only tested using gnu make. other makes may have different behaviour.
gnu make manual
https://www.gnu.org/software/make/manual/html_node/index.html
对于标准 make,您可以通过像这样定义宏来传递参数,
然后像这样使用它们
make
Microsoft 的 NMake
for standard make you can pass arguments by defining macros like this
then use them like this
References for make
Microsoft's NMake
您可以将变量传递给 Makefile,如下所示:
用法:
或:
或者使用 Beta 提供的解决方案:
用法:
You can pass the variable to the Makefile like below:
Usage:
or:
Alternatively use the solution provided by Beta:
Usage:
这是另一个可以帮助解决其中一些用例的解决方案:
换句话说,选择一些前缀(在本例中为
test-
),然后将目标名称直接传递给程序/运行程序。我想如果涉及一些运行程序脚本可以将目标名称解包为对底层程序有用的内容,那么这非常有用。Here's another solution that could help with some of these use cases:
In other words, pick some prefix (
test-
in this case), and then pass the target name directly to the program/runner. I guess this is mostly useful if there is some runner script involved that can unwrap the target name into something useful for the underlying program.否。从 GNU make 的手册页查看语法
您可以指定多个目标,因此“否”(至少没有按照您指定的确切方式)。
No. Looking at the syntax from the man page for GNU make
you can specify multiple targets, hence 'no' (at least no in the exact way you specified).
您可以在命令行中显式提取每个第 n 个参数。为此,您可以使用变量
MAKECMDGOALS
,它保存提供给“make”的命令行参数列表,并将其解释为目标列表。如果要提取第 n 个参数,可以将该变量与“word”函数结合使用,例如,如果想要第二个参数,可以将其存储在变量中,如下所示:You can explicitly extract each n-th argument in the command line. To do this, you can use variable
MAKECMDGOALS
, it holds the list of command line arguments given to 'make', which it interprets as a list of targets. If you want to extract n-th argument, you can use that variable combined with the "word" function, for instance, if you want the second argument, you can store it in a variable as follows:run: ./prog
看起来有点奇怪,因为正确的部分应该是先决条件,所以run: prog
看起来更好。我简单地建议:
我想补充一点,可以传递参数:
make arg1="asdf" run
arg1="asdf" make运行
run: ./prog
looks a bit strange, as right part should be a prerequisite, sorun: prog
looks better.I would suggest simply:
and I would like to add, that arguments can be passed:
make arg1="asdf" run
arg1="asdf" make run
对此并不太自豪,但我不想传递环境变量,因此我颠倒了运行预设命令的方式:
这将打印您想要运行的命令,因此只需在子 shell 中对其进行评估即可:
Not too proud of this, but I didn't want to pass in environment variables so I inverted the way to run a canned command:
this will print the command you want to run, so just evaluate it in a subshell:
这是我的例子。注意,我是在Windows 7下编写的,使用Dev-Cpp自带的mingw32-make.exe。 (我有 c:\Windows\System32\make.bat,所以该命令仍然称为“make”。)
定期清理的用法:
在 mydir/ 中清理和创建备份的用法:
Here is my example. Note that I am writing under Windows 7, using mingw32-make.exe that comes with Dev-Cpp. (I have c:\Windows\System32\make.bat, so the command is still called "make".)
Usage for regular cleaning:
Usage for cleaning and creating a backup in mydir/:
在idelic答案上进行一些构建。
您可以创建一个通用“函数”来获取参数
使用以下内容:
然后您可以像这样在目标中使用它:
这样您就可以在要从中检索值的任何目标上使用
res := $(call fetch_parameter)
。注意:我在这段代码上添加了一个额外的
:
$(eval $($(varname))::;@:)
因为如果您有多个目标调用fetch_parameter
,它也会被触发。因此,如果您有:
并且您调用
make my-target2 hello
(Make 的工作方式),则两个$(call fetch_parameter)
将被触发,导致创建 2 个伪造的hello
目标,但使用额外的:
(hello::) Make 不会抱怨您正在覆盖目标。Building a bit on idelic answer.
You can create a generic "function" to fetch parameters
using the following:
You can then user it in your target like so:
This way you can just use
res := $(call fetch_parameter)
on any target you want to retrieve values from.Note: I've added an extra
:
on this bit of code$(eval $($(varname))::;@:)
because if you have more than one target with a call tofetch_parameter
it will also be triggered.So if you have:
and you call
make my-target2 hello
, the way Make works, both$(call fetch_parameter)
will be triggered causing the creation of 2 bogushello
targets, but with the extra:
(hello::) Make won't complain that you are overriding a target.我找到了一种方法来获取带有等号
=
的参数!答案尤其是对 @lesmana 的答案 的补充(因为它是这里最完整和解释的答案),但它会太大了,无法将其写为评论。我再次重复他的信息:TL;DR 不要尝试这样做!我需要一种方法来处理我的参数
--xyz-enabled=false
(因为默认值为 true),我们现在都知道这不是 make 目标,因此不是的一部分>$(MAKECMDGOALS)
。在通过回显
$(.VARIABLES)
来查看 make 的所有变量 时,我得到了这些有趣的输出:这使我们可以采取两种方式:要么从
--
开始(如果这适用于您的情况),要么查看 GNU 制定特定(可能不适合我们使用) 变量-*-command-variables-*-
。 ** 有关其他选项,请参阅页脚 ** 在我的情况下,此变量保持:通过此变量,我们可以将其与
$(MAKECMDGOALS)
的现有解决方案结合起来,从而通过定义:并将其与 (显式混合参数的顺序):
返回:
如您所见,我们失去了参数的总顺序。带有“赋值”参数的部分似乎已颠倒,“目标”参数的顺序保持不变。我将“赋值”-args 放在开头,希望您的程序不关心参数放置在哪里。
以下 make 变量看起来也很有希望:
I found a way to get the arguments with an equal sign
=
! The answer is especially an addition to @lesmana 's answer (as it is the most complete and explained one here), but it would be too big to write it as a comment. Again, I repeat his message: TL;DR don't try to do this!I needed a way to treat my argument
--xyz-enabled=false
(since the default is true), which we all know by now that this is not a make target and thus not part of$(MAKECMDGOALS)
.While looking into all variables of make by echoing the
$(.VARIABLES)
i got these interesting outputs:This allows us to go two ways: either getting all starting with a
--
(if that applies to your case), or look into the GNU make specific (probably not intended for us to use) variable-*-command-variables-*-
. ** See footer for additional options ** In my case this variable held:With this variable we can combine it with the already existing solution with
$(MAKECMDGOALS)
and thus by defining:and using it with (explicitly mixing up order of arguments):
returned:
As you can see, we loose the total order of the args. The part with the "assignment"-args seem to have been reversed, the order of the "target"-args are kept. I placed the "assignment"-args in the beginning, hopefully your program doesn't care where the argument is placed.
following make variables looks promising as well:
已经有一段时间了,但我将提供我在生产中使用的版本。
我希望有人会发现它有用。
示例:
命令:
makegreeting s="hello world"
输出:
hello world
It's been for a while, but I'll provide mine version which I use in production.
I'll hope that someone will find it useful.
Example:
Command:
make greeting s="hello world"
Output:
hello world
我常用的Makefile
My usual Makefile
我喜欢这个:
结果:
I like this one:
Result:
我使用的另一个技巧是 -n 标志,它告诉 make 进行试运行。例如,
Another trick I use is the
-n
flag, which tellsmake
to do a dry run. For example,