794

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

4

8 回答 8

900

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

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

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

    FOO?=default_value_if_not_set_in_environment
    

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

    • MAKE从脚本的名称中获取
    • SHELL要么在 makefile 中设置,要么默认为/bin/sh(基本原理:命令在 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 调用的环境,并且从这些命令中进行调用会按照上面指定的方式选择这些环境变量。

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

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

于 2010-05-13T10:57:02.183 回答
310

最简单的方法是:

make foo=bar target

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

如果您正在使用子制作,请参阅这篇文章:将变量传递给子制作

于 2010-05-13T10:38:10.037 回答
128

假设你有一个这样的生成文件:

action:
    echo argument is $(argument)

然后你会调用它make action argument=something

于 2010-05-13T10:38:10.287 回答
27

手册

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

所以你可以做(​​来自bash):

FOOBAR=1 make

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

于 2010-05-13T10:38:17.610 回答
24

似乎命令 args 覆盖了环境变量。

生成文件:

send:
    echo $(MESSAGE1) $(MESSAGE2)

示例运行:

$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK
于 2019-12-08T04:41:33.900 回答
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

有了这个,你会:

  • 构建并运行带有/的文件make -r class02
  • 构建所有 w/makemake all;
  • 构建并运行所有 w/ make -r(假设它们都包含某种断言的东西,你只想测试它们)
于 2015-05-21T02:53:20.387 回答
5

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

例子 :

make unittest=*

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

于 2014-03-08T13:29:37.383 回答
4
export ROOT_DIR=<path/value>

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

于 2016-01-07T16:03:31.613 回答