1、添加开发板内核对应的工具链的环境变量
mkdir /usr/local/arm
解压工具链
sudo tar -xvjf arm-linux-gcc-3.4.1.tar.bz2 -C /
sudo vim /etc/bash.bashrc
vim /etc/bash.bashrc
文件末尾添加
PATH=$PATH:/usr/local/arm/3.4.1/bin
完成后检验,看添加是否成功:
~$ arm-linux-gcc --version
arm-linux-gcc (GCC) 3.4.1
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
这样就可以用该工具链来编译开发板上运行的应用或者内核模块了
如 arm-linux-gcc -o button button.c
注:其实没必要那么复杂,只需解压工具链,找到工具链的路径,然后添加到环境变量里就可以了。并不是一定要解压到/usr/local/arm下
2、编译内核树,也就是编译内核
注意:
1、使用 3.4.1 的交叉编译器
2、一定先将 utulinuxfor2440V1.5 目录下的 mkimage 文件拷贝到 PC 端 linux 的/usr/bin 下,
否则编译 utu-linux 内核时,make uImage 会出现错误! !
这应该是该开发板上的缺陷吧。不管它,照做。
cd /utuLinux/s3c2440/utu-linux_for_s3c2440_V1.5.3
make menuconfig
选择进入“Load an Alternate Configuration File”配置栏:
回车后填写 config_480272_ts的配置文件
ok ,然后exit并保存设置
make uImage
映像文件产生在内核源码包目录下的"arch/arm/boot",生成的有uImage。
3、编写内核模块hello.c和Makefile
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_INFO " Hello World enter\n");
printk(KERN_EMERG " ggggggggggg\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_INFO " Hello World exit....\n ");
printk(KERN_EMERG " kkkkk....\n ");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("Song Baohua");
MODULE_DESCRIPTION("A simple Hello World Module");
MODULE_ALIAS("a simplest module");
2.6内核模块的Makefile的编写与2.4内核的有较大差别,也相对简单
如:
ifneq ($(KERNELRELEASE),)
obj-m := hello.o //与文件名对应
else
KERNELDIR := /home/mxzh/opt2/utuLinuxfor2440V1.5.3/utu-linux_for_s3c2440_V1.5.3 //红色部分为板子的内核源码存放的目录
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
rm *.o *.ko
如是别的Makefile,只需修改红色部分即可。cd到hello.c所在的目录,然后make即可
mxzh@mxzh:~/opt2/linuxdriver_code/linuxdriver_code_tool/04/最简单的内核模块$ make
注:对于编译过程中类似 :不能创建hello.o.tmp文件的错误。说明权限不够,可设当更改hello.c Makefile文件所在目录的属性,或者是sudo到根用户
编译过程如下:
make -C /home/mxzh/opt2/utuLinuxfor2440V1.5.3/utu-linux_for_s3c2440_V1.5.3 M=/home/mxzh/opt2/linuxdriver_code/linuxdriver_code_tool/04/最简单的内核模块 modules
make[1]: Entering directory `/home/mxzh/opt2/utuLinuxfor2440V1.5.3/utu-linux_for_s3c2440_V1.5.3'
CC [M] /home/mxzh/opt2/linuxdriver_code/linuxdriver_code_tool/04/最简单的内核模块/hello.o
Building modules, stage 2.
MODPOST
CC /home/mxzh/opt2/linuxdriver_code/linuxdriver_code_tool/04/最简单的内核模块/hello.mod.o
LD [M] /home/mxzh/opt2/linuxdriver_code/linuxdriver_code_tool/04/最简单的内核模块/hello.ko
make[1]: Leaving directory `/home/mxzh/opt2/utuLinuxfor2440V1.5.3/utu-linux_for_s3c2440_V1.5.3'
至于怎样调用工具链,調哪个工具链,由内核源码指定了(编译内核源码时?呵呵),我们就不必理会关心了,自动完成的。具体过程可用可用make -n -C
/home/mxzh/opt2/utuLinuxfor2440V1.5.3/utu-linux_for_s3c2440_V1.5.3
M=/home/mxzh/opt2/linuxdriver_code/linuxdriver_code_tool/04/最简单的内核模块
modules 查看
4、测试:
cp hello.ko /nfsroot/rootfs //通过nfs挂载板子的文件系统
/ $ insmod hello.ko
Hello World enter
ggggggggggg
/ $ rmmod hello.o
Hello World exit....
<0> kkkkk....
一个改进后编译内核模块的方法:
首先
编译内核树时 在顶层的Makefile修改
ARCH ?=
CROSS_COMPILE ?=
修改为:
ARCH = arm
CROSS_COMPILE = /usr/local/arm/3.4.1/bin/arm-linux-
编译内核模块模块时的Makefile如下:
KERNELDIR = /home/mxzh/opt/utu-linux_for_s3c2440_V1.5.1
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)
INSTALLDIR = /nfsroot/rootfs/driver_test
CROSS_COMPILE =/usr/local/arm/3.4.1/bin/arm-linux-
CC = $(CROSS_COMPILE)gcc
obj-m := utu2440_buttons2.o
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
install:
cp utu2440_buttons2.ko $(INSTALLDIR)
clean:
rm -rf *.o *.ko *~ core .depend *.mod.c .*.cmd .tmp_versions .*.o.d
.PHONY: modules install clean
这样编译的时候就内核树和内核模块时不一定要把工具链的路径添加到环境变量了,只需在Makefile指定内核源码的地址和交叉工具链的绝对路径就可以了
一个Makefile的解析如下:
对于Makefile,其中建议为(将上面的改成):
ifneq ($(KERNELRELEASE),)
obj-m := mytest.o
mytest-objs := file1.o file2.o file3.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
endif
解释为:
KERNELRELEASE
是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义,
所以make将读取执行else之后的内容。如果make的目标是clean,直接执行clean操作,然后结束。当make的目标为all时,-C
$(KDIR) 指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD)
表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去
解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句,
指明模块源码中各文件的依赖关系,以及要生成的目标模块名。mytest-objs := file1.o file2.o
file3.o表示mytest.o 由file1.o,file2.o与file3.o 连接生成。obj-m :=
mytest.o表示编译连接后将生成mytest.o模块。
另外转载:
发现自己以前写的2.4的模块无法在2.6下面编译使用了,需要用新的Makefile才行。简单的说就像这个样子:obj-m := mytest.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
就可以了,模块的名称是mytest,最后编译出来是mytest.ko,剩下的系统搞定。当然这里有一些隐含规则了,就是mytest.o由
mytest.c或者mytest.S编译出来。如果模块是由多个源文件搞定的,那么建议去参考
~linuxsrc/Documentation/kbuild/下的一些文档。
--- add on 2005年11月16日 ---
如果是多个源文件编译出一个模块,那么假设模块名是mytest.ko,那么源文件名不能有mytest.c,下面是一个例子:
obj-m := mytest.o
mytest-objs := file1.o file2.o file3.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
这里比较奇怪的是makefile里面没有用SUBDIRS=,而是用了M=
--- end of add on 2005年11月16日 ---
--- add on 2006年5月20日 ---
关于前面的makefile当中用M=代替SUBDIR=,效果是一样的,但是M=更明确,参见《从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响》http://www-128.ibm.com/developerworks/cn/linux/l-module26/
对于Makefile,其中建议为(将上面的改成):
ifneq ($(KERNELRELEASE),)
obj-m := mytest.o
mytest-objs := file1.o file2.o file3.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
endif
解释为:
KERNELRELEASE
是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义,
所以make将读取执行else之后的内容。如果make的目标是clean,直接执行clean操作,然后结束。当make的目标为all时,-C
$(KDIR) 指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD)
表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去
解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句,
指明模块源码中各文件的依赖关系,以及要生成的目标模块名。mytest-objs := file1.o file2.o
file3.o表示mytest.o 由file1.o,file2.o与file3.o 连接生成。obj-m :=
mytest.o表示编译连接后将生成mytest.o模块。
--- end of add on 2006年5月20日 ---
另外,编译完内核以后用make INSTALL_MOD_PATH=/pathyouwant modules_install可以把内核模块装到指定目录
阅读(824) | 评论(0) | 转发(0) |