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

原理

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

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

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

Linux驱动的静态编译:

利用内核自身的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.

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

Linux驱动动态编译:

具体方法如下:
还是拿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讲解在这篇文章中,请点击这里!

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Qt是一款跨平台的应用程序开发框架,支持Windows、Linux、macOS等操作系统。Qt可以通过静态编译动态编译两种方式进行构建和部署。 静态编译是指将Qt库的代码编译进最终生成的可执行文件中,这样生成的可执行文件独立性较强,不依赖于系统中是否安装了Qt库。静态编译的优点是可移植性好,部署简单,无需担心用户环境中是否已安装相应的Qt版本。然而,静态编译会使得可执行文件的大小变大,占用较多的存储空间,而且在更新Qt库时,需要重新编译整个应用程序。 动态编译是指将Qt库编译动态链接库(.so文件),在运行时需要通过动态链接库来加载并运行程序。动态编译产生的可执行文件较小,因为它只包含应用程序的逻辑代码,依赖于系统中已经安装的Qt库。动态编译的优点是减少了可执行文件的大小,节省存储空间,同时多个应用程序可以共享同一份Qt库,节省系统资源。然而,动态编译需要保证用户的系统中已经安装了相应版本的Qt库,否则会导致程序无法运行。 根据实际需求,我们可以选择静态编译或者动态编译。如果应用程序需要在不同的系统上运行,或者需要独立性较强、便于部署和维护,可以选择静态编译。如果应用程序需要节省存储空间,可以选择动态编译。需要注意的是,在选择编译方式时,应该考虑到预算、性能以及用户环境等因素。总的来说,Qt提供了灵活的编译方式,以满足不同应用场景的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值