ChatGPT解决这个技术问题 Extra ChatGPT

从命令行传递额外的变量来制作

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


r
rogerdpack

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

从环境 - 每个环境变量都转换为具有相同名称和值的 makefile 变量。您可能还想设置 -e 选项(又名 --environments-override),并且您的环境变量将覆盖 makefile 中的分配(除非这些分配本身使用 override 指令。但是,不建议这样做,而且更好灵活使用 ?= 赋值(条件变量赋值运算符,仅在变量尚未定义时才有效):FOO?=default_value_if_not_set_in_environment 注意某些变量不是从环境继承的:MAKE 是从脚本名称获得的 SHELL要么在 makefile 中设置,要么默认为 /bin/sh(基本原理:命令在 makefile 中指定,并且它们是特定于 shell 的)。

MAKE 是从脚本名称中获取的

SHELL 要么在 makefile 中设置,要么默认为 /bin/sh(基本原理:命令在 makefile 中指定,并且它们是特定于 shell 的)。

从命令行 - make 可以将变量赋值作为其命令行的一部分,与目标混合: make target FOO=bar 但是,除非您在赋值中使用覆盖指令,否则 make 文件中对 FOO 变量的所有赋值都将被忽略。 (效果与环境变量的 -e 选项相同)。

从父 Make 导出 - 如果你从 Makefile 调用 Make,你通常不应该像这样显式地写变量赋值: # 不要这样做! target: $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS) 相反,更好的解决方案可能是导出这些变量。导出一个变量会使其进入每个 shell 调用的环境,并且从这些命令中进行调用会按照上面指定的方式选择这些环境变量。 # Do like this CFLAGS=-g export CFLAGS target: $(MAKE) -C target 你也可以使用不带参数的导出来导出所有变量。


从命令行传递带有空格的东西做make A='"as df"'
如果您关心环境变量,似乎您是在自找麻烦。一方面,如果它在 A 地工作而不在 B 地工作,那将是一场调试噩梦,只是因为它们有不同的环境。
根据经验,导出 CFLAGS 之类的东西是大型项目的噩梦。大型项目通常具有仅使用一组给定标志进行编译的 3rd 方库(没有人费心修复)。如果您导出 CFLAGS,您项目的 CFLAGS 最终会覆盖第 3 方库并触发编译错误。另一种方法可能是定义 export PROJECT_MAKE_ARGS = CC=$(CC) CFLAGS=$(CFLAGS) 并将其作为 make -C folder $(PROJECT_MAKE_FLAGS) 传递。如果有办法告诉库的 makefile 忽略环境,那将是理想的(与 -e 相反)。
警告:在上面的“从父 Make 导出”部分中,“不要这样做!”具有严重的误导性。在命令行上传递变量会覆盖子生成文件中的分配,但导出的变量不会覆盖子生成文件中的分配。这两种将变量传递给子 makefile 的方法是不等价的,不应混淆。
有什么区别吗? make target FOO=bar make FOO=bar target ?
M
Mark Byers

最简单的方法是:

make foo=bar target

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

如果您使用的是子制作,请参阅这篇文章:Communicating Variables to a Sub-make


子制作是指主makefile中的makefile included
@Michael:这意味着从makefile中再次调用make。我已经更新了我的答案,因为您似乎对此细节感兴趣。
“请注意,这不会自动传播到子品牌。”不真实! “默认情况下,只有来自环境或命令行的变量才会传递给递归调用。您可以使用 export 指令传递其他变量。” gnu.org/software/make/manual/html_node/…
如果您查看您引用的页面,您会看到它明确表示 make 会自动传递在命令行上定义的变量值,方法是将它们放入 MAKEFLAGS 变量中。请参阅选项/递归。因此,与这个答案相反,make 将自动传播到 sub-makes。
make target foo=bar 也可以!!
n
nc3b

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

action:
    echo argument is $(argument)

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


所以目标和论点可以在位置方面互换吗?
@Michael:是的(见马克拜尔斯的回答)
我喜欢这个答案。它简洁且内容丰富。正是我想要的。谢谢
2
2240

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

生成文件:

send:
    echo $(MESSAGE1) $(MESSAGE2)

示例运行:

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

T
Thomas

manual

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

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

FOOBAR=1 make

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


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

这里没有引用另一个选项,它包含在 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 构建并运行文件;

用 make 或 make all 建造所有东西;

使用 make -r 构建并运行所有内容(假设它们都包含某种断言内容,而您只想测试它们)


s
serup

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

例子 :

make unittest=*

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


p
parasrish
export ROOT_DIR=<path/value>

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