linux内核源码 编译-超级实用!一位嵌入式资深人士发现的Linux内核编译步骤和经验

这是免费软件; 请参阅复制条件的来源。 没有

保修单; 甚至不是为了适销性或特定用途的适用性。

注:arm工具链可以从这里下载:回复“ARM”即可查看。

2.设置编译目标

在配置或编译内核之前,必须首先确定目标CPU架构以及编译时使用哪些工具链。 这是必须首先确定的最基本的信息。

如果您正在为当前使用的PC编译内核,则无需进行设置。

否则,必须明确设置。

这里我们以arm为例来说明。

设置方法有两种():

a) 修改Makefile

打开内核源码根目录下的Makefile,修改以下两个Makefile变量并保存。

拱形:= 手臂

CROSS_COMPILE :=arm-linux-

注意,这里cross_compile的设置假设使用的交叉工具链的gcc程序名称为arm-linux-gcc。 如果实际使用的gcc名称是some-thing-else-gcc,则只需填写some-thing-else-即可。 简而言之,名称中的 gcc 的最后三个字母应该被省略。

b) 每次执行make命令时,该信息都会通过命令行参数传入。

这可能是通过 make 工具的命令行参数指定的变量值。

例如

要配置内核,请使用

使 ARCH=arm CROSS_COMPILE=arm-linux-menuconfig

编译内核时使用

使 ARCH=arm CROSS_COMPILE=arm-linux-

linux内核源码 编译-超级实用!一位嵌入式资深人士发现的Linux内核编译步骤和经验

需要注意的是,实际上,在编译PC内核时,虽然用户没有明确设置,但并不意味着这两项没有配置。 因为如果用户不设置这两项,内核源码最顶层的Makefile(位于源码根目录)就会通过下面的方法生成这两个变量的值。

SUBARCH := $(shell uname -m | sed -es/i.86/i386/ -es/sun4u/sparc64/

-es/arm.*/arm/ -es/sa110/arm/

-es/s390x/s390/ -es/parisc64/parisc/

-es/ppc.*/powerpc/ -es/mips.*/mips/

-es/sh[234].*/sh/ )

拱形?= $(子拱形)

交叉编译?=

通过前面的代码,ARCH就变成了PC编译器的arch,即SUBARCH。 因此,如果PC上uname -m的输出是ix86,那么ARCH的值就变成i386。

如果未配置,CROSS_COMPILE 的值为空字符串。 这样,所使用的工具链程序的名称就不再带有像arm-linux-这样的前缀了,相当于PC上使用gcc了。

最后我还想多说几句。 ARCH的价值需要进一步推广。 因为内核源码的arch目录下没有i386目录,也没有sparc64目录。

因此,在顶层的makefile中构造了一个SRCARCH变量,并通过以下代码生成其值。 这样,SRCARCH变量最终匹配了内核源代码arch目录中的某个架构名称。

SRCARCH := $(ARCH)

ifeq ($(ARCH),i386)

SRCARCH := x86

万一

ifeq ($(ARCH),x86_64)

SRCARCH := x86

万一

ifeq ($(ARCH),sparc64)

SRCARCH := sparc

万一

ifeq ($(ARCH),sh64)

SRCARCH := sh

万一

3.配置内核

内核有很多功能。 我们需要哪些部分,每个部分如何编译(进入内核或进入模块),以及每个部分的工作参数是什么? 这些都是可以配置的。 因此,在开始编译之前,我们需要创建一个配置列表,放在内核源码根目录下,命名为.config文件,然后根据这个.config文件编译我们需要的内核。

不过内核配置项太多,一一配置太麻烦。 而且,不同的CPU架构有不同的可配置的配置项。 例如,决定是否支持某个CPU的某个特性的配置项就是与CPU架构相关的配置项。 因此,内核提供了一种简单的配置方法。

以arm为例,具体方法如下。

a) 根据我们的目标CPU架构,从内核源码arch/arm/configs目录中找到距离目标系统最近的配置文件(如s3c2410_defconfig),将其复制到内核源码根目录linux内核源码 编译,并命名为.config。

注意,如果是为当前PC编译内核,最好将以下文件复制到内核源码根目录作为初始配置文件。 该文件是编译PC上当前运行的内核时使用的配置文件。

/lib/modules/`uname -r`/build/.config

顺便在这里我想说几句。 PC内核的配置文件有很多功能可供选择。 不编不知道,编了才知道。 Linux发行商这样做的目的可能是让他们发行的Linux能够满足用户的各种需求。

b) 执行 make menuconfig 对此配置进行一些必要的更改,并在退出时选择“保存”以将新配置更新到 .config 文件。

注-1,当我们执行这个操作时,内核会打开一组配置项供我们配置。 这组配置项是由我们上面设置的CPU架构决定的。 更具体地说,配置系统打开 arch/arm/Kconfig 文件(执行 make menuconfig 时,可以看到“scripts/kconfig/mconf arch/arm/Kconfig”行的副本)。 该文件还包含其他内核子系统。 Kconfig文件(文件名也可以是其他名称),其他子系统的Kconfig文件,然后逐层包含上层的Kconfig文件,从而生成一套完整的配置项。 每个配置项当前设置的值(例如是否编译进内核、编译成模块、也可能是参数)都是由内核源码根目录下的.config文件生成的。

Note-2,即使不需要对配置进行任何更改,也不必执行make menuconfig,然后进入配置界面并直接退出并保存。 否则以后编译的时候可能会遇到问题。 笔者就遇到过这个问题。 笔者猜测,原因可能是初始配置文件是基于旧版本内核的,而新版本内核可能增加了一些基本的功能项,导致功能项之间的依赖关系发生了变化。 例如,旧配置文件中选择的某个功能项在新版本内核中的实现可能会依赖于更多其他功能项。 因此,需要对旧的初始配置文件进行一些调整,以保证满足各个功能项的依赖条件。 在制作menuconfig后,作者发现.config文件的内容确实发生了变化。

四、编译内核

编译本身非常简单。 对于2.6及以上的内核版本,只需执行以下命令即可完成。

制作

我们不妨花点时间来了解一下内核编译的机制。

linux内核源码 编译-超级实用!一位嵌入式资深人士发现的Linux内核编译步骤和经验

a) 内核如何使用配置文件

.config 文件是之前生成的,它是一个文本文件,包含一些类似于以下内容的内容:

CONFIG_YENTA_ENE_TUNE=y

CONFIG_YENTA_TOSHIBA=y

CONFIG_PD6729=米

CONFIG_I82092=米

CONFIG_MTDRAM_ERASE_SIZE=128

可以看到,有的设置是把某个函数编译到内核中,有的设置是把某个函数编译成模块,有的设置是设置某个函数的某个参数。

这个文件的句型实际上就是定义makefile变量的句型。 是的linux内核源码 编译,这是 makefile。

当我们执行make开始编译内核时,编译系统会生成另一个配置文件,即include/config/auto.conf。 里面的内容和.config类似,但是内容比较少。

当内核编译时,顶层Makefile(位于源代码的根目录)将包含上述配置文件。

这样就得到了相应的makefile变量,从而知道如何编译内核的各个部分。

从顶楼的makefile中可以看到如下代码:

ifeq ($(点配置),1)

# 读入配置

-include include/config/auto.conf

不过,这两个配置文件之间是什么关系,会包含哪一个,下面我还没有说清楚……

b) 内核如何编译各个子系统或模块

从上一步来看,通过config文件,内核顶层的makefile已经生成了大量的makefile变量。

另一方面,每个子系统或模块在其源代码目录中都有一个 Makefile,它定义了该子系统或模块需要编译的内容。

linux内核源码 编译-超级实用!一位嵌入式资深人士发现的Linux内核编译步骤和经验

接下来,make工具可以取出顶层makefile中生成的大量makefile变量,逐层进入各个子系统或模块所在的目录,编译各个目录下Makefile中定义的内容。

该目录下的Makefile可以说非常简单。

如果某一目录下只有一个模块hello,则该模块只有一个.c文件,如xxx.c。 那么它的Makefile的全部内容就只有下面这行了。

obj-$(CONFIG_HELLO) := hello.o

如果hello模块由三个文件main.c ac bc组成,那么Makefile只需要两行内容。

obj-$(CONFIG_HELLO) := hello.o

hello-objs := main.o ao bo

如果多个模块的C文件存放在一个目录下,不要是hello、hello2、hello3。

hello模块的组成:main.c ac bc

hello2模块的组成:main2.c a2.c b2.c

hello3模块的组成:hello3.c

此时Makefile只需要5行内容。

obj-$(CONFIG_HELLO) += hello.o

obj-$(CONFIG_HELLO2) += hello2.o

obj-$(CONFIG_HELLO3) += hello3.o

hello-objs := main.o ao bo

hello2-objs := main2.o a2.o b2.o

由于顶层Makefile中有大量变量,子目录下Makefile中的$(CONFIG_HELLO)变量解析后会变成y或m。 这样的话,每个子目录下的Makefile解析完之后,相当于只是定义了一个名为obj-m或obj-y的变量。

变量 obj-m 或 obj-y 的值是 .o 文件的列表。 表中的每一项代表一个功能项。 如果变量名为 obj-m,则该函数被编译成模块。 如果变量名为 obj-y,则此功能将被编程到内核中。

c) 内核代码中,如何知道某个功能是否配置,以及通过什么方式配置

当我们执行make开始编译内核时,编译系统会生成一个C语言头文件

包含/生成/autoconf.h

该文件的内容类似于以下内容:

#定义CONFIG_DM9000 1

#define CONFIG_DM9000_DEBUGLEVEL 4

#define CONFIG_SND_RAWMIDI_SEQ_MODULE 1

第一行表示用户选择将DM9000驱动程序编译到内核中,第二行是该驱动程序的一个参数。 如果用户选择将DM9000编译成模块,则第一行的内容如下。

#定义CONFIG_DM9000_MODULE 1

有了这个头文件,如果某个内核源代码的.c文件中包含这个头文件,就可以通过#ifdef CONFIG_XXX知道用户是否配置了XXX功能。

好了,内核编译机制就说到这里了^_^

五、安装内核

a) 安装当前PC的内核

依次执行以下两条命令,分别完成模块和内核的安装。

进行模块安装

进行安装

然后打开boot/grub/grub.conf,你会听到上面多了一个条目。

将超时更改为 5,以便您有 5 秒的时间来选择启动时启动哪个内核。

最后,重新启动笔记本。 当出现bootloader界面时,选择启动新内核。

b) 安装嵌入式系统内核

这不是一两句话就能说清楚的事情。 具体问题请自行查阅相关资料^_^

对于普通的arm单板,常见的方法是通过SecureCrt将PC连接到单板的并口,通过网线连接到单板的网口。 在PC上启动tftp服务器,将内核镜像zImage文件放入tftp下载目录中。 重启开发板,当SecureCrt中看到u-boot启动倒计时时,按任意键进入u-boot界面。 然后在该界面中,通过相关命令下载内核镜像zImage文件,然后通过命令将下载的zImage烧录到板子的FLASH中。 最后,重新启动开发板。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 源码编译 linux内核源码 编译-超级实用!一位嵌入式资深人士发现的Linux内核编译步骤和经验 https://www.wkzy.net/game/187656.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务