从命令行传递其他变量以使


613

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

Answers:


752

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

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

    您可能还希望将-eoption(aka --environments-override)设置为on,并且您的环境变量将覆盖在makefile中进行的赋值(除非这些赋值本身使用override指令。但是,不建议这样做,并且使用?=赋值(条件变量)会更好,更灵活赋值运算符,它仅在尚未定义变量的情况下才有效):

    FOO?=default_value_if_not_set_in_environment
    

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

    • MAKE 是从脚本名称获得的
    • SHELL是在makefile中设置的,或者默认为/bin/sh(rationale:命令在makefile中指定,并且它们是特定于shell的)。
  • 从命令行 - make可以将变量分配作为其命令行的一部分,并与目标混合:

    make target FOO=bar
    

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

  • 从父Make导出 -如果从Makefile调用Make,通常不应显式编写如下变量分配:

    # Don't do this!
    target:
            $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
    

    相反,更好的解决方案可能是导出这些变量。导出变量会使它进入每次Shell调用的环境,并且从这些命令进行的Make调用将如上所述选择这些环境变量。

    # Do like this
    CFLAGS=-g
    export CFLAGS
    target:
            $(MAKE) -C target
    

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


10
从命令行通过空格进行传递make A='"as df"'
Ciro Santilli郝海东冠状病六四事件法轮功

4
如果您关心环境变量,似乎就在自找麻烦。一方面,如果在A位置而不在B位置工作,这是调试的噩梦,因为它们具有不同的环境。
James Moore 2013年

12
仅基于经验,导出CFLAGS之类的内容对于大型项目来说是一场噩梦。大型项目通常具有仅包含给定标志集的第3方库(没有人打扰修复)。如果导出CFLAGS,则项目的CFLAGS最终将覆盖第三方库,并触发编译错误。另一种方法是将其定义export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS)为as并将其传递make -C folder $(PROJECT_MAKE_FLAGS)。如果有办法告诉库的makefile忽略环境,那将是理想的选择(与-e相反)。
RD

24
警告:在上面的“从父母的品牌中导出”部分中,“不要这样做!” 具有严重的误导性。在命令行上传递变量会覆盖子makefile中的分配,但是导出的变量不会覆盖子makefile中的分配。这两种将变量传递到子Makefile的方法并不等效,因此不应混淆。
乔纳森·本·阿夫拉罕

4
有什么区别吗? make target FOO=bar make FOO=bar target
gfan

213

最简单的方法是:

make foo=bar target

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

如果您使用的是子品牌,请参阅本文:将变量传递给子品牌


2
通过子makes是指included主makefile中的makefile?
巴勃罗

2
@Michael:这意味着从makefile内部再次调用make。由于您似乎对此细节感兴趣,因此我已经更新了答案。
马克·拜尔斯

2
“请注意,这不会自动传播到子品牌。” 不对!“默认情况下,只有来自环境或命令行的变量才传递给递归调用。您可以使用export指令传递其他变量。” gnu.org/software/make/manual/html_node/…–
ThomasMcLeod

82

假设您有一个这样的makefile:

action:
    echo argument is $(argument)

然后,您将其称为 make action argument=something


5
这样目标和参数可以在位置上互换吗?
巴勃罗

4
@Michael:是的(请参阅Mark Byers的回答)
nc3b 2010年

25

手册

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

因此,您可以(从bash中)进行操作:

FOOBAR=1 make

FOOBAR在您的Makefile中产生一个变量。


2
在几乎所有情况下,另一种方法确实更好。为了完整起见,我将在此保留。
托马斯(Thomas)

这是在同一行上的make命令之前显示变量分配的唯一答案-值得知道这不是语法错误。
M_M

7

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

它涉及验证给定参数是否出现在中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

有了它,您将:

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

6

它似乎

命令args覆盖环境变量

生成文件

send:
    echo $(MESSAGE1) $(MESSAGE2)

运行示例

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK

5

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

例如:

make unittest=*

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


4
export ROOT_DIR=<path/value>

然后$(ROOT_DIR)在Makefile中使用变量。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.