Linux模块文件编译到内核与独立编译成.ko文件的方法 |
您所在的位置:网站首页 › 激活网卡需要编译内核吗 › Linux模块文件编译到内核与独立编译成.ko文件的方法 |
很多粉丝在群里提问,如何把一个模块文件编译到内核中或者独立变异成ko文件。本文给大家详解讲解。 1. 内核目录Linux内核源代码非常庞大,随着版本的发展不断增加。它使用目录树结构,并且使用Makefile组织配置、编译。 初次接触Linux内核,好仔细阅读顶层目录的readme文件,它是Linux内核的概述和编译命令说明。readme的说明侧重于X86等通用的平台,对于某些特殊的体系结构,可能有些特殊的说明。 顶层目录的Makefile是整个内核配置编译的核心文件,负责组织目录树中子目录的编译管理,还可以设置体系结构和版本号等。 内核源码的顶层有许多子目录,分别组织存放各种内核子系统或者文件。具体的目录说明如下表所示。 目录内容arch/体系结构相关的代码,如arch/i386、arch/arm、arch/ppccrypto常用加密和散列算法(如AES、SHA等),以及一些压缩和CRC校验算法drivers/各种设备驱动程序,如drivers/char、drivers/block……documentation/内核文档fs/文件系统,如fs/ext3、fs/jffs2……include/内核头文件:include/asm是体系结构相关的头文件,它是include/asm-arm、include/asm-i386等目录的链接;include/linux是Linux内核基本的头文件init/Linux初始化,如main.cipc/进程间通信的代码kernel/Linux内核核心代码(这部分比较小)lib/各种库子程序,如zlib、crc32mm/内存管理代码net/网络支持代码,主要是网络协议sound声音驱动的支持scripts/内部或者外部使用的脚本usr/用户的代码 2. 编译工具make mrproper: 清除内核生成的配置文件与目标文件等,一般在第一次编译时使用 导入默认配置信息(在内核根目录中) a) make xxx_deconfig b) cp arch/arm/configs/xx_deconfig .config 生成默认配置文件配置命令 make xxxxconfig 修改配置文件 make xconfig (图形界面 qt库) make menuconfig (常用 libncurses库) sudo apt-get install libncurses5-dev make config (精简)编译内核 make uImage ---生成内核镜像 /arch/arm/boot/uImage编译设备树 make dtbs ---生成设备树文件 /arch/arm/boot/dtb/xxxxxx.dtb编译生成模块文件 make modules ---把配置值选成M的代码编译生成模块文件。(.ko) 放在对应的源码目录下。 3. 内核编译现在很多基于Linux的产品开发,通常厂家都会提供集成开发环境SDK。builroot使我们搭建环境变得更加方便,但是作为初学者我们还是要掌握如何独立编译内核源码。 0) 前提条件必须先安装交叉编译工具链,关于交叉编译工具链的安装可以参考 《linux环境搭建-ubuntu16.04安装》 在这里我们使用的是arm-none-linux-gnueabi-gcc。 1)下载内核源码下载地址:https://mirrors.edge.kernel.org/pub/linux/kernel/ 我们下载Linux-3.14内核(可以是更高的版本)至/home/peng目录。 或者直接点击下面链接 https://mirrors.edge.kernel.org/pub/linux/kernel/v3.x/linux-3.14.10.tar.xz 解开压缩包,并进入内核源码目录,具体过程如下: $ tar xvf linux-3.14.tar.xz $ cd linux-3.14 2)修改内核目录树根下的Makefile,指明交叉编译器: $ vim Makefile找到ARCH和CROSS_COMPILE, 修改: ARCH ?= $(SUBARCH) CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)为 ARCH ?= arm CROSS_COMPILE ?= arm-none-linux-gnueabi- 4)配置内核产生.config文件:导入默认配置 $ make exynos_defconfig这里我们假定要编译的内核最终在三星的板子上运行,soc名字是exynos,三星公司其实已经将自己的配置文件放置在 ./arch/arm/configs/exynos_defconfig 执行这个命令,最终会在内核根目录下生成.config文件, 我们编译内核就完全依赖这个文件。该文件是exynos开发板所需要的一些内核模块宏定义和参数设置,这些值是厂商给的一个初始配置。实际项目开发中,需要在这个配置文件基础之上再重新移植自己需要的对应的驱动模块。 5)配置内核模块输入内核配置命令,进行内核选项的选择,命令如下: $ make menuconfig命令执行成功以后,会看到如下图所示的界面。其实我们在图1.5中看到过同样功能的界面,那个图也是内核选项配置界面,只不过那个界面在X-window下才能执行。 其中: 子菜单---> 表示有子菜单,按下回车可以进入子菜单。 中括号[] 在每一个选项前都有个括号,有的是中括号,有的是尖括号,还有的是圆括号。 [] 表示该选项只有两种选项,中括号中要么是空,要么是“*”; 用空格键可以做出选择。 尖括号 选择相应的配置时,有3种选择,它们代表的含义分别如下。 ● *:将该功能编译进内核。 ● 空:不将该功能编译进内核。 ● M:将该功能编译成可以在需要时动态插入到内核中的模块。模块配置圆括号() 而圆括号的内容是要你在所提供的几个选项中选择一项。 如果使用的是make xconfig,使用鼠标就可以选择对应的选项。如果使用的是make menuconfig,则需要使用回车键进行选取。 在编译内核的过程中,麻烦的事情就是配置这步工作了。初次接触Linux内核的开发者往往弄不清楚该如何选取这些选项。 实际上,在配置时,大部分选项可以使用其默认值,只有小部分需要根据用户不同的需要选择。 选择的原则是将与内核其他部分关系较远且不经常使用的部分功能代码编译成为可加载模块,这有利于减小内核的长度,减少内核消耗的内存,简化该功能相应的环境改变时对内核的影响;不需要的功能就不要选;与内核关系紧密而且经常使用的部分功能代码直接编译到内核中。 6)编译内核: root@ubuntu:/home/peng/linux-3.14# make uImageuImage 如果按照默认的配置,没有改动的话,编译后系统会在arch/arm/boot目录下生成一个uImage文件,这个文件就是刚刚生成的。 7)下载Linux内核因为不同的板子对应的uboot版本都不一样,所以下载程序的uboot命令也会有所差异,关于验证,本文暂不讨论。 4. 独立驱动程序的编译 1. 编译成独立模块假定我们有以下驱动程序,要编译成可以加载到开发板的独立ko文件 hello.c #include #include #include #include #include //#include #include #include #include static int major = 237; static int minor = 0; static dev_t devno; struct device *class_dev = NULL; struct class *cls; static int hello_open (struct inode *inode, struct file *filep) { printk("hello_open()\n"); return 0; } static int hello_release (struct inode *inode, struct file *filep) { printk("hello_release()\n"); return 0; } #define KMAX_LEN 32 char kbuf[KMAX_LEN+1] = "kernel"; //read(fd,buff,40); static ssize_t hello_read (struct file *filep, char __user *buf, size_t size, loff_t *pos) { int error; if(size > strlen(kbuf)) { size = strlen(kbuf); } if(copy_to_user(buf,kbuf, size)) { error = -EFAULT; return error; } return size; } //write(fd,buff,40); static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos) { int error; if(size > KMAX_LEN) { size = KMAX_LEN; } memset(kbuf,0,sizeof(kbuf)); if(copy_from_user(kbuf, buf, size)) { error = -EFAULT; return error; } printk("%s\n",kbuf); return size; } static struct file_operations hello_ops = { .open = hello_open, .release = hello_release, .read = hello_read, .write = hello_write, }; static int hello_init(void) { int result; printk("hello_init \n"); result = register_chrdev( major, "hello", &hello_ops); if(result Device Drivers -> Character devices找到我们刚才的模块配置路径 此处是尖括号,因为我们设置的属性是tristate 移动到Help处,可以看到前面我们填充的帮助信息 我们可以按下空格键设置为*,编译到内核中。 选择Save, 然后再点击2次Exit,就可以退出。 5)重新编译内核 root@ubuntu:/home/peng/linux-3.14# make uImage这样,我们的模块编译到了新生成的内核模块文件中。 3. 补充前面一节其实最终目的是生成CONFIG_HELLO=y 这个定义信息,并把该信息保存到内核根目录的.config文件中。 其实我们如果不修改Kconfig,直接在.config中增加这个宏定义也是可以的。 今天内容就到这里,还等什么?抓紧操练起来吧。 文中用到的虚拟机,叫交叉编译工具,还有源代码, |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |