内核源码树的构建1





xuxinyl的专栏
目录视图摘要视图订阅
 linux驱动学习:1.内核树的建立
标签: linuxmodulemakefilesun终端2010
2011-11-21 14:10 3534人阅读 评论(0) 收藏 举报
 分类:  linux编程(15)  
 首先,为什么要建立内核树呢?因为我们知道驱动可以编译进内核进行执行,也可以以模块的方式加载到内核里进行执行。编写驱动程序在2.6版本的内核与 2.4版本的内核有所不同,2.4版本的内核只需要有一套内核头文件就够了,而2.6的内核的模块则要和内核源代码树中的目标文件相连接,这样,就需要一个建立一个内核树,来提供上面这些目标文件。所以首先我们要建立一个内核源代码树,而这个内核源代码树的建立有两种方式:一,直接用发行版的内核源代码包建立(也就是你装的Linux 系统);二,用www.kernel.org上下的纯净版内核构造,这里选择第二种方式。因为,发行版厂商提供的内核源代码包通常打了许多补丁,从而和你从 www.kernel.org上下的内核存在很大的差异。在某些情况下,有可能厂商的补丁会修改设备驱动程序使用的内核API。而我们最终要一直 Linux系统到开发板上去,我们不会去移植发行版提供的内核,我们只会移植从www.kernel.org下的内核,所以不论是从学习的角度,还是从以后移植Linux的角度,我们都选择第二种办法。好了,废话少说,下面开始叙述建立内核树的详细过程。
       首先,用uname -r 查看当前运行内核的版本:
[root@localhost ~]# uname -r
2.6.18-53.el5
[root@localhost ~]# 
        然后,从www.kernel.org上下一个和你当前运行版本一样的内核,这里可以看到我当前运行的内核版本是2.6.18-53.el5,好,那我就下一个2.16.18.x的版本(必须有和当前运行的版本有同样的版本号,否则在加载模块时候insmod: error inserting '***.o'  :-l invalid module format这样的错误)。
        下下来之后放在一个目录下,我存放的目录为:
[root@localhost linux]# pwd
/home/linux
         解压:
[root@localhost linux]# tar xvzf linux-2.6.18.tar.gz 
解压完之后会生成linux-2.6.18目录。进入这个目录:
[root@localhost linux]# cd linux-2.6.18
拷贝当前系统的.config文件到这个目录下:
[root@localhost linux-2.6.18]# cp /usr/src/kernels/2.6.18-53.el5-i686/.config ./(ubantu版本下在/boot/config-2.6.32-28-generic-pae)
运行makemenuconfig
[root@localhost linux-2.6.18]# make menuconfig


学习Linux驱动第一步:内核树的建立
学习Linux驱动第一步:内核树的建立


去掉上图中的*
保存退出。(用ESC键退出,Y保存)
执行make
[root@localhost linux-2.6.18]# make
时间一个多小时,可以去看电影去了。
[root@localhost linux-2.6.18]# make bzImage(此处i要大写,编译压缩形式的内核)
[root@localhost linux-2.6.18]# make modules    (编译选择的模块) 
[root@localhost linux-2.6.18]# make  modules_install  (将编译后的模块转移到系统标准位置,模块在系统中的标准目录位于/lib/modules/x.y.z,后面的x.y.z是版本号,为安全起见,在运行#make modules-install之前最好对/lib/modules进行备份。模块通常是带有扩展名.o的文件,使用命令#lsmod可以对当前内核的模块进行列表。 )
可以看到在
[root@localhost code]# cd /lib/modules/
生成了2.6.18目录
[root@localhost modules]# ls
2.6.18  2.6.18-53.el5  2.6.18.8
下面编写一个hello模块
[root@localhost code]# gedit hello.c




view plaincopy to clipboard
#include <linux/init.h>       
#include <linux/module.h>       
MODULE_LICENSE("Dual BSD/GPL");      
static int hello_init(void)      
{      
printk(KERN_EMERG "Hello, li wei meng/n");      
return 0;      
}      
static void hello_exit(void)      
{      
printk(KERN_EMERG"Goodbye, li wei meng/n");      
}      
module_init(hello_init);      
module_exit(hello_exit);       
[cpp] view plain copy
#include <linux/init.h>      
#include <linux/module.h>      
MODULE_LICENSE("Dual BSD/GPL");      
static int hello_init(void)      
{      
printk(KERN_EMERG "Hello, li wei meng/n");      
return 0;      
}      
static void hello_exit(void)      
{      
printk(KERN_EMERG"Goodbye, li wei meng/n");      
}      
module_init(hello_init);      
module_exit(hello_exit);       




这个模块什么也不干,只是在模块加载时打印一条信息,卸载时也打印一条信息。麻雀虽小,但五脏具全,MODULE_LICENSE()指明认证方式,现在支持的有:“GPL” “GPL v2" "GPL and additional rights" "Dual BSD/GPL" "Dual MIT/GPL" "Dual MPL/GPL" "Proprietary",这是内核2.6里新添加的,实验发现它不是必需的。module_init()指明模块的入口,这是必需的;module_exit()指明模块的出口,这也是必需的。


 


同时编写Makefile,在同一目录下:
[root@localhost code]# gedit Makefile


view plaincopy to clipboard
ifneq ($(KERNELRELEASE),)    
obj-m := hello.o    
else    
    KDIR := /lib/modules/2.6.18/build    
all:    
    make -C $(KDIR) M=$(PWD) modules    
clean:    
    rm -f *.ko *.o *.mod.o *.mod.c *.symvers    
endif    
[cpp] view plain copy
ifneq ($(KERNELRELEASE),)    
obj-m := hello.o    
else    
    KDIR := /lib/modules/2.6.18/build    
all:    
    make -C $(KDIR) M=$(PWD) modules    
clean:    
    rm -f *.ko *.o *.mod.o *.mod.c *.symvers    
endif    






其中KDIR指明了引用头文件的位置,请根据具体情况修改该文件。不过有几点要说明,模块的编译需要有一个内核源码的目录结构,如果有内核源码当然更好,直接把KDIR改为源码的路径就OK了。当然只有一个内核目录结构也就可以了,毕竟需要的只是头文件,及一些编译脚本,在Linux各发行版的/usr/src/下是有这样一个目录结构的,比如我的系统为Ubuntu9.10,内核为2.6.31-19的通用版,在 /usr/src/下就有linux-headers-2.6.31-19-generic这样一个目录。所以我使用KDIR=/usr/src /linux-headers-2.6.31-19-generic。其实还有一个目录名为linux-headers-2.6.31-19,而且你会发现linux-headers-2.6.31-19-generic里的大部分文件只是指向linux-headers-2.6.31-19的一些链接,不过linux-headers-2.6.31-19里面默认缺少一些编译模块所需要的文件,不要使用它。
(切记:Makefile每个命令的第一个字符必须是制表符[tab]即KDIR,make,rm前不是四个空格空格开头而是一个[tab],不要想当然的随便认为只是个空格。否则会在编译是报出***missing seperater .stop. 的错误 )
执行make
[root@localhost code]# make
make -C /lib/modules/2.6.18/build M=/home/code modules
make[1]: Entering directory `/home/linux/linux-2.6.18'
  CC [M]  /home/code/hello.o
  Building modules, stage 2.
  MODPOST
  CC      /home/code/hello.mod.o
  LD [M]  /home/code/hello.ko
make[1]: Leaving directory `/home/linux/linux-2.6.18'执行insmod




[root@localhost code]# insmod hello.ko 
[root@localhost code]# 
Message from syslogd@ at Sun May 23 21:02:30 2010 ...
localhost kernel: Hello, li wei meng
 使用 insmod ./hello.ko来加载模块,如果你遇到insmod: error inserting 'hello.o'  :-l invalid module format这样的错误,不用惊慌,并不是你的模块有问题,而是你当前运行的内核版本与你编译链接的头文件版本不一致,所以会出现格式不对的问题。此时,你可以更换系统内核,也可以下载一个与系统版本一致的内核源码重新编译该模块。如果你没有遇到任何问题,也没有打印出任何信息,那么恭喜你,你的内核加载成功了,你可以使用lsmod命令来罗列出当前你系统加载的所有模块,相信你在列表中会找到hello的。你可能会疑惑,为什么没有如我们想像中的那样,打印出"Hello, World"?呵呵,这是因为printk并不会把打印内容打印到你当面的终端,要知道模块是运行在内核态的,而你所能面对的是用户态,内核态的打印信息需要通过log或者dmesg命令来查看,想看到打印結果,最简单的方法是敲入dmesg命令,你就可以看到你所希望看到的信息了,同时,你也可以打开 /var/log/message这个文件进行查看。


 


执行rmmod
[root@localhost code]# rmmod hello.ko 
[root@localhost code]# 
Message from syslogd@ at Sun May 23 21:02:46 2010 ...
localhost kernel: Goodbye, li wei meng


最后,使用rmmod hello来卸载模块,同样,使用dmesg可以看到打印出的"Goodbye, cruel world"。


 


 


附:


Linux 有许多功能是通过模块的方式,  在需要时才载入 kernel。 如此可使 kernel 较为精简,进而提高效率,以及保有较大的弹性。这些可动态加载的模块,通常是系统的设备驱动程序。加载模块采用 insmod 指令,其常用语法如下。


 insmod [-fkmpsvxX] [-o<模块名称>] [模块文件]
 其中的参数解释如下。
  -f:不检查目前 kernel 版本与模块编译时的 kernel 版本是否一致,强制将模块载入。
  -k:将模块设置为自动卸载。
  -m:输出模块的载入信息。
  -p:测试模块是否能正确地载入 kernel。
  -s:将所有信息记录在系统记录文件中。
  -v:执行时显示详细的信息。
  -x:要汇出模块的外部符号。
  -X:汇出模块所有的外部符号,此为预设置。
  • rmmod(卸载模块)指令 
  Linux 把系统的许多功能编译成一个个单独的模块,待有需要时再分别加载它们,如果不再需要这些模块的时候,就可以使用 rmmod 命令来卸载这些模块。其语法如下。
  rmmod [-as] [模块名称...]
  其使用参数说明如下。
  -a:删除所有目前不需要的模块。
  -s:把信息输出至 syslog 常驻服务,而非终端机界面


 


 


附:参考文档http://blog.chinaunix.net/link.php?url=http://www.91linux.com%2Fhtml%2Farticle%2Fkernel%2F20071204%2F8805.html


                        http://www.huomo.cn/os/article-10f16.html


                        http://blog.csdn.net/liangkaiming/archive/2010/10/13/5937929.aspx



0

0
上一篇解除android 2.2 每小时只能发100条短信的限制(转)
下一篇make命令参数详解
我的同类文章
linux编程(15)
•make命令参数详解2011-11-22阅读5890
•linux中fork()函数详解(原创!!实例讲解)2011-07-06阅读891
•ubuntu安装JDK及环境变量的配置2011-06-21阅读2806
•linux PPP,PPPoE (翻译,整理)2011-06-10阅读2100
•linux下实现虚拟网卡TAP/TUN例子2011-05-30阅读5941
•Gedit快捷键2011-07-12阅读2210
•linux socket 通信编程2011-07-06阅读355
•C调用Linux内核的错误errno2011-06-15阅读468
•LINUX 虚拟网卡tun例子2011-05-30阅读6242
更多文章
主题推荐linux驱动内核
猜你在找
Android底层技术:Linux驱动框架与开发嵌入式Linux高级驱动教程(韦东山2期)“攒课”课题3:安卓编译与开发、Linux内核及驱动Linux操作系统及常用基础命令深入讲解Linux操作系统及常用命令实战和进阶
linux驱动学习之内核线程分析Linux驱动学习笔记二--kset内核对象集合LINUX驱动内核源码树构建linux驱动内核学习Linux驱动学习11内核中jiffies的回绕问题
查看评论


  暂无评论


发表评论
用 户 名:
heixiaolong7
评论内容:
插入代码


  
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
核心技术类目
全部主题 Hadoop AWS 移动游戏 Java Android iOS Swift 智能硬件 Docker OpenStack VPN Spark ERP IE10 Eclipse CRM JavaScript 数据库 Ubuntu NFC WAP jQuery BI HTML5 Spring Apache .NET API HTML SDK IIS Fedora XML LBS Unity Splashtop UML components Windows Mobile Rails QEMU KDE Cassandra CloudStack FTC coremail OPhone CouchBase 云计算 iOS6 Rackspace Web App SpringSide Maemo Compuware 大数据 aptech Perl Tornado Ruby Hibernate ThinkPHP HBase Pure Solr Angular Cloud Foundry Redis Scala Django Bootstrap
个人资料
 访问我的空间 
xuxinyl
 
访问:270919次
积分:3370
等级: 
排名:第5793名
原创:57篇转载:64篇译文:0篇评论:78条
文章搜索


文章分类
android 中间件开发学习笔记(11)
android 应用开发(17)
C/C++ Language(1)
linux编程(16)
网络编程(4)
JAVA Language(3)
视频(3)
android内核机制(1)
android系统开发(4)
文章存档
2014年05月(4)
2012年05月(1)
2012年04月(3)
2012年03月(1)
2011年12月(1)
展开
阅读排行
android NDK的android.mk文件的详解(21290)
正确配置安装和卸载Cygwin(12950)
android 弹出“应用程序×××无法响应”窗口的解析和解决方案(11679)
android 亮屏及屏幕解锁代码(10824)
android监听用户的拨打电话的状态(8755)
android GPS定位,基站定位,WIFI定位开关的控制(7924)
android NDK 交叉编译(7339)
LINUX 虚拟网卡tun例子(6244)
Android的/system/lib里加入自己的so库(6159)
linux下实现虚拟网卡TAP/TUN例子(5950)
评论排行
android监听用户的拨打电话的状态(23)
读取联系人列表(7)
android 亮屏及屏幕解锁代码(4)
android 弹出“应用程序×××无法响应”窗口的解析和解决方案(3)
实现Launcher3的立方滚动特效(3)
android数据存储(3)
LINUX 虚拟网卡tun例子(2)
android NDK的android.mk文件的详解(2)
android发送与接收超长短信(2)
android ContentProvider共享数据方法(2)
推荐文章
*Android自定义ViewGroup打造各种风格的SlidingMenu
* Android 6.0 运行时权限处理完全解析
* 数据库性能优化之SQL语句优化
*Animation动画详解(七)——ObjectAnimator基本使用
* Chromium网页URL加载过程分析
* JavaScript “跑马灯”抽奖活动代码解析与优化(一)
最新评论
实现Launcher3的立方滚动特效
chengtingfei: 完全是扯淡,不看下launcher3 viewpager的源码就扯呼
实现Launcher3的立方滚动特效
HelloKen: 我添加到Launcher3的PagedView里面不生效啊。。。
make命令参数详解
H100: 学习了
android 亮屏及屏幕解锁代码
baidu_18355515: 这种方法在没有屏幕锁的时候是可以的,一旦屏幕锁密码开启,则不能解锁,怎么办?
JNI的某些数组和字符串类型转换(转)
yaotang: 有几个变量是什么类型都没有给出来,看不懂,有些懂
android NDK的android.mk文件的详解
qq_20324851: 我想知道,Android.mk的文件在哪里可以找到
实现Launcher3的立方滚动特效
hefangchi: 好文章
android NDK的android.mk文件的详解
rainberda: 楼主给力
android的硬件按钮的长按和短按事件
gaogaf: 这个 1s 是在哪里定义的呢?
LINUX 虚拟网卡tun例子
KnowledgeSeekers: 你好,我想问一下,我现在创建了一个TUN接口,如果我更改了默认路由到这个tun设备上。。那之后所有的...
公司简介|招贤纳士|广告服务|银行汇款帐号|联系方式|版权声明|法律顾问|问题报告|合作伙伴|论坛反馈
网站客服杂志客服微博客服webmaster@csdn.net400-600-2320|北京创新乐知信息技术有限公司 版权所有|江苏乐知网络技术有限公司 提供商务支持
京 ICP 证 09002463 号|Copyright © 1999-2014, CSDN.NET, All Rights Reserved GongshangLogo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值