编译Linux内核

编译Linux内核

以下内容由 xgfone 整理而成。

在编译Linux内核源码时,建议不要使用具有管理权限的账号(比如:root账号),用普通账号即可,因为编译内核不需要管理员权限,由于普通账号不具有管理权限,所以其操作不会损坏系统。

注:以下某些部分不适合低于 2.6 版本的Linux内核,比如:模块编译。另外,现在内核已经发展到 3.X 版本,但原理是一样的。

1、获得Linux内核源码,并进入其主目录

(1) 下载Linux内核源码

Linux内核的官方网址是 http://www.kernel.org/pub/linux/kernel/ 。
注:也可以从其他地方获得Linux内核源码,只要获得Linux内核源码即可。

(2) 解压Linux内核源码

$ gzip -cd linux-2.6.XX.tar.gz | tar xvf -

or

$ bzip2 -dc linux-2.6.XX.tar.bz2 | tar xvf -

以上是通用格式,如果是GNU tar,还可以直接使用GNU tar解压:

$ tar -xvzf linux-2.6.XX.tar.gz  [-C SRC_DIR]

or

$ tar -xvjf linux-2.6.XX.tar.bz2  [-C SRC_DIR]

其中,SRC_DIR是解压后的源码所放置的目录;如果没有-C选项,则解压到当前目录。

注:有很多介绍“编译Linux内核”的教材或文章都把解压后的Linux内核源码放到 /usr/src/linux 目录中,但是,在Linux内核源码的帮助文档中,Linux官方建议不要使用该目录。其实,在编译Linux内核源码时,在任何目录中都是可以的。

(3) 进入主目录

$ cd SRC_DIR/linux-2.6.XX

or

$ cd linux-2.6.XX

注:以上命令要根据自己的当前目录来确定怎么使用。

2、给Linux内核打补丁(可选)

如果linux-2.6.XX版本正是我们所要的,这一步可以略过。

如果我们需要的是linux-2.6.XX.2,则还需要给我们下载的linux-2.6.XX版本打上 patch-2.6.XX.2.gz 补丁。

$ gzip -cd linux-2.6.XX.2.gz | patch -p1

or

$ gzip2 -dc linux-2.6.XX.2.bz2 | patch -p1

如果我们的Linux内核源码的版本是 linux-2.6.XX.1,如果想用 linux-2.6.XX.2,但又没有 linux-2.6.XX.2 的内核源码,只有 patch-2.6.XX.1patch-2.6.XX.2 两个补丁,则我们不能在 linux-2.6.XX.1 上直接使用 patch-2.6.XX.2 这个补丁,而需要先用 patch-2.6.XX.1 补丁把我们的内核版本从 linux-2.6.XX.1 还原到 linux-2.6.XX,再用 patch-2.6.XX.2linux-2.6.XX 升级成 linux-2.6.XX.2。这样做的原因是,2.6版本的linux内核补丁都是基于 linux-2.6.XX 的,所以,只能应用到 linux-2.6.XX 上,不能应用到 linux-2.6.XX.YY 上。

3、移植Linux内核(可选)

如果我们下载的或已经打过补丁的Linux内核正是我们所想要的,即支持我们的硬件,那么可以跳过这一步。

一般来说,在我们的台式机(如常见的X86)上,我们不需要对Linux内核进行移植,可以略过这一步。

如果我们的Linux内核不支持我们的硬件,那么我们就需要对Linux内核进行移植。在大多数的Linux嵌入式中,经常须要移植Linux内核。

移植Linux内核需要修改Linux内核源码。

4、清除残留的信息(可选)

如果是刚刚下载的Linux内核源码并且没有执行过在编译Linux内核过程中所使用的任何一个make命令,则可以跳过这一步。

如果在当前的Linux内核源码中,已经执行过在编译Linux内核过程中所使用的任何一个make命令,并且想再次编译该Linux内核源码,则必须要执行这一步,不然,在编译的过程中,可能会遇到各种各样的小问题。

清除残留信息的过程很简单,只需要一个命令即可:

$ make  mrproper

在某些讲述如何编译Linux内核的教程中,很多教程都使用Makefile文件中的distclean选项,即使用命令:

$ make distclean

其实,这两个命令使用哪个都行。而且,使用后者时,清除的内容将会更多的,因为distclean选项所做的清除内容包含了mrproper选项所做的清除内容;换句话说,就是当使用distclean选项时,相当于也执行了mrproper选项,同时也执行了其他的一些清除工作。但是,在Linux内核源码的README文档中,在清除残留信息时,提到的是mrproper选项,而没有提到distclean选项。

5、生成.config配置文件

在执行make命令进行编译Linux内核时,我们需要.config配置文件,这个文件是指导Linux内核如何来编译Linux内核(这是Linux为了跨平台而设计的)。

.config是一个很大、很复杂的文件,从头开始配置是很麻烦的,所以,在编译Linux时,我们一般都会从其它的地方拷贝一个现成的.config到我们的Linux内核源码的主目录中。然后执行“make config”命令进行配置我们自己的.config文件。

make config”命令提供一个淳朴的命令行界面,我们一般不会使用它,可以使用其它能提供图形界面的配置命令:

make memuconfig         提供一个基于curses的命令行界面(需要curses库的支持)
make nconfig            提供一个基于ncurses(下一代curses)的命令行界面(需要ncurses库的支持)
make xconfig            基于QT的X Window图形化界面
make gconfig            基于GTK+的X Window图形化界面
make oldconfig          新配置的.config文件基于已经存在的.config,已经存在的.config中的值在新的.config文件中都成为默认值。
make silentoldconfig    同“make oldconfig”,但是该命令会避免被已经回答的问题弄乱屏幕,另外还会更新依赖。
make allyesconfig       在创建.config配置文件时,会尽可能选择“y”。
make allmodconfig       在创建.config配置文件时,会尽可能选择“m”。
make allnoconfig        在创建.config配置文件时,会尽可能选择“n”。
make randconfig         在创建.config配置文件时,会对各个选项进行随机设置(随机选择“y”、“m”、“n”)。
make defconfig          使用各架构下默认的.config文件(位于arch/<arch>/configs/*_defconfig)。

在执行这些命令中的任何一个时,对界面中的每个选项(即每个模块),可以选择“y”、“m”或“n”三个中的任何一个。

“y”选项要求make把该模块编译进Linux内核中(这会增大内核的大小);
“m”选项要求make把该模块编译成一个“模块”,该模块可以被动态地加载进Linux内核或从Linux内核中裁掉;
“n”选项要求make跳过该模块而不用编译它。

注:在选择如何编译内核时,一般有三种类型:方括号尖括号圆括号

如果出现的是方括号,只能选择“Y”或“N”,而且“Y”用“*”来代替(显示在方括号中),“N”用“ ”(空)来代替(显示在方括号中)。
如果出现的是尖括号,则可以选择“Y”、“N”或“M”,而且“Y”用“*”来代替(显示在尖括号中),“N”用“ ”(空)来代替(显示在尖括号中),
    “M”还是用“M”在尖括号中显示。
如果是出现的是圆括号,则允许输入选项内容。

6、解决各模块间的依赖关系(可选)

如果是编译2.6内核(及其以后版本)的话,这一步可以跳过。

主要是早期的Linux内核(比如:2.4版本)需要执行这一步,这一步能够解决各模块间的依赖关系,以及确保关键文件的正确位置。

执行的命令是:

$ make dep

7、编译Linux内核源码

make命令会生成相应的Linux内核镜像。

$ make [all]

make命令会根据.config配置文件来编译Linux内核。此命令会编译默认的目标,但不同的平台、体系,其默认的目标不同,这需要查看该平台、体系下的Makefile文件(位于arch/$(ARCH)/Makefile)。其实,Linux官方已经帮我们默认地设计好了即要生成的目标文件,我们按照默认的即可。在Linux内核中,执行makemake all是一样的。如果想加快、节约编译时间,可以在make命令中添加 -j N 选项,用来指定make的并发性,其中的 N 为数字,可以设置处理器的数量,一般设置成处理器的个数的两倍。

当我们需要特定的目标时,我们可以在make命令后明确地指定。比如:默认生成的是目标是zImage,但我们想要生成bzImage,则可以使用命令“make bzImage”。但是,在明确地指定生成目标时,请先查看该平台、体系下Makefile文件是否有该目标(在查看时,可以从Makefile文件的规则和名为“archhelp”的命令包中查看,其中“archhelp”可以看成是帮助文档);如果没有的话,就算明确指明,也不能生成该目标。

不过,对于大部分平台、体系的计算机来说,一般都会先编译成vmlinux目标,然后再把vmlinux目标转换成其它形式的目标。

注:

(1) 一般能生成的目标有:vmlinuxImagezImagebzImageuImage等等,且后三者在ARM嵌入式芯片上用的最多。

(2) 在编译上述指定的目标时,make只编译选项为“Y”的模块,不会编译选项为“M”或“N”的模块。如果想编译选项为“M”的模块,须要指定目标“modules”。

只编译选项为“M”的模块,但不编译选项为“Y”的模块:

1> 编译Linux内核源码中所有选项为“M”的模块:
   首先切换当前目录到Linux内核源码树的主目录,然后执行命令即可: $ make modules
   注:此命令可以把Linux内核源码树中所有选项为“M”的模块编译成可动态加载、卸载的模块;
      另外,用此命令编译的模块必须都是在Linux内核源码树内的。

2> 只编译Linux内核源码树中的某一个模块:
   如果不想编译Linux内核源码树中所有的选项为“M”的模块,则也可以只单独编译其中的一个模块。
   此时,首先须要先切换当前目录到Linux内核源码树的主目录中,然后以下命令即可:$ make  SUBDIR=MODULE_DIR  modules
   其中,MODULE_DIR为所要编译的模块的主目录。

3> 编译在Linux内核源码树外的模块:
   首先切换当前目录到要编译的模块的主目录内,然后执行以下命令即可:$ make  -C $(KERNEL_DIR)  M=$(pwd)  modules
   其中,KERNEL_DIR是Linux内核源码树的主目录, 而$(pwd)则是当前即要编译的模块的主目录(即当前目录),
   pwd 为Shell下的命令(打印当前路径的全称),$(pwd)表示替换pwd命令的输出。

   注:此时编译的模块虽然是在Linux内核源码树的外部,但也要遵循Linux内核源码的大框架,即在其主目录下,
       要有一个Makefile文件来指导make编译模块,但不一定要有Kconfig文件(既然不在Linux内核源码树中,
       所以一般也不需要)。

说明:由此可见,编译内核时分为两种编译:只编译选项为“Y”的模块(即把模块编译进内核中)和只编译选项为“M”的模块(即把模块编译成可动态加载、卸载的模块形式)。

8、安装编译后所生成的Linux内核(可选)

对于不同的平台,这一步的执行不同,甚至可以省略。比如:如果编译的是嵌入式Linux内核源码,这一步就可以省略。如果是X86平台、体系,并且想要安装刚刚编译的内核的话,则这一步是需要的。在X86下,安装编译后的Linux镜像的命令是:

# make install

相对于Linux内核的编译,Linux内核的安装也有多种。其实,对于Linux内核的安装分为三种:内核镜像内核模块内核头文件(头文件不需要编译)。

(1) 安装内核镜像

$ make install

此命令会完成以下动作:

1> 把内核镜像拷贝到/boot目录下,并建立相应的system.map符号链接;
2> 修改bootloader的配置文件(一般是Grub);
3> 调用mkinitrd程序创建内核的initrd映象。

注:该命令会将内核映像文件安装到/boot目录下。如果使用的是Fedora系统的发布版,就会同时生成boot初始化文件系统映像,并同样安装到/boot下。而UbuntuDebian系统的发布版则需要执行下列命令,另行生成和安装boot初始化文件系统映像。在 <内核版本> 的部分请输入表示当前生成的内核版本的文字:

update-initramfs -c -k <内核版本>

通过安装内核而生成的文件和目录

文件名或目录名 内容
/lib/modules/<内核版本> 安装模块的目录
/boot/vmlinuz-<内核版本> 内核映像文件
/boot/initramfs-<内核版本> 或 /boot/initrd.img-<内核版本> boot初始化文件系统映像
/boot/Systemmap-<内核版本> 地址信息文件

(2) 安装可动态加载、卸载的模块

$ make modules_install

此命令会把编译后的动态模块安装到标准的系统模块所在的位置(默认地,一般为/lib/moudules/$(KERNEL_RELEASE)目录,其中KERNEL_RELEASE为该内核的发行版本)。

(3) 安装Linux内核的头文件

$ make headers_install

此命令会把Linux内核中相应的头文件安装到标准的系统头文件所在的位置。

我们一般常安装的是内核镜像。

注:在编译Linux内核源码时(即,使用make),如果没有指定O选项,则在编译过程中,所产生的所有中间文件都将位于各自相应的源码所在的目录中;如果指定了O选项,则在编译过程中,所产生的所有中间文件将位于由O选项所指定的目录中。其使用方法是:

$ make O=BUILD_DIR

其中,BUILD_DIR是可以系统中的任何一个目录。但是,

(1)要使用 O 选项,就要在第5步配置 .config 文件时使用;
(2)如果使用了 O 选项,每次使用 make 命令时,都必须使用 O 选项,而且在每次使用 O 选项时所指定的目录必须都相同。

附:make的一些对象或变量

 对象        |                               说明

-----------------|-------------------------------------------------------------------------------- clean | 将源码树恢复到编译前的状态。obj 文件等删除,.config或编译过程中自动生成的部分文件不会被删除。 mrproper | 将源码树完全恢复到发布时的状态。发布时源码树中不存在的文件全部被删除,包括.config文件。 help | 显示可以使用的make对象。 tags | 生成标签文件。有了标签文件,就能使用Emacs等编辑器的 tag jump 功能跳到函数定义处,可以高效进行源码浏览。 cscope | 生成用于cscope的索引文件。cscope是基于控制台(文字界面)的源码浏览器。 <dir>/<file>.o | 仅进行生成指定的目标文件所必需的编译。当仅指定

时,由.config文件生成该目录内所有目标文件。 <dir>/<file>.ko | 仅生成指定的模块。

注:其它的一些对象或变量请参见“5、生成.config配置文件”。

Linux嵌入式必考必会 文章被收录于专栏

&quot;《Linux嵌入式必考必会》专栏,专为嵌入式开发者量身打造,聚焦Linux环境下嵌入式系统面试高频考点。涵盖基础架构、内核原理、驱动开发、系统优化等核心技能,实战案例与理论解析并重。助你快速掌握面试关键,提升竞争力。

全部评论

相关推荐

点赞 2 评论
分享
牛客网
牛客企业服务