Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2295046
  • 博文数量: 218
  • 博客积分: 5767
  • 博客等级: 大校
  • 技术积分: 5883
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-01 14:44
文章存档

2012年(53)

2011年(131)

2009年(1)

2008年(33)

分类: LINUX

2008-03-01 19:16:23

1.将嵌入式开发包的内核的源代码安装在/usr/src下,文件名为:linux-2.6.14.7-dma2410.tar.gz(我开发上用的)是一个压缩包,解压缩既可以得到整个内核的源代码:

# tar jxvf  linux-2.6.14.7-dma2410.tar.gz

解压后生成一个新的目录/usr/src/linux-2.6.14.7,所有的源代码都在该目录下。

注:该目录会因内核版本的不同而不同,各位动手实践的朋友只需知道自己的源代码所在的具体位置即可。

2.配置及编译内核。

进入/usr/src/ linux-source-2.6.14.7目录下,可以看到Makefile文件,它包含了整个内核树编译信息。该文件最上面四行是关于内核版本的信息。对于整个Makefile可以不用做修改(跟我的编译环境一致),采用默认的就可以了。否则,按上述修改。

一般情况下,需要先用命令诸如"make menuconfig", "make xconfig"或者"make oldcofig"对内核进行配置,这几个都是对内核进行配置的命令,只是它们运行的环境不一样,执行一下这几个命令中的任何一个即可对内核进行配置:

Loadable module support (可加载模块选项)
其选项如下:

[*] Enable loadable module support
这个选项可以让你的内核支持模块,模块是什么呢?模块是一小段代码,编译后可在系统内核运行时动态的加入内核,从而为内核增加一些特性或是对某种硬件进行支持。一般一些不常用到的驱动或特性可以编译为模块以减少内核的体积。在运行时可以使用modprobe命令来加载它到内核中去(在不需要时还可以移除它)

一些特性是否编译为模块的原则是,不常使用的,特别是在系统启动时不需要的驱动可以将其编译为模块,如果是一些在系统启动时就要用到的驱动比如说文件系统,系统总线的支持就不要编为模块了,否在无法启动系统。(当然还有一些变通的方法,我以后会提到)
[ *] Module unloading
这个选项可以让你卸载不再使用的模块,如果不选的话你将不能卸载任何模块(有些模块一旦加载就不能卸载,不管是否选择了这个选项)。不选择这个选项会让你的内核体积减小一点

[ ] Module versioning support (EXPERIMENTAL)
这个选项将让你可以使用其它版本内核中编译的模块,不过并不可靠,所以一般我们不选择它

[*] Automatic kernel module loading
一般情况下,如果我们的内核在某些任务中要使用一些被编译为模块的驱动或特性时,我们要先使用modprobe命令来加载它,内核才能使用。不过,如果你选择了这个选项,在内核需要一些模块时它可以自动调用modprobe命令来加载需要的模块,这是个很棒的特性,当然要选Y喽:
)
Kernel Feautre -> Preemptible Kernel

[*]

注:该项为内核抢占式调度设置, 必须保证在构建运行的内核与编译环境的内核时都选上,一般PC机运行的内核已经选上了,否则在insmod时将出现如下错误:

# insmod st7565p_driver26.ko
Using st7565p_driver26.ko
st7565p_driver26: version magic '2.6.14.7 ARMv4 gcc-3.4' should be '2.6.14.7 preempt ARMv4
gcc-3.4'
insmod: cannot insert `st7565p_driver26.ko': Invalid module format (-1): Exec format error

 

在内核源码的目录下执行:

# make

# make bzImage

其中,第一个make也可以不执行,直接make bzImage。这个过程可能要持续一个小时左右,因此是对整个内核重新编译了。执行结束后,可以看到在当前目录下生成了一个新的文件: vmlinux, 其属性为-rwxr-xr-x

然后执行:

# touch *  // 时间或时区设置,源代码的时间戳比本机的时间更新,否则产生:make[2]: 警告:检测到时钟错误。您的创建可能是不完整的。

# make modules   对内核的所有模块进行编译

# make modules_install  对内核的所有模块进行和安装

执行结束之后,会在/lib/modules下生成新的目录/lib/modules/2.6.14.7 在随后的编译模块文件时,要用到这个路径下的build目录。至此,内核编译完成。

目录“/usr/src/2.6.14.7中就是所谓的内核代码树但是“/lib/modules/2.6.14.7/build”是个符号链接,也指向这个目录,所以这里也可以叫做内核代码树

可以重启一下系统。

3.编写模块文件及Makefile

也以LDD3上的hello.c为例:

#include

#include

#include

MODULE_LICENSE("Dual BSD/GPL");

 static int hello_init(void)

{

printk("hello,world.\n");

return 0;

}

 

static void hello_exit(void)

{

printk("Good bye!\n");

 

}

 

module_init(hello_init);

module_exit(hello_exit);

 

Makefile文件的内容为:

obj-m := hello.o

#KERNELDIR:=/lib/modules/$(shell uname -r)/build

KERNELDIR:=/lib/modules/2.6.14.7/build  //注意与上面的不同

 

PWD:=$(shell pwd)

 

all:

       make -C $(KERNELDIR) M=$(PWD) modules

 

clean:

       rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

#     make -C $(KERNELDIR) M=$(PWD) clean

上面的Makefile是这样确定内核源码树所在的目录的: 我们先到/lib/modules目录, 会看到一些以内核版本为名的目录, 目录中有一个build文件, 它是一个符号连接, 指向内核源码树.

上面的例子中只讨论了所有的代码在一个文件中的情况. 若代码分布在多个源文件中比如file1.c, file2.c, 生成hello.ko. 应该这样写Makefile:
obj-m :=  hello.o
hello-objs := file1.o file2.o
注意, 虽然我们的目的是生成.ko文件, 但在Makefile中写为.o!

hello.cMakefile文件应该位于同一个目录下,可以放在/home下。

4:编译和装载模块

在文件所处的目录下,执行:

# make
然后查看该目录下有哪些文件生成:可见,已经生成模块文件hello.ko.

然后,下载该文件到开发板,就可以加载该模块:

运行命令:

# insmod hello.ko

应该可以看到返回的信息:Hello, world
然后再运行命令:

# rmmod hello

应该可以看到返回的信息:Goodbye

 

以上讲的是在在源码树之外编译模块,那么在源码树中呢?

在源码树中编译模块

 

官方内核模块的源代码都是按模块(驱动)类型组织的, 我们到内核源码树的drivers目录可以看到char, usb, block之类的子目录. 那么我们在内核源码树中添加文件时, 最好也遵循这些分类. 分类的规则自己灵活把握.

下面以前面的"hello, world"这个简单的模块为例, 来看看如何在内核源码树中编译模块
.

1,
不新建子目录

(1)
先在内核源码树中的drivers目录编辑一个c源程序, 名为hello.c.
(2)
修改drivers目录的Makefile文件, 添加
: obj-m += hello.o
(3)
重新编译内核(回到源码树根目录, 运行
$ make).

这样, drivers目录多出了这样几个文件: hello.mod.c, hello.mod.o, hello.o, hello.ko. hello.ko就是编译出来的模块了
.

2,
新建子目录

如果源文件比较多, 可以在drivers目录中新建子目录. 还是以hello, world为例:
(1)
在内核源码树的drivers目录中新建一个hello子目录, 并将hello.c放在hello目录中
.
(2)
修改drivers目录的Makefile文件, 添加
: obj-m += hello/
(3)
hello目录中新建一个Makefile文件, 内容为
: obj-m += hello.o
(4)
重新编译内核(回到源码树根目录, 运行
$ make).

这样, 新生成的模块文件就位于hello目录中.

阅读(1757) | 评论(3) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2011-03-21 13:57:51

你好,你能帮我解决一下我的问题吗? 1,Loadable module support 在哪呢?我执行make menuconfig后,找不到Loadable module support 2,我是这样做的,能帮我看看问题出在哪吗? 1,我先把开发包中自带的linux镜像装到s3c2440上,并且能实现一个简单的应用程序。 2,编译简单的hello驱动模块,s3c2440的内核是2.6.31,主机上用的是ubuntu10.04,交叉编译器是 arm-linux4.1.2 我先把开发包中的内核源码包linux-2.6.31_TX2440A20100612.tar.bz2和它的补丁linux-2.6.31_TX2440A201000612.patch下载到我的一个目录下,解压linux-2.6.31_TX2440A20100612.tar.bz2,然后进入到解压后的linux-2.6.31_TX2440A目录,打上补丁 patch -p1 < /home/cao/tx2440a/linux-2.6.31_TX2440A201000612.patch,出现了下面的一些

chinaunix网友2008-04-23 20:20:02

你如果按我上述方法做的话,那么你只要修改一下linux-2.6.14.7中的Makefile的CROSS_COMPILE = /usr/local/arm/3.4.1/bin/arm-linux-就可以了,之后在写驱动时按我上述Makefile的写法,就是使用arm-linux-gcc编译器

chinaunix网友2008-04-20 00:08:33

你好,我最近刚接触linux驱动移植,试了好长时间才把“hello world”移成功,但一直有个疑问:在make时到底是调用的哪个编译器?gcc还是arm-linux-gcc?我尝试通过在Makefile中加“CC = arm-linux-gcc”,但在最后查看内核信息时还是显示所用编译器为gcc!