inux 模块编译步骤(转)

本文将直接了当的带你进入linux的模块编译。当然在介绍的过程当中,我也会添加一些必要的注释,以便初学者能够看懂。之所以要写这篇文章,主要是因为从书本上学的话,可能要花更长的时间才能学会整个过程,因为看书的话是一个学习过程,而我这篇文章更像是一个培训。所以实践性和总结性更强。通过本文你将会学到编译一个模块和模块makefile的基本知识。以及加载(卸载)模块,查看系统消息的一些知识;

声明:本文为初学者所写,如果你已经是一个linux模块编译高手,还请指正我文章中的错误和不足,谢谢

第一步:准备源代码

首先我们还是要来编写一个符合linux格式的模块文件,这样我们才能开始我们的模块编译。假设我们有一个源文件mymod.c。它的源码如下:


mymodules.c

1. #include
     
2. #include
        
3. #include  
4

5. MODULE_AUTHOR("Yu Qiang");
6. MODULE_LICENSE("GPL"); 
7
8. static int nbr = 10;
9. module_param(nbr, int, S_IRUGO);
10.
11. static int __init yuer_init(void)
12.{
13.    int i;
14.    for(i=0; i
15.    {
16.   
   
printk(KERN_ALERT "Hello, How are you. %d/n", i);
17.    }
18.    return 0;
19.}
20.
21.static void __exit yuer_exit(void)
22.{
23.    printk(KERN_ALERT"I come
from yuer's module, I have been unlad./n");
24.}
25.
26. module_init(yuer_init);
27. module_exit(yuer_exit);

我们的源文件就准备的差不多了,这就是一个linux下的模块的基本结构。第9行是导出我们的符号变量nbr。这样在你加载这个模块的时候可以动态修改这个变量的值。稍后将演示。yuer_init()函数将在模块加载的时候运行,通过输出的结果可以看到我们的模块是否加载成功。

第二步:编写Makefile文件

首先还是来看看我们Makefile的源文件,然后我们再来解释;

Makefile
obj-m :=
modules.o                   #要生成的模块名

modules-objs:= mymod.o        #生成这个模块名所需要的目标文件

KDIR := /lib/modules/`uname
-r`/build

PWD := $(shell pwd)

default:
make -C $(KDIR) M=$(PWD) modules

clean:
rm -rf *.o .* .cmd *.ko *.mod.c .tmp_versions

ARM平台

Makefile

obj-m += mymod.o
KDIR := /home/workspace2/kernel/linux-2.6.25    #如果是用于arm平台,则内核路径为arm内核的路径

PWD = $(shell pwd)
all:
       
make -C $(KDIR) M=$(PWD) modules
clean:
       
rm -rf *.o

在arm板上插入是

insmod
mymod 


如果出现以下错误

insmod:
chdir(/lib/modules): No such file or
directory

则运行

mkdir
/lib/modules/2.6.25 (与arm内核版本相同)

并将mymod.ko文件复制到该目录下

cp mymod.ko
/lib/modules/2.6.25

然后再执行 (insmod
只在/lib/modules/2.6.25目录下查找相关驱动模块)

insmod
mymod


现在我来说明一下这个Makefile。请记住是大写的Makefile而不是小写的makefile;

obj-m :这个变量是指定你要声称哪些模块模块的格式为 obj-m :=
<模块名>.o
modules-objs
:这个变量是说明声称模块modules需要的目标文件 格式要求  
<模块名>-objs := <目标文件>
      
切记:模块的名字不能取与目标文件相同的名字。如在这里模块名不能取成 mymod;
KDIR  
:这是我们正在运行的操作系统内核编译目录。也就是编译模块需要的环境
M=    
:指定我们源文件的位置
PWD  
:这是当前工作路径$(shell  
)是make的一个内置函数。用来执行shell命令。

第三步:编译模块

现在我们已经准备好了我们所需要的源文件和相应的Makefile。我们现在就可以编译了。在终端进入源文件目录输入make
运行结果:
   
make[1]: Entering directory
`/usr/src/linux-headers-2.6.24-24-generic'
    CC
[M] /home/yuqiang/桌面/mymodule/mymodules.o
    LD
[M] /home/yuqiang/桌面/mymodule/modules.o
    Building
modules, stage 2.
    MODPOST
1 modules
    CC     
/home/yuqiang/桌面/mymodule/modules.mod.o
    LD
[M] /home/yuqiang/桌面/mymodule/modules.ko
    make[1]:
Leaving directory `/usr/src/linux-headers-2.6.24-24-generic'

第四步:加载/卸载我们的模块

从上面的编译中我可以看到。已经有一个modules.ko生成了。这就是我们的模块了。现在我们就可以来加载了。
首先在终端输入:sudo insmod
modules.ko
现在我们来看看我们的模块加载成功没有呢?
在终端输入:dmesg | tail
-12    这是查看内核输出信息的意思。tail
-12 显示最后12条;
显示结果如下:
    [17945.024417]
sd 9:0:0:0: Attached scsi generic sg2 type 0
    [18046.790019]
usb 5-8: USB disconnect, address 9
    [19934.224812]
Hello, How are you. 0
    [19934.224817]
Hello, How are you. 1
    [19934.224818]
Hello, How are you. 2
    [19934.224820]
Hello, How are you. 3
    [19934.224821]
Hello, How are you. 4
    [19934.224822]
Hello, How are you. 5
    [19934.224824]
Hello, How are you. 6
    [19934.224825]
Hello, How are you. 7
    [19934.224826]
Hello, How are you. 8
    [19934.224828]
Hello, How are you. 9

看到了吧。我们的模块的初始化函数yuer_init();已经成功运行了。说明我们的模块已经加载成功;
现在我们再来卸载模块试试看。
在终端输入:sudo rmmod
modules
在终端输入:dmesg | tail
-3
   
[19934.224826] Hello, How are you. 8
[19934.224828] Hello, How are you. 9
[20412.046932] I come from yuer's module, I have been unlad.

可以从打印的信息中看到,我们的模块的退出函数已经被执行了。说明我们的模块已经被成功的卸载了。到目前位置我们就已经算是对模块的编译到编译运行算是有了一个整体上的认识了。对于以后深入的学习还是应该有点帮助的。下面我们将在看看于模块相关的一些简单的操作。

第五步:加载模块时传递参数
在终端输入:sudo insmod module_name.ko
nbr=4
在终端输入:dmesg | tail
-6
显示结果如下:
[20800.655694] Hello, How are you. 9
[21318.675593] I come from onefile module, I have been unlad.
[21334.425373] Hello, How are you. 0
[21334.425378] Hello, How are you. 1
[21334.425380] Hello, How are you. 2
[21334.425381] Hello, How are you. 3

这样我们就可以看到在模块加载的时候动态设置了我们的一个变量。初始化函数中的循环只执行了4次。
可能你会问我怎么知道一个模块可以设置那些变量呢。当然,你可以先不设变量加载一次。然后可以在终端输入ls
/sys/module//parameters/来查看。在这里我们是这样输入的
在终端输入:ls
/sys/moedle/modules/parameters/
显示结果:
nbr

如果我们的模块加载成功了。最后我们还可以通过modinfo来查看我们的模块信息。如下
在终端输入:sudo modinfo
modules.ko
   
显示结果:
filename:      
modules.ko
license:       
GPL
author:        
Yu Qiang
srcversion:    
20E9C3C4E02D130E6E92533
depends:

vermagic:      
2.6.24-24-generic SMP mod_unload 586 
parm:          
nbr:int

本文总结:
   
本文的相关知识都好像有一点浅尝辙止的感觉。因为本篇文章主要是通过一条线式方式来讲解了模块编写的相关过程,其实在这个过程中还有很多可以发散的地方。例如:

在写到MODULE_AUTHOR("Yu Qiang")的时候,你应该想到还有
    
MODULE_DESCRIPTION(模块用途的简单描述);
    MODULE_VERSION(模块的版本字符串);
    MODULE_ALIAS(模块的别名);
    ...

在写到module_param(nbr, int, S_IRUGO);的时候,你应该想到还有
    
EXPORT_SYMBOL(name); 可以导出模块的函数,这也是模块编写的最终目的
...

在用到insmod 和 modinfo的时候。你应该想到还有
     depmod    
分析可加载模块的依赖性,并生成modules.dep文件和映射文件
     modprobe   Linux内核添加删除模块

...

如果要成为一名专业的linux模块开发人员,还要走很多的路,就看各位的了,祝大家学习顺利。

我并不是什么linux相关的专家,我只是一个普通的linux相关开发人员(在读),我的目的也很简单,就是想给大家介绍一个方法,希望大家在学习的时候不要走过多的弯路。由于个人能力所限难免存在错误和缺点,所以请不要介意,如有发现请提出,我立即修改。方便大家学习


linux驱动模块编译(初学者)的更多相关文章

  1. 【转】Linux驱动模块编译进内核中

    原文网址:http://blog.chinaunix.net/uid-29287950-id-4573481.html BQ27501驱动编译进内核 一.       驱动程序编译进内核的步骤 在 l ...

  2. Linux驱动模块编译模板

    hello.c文件: #include <linux/module.h> #include <linux/kernel.h> static int hello_init(voi ...

  3. linux下 驱动模块编译步骤

    本文将直接了当的带你进入linux的模块编译.当然在介绍的过程当中,我也会添加一些必要的注释,以便初学者能够看懂.之所以要写这篇文章,主要是因为从书本上学的话,可能要花更长的时间才能学会整个过程,因为 ...

  4. Linux 内核源码外编译 linux模块--编译驱动模块的基本方法

    1.先编写一个简单的hello模块,hello.c 源码如下: #ifndef __KERNEL__ # define __KERNEL__ #endif #ifndef MODULE # defin ...

  5. linux下编译eXosip、osip,以及UAC和UAS的例子

    从网站上看到了这样的一篇博文 :Windows下编译eXosip.osip,以及UAC和UAS的例子 (链接:http://www.cnblogs.com/dyllove98/archive/2013 ...

  6. Linux内核编译与安装

    2013-04-16    Linux内核介绍  Linux内核是一个用C语言写成的,符合POSIX标准的类Unix操作系统.内核是操作系统中最基本的一部分,提供了众多应用程序访问计算机硬件的机制.L ...

  7. linux下编译wpa_supplicant&nbsp;…

    linux下编译wpa_supplicant 收藏 前一段时间只在vs2005下编译成功过.经过近一段时间的琢磨,今天终于在linux下成功编译了wpa_supplicant. 挺简单的事情折腾了这么 ...

  8. linux 模块编译步骤(原)

    linux 模块编译步骤(原) 博主推荐:<Linux命令模板Licote(原)> 本文将直接了当的带你进入linux的模块编译.当然在介绍的过程当中,我也会添加一些必要的注释,以便初学者 ...

  9. linux下编译gcc6.2.0

    linux下编译gcc6.2.0 在archlinx的下gcc已经更新到6.2.1了,win10的WSL下还是gcc4.8.官方源没有比较新的版本,于是自己编译使用. GCC6的几个新特性 GCC 6 ...

随机推荐

  1. Java丨简单的登录过滤器实现方法

    过滤过滤,实际就是把需要和不需要的东西分开! 今天来说道说道我们程序中的‘登录过滤器’ ,首先我们看看一下面的问题: 1.“登录过滤器”是干什么用的? 1)“登录过滤器”就是为了防止在用户没有登录的情 ...

  2. HAWQ取代传统数仓实践(十四)——事实表技术之累积快照

    一.累积快照简介 累积快照事实表用于定义业务过程开始.结束以及期间的可区分的里程碑事件.通常在此类事实表中针对过程中的关键步骤都包含日期外键,并包含每个步骤的度量,这些度量的产生一般都会滞后于数据行的 ...

  3. ng 自定义服务

    服务的本质是对象. 创建服务的常见方式:factory(返回对象) service (方法.属性)constant(常量服务) value(变量服务) 1.factoryapp.factory('服务 ...

  4. 基于UDP协议编程

    基于udp套接字 udp是无链接的,先启动哪一端都不会报错. UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务.不会使用块的合并优化算法,, ...

  5. Laraver 框架资料

    重定向: return redirect()->to('http://www.baidu.com'); 重定向到内部路由 return redirect()->route(‘name’); ...

  6. HDU - 6197:array array array (简单LIS)

    One day, Kaitou Kiddo had stolen a priceless diamond ring. But detective Conan blocked Kiddo's path ...

  7. kali视频(1-5)

    第二周 kali视频(1-5) 1.kali安装 2.基本配置 vmtools安装过程. 3.安全渗透测试一般流程 4.信息搜集之GoogleHack 5.信息搜集之目标获取 1.kali安装 直接在 ...

  8. 数据分析笔试-sql

    题目说明及要求: 以下是模似数据库里的表单信息,请根据要求写出SQL语句 表1:职工信息 表结构如下: 表名:Employee 职工ID   职工姓名       入职年份       部门ID A1 ...

  9. LeetCode 621. Task Scheduler

    原题链接在这里:https://leetcode.com/problems/task-scheduler/description/ 题目: Given a char array representin ...

  10. Java Config 注解

    java config是指基于java配置的spring.传统的Spring一般都是基本xml配置的,后来spring3.0新增了许多java config的注解,特别是spring boot,基本都 ...