Makefile 从命令行传递附加变量以使

Makefile 从命令行传递附加变量以使,makefile,gnu,command-line-arguments,Makefile,Gnu,Command Line Arguments,我可以将变量作为命令行参数传递给GNU Makefile吗?换句话说,我想传递一些参数,这些参数最终将成为Makefile中的变量。最简单的方法是: make foo=bar target 然后在makefile中,您可以参考$(foo)。请注意,这不会自动传播到子品牌 如果您使用的是sub Make,请参阅本文:假设您有这样一个Make文件: action: echo argument is $(argument) # Don't do this! target:

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

最简单的方法是:

make foo=bar target

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


如果您使用的是sub Make,请参阅本文:

假设您有这样一个Make文件:

action:
    echo argument is $(argument)
# Don't do this!
target:
        $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)
然后,您可以从以下位置将其称为
make action argument=something

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

因此,您可以(从bash)执行以下操作:


在您的Makefile中生成一个变量
FOOBAR

您可以从Makefile外部设置变量:

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

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

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

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

    make target FOO=bar
    
    但是,除非使用in赋值,否则makefile中对
    FOO
    变量的所有赋值都将被忽略。(效果与环境变量的
    -e
    选项相同)

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

    action:
        echo argument is $(argument)
    
    # 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
    导出所有变量


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

例如:

make unittest=*
我使用BOOST_-TEST,并为参数--run_-TEST=$(unittest)提供一个通配符 然后,我将能够使用正则表达式过滤掉我想要的Makefile测试
要运行

还有一个选项未在此处引用,它包含在Stallman和McGrath的GNU Make书中(请参阅)。它提供了以下示例:

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif
它涉及到验证给定参数是否出现在
MAKEFLAGS
中。例如..假设您正在学习c++11中的线程,并且您已经将您的学习划分到多个文件(
class01
,…,
classNM
)您希望:先编译所有文件,然后单独运行,或者一次编译一个文件,如果指定了标志(例如,
-r
),则运行它

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
  • 构建所有w/
    生成
    生成所有
  • 构建并运行所有的w/
    make-r
    (假设它们都包含某种断言内容,您只想测试它们)
导出根目录=
然后在Makefile中使用变量
$(ROOT\u DIR)

看起来

命令args覆盖环境变量

生成文件

send:
    echo $(MESSAGE1) $(MESSAGE2)
运行示例

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

因此,目标和参数可以在位置上互换?@Michael:是的(请参阅Mark Byers的答案),sub使你指的是主makefile中包含的makefiles
吗?@Michael:这意味着从makefile内部再次调用make。我更新了我的答案,因为你似乎对这个细节感兴趣。请注意,这不会自动传播到sub makes。“不真实!”默认情况下,只有来自环境或命令行的变量才会传递给递归调用。您可以使用export指令传递其他变量。“在几乎所有情况下,另一种方法确实更好。为了完整起见,我将把它留在这里。这是唯一一个在同一行上显示make命令之前的变量赋值的答案-值得知道的是,这不是语法错误。要从命令行传递带有空格的somthing do
make a='”作为df”“
如果你关心环境变量,你似乎是在自找麻烦。首先,如果它在a位置工作而不是在B位置工作,那就是一场调试噩梦,仅仅因为它们有不同的环境。仅仅根据经验,导出CFLAGS之类的东西对于大型项目来说是一场噩梦。大型项目通常都有第三方仅使用给定标志集编译的参与方库(没有人费心修复)。如果导出CFLAGS,项目的CFLAGS将覆盖第三方库并触发编译错误。另一种方法可能是定义
export project\u MAKE\u ARGS=CC=$(CC)CFLAGS=$(CFLAGS)
并将其作为
make-C folder$(PROJECT\u make\u FLAGS)
传递
$ MESSAGE1=YES MESSAGE2=NG  make send MESSAGE2=OK
echo YES OK
YES OK