如何从命令行将参数传递给 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? [复制]

如何将参数/参数传递给通过Grunt调用的mocha测试

如何从 Git Bash 中将命令行参数传递给 Windows 应用程序?

自动将参数传递给子目录

如何在 Linux 中使用终端命令将文件参数传递给我的 bash 脚本? [复制]