Linux Kconfig及Makefile学习

Linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解
blog.csdn.net/u013554213/article/details/79012612

make menuconfig/.config/Kconfig解析  -- 这篇文章对kconfig分析的很透彻

blog.chinaunix.net/uid-24227137-id-3277449.html



                        linux内核的配置机制及其编译过程
                       ---------------------------------
一、Linux内核配置系统的基本结构
Linux内核的配置系统由三个部分组成,分别是:
    1) Makefile:分布在Linux内核源代码根目录及各层目录中,定义Linux内核的编译规则;
    2) 配置文件:(config.in(2.4内核),Kconfig(2.6及以后的内核)),给用户提供配置选择的功能;
    3) 配置工具:包括配置命令解释器(对配置脚本中使用的配置命令进行解释)和配置用户界面(提供基于字符界面、基于 Ncurses 图形界面以及基于 Xwindows 图形界面的用户配置界面,各自对应于 make config、make menuconfig 和 make xconfig)。

这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。本文并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。

二、makefile menuconfig过程讲解
当我们在执行make menuconfig这个命令时,系统到底帮我们做了哪些工作呢?这里面一共涉及到以下几个文件:
    1) Linux内核根目录下的scripts文件夹
    2) arch/$(ARCH)/Kconfig文件、各层目录下的Kconfig文件
    3) Linux内核根目录下的Makefile文件、各层目录下的Makefile文件
    4) Linux内核根目录下的.config文件、arm/$(ARCH)/下的config文件
    5) Linux内核根目录下的include/generated/autoconf.h文件

下面来一一讲解:
1) Linux内核根目录下的scripts文件夹
scripts文件夹存放的是跟make menuconfig配置界面的图形绘制相关的文件,我们作为使用者无需关心这个文件夹的内容

2) arch/$(ARCH)/Kconfig文件、各层目录下的Kconfig文件
当我们执行make menuconfig命令出现上述蓝色配置界面以前,系统帮我们做了以下工作:
首先系统会读取arch/$(ARCH)/目录下的Kconfig文件生成整个配置界面选项(Kconfig是整个linux配置机制的核心),那么ARCH环境变量的值等于多少呢?
它是由linux内核根目录下的Makefile文件决定的,在Makefile下有此环境变量的定义,例如:

ARCH ?= arm
CROSS_COMPILE ?= arm-eabi-

或者通过make ARCH=arm menuconfig命令来生成配置界面。

3) Linux内核根目录下的.config文件、arm/$(ARCH)/下的config文件
执行make menuconfig命令之后,内核默认读取linux内核根目录下.config文件作为内核配置项的默认值。如果内核根目录下没有.config文件,我们一般会根据开发板的类型从arch/$(ARCH)/configs目录中选取一个与我们开发板最接近的配置文件到Linux内核根目录下,例如:
cp arch/arm/configs/s3c2410_defconfig .config

如何更改内核配置选项呢?我们可以选择直接修改.config文件然后执行make menuconfig命令读取新的选项。但是一般我们不采取这个方案,我们选择在配置界面中通过空格、esc、回车选择某些选项选中或者不选中,最后保存退出的时候,Linux内核会把新的选项更新到.config中。

4)经过以上几步,我们可以正确的读取、配置我们需要的界面了。那么他们是如何与Makefile文件建立编译关系呢?当你保存make menuconfig选项时,系统会除了会自动更新.config外,还会将所有的选项以宏的形式保存在Linux内核根目录下的include/generated/autoconf.h文件下,内核中的源代码就都会包含这个.h文件,跟宏的定义情况进行条件编译。

至此,我们就完成了整个linux内核的编译过程。最后我们会发现,整个linux内核配置过程中,留给用户的接口其实只有各层Kconfig、Makefile文件以及对应的源文件。比如想要给内核增加一个功能,并且通过make menuconfig控制其生成过程,需要做的工作:
首先,修改/增加对应目录下的Kconfig文件,按照Kconfig语法增加对应的选项;
其次,make menuconfig选择编译进内核或者不编译进内核,或者编译为模块。保存之后自动生成.config和autoconf.h文件;
然后,修改/增加对应目录下的Makefile文件完成编译选项的添加;
最后,执行make zImage命令进行编译。

三、总结
跟make menuconfig这个命令相关的文件,包括三类,包括.config,Kconfig,Makefile。为什么不说三个,而说三类呢?因为 Kconfig和Makefile是配合使用的,在很多的子目录都存在,而.config只存在于根目录中。这三个文件的作用分别是:
    Kconfig:   定义了配置项
    .config:   对配置项进行赋值
    Makefile:  建立配置项的生成法则



                               Kconfig语法
                              -------------
Kconfig的基本构成包括五种,menu/endmenu,menuconfig,config,choice/endchoice,source。下面就对每种详细介绍:
(1) menu/endmenu
menu的作用,可以理解成一个目录,menu可以把其中一部分配置项包含到一个menu中,这样有利于配置的分类显示。menu与endmenu是一组指令,必须同时出现。menu和endmenu中包含的部分就是子目录中的配置项。

(2) menuconfig
menuconfig有点类似menu,它是可以配置的,在内核配置界面下通过空格可以修改这个配置项的选中状态。而且从格式上来看,也是有区别的。如init/Kconfig文件中:

menuconfig MODULES
bool "Enable loadable module support"config
if MODULES
...
...
endif

如果选中了MODULE,那么if和endif中的内容可以显示。如果没有定义,就只能进入一个空目录。

(3) config
config是构成Kconfig的最基本单元,其中定义了配置项的详细信息。如:

config ARM
    bool
    default y
    
    ****************

config的类型有5种:
    bool(y/n)
    tristate(y/m/n)
    string(字符串)
    hex(十六进 制)
    integer(整数)
其中,bool只能表示选中和不选,而tristate还可以配置成模块 (m),特别对于驱动程序的开发非常有用。

config的其他语法如下:
1) prompt:提示,显示在make menuconfig中的名称,一般省略。下面两种写法相同。
a.  bool “Networking Support”
b.  bool
prompt “Networking Support”

2) default:默认值
一个配置项可以有多个默认值,但是只有第一个被定义的值是有效的。

3)depends on/requires:依赖关系
如果依赖的配置项没有选中,那么就当前项也无法选中。

4) select:反向依赖
如果当前项选中,那么也选中select后的选项。

5) range:范围,用于hex和integer
range A B表示当前值不小于A,不大于B

6) comment:注释

(4) choice/endchoice
choice的作用,多选一,有点像MFC中的Radio控件。如:

choice
    prompt "Memory split"
    default VMSPLIT_3G
    help
      Select the desired split between kernel and user memory.

      If you are not absolutely sure what you are doing, leave this
      option alone!

    config VMSPLIT_3G
        bool "3G/1G user/kernel split"
    config VMSPLIT_2G
        bool "2G/2G user/kernel split"
    config VMSPLIT_1G
        bool "1G/3G user/kernel split"
endchoice

(5) source
source只是将另外一个Kconfig文件直接复制到当前位置而已。但它的作用也是明显的,可以将这个系统贯穿在一起。从开始位置arch/arm/Kconfig,来将整个系统都作为配置型

总结:

当我们进入了linux源码的根目录时,输入make menuconfig。假设,此时根目录已经存在.config,如果不存在,会自动生成。显然,在执行make menuconfig时,会自动调用scripts/Kconfig/mconf arch/arm/Kconfig开始系统的配置,那么arch/arm/Kconfig就是配置的起点。这个文件会通过source指令来调用其他目录 下的Kconfig文件,从而完成整体配置。这样,arch/arm/Kconfig就可以理解成main函数,而source指令就有点类似于 include。可以按照上面的语法,来分析Kconfig文件。





                       KBuild Makefile
                    ---------------------
从Linux内核2.6开始,Linux内核的编译采用Kbuild系统,这同过去的编译系统有很大的不同,尤其对于Linux 内核模块的编译。在新的系统下,Linux编译系统会两次扫描Linux的Makefile:首先编译系统会读取Linux内核顶层的Makefile ,然后根据读到的内容第二次读取Kbuild的Makefile来编译Linux内核。

Linux内核Makefile分类:
1. Kernel Makefile
Kernel Makefile 位于Linux 内核源代码的顶层目录,也叫 Top Makefile 。它主要用于指定编译Linux Kernel 目标文件(vmlinux )和模块(module )。这编译内核或模块是,这个文件会被首先读取,并根据读到的内容配置编译环境变量。对于内核或驱动开发人员来说,这个文件几乎不用任何修改。截取Kernel Makefiel部分内容如下:

# The all: target is the default when no target is given on the
# command line.
# This allow a user to issue only 'make' to build a kernel including modules
# Defaults to vmlinux, but the arch makefile usually adds further targets
all: vmlinux

ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS    += -Os $(call cc-disable-warning,maybe-uninitialized,)
else
KBUILD_CFLAGS    += -O2
endif

include $(srctree)/arch/$(SRCARCH)/Makefile

...

# ---------------------------------------------------------------------------
# Modules

ifdef CONFIG_MODULES

# By default, build modules as well

all: modules

#    Build modules
#
#    A module can be listed more than once in obj-m resulting in
#    duplicate lines in modules.order files.  Those are removed
#    using awk while concatenating to the final file.

PHONY += modules
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin
    $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
    @$(kecho) '  Building modules, stage 2.';
    $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
    $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild

modules.builtin: $(vmlinux-dirs:%=%/modules.builtin)
    $(Q)$(AWK) '!x[$$0]++' $^ > $(objtree)/modules.builtin

%/modules.builtin: include/config/auto.conf
    $(Q)$(MAKE) $(modbuiltin)=$*

...

# Where to locate arch specific headers
hdr-arch  := $(SRCARCH)

KCONFIG_CONFIG    ?= .config
export KCONFIG_CONFIG

# SHELL used by kbuild
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
      else if [ -x /bin/bash ]; then echo /bin/bash; \
      else echo sh; fi ; fi)

HOSTCC       = gcc
HOSTCXX      = g++
HOSTCFLAGS   = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer
HOSTCXXFLAGS = -O2

...

# Make variables (CC, etc...)

AS        = $(CROSS_COMPILE)as
LD        = $(CROSS_COMPILE)ld
CC        = $(CROSS_COMPILE)gcc
CPP        = $(CC) -E
AR        = $(CROSS_COMPILE)ar
NM        = $(CROSS_COMPILE)nm
STRIP        = $(CROSS_COMPILE)strip
OBJCOPY        = $(CROSS_COMPILE)objcopy
OBJDUMP        = $(CROSS_COMPILE)objdump
AWK        = awk
GENKSYMS    = scripts/genksyms/genksyms
INSTALLKERNEL  := installkernel
DEPMOD        = /sbin/depmod
PERL        = perl
CHECK        = sparse

CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise -Wno-return-void $(CF)
CFLAGS_MODULE   =
AFLAGS_MODULE   =
LDFLAGS_MODULE  =
CFLAGS_KERNEL    =
AFLAGS_KERNEL    =
CFLAGS_GCOV    = -fprofile-arcs -ftest-coverage

...

kernelrelease:
    @echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))"

kernelversion:
    @echo $(KERNELVERSION)


2. ARCH Makefile
ARCH Makefile 位于ARCH/$(ARCH)/Makefile,是系统对应平台的Makefile。Kernel Top Makefile 会包含这个文件来指定平台相关信息,如下所示:
include $(srctree)/arch/$(SRCARCH)/Makefile
只有平台开发人员会关心这个文件。

3. Kbuild Makefile
Kbuild 系统使用Kbuild Makefile 来编译内核或模块。当Kernel Makefile 被解析完成后,Kbuild 会读取相关的Kbuild Makefile 进行内核或模块的编译。Kbuild Makefile 有特定的语法指定哪些编译进内核中、哪些编译为模块、及对应的源文件是什么等。内核及驱动开发人员需要编写这个Kbuild Makefile 文件。

Kbuild Makefile 的文件名不一定是 Makefile ,尽管推荐使用Makefile 这个名字。大多的Kbuild 文件的名字都是Makefile 。为了与其他Makefile 文件相区别,你也可以指定Kbuild Makefile 的名字为 Kbuild 。而且如果“Makefile ”和“Kbuild ”文件同时存在,则Kbuild 系统会使用“Kbuild ”文件。

1) 目标定义
Kbuild Makefile 的一个最主要功能就是指定编译什么,这个功能是通过下面两个对象指定的obj-? 和xxx-objs :

· obj-?
obj-?指定编译什么,怎么编译,其中的“?”可能是“y”或“m”,“y”指定把对象编译进内核中,“m”指定把对象编译为模块。语法如下:
    obj-? = $(target).o
target为编译对象的名字。如果没有指定xxx-objs ,这编译这个对象需要的源文件就是$(target).c 或$(target).s 。如果指定了$(target)-objs ,则编译这个对象需要的源文件由$(target)-objs 指定,并且不能有$(target).c 或$(target).s 文件。

· xxx-objs
xxx-objs 指定了编译对象需要的文件,一般只有在源文件是多个时才需要它。
只要包含了这两行,Kbuild Makefile 就应该可以工作了。

2) 嵌套编译
有时一个对象可能嵌入到另一个对象的目录下,那个如何编译子目录下的对象呢? 其实很简单,只要指定obj_? 的对象为子目录的名字就可以了:
obj-? = $(sub_target)/
其中“? ”可以是“y”或“m”,$(sub_target) 是子目录名字。

3) 编译器选项
尽管在大多数情况下不需要指定编译器选项,有时我们还是需要指定一些编译选项的。

· ccflags-y, asflags-y and ldflags-y
这些编译选项用于指定cc 、as 和ld 的编译选项

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值