iis服务器助手广告广告
返回顶部
首页 > 资讯 > 操作系统 >Linux模块文件如何编译到内核和独立编译成模块
  • 148
分享到

Linux模块文件如何编译到内核和独立编译成模块

2023-06-15 12:06:11 148人浏览 泡泡鱼
摘要

这篇文章主要介绍“linux模块文件如何编译到内核和独立编译成模块”,在日常操作中,相信很多人在Linux模块文件如何编译到内核和独立编译成模块问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux模块文件

这篇文章主要介绍“linux模块文件如何编译到内核和独立编译成模块”,在日常操作中,相信很多人在Linux模块文件如何编译到内核和独立编译成模块问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux模块文件如何编译到内核和独立编译成模块”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1. 内核目录

Linux内核源代码非常庞大,随着版本的发展不断增加。它使用目录树结构,并且使用Makefile组织配置、编译。

初次接触Linux内核,好仔细阅读顶层目录的readme文件,它是Linux内核的概述和编译命令说明。readme的说明侧重于X86等通用的平台,对于某些特殊的体系结构,可能有些特殊的说明。

顶层目录的Makefile是整个内核配置编译的核心文件,负责组织目录树中子目录的编译管理,还可以设置体系结构和版本号等。

内核源码的顶层有许多子目录,分别组织存放各种内核子系统或者文件。具体的目录说明如下表所示。

Linux模块文件如何编译到内核和独立编译成模块

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目录。

Linux模块文件如何编译到内核和独立编译成模块

或者直接点击下面链接  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-

  Linux模块文件如何编译到内核和独立编译成模块

3)配置内核产生.config文件:

导入默认配置

$ make  exynos_defconfig

这里我们假定要编译的内核最终在三星的板子上运行,soc名字是exynos,三星公司其实已经将自己的配置文件放置在  ./arch/arm/configs/exynos_defconfig

执行这个命令,最终会在内核根目录下生成.config文件,

Linux模块文件如何编译到内核和独立编译成模块

我们编译内核就完全依赖这个文件。该文件是exynos开发板所需要的一些内核模块宏定义和参数设置,这些值是厂商给的一个初始配置。实际项目开发中,需要在这个配置文件基础之上再重新移植自己需要的对应的驱动模块。

4)配置内核模块

输入内核配置命令,进行内核选项的选择,命令如下:

$ make menuconfig

命令执行成功以后,会看到如下图所示的界面。其实我们在图1.5中看到过同样功能的界面,那个图也是内核选项配置界面,只不过那个界面在X-window下才能执行。

Linux模块文件如何编译到内核和独立编译成模块

其中:

子菜单--->

Linux模块文件如何编译到内核和独立编译成模块

表示有子菜单,按下回车可以进入子菜单。

中括号[] 在每一个选项前都有个括号,有的是中括号,有的是尖括号,还有的是圆括号。

Linux模块文件如何编译到内核和独立编译成模块

[]  表示该选项只有两种选项,中括号中要么是空,要么是“*”;

用空格键可以做出选择。

尖括号<>

Linux模块文件如何编译到内核和独立编译成模块

<>选择相应的配置时,有3种选择,它们代表的含义分别如下。

● *:将该功能编译进内核。 ● 空:不将该功能编译进内核。 ● M:将该功能编译成可以在需要时动态插入到内核中的模块。

模块配置圆括号() 而圆括号的内容是要你在所提供的几个选项中选择一项。

Linux模块文件如何编译到内核和独立编译成模块

如果使用的是make xconfig,使用鼠标就可以选择对应的选项。如果使用的是make menuconfig,则需要使用回车键进行选取。

在编译内核的过程中,麻烦的事情就是配置这步工作了。初次接触Linux内核的开发者往往弄不清楚该如何选取这些选项。

实际上,在配置时,大部分选项可以使用其默认值,只有小部分需要根据用户不同的需要选择。

选择的原则是将与内核其他部分关系较远且不经常使用的部分功能代码编译成为可加载模块,这有利于减小内核的长度,减少内核消耗的内存,简化该功能相应的环境改变时对内核的影响;不需要的功能就不要选;与内核关系紧密而且经常使用的部分功能代码直接编译到内核中。

5)编译内核:

root@ubuntu:/home/peng/linux-3.14# make uImage

 Linux模块文件如何编译到内核和独立编译成模块

uImage

如果按照默认的配置,没有改动的话,编译后系统会在arch/arm/boot目录下生成一个uImage文件,这个文件就是刚刚生成的。

6)下载Linux内核

因为不同的板子对应的uboot版本都不一样,所以下载程序的uboot命令也会有所差异,关于验证,本文暂不讨论。

4. 独立驱动程序的编译

1. 编译成独立模块

假定我们有以下驱动程序,要编译成可以加载到开发板的独立ko文件

hello.c

#include <linux/init.h> #include <linux/module.h> #include <linux/kdev_t.h> #include <linux/fs.h> #include <linux/cdev.h> //#include <io/uaccess.h> #include <linux/device.h> #include <asm/io.h> #include <asm/uaccess.h>  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 < 0)  {   printk("register_chrdev fail \n");   return result;  }  cls = class_create(THIS_MODULE, "hellocls");  if (IS_ERR(cls)) {   printk(KERN_ERR "class_create() failed for cls\n");   result = PTR_ERR(cls);   Goto out_err_1;  }  devno = MKDEV(major, minor);    class_dev = device_create(cls, NULL, devno, NULL, "hellodev");  if (IS_ERR(class_dev)) {   result = PTR_ERR(class_dev);   goto out_err_2;  }    return 0;  out_err_2:  class_destroy(cls); out_err_1:  unregister_chrdev(major,"hello");  return  result; } static void hello_exit(void) {  printk("hello_exit \n");  device_destroy(cls, devno);  class_destroy(cls);  unregister_chrdev(major,"hello");  return; } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); //proc/devices

注意我们需要编写Makefile如下:

ifneq ($(KERNELRELEASE),) obj-m:=hello.o else KDIR :=/home/peng/linux-3.14 PWD  :=$(shell pwd) all:  make -C $(KDIR) M=$(PWD) modules clean:  rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order endif

关于Makefile的详解,大家可以参考我们之前的文章 《手把手教Linux驱动1-模块化编程》 其中内核路径:

KDIR :=/home/peng/linux-3.14

必须是我们刚才编译过的内核源码根目录。

编译时,程序可以放到其他目录下:

Linux模块文件如何编译到内核和独立编译成模块

用file命令查看文件属性,是基于ARM的。该模块文件就是与前面编译的内核配套的驱动模块,如果开发板的内核版本与上面编译的版本号一致,那么该模块文件就可以在开发板上insmod。

Linux模块文件如何编译到内核和独立编译成模块

2. 编译到内核

步骤:

1)拷贝文件 如果要将刚才的驱动程序直接编译到内核,那么我们必须把hello.c拷贝到内核的某个目录下。

字符设备可以考虑放到以下目录:

linux-3.14/drivers/char

 Linux模块文件如何编译到内核和独立编译成模块

2)修改Makefile

root@ubuntu:/home/peng/linux-3.14/drivers/char# vim Makefile

修改如下:

Linux模块文件如何编译到内核和独立编译成模块

该行内容是根据宏CONFIG_HELLO来决定是否编译hello.c这个文件。

3)修改Kconfig

Linux模块文件如何编译到内核和独立编译成模块

7 HELLO 取前面步骤CONFIG_HELLO下划线后面的字符串 8 tristate 表示该模块最终有3个选项 空 * M 9  表示该模块依赖的模块,如果ARCH_EXYNOS4模块没有被选中,那么HELLO模块也不会被编译到内核 10 帮助信息

4) 重新配置 执行

make menuconfig

进入配置页面,

输入 / 可以根据关键字查找模块所在位置。

Linux模块文件如何编译到内核和独立编译成模块

我们添加的模块文件的位置:

Linux模块文件如何编译到内核和独立编译成模块

根据路径

-> Device Drivers     -> Character devices

找到我们刚才的模块配置路径

Linux模块文件如何编译到内核和独立编译成模块

此处是尖括号,因为我们设置的属性是tristate

移动到Help处,可以看到前面我们填充的帮助信息

我们可以按下空格键设置为*,编译到内核中。

选择Save,

Linux模块文件如何编译到内核和独立编译成模块

Linux模块文件如何编译到内核和独立编译成模块

然后再点击2次Exit,就可以退出。

5)重新编译内核

root@ubuntu:/home/peng/linux-3.14# make uImage

这样,我们的模块编译到了新生成的内核模块文件中。

3. 补充

前面一节其实最终目的是生成CONFIG_HELLO=y 这个定义信息,并把该信息保存到内核根目录的.config文件中。

Linux模块文件如何编译到内核和独立编译成模块

其实我们如果不修改Kconfig,直接在.config中增加这个宏定义也是可以的。

今天内容就到这里,还等什么?抓紧操练起来吧。

文中用到的虚拟机,叫交叉编译工具,还有源代码,

到此,关于“Linux模块文件如何编译到内核和独立编译成模块”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Linux模块文件如何编译到内核和独立编译成模块

本文链接: https://www.lsjlt.com/news/280180.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Linux模块文件如何编译到内核和独立编译成模块
    这篇文章主要介绍“Linux模块文件如何编译到内核和独立编译成模块”,在日常操作中,相信很多人在Linux模块文件如何编译到内核和独立编译成模块问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux模块文件...
    99+
    2023-06-15
  • linux怎么在2.6内核中编译内核模块
    这篇文章主要介绍linux怎么在2.6内核中编译内核模块,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!编译内核模块的方法与编译一般应用程序的方法略有不同. 我们会发现在内核源码树的层层目录中, 都存在有Makefil...
    99+
    2023-06-16
  • Linux系统下怎么编译安装支持NTFS的内核模块
    这篇文章主要讲解了“Linux系统下怎么编译安装支持NTFS的内核模块”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux系统下怎么编译安装支持NTFS的内核模块”吧!当你安装完Linu...
    99+
    2023-06-10
  • netfilter/iptables模块编译及如何应用
    本篇文章为大家展示了netfilter/iptables模块编译及如何应用,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。by KindGeorge # yahoo.com  2005.4....
    99+
    2023-06-13
  • 如何编译php-fpm模块与apache2.4结合
    这篇文章主要为大家展示了“如何编译php-fpm模块与apache2.4结合”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何编译php-fpm模块与apach...
    99+
    2024-04-02
  • Ubuntu编译内核模块和内容体现系统日志中的示例分析
    这篇文章给大家分享的是有关Ubuntu编译内核模块和内容体现系统日志中的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1.Linux登陆界面检查当前文件目录:通过Xshell连接Linux系统后输入命令:...
    99+
    2023-06-22
  • 如何解决nginx中rtmp模块编译arm版本的问题
    这篇文章主要为大家展示了“如何解决nginx中rtmp模块编译arm版本的问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何解决nginx中rtmp模块编译arm版本的问题”这篇文章吧。一、...
    99+
    2023-06-22
  • 如何在已编译安装的PHP环境下安装LDAP模块
    本篇内容主要讲解“如何在已编译安装的PHP环境下安装LDAP模块”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何在已编译安装的PHP环境下安装LDAP模块”吧!在已编译安装的PHP环境下安装L...
    99+
    2023-06-06
  • Linux下如何查看.so和可执行文件是否debug编译
    这篇文章将为大家详细讲解有关Linux下如何查看.so和可执行文件是否debug编译,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。如何判断一个.so是否是debug编译的。我记得以前自己是用file来查看...
    99+
    2023-06-09
  • Node.js 原生插件:如何编写、调试和部署自定义模块
    Node.js 原生插件是一种特殊的模块,它可以通过 C/C++ 语言编写,并在项目中使用。由于原生插件是直接通过 C/C++ 语言编写的,因此它的执行速度比纯 JavaScript 模块更快。此外,原生插件还可以访问一些 JavaSc...
    99+
    2024-02-25
    Node.js 插件 Node.js 原生插件 Node.js 模块 Node.js 自定义模块 Node.js 插件编写 Node.js 插件调试 Node.js 插件部署
  • Java文件学习笔记:如何在Linux系统中使用命令行编译和运行Java程序?
    Java是一种跨平台的编程语言,可以在各种操作系统上运行。在Linux系统中,我们可以使用命令行编译和运行Java程序。本篇文章将介绍如何在Linux系统中使用命令行编译和运行Java程序。 一、安装JDK 在Linux系统中,我们需要先...
    99+
    2023-08-30
    文件 学习笔记 linux
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作