1、 嵌入式 Linux 内核模块的配置与编译一、简介 随着 Linux 操作系统在嵌入式领域的快速发展,越来越多的人开始投身到这方面的开发中来。但是,面对庞大的 Linux 内核源代码,开发者如何开始自己的开发工作,在完成自己的代码后,该如何编译测试,以及如何将自己的代码编译进内核中,所有的这些问题都直接和 Linux 的驱动的编译以及 Linux 的内核配置系统相关。 内核模块是一些在操作系统内核需要时载入和执行的代码,它们扩展了操作系统内核的功能却不需要重新启动系统,在不需要时可以被操作系统卸载,又节约了系统的资源占用。设备驱动程序模块就是一种内核模块,它们可以用来让操作系统正确识别和使用使
2、用安装在系统上的硬件设备。 Linux 内核是由分布在全球的 Linux 爱好者共同开发的,为了方便开发者修改内核,Linux 的内核采用了模块化的内核配置系统,从而保证内核扩展的简单与方便。 本文通过一个简单的示例,首先介绍了如何在 Linux 下编译出一个内核模块,然后介绍了 Linux 内核中的配置系统,讲述了如何将一个自定义的模块作为系统源码的一部分编译出新的操作系统,注意,在这里我们介绍的内容均在内核 2.6.13.2(也是笔者的开发平台的版本)上编译运行通过,在 2.6.*的版本上基本上是可以通用的。 二、单独编译内核模块 首先,我们先来写一个最简单的内核模块: #include
3、#include #include #define DRIVER_VERSION “v1.0“ #define DRIVER_AUTHOR “RF“ #define DRIVER_DESC “just for test“ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE(“GPL“); static int rfmodule_init(void) printk(“hello,world:modele_init“); return 0; static void rfmodule_exit(v
4、oid) printk(“hello,world:modele_exit“); module_init (rfmodule_init); module_exit (rfmodule_exit); 这个内核模块除了在载入和卸载的时候打印 2 条信息之外,没有任何其他功能,不过,对于我们这个编译的例子来讲,已经足够了。 将上述源代码保存到一个 test.c 文件中,然后开始我们的内核模块的编译工作。 内核模块的编译与普通应用程序的编译一样,也使用的 GCC,但是内核模块在用 GCC 编译的时候时需要使用特定的参数并定义一些宏。 这是因为在编译普通应用程序的可执行文件和内核模块时,内核头文件起的作用
5、是不同的。在以往的内核版本需要我们去在 Makefile 中手动设置这些设定,虽然这些Makefile 都是按目录分层次存放的,但使用维护起来还是比较伏在。幸运的是,一种称为 kbuild 的新方法被引入,现在外部的可加载内核模块的编译的方法已经同内核编译统一起来,编译新的内核模块或者将自己的内核模块集成到内核源码中都已经变得非常简单了。 现在让我们看一下如何编译一个名字叫做 test.c 的模块。 首先,我们需要写一个简单的 Makefile 文件: obj-m += test.o 将 test.c 和 Makefile 文件放在同一个目录下,然后就可以开始编译了,使用编译命令: make
6、-C /usr/src/linux-2.6.13.2/ SUBDIRS=$PWD modules 回车后,也许你会发现有一堆的报错,请检查如下配置是否正确: 1、在/usr/src/下有无放置你需要使用的内核源码树?如果没有,请上网down 一个你需要的内核源码版本,解压后放在这里。 2、如果你已经将内核源码解压在/usr/src/下了,那么请先使用在内核源码的主目录下,在笔者的系统中就是/usr/src/linux-2.6.13.2/,使用: make config 或者 make menuconfig 或者 make gconfig 等命令来配置内核,然后使用 make all 将整个内核
7、完整编译一次。 3、上述命令中的 linux-2.6.13.2 是笔者使用的内核源码的目录名,你需要将它改成你自己使用对应版本的的内核源码的目录名。 经过上述三步,一般来将,该内核模块都可以编译通过了,生成的test.ko 就是我们需要的内核模块的最终版本,你可以使用: insmod ./test.ko 将该模块载入系统。请注意:如果想将模块载入系统,请保证编译模块使用的内核源码的版本与要载入的系统的版本一致!否则无法载入! 嵌入式开发实作(Linux 内核编译及安装) 部分内容译自Embedded Linux kernel and driver development by Michael
8、Opdenacker刘建文(http:/ ) KEY:Linux 内核编译 内核配置 嵌入式 内核配置(Kernel configuration) Makefile 版本修改 为了区别基于同一源码构建(bulid)的不内核镜像,可使用变量 EXTRAVERSION(定义位于makefile 的顶部): VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 7 EXTRAVERSION = -acme1 VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 7 EXTRAVERSION = -acme1 VERSION = 2PATCHLEVEL =
9、6SUBLEVEL = 7EXTRAVERSION = -acme1 运行“uname -r”会返回: 2.6.7-acme1 2.内核配置 先定义内核需要什么特性,并进行配置。内核构建系统(The kernel build system)远不是简单用来构建整个内核和模块,想了解更多的高级内核构建选项,你可以查看 Documentation/kbuild 目录内的内核文档。 可用的配置命令和方式: make xconfig make menuconfig make oldconfig 或者 手动编写 内核编译的配置文件.config 与内核配置的 makefile? 内核配置文件(Makefi
10、le 语法的)保存为内核源代码的顶层目录的.config 文件。发行版的内核配置文件通常在/boot/内。 命令:make xconfig qconf: 全新的基于 QT 的配置接口,2.6 版本内核 更易使用(切记阅读 help - introduction: useful options!) 具有文件浏览功能,更易的加载配置文件 命令:make menuconfig 老式字符界面,依然很管用。你够自信,完全可以手写配置文件! 命令:make oldconfig 用于升级早期发布内核的配置文件 对一些绝对符号(obsolete symbols)发出警告 询问新符号的配置值 何为 makefi
11、le? makefile 包含用以构建应用程序的一组规则集(set of rules) 。并且第一条规则 是特殊的规则 ,叫 默认规则 (default rule) 。一条规则由三部分组成:目标( target) 、前提条件(prerequisites)和命令动作(command):target: prereq1 prereq2 commands target: prereq1 prereq2 commands target: prereq1 prereq2commands 目标 是被构建(made )的文件 或其它东西。前提条件 或者叫依赖(dependents )构建目标的“材料” 。而命
12、令动作是利用前提条件构建目标的 shell 命令。 以下是编译 C 源码的规则例子: foo.o: foo.c foo.h lt;tabgcc -c foo.c foo.o: foo.c foo.h lt;tabgcc -c foo.c foo.o: foo.c foo.hgcc -c foo.c 注意格式,冒号前是目标,后是前提条件;命令在第二行,并且开始于一个 tab 字符。编译内核 编译和安装内核 编译步骤: $ cd /usr/src/linux2. 6 $ make $ cd /usr/src/linux2.6 $ make $ cd /usr/src/linux2.6$ make
13、安装步骤 (logged as root!) $ make install $ make modules_install $ make install $ make modules_install $ make install$ make modules_install 以下的步骤在 2.6 版本不再使用: $ make depends $ make modules (done by make) $ make depends $ make modules (done by make) $ make depends$ make modules (done by make) 提升编译速度 多花一些
14、时间在内核配置上,并且只编译那些你硬件需要的模块。这样可以把编译时间缩短为原来的 1/30,并且节省数百 MB 的空间。另外,你还可以并行编译多个文件: $ make -j make 可以并行执行多个目标(target ) (KEMIN: 前提是目标规则间没有交叉依赖项,这个怎么做到的?) $ make -j 4 即便是在单处理器的工作站上也会很快,读写文件的时间被节省下来了。多线程让 CPU 保持忙碌。 number 大于 4 不见得有效了,因为上下文切换过多反而降低的工作的速度。 make -j 内核编译 tips 查看完整的 (gcc, ld)命令行: $ make V=1 清理所有的生
15、成文件 (to create patches.): $ make mrproper 部分编译:$ make M=drivers/usb/serial 单独模块编译:$ make drivers/usb/serial/visor.ko 别处编译(假设源码在 CDROM): $ cd /mnt/cdrom/linux-2.6.17.11 $ make O=/linux/linux-2.6.17.11 最终生成的文件 vmlinux 原始内核镜像,非压缩的 arch/boot/zImage zlib 压缩的内核镜像(Default image on arm) arch/boot/bzImage bz
16、ip2 压缩的内核镜像。通常很小,足够放入一张软盘(Default image on i386) 安装的文件 /boot/vmlinuz- 内核镜像; /boot/System.map- 保存有内核的符号地址(symbol addresses) ; /boot/initrd-.img Initial RAM disk:保存有你需要在引导时挂接最终根文件系统的模块。安装命令“make install”为替你运行“mkinitrd ”生成 initrd; /etc/grub.conf or /etc/lilo.conf bootloader 的配置文件:“make install”会为你的新内核更
17、新相应的 bootloader 的配置文件。如果你使用的是 LILO,它会在生成配置文件后,执行/sbin/lilo,让 LILO 的配置生效。 /lib/modules/ Kernel modules + extras build/为本的内核添加模块所需的所有东西: .config file (build/.config), module symbol information (build/module.symVers), kernel headers (build/include/) kernel/内核模块文件 .ko (Kernel Object),目录结构与源代码目标一一对应。 mod
18、ules.alias模块别名记录(用于 insmod 和 modprobe) ,例如:alias sound-service-?-0 snd_mixer_oss modules.dep模块依赖记录(用于 insmod 和 modprobe) modules.symbols标识某符号是属于哪个模块的。 这个目录的所有文件都是文本文件,可以直接查看。 小结编译及安装步骤: 编辑 Makefile 版本信息 定义内核特性,生成配置文件.config,用于编译:make xconfig 编译内核:make 安装内核:make install 安装模块:make modules_install 交叉编译
19、内核 Makefile 修改 通常通过修改已有的 makefile 获得 你必须修改目标平台,假设目标平台是 ARM,修改以下: ARCH ?= arm CROSS_COMPILE ?= arm-linux- ARCH ?= arm CROSS_COMPILE ?= arm-linux- ARCH ?= armCROSS_COMPILE ?= arm-linux- 或运行带参数的 make: $ cd /usr/scr/linuxXX $ make ARCH=arm CROSS_COMPILE=arm-linux- $ cd /usr/scr/linuxXX $ make ARCH=arm C
20、ROSS_COMPILE=arm-linux- $ cd /usr/scr/linuxXX$ make ARCH=arm CROSS_COMPILE=arm-linux- 内核配置文件 配置过程和本地配置一样; 可以把生成的配置文件(.config)分享给其他人,比如像: $ $ cp .config arch/config/acme_defconfig $ $ cp .config arch/config/acme_defconfig $ cp .config arch/config/acme_defconfig 这样其他同样开发 ACME 系统的开发人员可以通过以下命令编译出同样的内核:
21、$ make acme_defconfig $ $ make acme_defconfig $ $ make acme_defconfig$ 建立交叉编译环境(Cross-compiling setup) 假设你有 ARM 的交叉编译工具(cross-compiling toolchain)在 in /usr/local/arm/3.3.2/, 你得把它输出到 PATH: $ export PATH=/usr/local/arm/ 3.3 . 2 /bin:$PATH $ export PATH=/usr/local/arm/3.3.2/bin:$PATH $ export PATH=/usr
22、/local/arm/3.3.2/bin:$PATH 注意查看内核文档(在 Documentation/Changes)有关最低工具版本要求。 编译并安装内核 1. $ make /如果你修改了 Makefile 或者 1. $ make ARCH=arm CROSS_COMPILE=arm-linux- 2. 拷贝 arch/boot/zImage 到目标系统 $ make modules_install 3. 拷贝 /lib/modules/ 到目标系统 你可以通过 arch/boot/install.sh 自定义安装,让”make install“自动代劳。 何为交叉编译工具链(cros
23、s-compiling toolchain)? 有如任何其它开发活动一般,嵌入式开发的第一步是建立(setting up)用于构建嵌入式Linux 内核(当然包括驱动程序)及应用程序的工具链(toolchains ) 。不过,嵌入式开发需要是跨平台工具链。跨平台是什么意思呢?一般开发活动是在本地编译,使用是本地的工具链;而由于嵌入式的软硬资源(内存不足、没有本地编译器或操作系统都没有)限制等没法进行本地开发。需要在 Linux-x86 主机(HOST)开发,使用主机的编译器生成目标(TARGET)平台代码,这个过程叫交叉编译。 我们常常说的编译器有广义和狭义之分。狭义的编译器只完软件编译(或者
24、叫软件构建)的第一步;广义的编译器包括了软件编译(或者叫软件构建)所需要代码库(比如 libc)和其它构建工具(比如汇编器和连接器) 。无论是什么编译器都需要支持的代码库和各种构建工具,交叉编译也不例外。一整套广义的编译器称为交叉编译工具链。 何为工具链? In software, a toolchain is the set of computer programs (tools) that are used to create a product (typically another computer program or system of programs). The tools ma
25、y be used in a chain, so that the output of each tool becomes the input for the next, but the term is used widely to refer to any set of linked development tools. A simple software development toolchain consists of a text editor for editing source code, a compiler and linker to transform the source
26、code into an executable program, libraries to provide interfaces to the operating system, and a debugger. The GNU toolchain is a blanket term for a collection of programming tools produced by the GNU Project. These tools form a toolchain (suite of tools used in a serial manner) used for developing a
27、pplications and operating systems. Projects included in the GNU toolchain are: * GNU make: Automation tool for compilation and build; * GNU Compiler Collection (GCC): Suite of compilers for several programming languages; * GNU Binutils: Suite of tools including linker, assembler and other tools; * GNU Bison: Parser generator * GNU m4: m4 macro processor * GNU Debugger (GDB): Code debugging tool; * GNU build system (autotools): o Autoconf o Autoheader o Automake o Libtool 参考 http:/ 本文来自 CSDN 博客,转载请标明出处:http:/