【问题标题】:How to pass argument to Makefile from command line?如何从命令行将参数传递给 Makefile?
【发布时间】: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

【问题讨论】:

标签: command-line parameters makefile arguments


【解决方案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】:

      几年后,想为此推荐justhttps://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
        

        【讨论】:

          猜你喜欢
          • 2013-03-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多