如何从命令行将参数传递给 Makefile?
Posted
技术标签:
【中文标题】如何从命令行将参数传递给 Makefile?【英文标题】:How to pass argument to Makefile from command line? 【发布时间】:2011-09-10 13:03:29 【问题描述】:如何从命令行向 Makefile 传递参数?
我知道我能做到
$ make action VAR="value"
$ value
Makefile
VAR = "default"
action:
@echo $(VAR)
如何获得以下行为?
$ make action value
value
怎么样
$make action value1 value2
value1 value2
【问题讨论】:
类似:Passing arguments to “make run” Passing arguments to "make run"的可能重复 【参考方案1】:您可能不应该这样做;你打破了 Make 工作的基本模式。但这里是:
action:
@echo action $(filter-out $@,$(MAKECMDGOALS))
%: # thanks to chakrit
@: # thanks to William Pursell
编辑: 为了解释第一个命令,
$(MAKECMDGOALS)
是在命令行上拼写的“目标”列表,例如“行动价值1价值2”。
$@
是规则目标名称的automatic variable,在本例中为“action”。
filter-out
是一个从列表中删除一些元素的函数。所以$(filter-out bar, foo bar baz)
返回foo baz
(它可以更微妙,但我们在这里不需要微妙)。
将这些放在一起,$(filter-out $@,$(MAKECMDGOALS))
返回在命令行上指定的目标列表,而不是“action”,可能是“value1 value2”。
【讨论】:
$(shell echo $(MAKECMDGOALS) | sed 's!^.* $@ !!')
忽略之前的所有目标,只考虑以下作为参数:make target1 target2 action value1 value2
原谅我的无知。我试过用谷歌搜索 %:
和 @:
并找不到关于这些“指令”(或任何它们被称为)做什么的信息。你能解释一下吗?
@Jon:手册是here。由%:
和@:
组成的部分是rule。目标名称%
表示为a rule that matches anything;也就是说,如果 Make 找不到任何其他方法来构建您告诉它构建的东西,它将执行该规则。 @:
是 recipe; :
表示什么都不做,@
表示默默地做。
谢谢。我一直在阅读该手册,但起初我并没有考虑到,%:
实际上是% :
,一个通配符类型的目标名称。我在该手册页中没有看到任何关于 @:
的内容......它确实表明“无所事事”规则只会在目标规范之后有一个 ;
,所以,它会不会更准确将% : ;
写为“通配符不作为”规则?
filter-out
在操作是命令行上指定的目标的依赖项时不起作用,因为 $@
将设置为依赖项的名称,而不是命令上调用的原始参数线。相反,我将 MAKECMDGOALS
分配给一个 shell 数组,然后删除第一个元素:@ args=($(MAKECMDGOALS)); args=("$$args[@]:1")
【参考方案2】:
更容易的方法。考虑一个任务:
provision:
ansible-playbook -vvvv \
-i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory \
--private-key=.vagrant/machines/default/virtualbox/private_key \
--start-at-task="$(AT)" \
-u vagrant playbook.yml
现在,当我想调用它时,我只需要运行以下命令:
AT="build assets" make provision
或者只是:
make provision
在这种情况下AT
是一个空字符串
【讨论】:
【参考方案3】:这是一个基于@Beta 的通用工作解决方案
我正在使用 GNU Make 4.1 和我的 Makefile 顶部的 SHELL=/bin/bash
,所以 YMMV!
这允许我们接受额外的参数(当我们得到一个不匹配的工作时什么都不做,而不是抛出一个错误)。
%:
@:
这是一个为我们获取参数的宏:
args = `arg="$(filter-out $@,$(MAKECMDGOALS))" && echo $$arg:-$1`
这是一份工作,可以称之为:
test:
@echo $(call args,defaultstring)
结果是:
$ make test
defaultstring
$ make test hi
hi
注意!使用“Taskfile”可能会更好,它是一种 bash 模式,其工作方式与 make 类似,只是没有 Maketools 的细微差别。见https://github.com/adriancooney/Taskfile
【讨论】:
成功了!!对于尝试它的其他人,请确保在@echo
之前有 tab
,而不是 space
。
如果操作(例如,测试:)是命令行上指定的目标的依赖项,这也有效。
如果这个目标存在于 Makefile 中,这将执行目标hi
。知道如何避免这种情况吗?
@oz123 您可能想研究使用环境变量,而不是位置参数。您还可以考虑为此使用脚本语言。如前所述,bash 对此有一些有用的模式。【参考方案4】:
不要尝试这样做
$ make action value1 value2
改为创建脚本:
#! /bin/sh
# rebuild if necessary
make
# do action with arguments
action "$@"
然后这样做:
$ ./buildthenaction.sh value1 value2
更多解释为什么这样做和makefilehackery的警告阅读我对另一个非常相似但看似不重复的问题的回答:Passing arguments to "make run"
【讨论】:
【参考方案5】:几年后,想为此推荐just
:https://github.com/casey/just
action v1 v2=default:
@echo 'take action on v1 and v2...'
【讨论】:
【参考方案6】:你会更好地定义变量并调用你的 make 而不是使用参数:
生成文件
action: ## My action helper
@echo $$VAR_NAME
终端
> VAR_NAME="Hello World" make action
Hello World
【讨论】:
以上是关于如何从命令行将参数传递给 Makefile?的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法通过命令行将 JVM 参数传递给 Maven? [复制]