为啥使用 Make 3.8.1 构建与 Make 4.1 不同?

Posted

技术标签:

【中文标题】为啥使用 Make 3.8.1 构建与 Make 4.1 不同?【英文标题】:Why is building with Make 3.8.1 different to Make 4.1?为什么使用 Make 3.8.1 构建与 Make 4.1 不同? 【发布时间】:2016-01-25 11:09:05 【问题描述】:

我正在使用 gcc 和 C++ 构建嵌入式 ARM 项目:

11:01:29 ○⨠ arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 224288]
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is  NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

然后制作:

17:11:17 ○⨠ make --version
GNU Make 3.81
Copyright (C) 2006  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

This program built for i386-apple-darwin11.3.0

我正在构建最近的一段代码,但它根本不适合我 - 代码构建和部署良好,但功能不存在。 Tt 没有任何意义,因为代码看起来完全没问题。

一位同事和我一起审查了它,我们发现代码没有问题,所以为了一笑,我们决定让他来构建和部署它。

效果很好!

所以检查我们的版本,他正在运行make 4.1。我升级到这个,嘿presto,它工作得很好。

11:06:15 ○⨠ make --version
GNU Make 4.1
Built for x86_64-apple-darwin14.3.0
Copyright (C) 1988-2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

我们用3.81 玩了更多,并推断优化可能是问题所在。

但两个实例都将-Os 传递给gcc

那么,我的问题是——为什么Make 会对这里的编译器产生影响?!

【问题讨论】:

make 本身对-Os、GCC 和优化标志知之甚少。 Makefile 是使用特定参数调用外部程序的规则,make 执行这些规则。关于-Os 的知识包含在这些规则之一中。 您应该将在 Make 3.8.1 中运行 Makefile 时执行的命令与在 Make 4.1 中运行时执行的命令进行比较。 Make 所做的只是运行 Makefile 指定的命令。另外,您是如何推断出优化可能是问题所在? 你的意思是3.81,而不是3.8.1 @MSalters 我知道 - 这就是为什么它让我如此困惑! Make 应该只是传递相同的参数吗? @Archimaredes 我们通过从决策路径中取出一个变量来推断它,它工作得很好,就好像它正在优化这个变量一样。也就是说,也许这是一个很大的飞跃?我将更仔细地检查执行的命令,因为我无法立即注意到有太大的不同。 【参考方案1】:

当 'Makefiles remade' 发生时,Gnu make 的行为在 3.8.2 和 4.1 版本之间略有不同。 例如,执行以下命令:

----- commands ----
rm ./sub.mk ./add_rule ; make -f test.mk HOSTCC=GCC

----- test.mk -----
$(info ===== test.mk(lv $(MAKELEVEL)) ==== )
$(info origin=$(origin HOSTCC))
HOSTCC = cc
$(info HOSTCC=$(HOSTCC))
$(info ------------------ )

.PHONY: all sub sub2

all:
    @echo "... build $@ ..."
    touch ./add_rule 
    @echo "*** using HOSTCC=$(HOSTCC) at all: ***"
    $(MAKE) -f ./test.mk sub
    @echo "*** using HOSTCC=$(HOSTCC) at all: ***"

sub:
    @echo "... build $@ ..."
    @echo "*** using HOSTCC=$(HOSTCC) at sub: ***"

-include sub.mk
ifneq ($(wildcard ./add_rule),)
sub.mk:
    @echo "... build $@ ..."
    echo "\$$$ (info --- $@(included) ---)" > $@
endif
----- end of test.mk -----

使用 Ver 3.8.2 Gnu Make,控制台输出的最后几行是:

....
===== test.mk(lv 1) ==== 
origin=environment
HOSTCC=cc
------------------ 
--- sub.mk(included) ---
make[1]: Entering directory `/home/user/make-test'
... build sub ...
*** using HOSTCC=cc at sub: ***
make[1]: Leaving directory `/home/user/make-test'
*** using HOSTCC=GCC at all: ***

使用 4.1 版,“cc”不显示,但只有 GCC。

重点是:

在 3.8.2 版 Gnu make 中,变量 'HOSTCC' 在 sub:recipe 中没有被覆盖, 即使它是在命令行中指定的。

( 我在构建 u-boot 时注意到了这个现象。 有关“Makefile remade”的更多信息, 请参阅制作手册“3.5 如何重新制作 Makefile”。)

这种差异似乎来自 3.8.2 版 gnu make 的 main.c(第 2091 行)。

在 4.1 版代码中,putenv() 不存在。

/* Reset makeflags in case they were changed.  */

  const char *pv = define_makeflags (1, 1);
  char *p = alloca (sizeof ("MAKEFLAGS=") + strlen (pv) + 1);
  sprintf (p, "MAKEFLAGS=%s", pv);
  putenv (p); //<<=== the different point.

【讨论】:

对不起,3.81版和3.82版的控制台输出不同,但是3.81版和4.1版是一样的。

以上是关于为啥使用 Make 3.8.1 构建与 Make 4.1 不同?的主要内容,如果未能解决你的问题,请参考以下文章

Linux项目自动化构建工具make与makefile

如何将 CMock 单元测试框架与 Make 集成

CMake 错误:CMake 无法找到与“Unix Makefiles”对应的构建程序。 CMAKE_MAKE_PROGRAM 未设置

Linux项目自动化构建工具——make/Makefile

Linux | 项目自动化构建工具 - make/Makefile

cmake与make的项目构建快速上手