Linux驱动静态编译和动态编译方法详解


内核源码树的目录下都有两个文档Kconfig和Makefile。分布到各目录的Kconfig构成了一个分布式的内核配置数据库,每个Kconfig分别描述了所属目录源文档相关的内核配置菜单。在内核配置make menuconfig时,从Kconfig中读出菜单,用户选择后保存到.config的内核配置文档中。在内核编译时,主Makefile调用这个.config,就知道了用户的选择。

上面的内容说明了,Kconfig就是对应着内核的配置菜单。假如要想添加新的驱动到内核的源码中,能够修改Kconfig,这样就能够选择这个驱动,假如想使这个驱动被编译,要修改Makefile。所以,添加新的驱动时需要修改的文档有两种(注意不只是两个)*Kconfig,*Makefile

.config是make menuconfig【配置后生成的一个配置文件,也就是说可以拷贝一个别人配置好的.config来使用,内核中不同开发板也自带了一些配置文件在arch/arm/config/目录下面有很多配置文件可以选择和自己单板相似。

第一种方法:

利用内核自身的Makefile特性来编译我们的驱动程序,下面由一个简单的hello.c驱动程序来说明。

在/drivers/char/目录下写hello.c  修改Makefile,Kconfig

hello.c内容:
#include <Linux/init.h>           /* 初始化模块所用到的头文件 */
#include <linux/module.h>   /* KERN_ALERT用到的 头文件*/

static int hello_init(void)      /* 入口函数,加载驱动程序所调用的函数 */

{
        printk(KERN_ALERT"Hello, world\n");
        return 0;
}


static void hello_exit(void)     /* 出口函数 ,卸载驱动程序所调用的函数 */
{

        printk(KERN_ALERT"Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("Dual BSD/GPL");   /* 通用的协议 */

MODULE_AUTHOR("wangluoren");     /* 作者 */

MODULE_DESCRIPTION("A simple hello world module");   /* 程序描述 */

MODULE_ALIAS("A simplest module");             /* 别名 */


Kconfig内容:
config HELLO           /* Makefile中编译可变选项中宏的名字,作用就是定义一个可以选择的变量 */
tristate "Hello Driver added by Dong"        /* make menuconfig 菜单界面显示的信息,tristate 提供Y M N三种选项 */
default n           /* 菜单选项默认为N */
help
   test for adding driver to menuconfig.     /* 一些帮助信息,写不写没有关系 */


MakeFile内容: 
obj-$(CONFIG_HELLO) += hello.o     /*CONFIG_HELLO我们在Kconfig中区定义它,我们用 HELLO ,hello是文件名字*/

到此为止我们就写好了这个hello的驱动程序,然后我们可以make menuconfig 在

Device Drivers  --->

 Character devices  --->

< > Hello Driver added by Dong   /* 可以按空格选择Y M N ,来分别 编译进内核,模块,不编译*/

如果是直接编译进内核就可以执行make uImage ,如果是编译成模块就执行make modules.


上面我们采用的是静态编译方法看起来是那么的麻烦,当我们写驱动程序的时候如果采用这种方法的话那就够折腾了,我估计你调试一个驱动程序你都得折腾大半天,这种方法是我们确定我们驱动程序没有问题后在编译进内核。

第二种方法:

一般我们采用动态编译来写驱动程序,具体方法如下:

还是拿hello.c程序为例:

hello.c内容:
#include <linux/init.h>           /* 初始化模块所用到的头文件 */
#include <linux/module.h>   /* KERN_ALERT用到的 头文件*/

static int hello_init(void)      /* 入口函数,加载驱动程序所调用的函数 */

{
        printk(KERN_ALERT"Hello, world\n");
        return 0;
}


static void hello_exit(void)     /* 出口函数 ,卸载驱动程序所调用的函数 */
{

        printk(KERN_ALERT"Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("Dual BSD/GPL");   /* 通用的协议 */

MODULE_AUTHOR("wangluoren");     /* 作者 */

MODULE_DESCRIPTION("A simple hello world module");   /* 程序描述 */

MODULE_ALIAS("A simplest module");             /* 别名 */


Makefile文件编写如下:(和hello.c放在同一层目录就OK)

KERN_DIR = /home/book/workspace/kernel/linux-3.4.2_jz2440   /* 虚拟机kernel的路径,每个人不一样 */

all:
        make -C $(KERN_DIR) M=`pwd` modules   /* -C 表示进入后面KERN_DIR这个目录把当前路径的hello.c编译成模块*/

clean:
        make -C $(KERN_DIR) M=`pwd` modules clean  /* 一些清除工作,清除中间生成的中间文件 */
        rm -rf modules.order
obj-m   += hello.o                        /* 编译,这里要注意这个hello是你要编译的程序的文件名字 */ 


上面两种方法编译完成后都会生成一个hello.ko的文件,我们把这个文件复制到开发板的目录下面,执行如下命令      insmod hello.ko  就会打印:Hello, world

rmmod hello    就会打印  Goodbye, cruel world  (这个是一一对应的,加载一次只能卸载一次,不能重复加载)


补充一:

动态加载补充一点:如果我要用一个Makefile同时编译多个文件该怎么办呢?(这个文件的一个函数在另外一个文件当中定义,我们可以采取如下方法)方法如下:

有来个驱动文件:hello.c  hello1.c

我们可以把上面Makefile中obj-m +=hello.o改成如下命令就可以了

obj-m :=led.o
module-objs :=hello.o hello1.o   /* 这时候生成的 驱动文件就是led.ko */


补充二:

如果同时又两个驱动程序都需要编译(两者之间没有任何联系的,就是共同用kernel来编译自己的驱动)

比如有两个文件:hello1.c  hello2.c 

我们可以在同一个Makefile中这样来编写:

obj-m+=hello1.o
obj-m += hello2.o    (注意这个:=已经变成+=,这两者的区别这里就不说明了)


补充三:

上面静态编译驱动我们采用的是在/drivers/char目录下面添加一个文件,我们也可以在/drivers目录下面添加一个文件夹,下面我们讲讲具体的怎么来实现。

我们在/drivers目录下面添加一个hello的文件夹,里面创建一个hello.c,Kconfig,Makefile,这个三个文件和静态编译添加一个文件是完全相同的,主要是更改的是/drivers目录下的Makefile和Kconfig文件。

Makefile中添加如下命令:

obj-$(CONFIG_HELLO) += hello/        /* CONFIG_HELLO这个宏定义在hello目录里面的Kconfig中,‘/’表示进入这个目录,调用子目录Makefile来编译子目录中的文件 */

Kconfig添加如下命令:

source "drivers/hello/Kconfig"     /* 把Kconfig导出到子菜单界面 */

然后执行make modules   就在drivers/hello目录下面生成了一个hello.ko的文件

现在这个驱动编译的全部用法基本讲解完毕,有了这些知识你自己都可以去分析内核的结构,从顶层Makefile开始分析,子目录下的Makefile想对简单的多,顶层Makefile是比较难的,顶层Makefile讲解在这篇文章中,请点击这里!


上面讲解了一些基础的知识,这些知识对一个驱动开发成员已经足够了,如果你是工作在内核空间,那你就应该深入分析这些结构的原理,比如怎么添加递归创建子目录,通配符,正则表达式等,你都需要去深入了解。希望我这篇文章能给驱动开发者带来帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252925.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux学习-11月12日(Apache安装)

2019独角兽企业重金招聘Python工程师标准>>> 11.6 MariaDB安装 11.7/11.8/11.9 Apache安装 扩展 apache dso https://yq.aliyun.com/articles/6298 apache apxs https://wizardforcel.gitbooks.io/apache-doc/content/51.html apache工作模式 https://blog.csdn.…

11. sql DDL

SQL分为5大类&#xff1a; DDL:数据定义语言 DCL:数据控制语言 DML:数据操纵语言 DTL:数据事务语言 DQL:数据查询语言 1、DDL(data definition language):create,drop,alter,rename to 数据类型 ①、数字类型&#xff0c;可以数学运算 number&#xff08;4&#xff09;代表整数…

[bzoj2243][SDOI2011]染色

来自FallDream 的博客&#xff0c;未经允许&#xff0c;请勿转载&#xff0c;谢谢qaq 给定一棵有n个节点的无根树和m个操作&#xff0c;操作有2类&#xff1a; 1、将节点a到节点b路径上所有点都染成颜色c&#xff1b; 2、询问节点a到节点b路径上的颜色段数量&#xff08;连续相…

Linux学习笔记——例说makefile 增加宏定义

从学习C语言开始就慢慢开始接触makefile&#xff0c;查阅了很多的makefile的资料但总感觉没有真正掌握makefile&#xff0c;如果自己动手写一个makefile总觉得非常吃力。所以特意借助博客总结makefile的相关知识&#xff0c;通过例子说明makefile的具体用法。 例说makefile…

Android基本组件是什么?

1、ImageView继承View组件,不单单用于显示图片,用 XML代码 编写的Drawable也可以显示出来。其中的XML属性 android:scaleType(设置图片如何缩放或移动以适应ImageView的大小) 有很多的属性值,如:matrix(使用矩形方式进行缩放)fitXY(对图片横向纵向缩放)center(图片放在ImageVie…

Java 运算符及优先级

运算符 分割符&#xff1a;  ,  ;  []  ()算数运算符&#xff1a;    -  *  /  %    --关系运算符&#xff1a;  >  <  >  <    !逻辑运算符&#xff1a;  !  &  |  ^  &&  ||赋值运算符&#xff1a; …

array sort - 2 : quick sort

递归实现&#xff1a; #include <stdio.h>int arr[10] {3, 2, 4, 1, 9, 7, 5, 6, 0, 8};void print_array(){ int i 0; for (i 0; i < 10; i) printf("arr[%d]:%d ", i, arr[i]); printf("\n");}void swap(int *i, int *j){ …

Linux C 读取文件夹下所有文件(包括子文件夹)的文件名

本文&#xff1a;http://www.cnblogs.com/xudong-bupt/p/3504442.html Linux C 下面读取文件夹要用到结构体struct dirent&#xff0c;在头#include <dirent.h>中&#xff0c;如下&#xff1a; #include <dirent.h> struct dirent {long d_ino; /* inode number 索…

报表工具实现单据套打

【摘要】 单据套打再也不用手动测量&#xff0c;反复调试了&#xff0c;报表工具实现单据套打&#xff0c;去乾学院看个究竟&#xff1a;报表工具实现单据套打!实际项目开发中&#xff0c;很多情况会涉及到单据的打印。即在一张印刷好的空白单据上&#xff0c;准确无误地打印上…

每隔10秒钟打印一个“Helloworld”

/*** 每隔10秒钟打印一个“Helloworld”*/ public class Test03 {public static void main(String[] args) throws InterruptedException {ThreadImp threadImp new ThreadImp();Thread thread1 new Thread(threadImp);thread1.start();} }class ThreadImp extends Thread {p…

C++ STL 优先队列

//优先队列//Priority_queue //STL#include<iostream>#include<cstdio>#include<cstdlib>#include<queue>using namespace std;struct cmp{ bool operator() (const int a,const int b) const{//用const定义的a,b是包裹着变量外衣的常数&#xff0c;不…

GDB调试core文件样例(如何定位Segment fault)

core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump. (Linux中如果内存越界会收到SIGSEGV信号&#xff0c;然后就会core dump) 在程序运行的过程中&#xff0c;有的时候我们会遇到Segment fa…

管理信息系统的开发与管理

{% extendsmuban.html %} {% block head %}输入{% endblock %} {% block main %} <div><div class"form-group"><label for"question">标题</label><textarea class"form-control" cols"50" rows"2&q…

python11-28笔记(1.6-1.7)

1.6 多类型传值和冗余参数多类型传值&#xff1a;比如def fun(x,y)&#xff0c;定义2个形参定义一个元组t(1,2),如果把元组当做实参传入到函数中&#xff0c;会报错 如何将元组当做不同类型的参数传入到函数中fun(t) 代表传入的是元组或者这样调用fun((1,2))注意实参的个数要和…

session机制详解以及session的相关应用

session是web开发里一个重要的概念&#xff0c;在大多数web应用里session都是被当做现成的东西&#xff0c;拿来就直接用&#xff0c;但是一些复杂的web应用里能拿来用的session已经满足不了实际的需求&#xff0c;当碰到这样的情况时候我们需要更加深入的理解session的机制&am…

(转)Shell中获取字符串长度的七种方法

Shell中获取字符串长度的七种方法 原文&#xff1a;http://blog.csdn.net/jerry_1126/article/details/51835119 求字符串操作在shell脚本中很常用&#xff0c;下面归纳、汇总了求字符串的几种可能方法: 【方法一】:利用${#str}来获取字符串的长度 【方法二】:利用awk的length方…

linux下用core和gdb查询出现段错误的地方

有些时候我们在一段C代码的时候&#xff0c;由于对一个非法内存进行了操作&#xff0c;在程序运行的过程中&#xff0c;出现了"段错误"。呵呵&#xff0c;这种问题我想很多人会经常遇到。遇到这种问题是非常无语的&#xff0c;只是提示了"段错误"&#xff…

第一篇-Html标签中head标签,body标签中input系列,textarea和select标签

第十四周课程&#xff08;1-12章节&#xff09; HTML 裸体 CSS 穿华丽衣服 Javascript 动起来 一 HTML &#xff08;20个标签&#xff09; 1.我们的浏览器是socket客户端 2.一套规则&#xff0c;浏览器认识的规则 3.开发者&#xff1a; 学习html规则 开发后台程序&#xff1a…

opencv3.2.0 Cmake 3.8.0 + tdm-gcc-5.1.0-3

实测 tdm-gcc-5.1.0-3 tdm32-1 32位版本无法正确编译Opencv 3.2.0 会遇到诸多编译问题 解决办法 使用tdm-gcc-5.1.0-2 tdm64-1 64位版本转载于:https://www.cnblogs.com/fundou/p/6710209.html

什么是商品属性

一、什么是商品属性&#xff1a; Definition of Product Attributes A product attribute is a characteristic that defines a particular product and will affect a consumers purchase decision. Product attributes can be tangible (or physical in nature) or intangibl…