admin 管理员组

文章数量: 1086019


2024年6月7日发(作者:unicode 解码)

嵌入式Linux内核模块的配置与编译

一、简介

随着 Linux操作系统在嵌入式领域的快速发展,越来越多的人开始投身到

这方面的开发中来。但是,面对庞大的Linux内核源代码,开发者如何开始自己

的开发工作,在完成自己的代码后,该如何编译测试,以及如何将自己的代码编

译进内核中,所有的这些问题都直接和Linux的驱动的编译以及Linux的内核配

置系统相关。

内核模块是一些在操作系统内核需要时载入和执行的代码,它们扩展了操作

系统内核的功能却不需要重新启动系统,在不需要时可以被操作系统卸载,又节

约了系统的资源占用。设备驱动程序模块就是一种内核模块,它们可以用来让操

作系统正确识别和使用使用安装在系统上的硬件设备。

Linux内核是由分布在全球的Linux爱好者共同开发的,为了方便开发者修

改内核,Linux的内核采用了模块化的内核配置系统,从而保证内核扩展的简单

与方便。

本文通过一个简单的示例,首先介绍了如何在Linux下编译出一个内核模块,

然后介绍了Linux内核中的配置系统,讲述了如何将一个自定义的模块作为系统

源码的一部分编译出新的操作系统,注意,在这里我们介绍的内容均在内核

2.6.13.2(也是笔者的开发平台的版本)上编译运行通过,在2.6.*的版本上基

本上是可以通用的。

二、单独编译内核模块

首先,我们先来写一个最简单的内核模块:

#include

#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");

staticintrfmodule_init(void)

{

printk("hello,world:modele_init");

return 0;

}

static void rfmodule_exit(void)

{

printk("hello,world:modele_exit");

}

module_init (rfmodule_init);

module_exit (rfmodule_exit);

这个内核模块除了在载入和卸载的时候打印2条信息之外,没有任何其他功

能,不过,对于我们这个编译的例子来讲,已经足够了。

将上述源代码保存到一个test.c文件中,然后开始我们的内核模块的编译

工作。

内核模块的编译与普通应用程序的编译一样,也使用的GCC,但是内核模块

在用GCC编译的时候时需要使用特定的参数并定义一些宏。 这是因为在编译普

通应用程序的可执行文件和内核模块时,内核头文件起的作用是不同的。在以往

的内核版本需要我们去在Makefile中手动设置这些设定,虽然这些Makefile

都是按目录分层次存放的,但使用维护起来还是比较伏在。幸运的是,一种称为

kbuild的新方法被引入,现在外部的可加载内核模块的编译的方法已经同内核

编译统一起来,编译新的内核模块或者将自己的内核模块集成到内核源码中都已

经变得非常简单了。

现在让我们看一下如何编译一个名字叫做test.c的模块。

首先,我们需要写一个简单的Makefile文件:

obj-m += test.o

将test.c和Makefile文件放在同一个目录下,然后就可以开始编译了,使

用编译命令:

make -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将整个内核完整编译一次。

3、上述命令中的linux-2.6.13.2是笔者使用的内核源码的目录名,你需要

将它改成你自己使用对应版本的的内核源码的目录名。

经过上述三步,一般来将,该内核模块都可以编译通过了,生成的

就是我们需要的内核模块的最终版本,你可以使用:

insmod ./将该模块载入系统。

请注意:如果想将模块载入系统,请保证编译模块使用的内核源码的版本与

要载入的系统的版本一致!否则无法载入!

嵌入式开发实作(Linux内核编译及安装)

部分内容译自《Embedded Linux kernel and driver development 》by Michael Opdenacker

刘建文(/keminlau )

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 = 2

PATCHLEVEL = 6

SUBLEVEL = 7

EXTRAVERSION = -acme1

运行“uname --r”会返回: 2.6.7--acme1

2.内核配置

先定义内核需要什么特性,并进行配置。内核构建系统(The kernel build system)远不是简

单用来构建整个内核和模块,想了解更多的高级内核构建选项,你可以查看

Documentation/kbuild目录内的内核文档。

可用的配置命令和方式:

makexconfig

makemenuconfig

makeoldconfig

或者手动编写

内核编译的配置文件.config与内核配置的makefile?

内核配置文件(Makefile语法的)保存为内核源代码的顶层目录的.config文件。发行版的内

核配置文件通常在/boot/内。

命令:makexconfig

qconf: 全新的基于QT的配置接口,2.6版本内核

更易使用(切记阅读 help -> introduction: useful options!)

具有文件浏览功能,更易的加载配置文件

命令:makemenuconfig

老式字符界面,依然很管用。你够自信,完全可以手写配置文件!

命令:makeoldconfig

用于升级早期发布内核的配置文件

对一些绝对符号(obsolete symbols)发出警告

询问新符号的配置值

何为makefile?

makefile包含用以构建应用程序的一组规则集(set of rules)。并且第一条[规则 ]是特殊的[规

则 ],叫[默认规则 ](default rule)。一条[规则]由三部分组成:目标(target)、前提条件

(prerequisites)和命令动作(command):

target: prereq1 prereq2

commands

target: prereq1 prereq2

commands

target: prereq1 prereq2

commands

[目标]是被构建(made)的[文件 ]或其它东西。[前提条件 ]或者叫依赖(dependents)构建

目标的“材料”。而[命令动作]是利用[前提条件]构建[目标]的shell命令。

以下是编译C源码的规则例子:

foo.o: .h

lt;tab>gcc -c foo.c

foo.o: .h

lt;tab>gcc -c foo.c

foo.o: .h

gcc -c foo.c

注意格式,冒号前是[目标],后是[前提条件];[命令]在第二行,并且开始于一个tab字符。

编译内核

编译和安装内核

编译步骤:

$ cd /usr/src/linux2. 6

$ make

$ cd /usr/src/linux2.6

$ make

$ cd /usr/src/linux2.6

$ make

安装步骤 (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)

提升编译速度

多花一些时间在内核配置上,并且只编译那些你硬件需要的模块。这样可以把编译时间缩短

为原来的1/30,并且节省数百MB的空间。另外,你还可以并行编译多个文件:

$ make -j

make 可以并行执行多个目标(target)(KEMIN:前提是目标规则间没有交叉依赖项,这个怎

么做到的?)

$ make -j 4

即便是在单处理器的工作站上也会很快,读写文件的时间被节省下来了。多线程让CPU保

持忙碌。

number大于4不见得有效了,因为上下文切换过多反而降低的工作的速度。

make -j <4*number_of_processors>

内核编译tips

查看完整的 (gcc, ld)命令行: $ make V=1

清理所有的生成文件 (to ): $ make mrproper

部分编译:$ make M=drivers/usb/serial

单独模块编译:$ make drivers/usb/serial/

别处编译(假设源码在CDROM):

$ cd /mnt/cdrom/linux-2.6.17.11

$ make O=~/linux/linux-2.6.17.11

最终生成的文件

vmlinux原始内核镜像,非压缩的

arch//boot/zImagezlib压缩的内核镜像(Default image on arm)

arch//boot/bzImage bzip2压缩的内核镜像。通常很小,足够放入一张软盘(Default

image on i386)

安装的文件

/boot/vmlinuz-内核镜像;

/boot/-保存有内核的符号地址(symbol addresses);

/boot/initrd-.img Initial RAM disk:保存有你需要在引导时挂接最终根文件系统的模

块。安装命令“make install”为替你运行“mkinitrd”生成initrd;

/etc/ or /etc/

bootloader的配置文件:“make install”会为你的新内核更新相应的bootloader的配置文件。

如果你使用的是LILO,它会在生成配置文件后,执行/sbin/lilo,让LILO的配置生效。

/lib/modules// Kernel modules + extras

build/

为本的内核添加模块所需的所有东西: .config file (build/.config), module symbol

information (build/s), kernel headers (build/include/)

kernel/

内核模块文件 .ko (Kernel Object),目录结构与源代码目标一一对应。

模块别名记录(用于insmod和modprobe),例如:

alias sound--service--?-0 snd_mixer_oss

模块依赖记录(用于insmod和modprobe)

s

标识某符号是属于哪个模块的。

这个目录的所有文件都是文本文件,可以直接查看。

小结编译及安装步骤:

编辑Makefile版本信息

定义内核特性,生成配置文件.config,用于编译:makexconfig

编译内核:make

安装内核:make install

安装模块:makemodules_install

交叉编译内核

Makefile修改

通常通过修改已有的makefile获得

你必须修改目标平台,假设目标平台是ARM,修改以下:

ARCH ?= arm

CROSS_COMPILE ?= arm-linux-

ARCH ?= arm

CROSS_COMPILE ?= arm-linux-

ARCH ?= arm

CROSS_COMPILE ?= arm-linux-

或运行带参数的make:

$ cd /usr/scr/linuxXX

$ make ARCH=arm CROSS_COMPILE=arm-linux-

$ cd /usr/scr/linuxXX

$ make ARCH=arm CROSS_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系统的开发人员可以通过以下命令编译出同样的内核:

$ 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/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/ 自定义安装,让”make install“自动代劳。

何为交叉编译工具链(cross--compiling toolchain)?

有如任何其它开发活动一般,嵌入式开发的第一步是建立(setting up)用于构建嵌入式Linux

内核(当然包括驱动程序)及应用程序的工具链(toolchains)。不过,嵌入式开发需要是跨

平台工具链。跨平台是什么意思呢?一般开发活动是在本地编译,使用是本地的工具链;而

由于嵌入式的软硬资源(内存不足、没有本地编译器或操作系统都没有)限制等没法进行本

地开发。需要在Linux-x86 主机(HOST)开发,使用主机的编译器生成目标(TARGET)平台

代码,这个过程叫交叉编译。

我们常常说的编译器有广义和狭义之分。狭义的编译器只完软件编译(或者叫软件构建)的

第一步;广义的编译器包括了软件编译(或者叫软件构建)所需要代码库(比如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 may 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 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

applications 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):

oAutoconf

oAutoheader

oAutomake

oLibtool

参考

//2006/01/05/autotools-tutorial/

本文来自CSDN博客,转载请标明出处

/shijizhisheng/archive/2009/09/16/

把设备驱动程序编译进嵌入式linux内核

文章来源网络 属于linux分类 电脑编程网整理 2007107

简介:这是把设备驱动程序编译进嵌入式linux内核的详细页面,介绍了和linux,有关的知识,加入收藏

请按键盘ctrl+D,谢谢大家的观看!要查看更多有关信息,请点击此处

驱动程序的使用可以按照两种方式编译,一种是静态编译进内核,另一种是编译成模块以供动态加载。

由于uclinux不支持模块动态加载,而且嵌入式linux不能够象桌面linux那样灵活的使用insmod/rmmod加

载卸载设备驱动程序,因而这里只介绍将设备驱动程序静态编译进uclinux内核的方法。

下面以uclinux为例,介绍在一个以模块方式出现的驱动程序test.c基础之上,将其编译进内核的一

系列步骤:

(1) 改动test.c源带代码

第一步,将原来的:

#include

#include

char kernel_version[]=uts_release;

和 "把设备驱动程序编译进嵌入式linux内核" 有关的编程小帖士:

strong>session_encode

Session 资料编码。

语法: booleansession_encode(void);

返回值: 布尔值

内容说明

本函数可将 Session 资料编码,编码以 ZEND 引擎做哈稀编码。本函数没有参数。成功则返回 true 值。

改动为:

#ifdef module

#include

#include

char kernel_version[]=uts_release;

#else

#define mod_inc_use_count

#define mod_dec_use_count

#endif

第二步,新建函数intinit_test(void)

将设备注册写在此处:

result=register_chrdev(254,"test",&test_fops);

(2) 将test.c复制到/uclinux/linux/drivers/char目录下,并且在/uclinux/linux/drivers/char

目录下mem.c中,intchr_dev_init( )函数中增加如下代码:

#ifdefconfig_testdrive

init_test();

#endif

(3) 在/uclinux/cinux/drivers/char目录下makefile中增加如下代码:

ifeq($(config_testdrive),y)

l_objs+=test.o

endif

(4) 在/uclinux/linux/arch/m68knommu目录下中字符设备段里增加如下代码:

bool 'support for testdrive' config_testdrive y

(5) 运行make menuconfig(在menuconfig的字符设备选项里你可以看见我们刚刚添加的'support

for testdrive'选项,并且已经被选中);make dep;make linux;make ;make ;

>.

(6) 在 /uclinux/romdisk/romdisk/dev/目录下创建设备:

mknod test c 254 0

并且在/uclinux/appsrc/下运行make,生成新的romdisk.s19文件。

到这里,在uclinux中增加设备驱动程序的工作可以说是完成了,只要将新的与romdisk.s19

烧入目标板中,你就可以使用自己的新设备test了。

用命令行加挂linux的文件系统简介

linux中mount其他文件系统


本文标签: 内核 编译 使用 模块 配置