首页 文章

将参数传递给“make run”

提问于
浏览
252

我使用Makefiles .

我有一个名为 run 的目标,它运行构建目标 . 简化后,它看起来如下:

prog: ....
  ...

run: prog
  ./prog

坐下来 . 我知道这是巧妙的,但不需要起立鼓掌 .

现在,我的问题是 - 有没有办法传递参数?以便

make run asdf --> ./prog asdf
make run the dog kicked the cat --> ./prog the dog kicked the cat

谢谢!

11 回答

  • 147

    对于标准make,您可以通过定义这样的宏来传递参数

    make run arg1=asdf
    

    然后像这样使用它们

    run: ./prog $(arg1)
       etc
    

    参考资料make微软的NMake

  • 24

    我不知道如何完全按照您的意愿行事,但解决方法可能是:

    run: ./prog
        ./prog ${ARGS}
    

    然后:

    make ARGS="asdf" run
    
  • 2

    这个问题差不多有三年了,但无论如何......

    如果你正在使用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
    
  • 8

    您可以将变量传递给Makefile,如下所示:

    run:
        @echo ./prog $$FOO
    

    用法:

    $ make run FOO="the dog kicked the cat"
    ./prog the dog kicked the cat
    

    要么:

    $ FOO="the dog kicked the cat" make run
    ./prog the dog kicked the cat
    

    或者使用Beta提供的解决方案:

    run:
        @echo ./prog $(filter-out $@,$(MAKECMDGOALS))
    %:
        @:
    

    %: - 匹配任何任务名称的规则; @: - 空食谱=什么也不做

    用法:

    $ make run the dog kicked the cat
    ./prog the dog kicked the cat
    
  • 37

    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

    $ 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会将 runfoobar 解释为目标(目标),以根据他们的食谱进行更新 . --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

    在我看来,这有一个很大的缺点:你想要做的是用参数 arg 运行 prog . 但不是写作:

    $ ./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
    

    请注意,当您将 $(var) 放在makefile中的引号中时:

    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 试图创建不做任何目标 .

    解决方法:创建全局捕获所有目标,如上所述 . 如上所述,它将再次默默地忽略错误的合法目标 .

    解决方法:不要这样做!! 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
    
  • 182

    不 . 查看GNU make手册页的语法

    make [-f makefile] [options] ... [targets] ......

    你可以指定多个目标,因此'不'(至少没有你指定的确切方式) .

  • 9

    这是另一个可以帮助解决其中一些用例的解决方案:

    test-%:
        $(PYTHON) run-tests.py $@
    

    换句话说,选择一些前缀(在这种情况下为 test- ),然后将目标名称直接传递给程序/运行器 . 我想如果涉及一些可以将目标名称解包为对底层程序有用的东西的转子脚本,这大部分都是有用的 .

  • 2

    您可以在命令行中显式提取每个第n个参数 . 为此,您可以使用变量MAKECMDGOALS,它保存给予'make'的命令行参数列表,它将其解释为目标列表 . 如果要提取第n个参数,可以将该变量与“word”函数结合使用,例如,如果需要第二个参数,可以将其存储在变量中,如下所示:

    second_argument := $(word 2, $(MAKECMDGOALS) )
    
  • 10

    对此并不感到骄傲,但我不想传递环境变量,所以我颠倒了运行canned命令的方式:

    run:
        @echo command-you-want
    

    这将打印您要运行的命令,因此只需在子shell中进行评估:

    $(make run) args to my command
    
  • 4

    anonrun: ./prog 看起来有点奇怪,因为正确的部分应该是目标,所以 run: prog 看起来更好 .

    我建议简单地说:

    .PHONY: run
    
    run:
            prog $(arg1)
    

    我想补充说,可以传递参数:

    • 作为参数: make arg1="asdf" run

    • 或被定义为环境: arg1="asdf" make run

  • 3

    这是我的例子 . 请注意,我使用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
    

相关问题