引言
近来总算成功的在自己的手上将一个hello的内核模块成功的编译并加载进自己的嵌入式linux系统,教程翻了无数篇linux c,果然理论的了解和实际上的晓得怎样做之间,还存在着很大的差别。。鉴于在查找资料中见到不少的教程中都存在着部份知识缺位的问题linux交叉编译环境,总的来说就是:“我认为个别东西太过简单我没有必要再讲”,而这一部份又直接引起我一个萌新给完全的给看懵了,因而在这儿写一下自己的笔记,注重讲一些当时自己走了弯路的地方。
打算工作
为了才能交叉编译内核驱动,首先你须要:
获取到了这两个工具以后还须要进行配置才可以使用。。
交叉编译器
将交叉编译器置于一个准确的位置,此后在进行工作前须要将它添加到环境变量(可以使用export单独导入,也可以编辑一个setting.sh每次工作前运行一下,甚至可以添加到~/.bashrc中每次启动终端时手动设定)。倘若不添加环境变量的话则须要在每次make指令前面都自动加上编译器参数和构架参数。常见的配置参数如下深度linux,按照自己具体须要进行更改:
#!/usr/bin/bash
export ARCH=arm
export CROSS_COMPILE=arm-linux-
内核的编译
要想成功的进行驱动的编译,首先须要有一个成功编译过的内核源码。所以我们须要先进行内核的编译。通常内核须要先通过makemenuconfig生成内核的编译配置选项。在没有特定需求的时侯我们只须要保存退出即可。完成内核的编译配置选项后就可以使用make进行编译了。注意:使用make之前必须确保构架和交叉编译器的参数都已在环境变量中!
驱动编撰
接出来到这一步才是即将开始驱动的编译。我们的第一个测试用的驱动,仅仅实现加载和卸载时对内核的消息日志输出。驱动工程的文件夹可以在源码树下,也可以在源码树外的自定义目录,在这儿我将驱动工程文件夹置于了源码树外的目录,其文件信息如下:
hello.c
#include
#include
static int hello_init(void)
{
printk("Hello kernel world!n");
return 0;
}
static void hello_exit(void)
{
printk("Goodbye world!n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("[email protected]>");
MODULE_LICENSE("Dual BSD/GPL");
在内核的编译中,由于不是输出为普通的可执行程序而是输出为内核模块,因而须要独立编撰Makefile文件,也建议在进行驱动学习的时侯要了解Makefile的简单原理。
Makefile
obj-m:=hello.o
这儿是一个最简单没有任何其他功能的Makefile,目的就是把hello.c编译成可加载模块hello.ko文件linux交叉编译环境,当读者进一步了解Makefile机制的时侯可以选择添加更多的功能,例如清除等。
驱动编译
在完成以上工程文件后,我们就可以使用这个最简单的Makefile来编译文件了。并且因为编译驱动须要依照内核的源码树进行操作,因而我们在编译的指令中还须要加入内核源码树的目录,之后还要指定编译为模块,最终编译指令如下:
make -C /media/wmd/a1f4b143-42e4-413c-8c1e-bacea116f841/kernel-src/linux-nanopineo/ M=`pwd` modules
其中-C前面跟随的就是内核的源码(早已编译过的),而M=则为我们的新模块的目录,因为我们在当前目录下,所以使用内嵌命令pwd即可得到,最后一个参数modules指定编译为模块。
编译完成后可以看见工作目录下会得到hello.ko文件和其他相关文件。
驱动加载
到了这一步虽然早已很简单了,将编译好的内核模块传输到目标机上,此后在目标机上使用sudoinsmodhello.ko指令来添加模块。添加完成后可以使用lsmod来查看模块。使用rmmod来进行模块的卸载。因为模块不仅内核复印日志外没有任何响应,我们可以通过查看内核日志dmesg的方式来查看内核是否正常工作。
最终我们可以看见驱动的日志被正常的复印,也就是我们的驱动可以正常的工作!