linux的makefile中":="与"?="有啥区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux的makefile中":="与"?="有啥区别相关的知识,希望对你有一定的参考价值。

:= 就是简单的赋值, 比如

foo := $(bar)
将bar的值赋给foo

?= 是条件赋值, 比如

foo ?= $(bar)

只有当foo变量还没有被定义的时候,才会将bar的值赋给foo。 注意,如果foo已经被定义过,但是是空值了话,?=不会给他赋值。比方说你的makefile是

foo = hello
foo ?= new

则最终foo的值是hello

如果你的makefile是

foo =
foo ?= new

foo的值是空
参考技术A GNU make支持另外一种风格的变量,称为“直接展开”式。这种风格的变量使用“:=”定义。在使用“:=”定义变量时,变量值中对其他量或者函数的引用在定义变量时被展开(对变量进行替换)。所以变量被定义后就是一个实际需要的文本串,其中不再包含任何变量的引用。因此

x := foo

y := $(x) bar

x := later

就等价于:

y := foo bar

x := later

和递归展开式变量不同:此风格变量在定义时就完成了对所引用变量和函数的展开,因此不能实现对其后定义变量的引用。如:

CFLAGS := $(include_dirs) -O

include_dirs := -Ifoo -Ibar

由于变量“include_dirs”的定义出现在“CFLAGS”定义之后。因此在“CFLAGS”的定义中,“include_dirs”的值为空。“CFLAGS”的值为“-O”而不是“-Ifoo -Ibar -O”。这一点也是直接展开式和递归展开式变量的不同点。注意这里的两个变量都是“直接展开”式的。大家不妨试试将其中某一个变量使用递归展开式定义后看一下又会出现什么样的结果。

下边我们来看一个复杂一点的例子。分析一下直接展开式变量定义(:=)的用法,这里也用到了make的shell函数和变量“MAKELEVEL”(此变量在make的递归调用时代表make的调用深度)。

其中包括了对函数、条件表达式和系统变量“MAKELEVEL”的使用:

ifeq (0,$MAKELEVEL)

cur-dir := $(shell pwd)

whoami := $(shell whoami)

host-type := $(shell arch)

MAKE := $MAKE host-type=$host-type whoami=$whoami

endif

第一行是一个条件判断,如果是顶层Makefile,就定义下列变量。否则不定义任何变量。第二、三、四、五行分别定义了一个变量,在进行变量定义时对引用到的其它变量和函数展开。最后结束定义。利用直接展开式的特点我们可以书写这样一个规则:

$subdirs:

$MAKE cur-dir=$cur-dir/$@ -C $@ all

它实现了在不同子目录下变量“cur_dir”使用不同的值(为当前工作目录)。

在复杂的Makefile中,推荐使用直接展开式变量。因为这种风格变量的使用方式和大多数编程语言中的变量使用方式基本上相同。它可以使一个比较复杂的Makefile在一定程度上具有可预测性。而且这种变量允许我们利用之前所定义的值来重新定义它(比如使用某一个函数来对它以前的值进行处理并重新赋值),此方式在Makefile中经常用到。尽量避免和减少递归式变量的使用。

“?=”操作符
GNU make中,还有一个被称为条件赋值的赋值操作符“?=”。被称为条件赋值是因为:只有此变量在之前没有赋值的情况下才会对这个变量进行赋值。例如:

FOO ?= bar

其等价于:

ifeq ($(origin FOO), undefined)

FOO = bar

endif

含义是:如果变量“FOO”在之前没有定义,就给它赋值“bar”。否则不改变它的值。

“make oldconfig”在 Linux 内核 makefile 中究竟做了啥?

【中文标题】“make oldconfig”在 Linux 内核 makefile 中究竟做了啥?【英文标题】:What does "make oldconfig" do exactly in the Linux kernel makefile?“make oldconfig”在 Linux 内核 makefile 中究竟做了什么? 【发布时间】:2011-05-09 21:01:30 【问题描述】:

谁能解释一下目标“oldconfig”在Linux内核makefile中的作用?我看到它在一些构建文档中被引用,但从未解释过它的确切作用。

【问题讨论】:

【参考方案1】:

它读取用于旧内核的现有.config 文件,并提示用户在当前内核源代码中未在文件中找到的选项。这在采用现有配置并将其移动到新内核时很有用。

【讨论】:

【参考方案2】:

总结

如by Ignacio 所述,它会在您更新内核源代码后为您更新您的.config,例如git pull

它试图保留您现有的选择。

为此编写一个脚本会很有帮助,因为:

可能已添加新选项,或已删除旧选项

内核的 Kconfig 配置格式具有以下选项:

通过select相互暗示 通过depends依赖另一个

这些选项关系使手动配置解析更加困难。

让我们手动修改 .config 以了解它如何解析配置

首先生成一个默认配置:

make defconfig

现在手动编辑生成的.config 文件以模拟内核更新并运行:

make oldconfig

看看会发生什么。一些结论:

    类型的行:

    # CONFIG_XXX is not set
    

    不是单纯的cmets,而是实际表示没有设置参数。

    例如,如果我们删除该行:

    # CONFIG_DEBUG_INFO is not set
    

    然后运行make oldconfig,它会问我们:

    Compile the kernel with debug info (DEBUG_INFO) [N/y/?] (NEW)
    

    结束后,.config 文件将被更新。

    如果您更改行的任何字符,例如到# CONFIG_DEBUG_INFO,不算数。

    类型的行:

    # CONFIG_XXX is not set
    

    总是用于否定属性,虽然:

    CONFIG_XXX=n
    

    也可以理解为否定。

    例如,如果您删除 # CONFIG_DEBUG_INFO is not set 并回答:

    Compile the kernel with debug info (DEBUG_INFO) [N/y/?] (NEW)
    

    使用N,则输出文件包含:

    # CONFIG_DEBUG_INFO is not set
    

    而不是:

    CONFIG_DEBUG_INFO=n
    

    另外,如果我们手动修改该行为:

    CONFIG_DEBUG_INFO=n
    

    并运行make oldconfig,然后该行被修改为:

    # CONFIG_DEBUG_INFO is not set
    

    没有oldconfig 询问我们。

    不满足依赖关系的配置不会出现在.config 上。所有其他人都这样做。

    例如设置:

    CONFIG_DEBUG_INFO=y
    

    然后运行make oldconfig。它现在会要求我们提供:DEBUG_INFO_REDUCEDDEBUG_INFO_SPLIT 等配置。

    这些属性之前没有出现在defconfig上。

    如果我们查看定义它们的lib/Kconfig.debug,我们会看到它们依赖于DEBUG_INFO

    config DEBUG_INFO_REDUCED
        bool "Reduce debugging information"
        depends on DEBUG_INFO
    

    所以当DEBUG_INFO 关闭时,他们根本没有出现。

    selected 开启的配置会自动设置,无需询问用户。

    例如,如果CONFIG_X86=y 并且我们删除该行:

    CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
    

    然后运行make oldconfig,与DEBUG_INFO不同,该行无需询问我们即可重新创建。

    这是因为arch/x86/Kconfig 包含:

    config X86
        def_bool y
        [...]
        select ARCH_MIGHT_HAVE_PC_PARPORT
    

    并选择强制该选项为真。另见:https://unix.stackexchange.com/questions/117521/select-vs-depends-in-kernel-kconfig

    要求不满足约束的配置。

    例如,defconfig 已设置:

    CONFIG_64BIT=y
    CONFIG_RCU_FANOUT=64
    

    如果我们编辑:

    CONFIG_64BIT=n
    

    然后运行make oldconfig,它会问我们:

    Tree-based hierarchical RCU fanout value (RCU_FANOUT) [32] (NEW)
    

    这是因为RCU_FANOUTinit/Kconfig 中定义为:

    config RCU_FANOUT
        int "Tree-based hierarchical RCU fanout value"
        range 2 64 if 64BIT
        range 2 32 if !64BIT
    

    因此,没有64BIT,最大值为32,但我们在.config 上设置了64,这会使其不一致。

奖金

make olddefconfig 将每个选项设置为默认值,无需交互询问。它会在make 上自动运行,以确保.config 是一致的,以防您像我们一样手动修改它。另见:https://serverfault.com/questions/116299/automatically-answer-defaults-when-doing-make-oldconfig-on-a-kernel-tree

make alldefconfig 类似于make olddefconfig,但它也接受配置片段进行合并。此目标由merge_config.sh 脚本使用:https://***.com/a/39440863/895245

如果你想自动修改.config,那就不太简单了:How do you non-interactively turn on features in a Linux kernel .config file?

【讨论】:

【参考方案3】:

在运行make oldconfig之前,您需要将内核配置文件从旧内核复制到新内核的根目录中。

您可以在/boot/config-3.11.0 找到正在运行的系统上的旧内核配置文件的副本。或者,内核源代码在linux-3.11.0/arch/x86/configs/i386_defconfig / x86_64_defconfig中有配置

如果你的内核源代码位于/usr/src/linux:

cd /usr/src/linux
cp /boot/config-3.9.6-gentoo .config
make oldconfig

【讨论】:

不要以root身份构建内核!见youtube.com/watch?v=fMeH7wqOwXA#t=15m44s【参考方案4】:

使用新的/更改的/删除的选项更新旧配置。

【讨论】:

【参考方案5】:

来自page:

Make oldconfig 获取 .config 并通过 Kconfig 文件并生成一个与 Kconfig 规则。如果缺少 CONFIG 值,则 make oldconfig 会要求他们。

如果 .config 已经与 Kconfig 中的规则一致, 那么 make oldconfig 本质上是一个空操作。

如果您要运行 make oldconfig,然后运行 ​​make oldconfig a 第二次,第二次不会导致任何额外的变化 制作。

【讨论】:

【参考方案6】:

这是一种折磨。它们不是包含一个通用的 conf 文件,而是让你点击 return 9000 次来生成一个。

【讨论】:

试试:yes "" | make oldconfig

以上是关于linux的makefile中":="与"?="有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

linux的makefile中":="与"?="有啥区别

“make oldconfig”在 Linux 内核 makefile 中究竟做了啥?

makefile中wildcard判断文件存在

求助 怎么把makefile文件中的编译方法换成arm-linux-的编译方法 把该换的地方都换了 还是老提示错误

如何调试makefile

如何调试makefile