当前位置:文档之家› 如何安装Linux内核源代码

如何安装Linux内核源代码

如何获取Linux内核源代码下载Linux内核当然要去官方网站了,网站提供了两种文件下载,一种是完整的Linux 内核,另一种是内核增量补丁,它们都是tar归档压缩包。

除非你有特别的原因需要使用旧版本的Linux内核,否则你应该总是升级到最新版本。

使用Git由Linus领头的内核开发队伍从几年前就开始使用Git版本控制系统管理Linux内核了(参考阅读:什么是Git?),而Git项目本身也是由Linus创建的,它和传统的CVS不一样,Git是分布式的,因此它的用法和工作流程很多开发人员可能会感到很陌生,但我强烈建议使用Git下载和管理Linux内核源代码。

你可以使用下面的Git命令获取Linus内核代码树的最新“推送”版本:$ git clonegit:///pub/scm/linux/kernel/git/torvalds/linux-2.6.git 然后使用下面的命令将你的代码树与Linus的代码树最新状态同步:$ git pull安装内核源代码内核包有GNU zip(gzip)和bzip2格式。

Bzip2是默认和首选格式,因为它的压缩比通常比gzip更好,bzip2格式的Linux内核包一般采用linux-x.y.z.tar.bz2形式的文件名,这里的x.y.z是内核源代码的具体版本号,下载到源代码包后,解压和抽取就很简单了,如果你下载的是bzip2包,运行:$ tar xvjf linux-x.y.z.tar.bz2如果你下载的是gzip包,则运行:$ tar xvzf linux-x.y.z.tar.gz无论执行上面哪一个命令,最后都会将源代码解压和抽取到linux-x.y.z目录下,如果你使用Git下载和管理内核源代码,你不需要下载tar包,只需要运行git clone命令,它就会自动下载和解压。

内核源代码通常都会安装到/usr/src/linux下,但在开发的时候最好不要使用这个源代码树,因为针对你的C库编译的内核版本通常也链接到这里的。

应用补丁在源代码树的根目录下还有很多文件需要说明,COPYING是内核许可描述文件(即GNU GPL v2),CREDITS是参与Linux内核的开发人员名单,MAINTAINERS列出了维护各个子系统和驱动的个人,Makefile是内核Makefile的基础。

生成内核生成内核其实很简单,甚至比编译和安装其它系统级组件,如glibc还要简单,从2.6版本开始,Linux内核引入了一个新的配置和生成系统,它使生产内核的操作变得更加简单了。

配置内核既然已经拿到内核源代码,那我们在开始编译前就可以根据需要自行配置和定制,可以编译你指定的功能和想要的驱动,配置内核是生成内核必须的一步,因为内核提供了大量的功能,支持各种不同的硬件,有很多都需要配置,内核配置是由配置选项控制的,配置选项都有CONFIG前缀,例如,对称多处理(SMP)是由CONFIG_SMP配置选项配置的,如果设置了这个选项,SMP就被启用了,反之则被禁用,配置选项可以确定会生成哪个文件,也可以通过预处理指令操控代码。

配置选项可以控制生成过程要么是布尔型,要么是三态型,布尔型就是“是”或“否”,大部分内核配置选项都属于布尔型,如CONFIG_PREEMPT,而三态型则在“是”和“否”的基础上,又增加一个“模块”选项,模块选项表示配置选项被设置了,但最后会编译成模块,而不是直接编译进内核,模块可以理解为可独立动态载入的对象,一般来说,驱动配置通常都是三态型。

配置选项也可以是字符串或整数,这样的选项不会控制生成过程,指定的值由内核源代码访问预处理宏时使用,例如,可以为某个配置选项指定静态分配数组的大小。

Linux厂商也会随发行版提供预编译的内核,如Canonical为Ubuntu,或Red Hat为Fedora 提供的内核,这样的内核通常只启用了需要的内核功能,几乎所有驱动都被编译成模块了,这样的内核提供了一个良好的基础内核和广泛的硬件模块支持,无论如何,想要成为内核高手,你应该编译自己的内核。

值得庆幸的是,内核提供了很多工具简化配置,最简单的工具是基于文本命令行的实用程序,如:$ make config这个工具会一个选项一个选项地配置,但用户需要参与,如指定“是(y)”,“否(m)”还是“模块(m)”,整个配置过程需要很长的时间,因此,除非是有人按小时计费请你升级内核,实在找不出别的理由用这种最原始的方法配置内核了,相反,有现成的基于ncurses 的图形化工具可以代替。

$ make menuconfig或是基于gtk+的图形化工具$ make gconfig上述三个工具都将配置选项分成多个类别,如“处理器类型和特征”,你可以在这些类别上来回移动,查看内核选项,当然也可以修改它们的设置了。

下面这个命令会根据你的架构创建一个默认的配置基础。

$ make defconfig虽然默认配置有些武断(在i386上,默认配置是由Linus配置的),但如果你从未配置过内核,它提供了一个良好的开端。

配置选项存储在源代码树根目录下一个名叫.config的文件中,你可以打开这个文件手工编辑其中的配置选项,修改后或要在新的内核源代码树上应用现有配置文件,你可以使用下面的命令验证和更新配置:$ make oldconfig在生成内核之前必须运行这个命令。

配置选项CONFIG_IKCONFIG_PROC指定了完整的内核配置文件压缩包位置,默认是/proc/config.gz,这样在生成新内核时要克隆现有的配置就变得非常简单了。

如果你当前的内核开启了这个选项,你可以从/proc拷贝该配置文件,然后在此基础上生成新的内核:$ zcat /proc/config.gz > .config$ make oldconfig内核配置好后,使用下面的命令进行生成:$ make和2.6以前的内核不一样,在生成内核前不再需要执行make dep命令了,依赖树会自动维护,也不需要再指定特定的生成类型,如bzImage,或独立生成模块,默认Makefile规则会自动处理好一切。

将干扰信息最小化在生成过程中会遭到警告和错误的干扰。

最小化干扰信息的一个诀窍是重定向make的输出,但仍然会看到一些警告和错误:$ make > ../detritus如果你想查看生成输出,你可以事后阅读这个文件,如果你完全不想看到任何输出,那么就重定向到/dev/null:$ make > /dev/null同时执行多个生成作业Make命令提供了一个功能可以将生成过程拆分成多个平行的作业,这些作业可以独立运行,也可以并行运行,在多处理器系统上可以极大地提高生成速度,也提高了处理器利用率,因为生成大型源代码树会出现大量的I/O等待时间。

默认情况下,make只能拆分成一个作业,因为Makefiles常常会包含不正确的依赖信息,如果真是这样,多个并行执行的作业将会引起混乱,最终会导致生成过程失败,如果Makefiles中的依赖信息无误,那么完全可以拆分成多个作业执行,如:$ make –jn这里的n表示拆分的作业数量,通常按每个处理器拆分成1-2个作业,例如,在一个16核心的机器上,你可以运行:$ make -j32 > /dev/null使用distcc或ccache等优秀的工具也可以大大提高生成速度。

安装新内核内核生成好之后,你需要安装它,如何安装于系统架构和引导加载程序有关,我们以x86架构,grub引导加载程序为例进行说明。

首先将arch/i386/boot/bzImage拷贝到/boot,重命名为vmlinuz- version,这里的version 也是版本号,然后编辑/boot/grub/grub.conf,为新内核添加相应的项目,如果是使用LILO 引导装载程序,则修改/etc/lilo.conf文件,然后运行lilo。

模块的安装与系统架构无关,都是自动完成的,以root用户运行:% make modules_install这个命令会将所有编译好的模块安装到/lib/modules下对应的子目录中。

生成过程会在源代码树根目录下创建一个System.map文件,它包含一个符号查找表,映射内核符号到它们的起始地址,在调试期间可以用它将内存地址转换成函数和变量名。

可能会遇到的问题与普通用户空间的应用程序相比,Linux内核有多个特殊的属性,下面是我认为最重要的一些不同:◆内核既不访问C库也不访问标准C头;◆内核是用GNU C编码的;◆内核缺少用户空间提供的内存保护;◆内核不能容易地执行浮点运算;◆内核有一个小型的固定大小的进程堆栈;◆由于内核支持异步中断和SMP,因此同步和并发是内核主要担心的问题;◆可移植性也很重要。

下面我们就逐个来了解一下这些问题,所有内核开发人员都必须记住它们。

无libc或标准头和用户空间应用程序不一样,内核并没有链接到标准的C库,也没有链接到任何其它的库,这样设计的原因有很多,包括如先有鸡还是先有蛋的问题,但主要原因还是速度和内核大小,不要说完整的C库,就是它的一个子集也够大,内核太大只会导致效率低下。

不要担心,许多常用的libc函数都在内核中实现了,例如,常见的字符串操作函数就位于lib/string.c中,只需要包括它的头文件<linux/string.h >就可以了。

这里的头文件指的是内核源代码树中的头文件,内核也只能使用树内的头文件,基础文件位于源代码根目录的include/目录下,例如,<linux/inotify.h>头文件就位于include/linux/inotify.h。

与架构相关的头文件则位于arch/<architecture>/include/asm,例如,如果在x86架构下编译,与你架构相关的文件就是arch/x86/include/asm,只需要在引用这些头的地方加上asm/前缀即可,如<asm/ioctl.h>。

漏掉的大部分都是类似printf()这样的函数,内核不会使用printf(),但它提供了printk()函数,其表现绝不比printf()差,printk()会拷贝格式化的字符串到内核日志缓冲区,syslog 程序就是从这里读取信息的,其用法也和printf()类似:printk("Hello world! A string '%s' and an integer '%d'\n", str, i);printf()和printk()之间最大的不同是,printk()允许你指定一个优先级标记,syslogd使用这个标记确定在哪里显示内核消息,下面是一个使用优先级标记的示例:printk(KERN_ERR "this is an error!\n");注意在KERN_ERR和打印的消息之间没有逗号,这是故意这么设计的,优先级使用一个预定义的字符定义,在编译期间它与打印的信息是串联的。

相关主题