从命令行传递其他变量来制作

Pab*_*blo 560 gnu makefile command-line-arguments

我可以将变量作为命令行参数传递给GNU Makefile吗?换句话说,我想传递一些最终会成为Makefile变量的参数.

P S*_*ved 689

您有几个选项可以从makefile外部设置变量:

  • 从环境 - 每个环境变量都转换为具有相同名称和值的makefile变量.

    您可能还想设置-e选项(aka --environments-override),您的环境变量将覆盖makefile中的赋值(除非这些赋值本身使用该override指令.但是,不建议这样做,并且使用?=赋值(条件变量)更好更灵活赋值运算符,它只有在尚未定义变量时才有效:):

    FOO?=default_value_if_not_set_in_environment
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,某些变量不是从环境继承的:

    • MAKE 是从脚本的名字得到的
    • SHELL要么在makefile中设置,要么默认为/bin/sh(基本原理:命令在makefile中指定,并且它们是特定于shell的).
  • 从命令行 - make可以将变量赋值作为其命令行的一部分,与目标混合:

    make target FOO=bar
    
    Run Code Online (Sandbox Code Playgroud)

    但是,除非在赋值中使用该指令,否则将忽略makefile中变量的所有FOO赋值.(效果与环境变量选项相同).override-e

  • 从父Make导出 - 如果从Makefile调用Make,通常不应该显式写这样的变量赋值:

    # Don't do this!
    target:
            $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
    
    Run Code Online (Sandbox Code Playgroud)

    相反,更好的解决方案可能是导出这些变量.导出变量使其进入每个shell调用的环境中,并且使用这些命令进行调用将按照上面的指定选择这些环境变量.

    # Do like this
    CFLAGS=-g
    export CFLAGS
    target:
            $(MAKE) -C target
    
    Run Code Online (Sandbox Code Playgroud)

    您也可以使用不带参数导出所有变量export.

  • 警告:在上面的"从父级导出"部分中,"不要这样做!" 是*严重误导*.在命令行上传递变量会覆盖子makefile中的赋值,但导出的变量不会覆盖子makefile中的赋值.将变量传递给子makefile的这两种方法都不是*等价的,不应混淆. (21认同)
  • 仅仅基于经验,出口像CFLAGS这样的东西是大型项目的噩梦.大型项目通常有第三方库,只能使用一组给定的标志进行编译(没有人烦恼修复).如果导出CFLAGS,则项目的CFLAGS最终会覆盖第三方库并触发编译错误.另一种方法可能是定义`export PROJECT_MAKE_ARGS = CC = $(CC)CFLAGS = $(CFLAGS)`并将其传递为`make -C folder $(PROJECT_MAKE_FLAGS)`.如果有办法告诉库的makefile忽略环境,这是理想的(与-e相反). (12认同)
  • 从命令行传递带空格的东西``make A ='"as df"'`` (10认同)
  • 如果你关心环境变量,似乎你会遇到麻烦.首先,它是一个调试噩梦,如果它在A处工作而不在B处,只是因为它们有不同的环境. (4认同)
  • 多个参数? (2认同)
  • 有什么区别吗?`make target FOO = bar``make FOO = bar target`? (2认同)

Mar*_*ers 191

最简单的方法是:

make foo=bar target
Run Code Online (Sandbox Code Playgroud)

然后在你的makefile中你可以参考$(foo).请注意,这不会自动传播到子品牌.

如果您正在使用子品牌,请参阅此文章:将变量传递给子品牌

  • 通过sub使你的意思是主makefile中的makefiles`included`? (2认同)
  • @Michael:这意味着从makefile中再次调用make.我已经更新了我的答案,因为你似乎对这个细节很感兴趣. (2认同)
  • “请注意,这不会自动传播到子品牌。” 不对!“默认情况下,仅将来自环境或命令行的变量传递给递归调用。您可以使用export指令传递其他变量。” https://www.gnu.org/software/make/manual/html_node/Environment.html#Environment (2认同)
  • make target foo=bar 也有效! (2认同)

nc3*_*c3b 70

假设您有一个这样的makefile:

action:
    echo argument is $(argument)
Run Code Online (Sandbox Code Playgroud)

然后你会打电话给它 make action argument=something

  • @Michael:是的(见Mark Byers的回答) (4认同)
  • 所以目标和论点可以在位置上互换? (3认同)
  • 我喜欢这个答案。它简洁且内容丰富。正是我正在寻找的东西。谢谢 (3认同)

Tho*_*mas 21

手册:

make中的变量可以来自运行make的环境.在启动时查看的每个环境变量都将转换为具有相同名称和值的make变量.但是,makefile中的显式赋值或命令参数会覆盖环境.

所以你可以做(​​从bash):

FOOBAR=1 make
Run Code Online (Sandbox Code Playgroud)

导致FOOBARMakefile 中的变量.

  • 需要理解的细微差别是,通过前面的赋值,您将为 make 子进程设置一个环境变量。通过目标后面的赋值,您将传递一个参数给 make,它正在解析它,它将覆盖您环境中设置的内容。 (5认同)
  • 这是唯一显示同一行上 make 命令之前变量分配的答案 - 值得知道这不是语法错误。 (3认同)
  • 在几乎所有情况下,另一种方式确实更好。为了完整起见,我将把它留在这里。 (2认同)

小智 16

它似乎

命令参数覆盖环境变量

生成文件

send:
    echo $(MESSAGE1) $(MESSAGE2)
Run Code Online (Sandbox Code Playgroud)

运行示例

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK
Run Code Online (Sandbox Code Playgroud)


Cir*_*sta 6

Stallman和McGrath撰写的GNU Make书中还包含未在此处引用的另一个选项(请参见http://www.chemie.fu-berlin.de/chemnet/use/info/make/make_7.html)。它提供了示例:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif
Run Code Online (Sandbox Code Playgroud)

它涉及验证给定参数是否出现在中MAKEFLAGS。例如,..假设您正在研究c ++ 11中的线程,并且已将研究分为多个文件(class01,...,classNM),并且您希望:然后全部编译并单独运行或一次编译一个文件。时间并运行(如果指定了标志-r,例如)。因此,您可以提出以下建议Makefile

CXX=clang++-3.5
CXXFLAGS = -Wall -Werror -std=c++11
LDLIBS = -lpthread

SOURCES = class01 class02 class03

%: %.cxx
    $(CXX) $(CXXFLAGS) -o $@.out $^ $(LDLIBS)
ifneq (,$(findstring r,  $(MAKEFLAGS)))
    ./$@.out
endif

all: $(SOURCES)

.PHONY: clean

clean:
    find . -name "*.out" -delete
Run Code Online (Sandbox Code Playgroud)

有了它,您将:

  • 建立并运行一个文件w / make -r class02;
  • 建立所有瓦特makemake all;
  • 构建并运行所有w / make -r(假设它们都包含某种肯定的东西,而您只想测试它们)


小智 5

如果您创建一个名为 Makefile 的文件并添加一个像 $(unittest) 这样的变量,那么即使使用通配符,您也可以在 Makefile 中使用此变量

例子 :

make unittest=*
Run Code Online (Sandbox Code Playgroud)

我使用 BOOST_TEST 并通过给参数 --run_test=$(unittest) 一个通配符然后我将能够使用正则表达式来过滤掉我希望我的 Makefile 运行的测试