深度解析linux内核模块编译makefile

news/2024/4/26 3:31:31/文章来源:https://blog.csdn.net/m0_74282605/article/details/128114212

linux内核可加载模块的makefile

在开发linux内核驱动时,免不了要接触到makefile的编写和修改,尽管网上的makefile模板一大堆,做一些简单的修改就能用到自己的项目上,但是,对于这些基础的东西,更应该做到知其然并知其所以然。

linux内核使用的是kbuild编译系统,在编译可加载模块时,其makefile的风格和常用的编译C程序的makefile有所不同,尽管如此,makefile的作用总归是给编译器提供编译信息。

最简单的makefile

我们先来看看一个最简单的makefile是怎样的:

obj-m+=hello.oall:make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modulesclean:make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean

这个makefile的作用就是编译hello.c文件,最终生成hello.ko文件。

obj-m+=hello.o

obj-m表示编译生成可加载模块。

相对应的,obj-y表示直接将模块编译进内核。

可以看到,这里并没有输入hello.c源文件,熟悉makefile的人应该知道,这得益于makefile的自动推导功能,需要编译生成filename.o文件而没有显示地指定filename.c文件位置时,make查找filename.c是否存在,如果存在就正常编译,如果不存在,则报错。

obj-m+=hello.o,这条语句就是显式地将hello.o编译成hello.ko,而hello.o则由make的自动推导功能编译hello.c文件生成。

all,clean

all,clean这一类的是makefile中的伪目标,伪目标并不是一个真正的编译目标,它代表着一系列你想要执行的命令集合,通常一个makefile会对应多个操作,例如编译,清除编译结果,安装,就可以使用这些伪目标来进行标记。在执行时就可以键入:

make cleanmake install

等指令来完成相应的指令操作,当make后不带参数时,默认执行第一个伪目标的操作。

make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules

标准的make指令是这样的:make -C $KDIR M=$PWD [target],下面分别介绍每个字段的含义。

-C选项:此选项指定内核源码的位置,make在编译时将会进入内核源码目录,执行编译,编译完成时返回。

$KDIR:/lib/modules/$(shell uname -r)/build/,指定内核源码的位置。

直接在目标板上编译时,内核头文件默认存放在/lib/modules/$(shell uname -r)/build/中,这个build/目录是一个软连接,链接到源码头文件的安装位置。而内核真正的源码库则直接引用正在运行的内核镜像。

当跨平台编译时,就需要指定相应的内核源码目录,而不是系统中的源码目录,但是交叉编译时,需不需要指定架构平台和交叉编译工具链呢?我们接着往下看;

M=$(PWD):需要编译的模块源文件地址

[target]:modules,事实上,这是个可选选项。默认行为是将源文件编译并生成内核模块,即module(s),但是它还支持一下选项:

  • modules_install:安装这个外部模块,默认安装地址是/lib/modules/$(uname -r)/extra/,同时可以由内建变量INSTALL_MOD_PATH指定安装目录
  • clean:卸载源文件目录下编译过程生成的文件,在上文的makefile最后一行可以看到。
  • help:帮助信息

更多选项

编译多个源文件

hello_world总是简单的,但是在实际开发中,就会出现更复杂的情况,这时候就需要了解更多的makefile选项:

首先,当一个.o目标文件的生成依赖多个源文件时,显然make的自动推导规则就力不从心了(它只能根据同名推导,比如编译filename.o,只会去查找filename.c),我们可以这样指定:

obj-m  += hello.ohello-y := a.o b.o hello_world.o

hello.o目标文件依赖于a.o,b.o,hello_world.o,那么这里的a.o和b.o如果没有指定源文件,根据推导规则就是依赖源文件a.c,b.c,hello_world.c.
除了hello-y,同时也可以用hello-objs,实现效果是一样的。

同时编译多个可加载模块

kbuild支持同时编译多个可加载模块,也就是生成多个.ko文件,它的格式是这样的:

obj-m := foo.o bar.ofoo-y := <foo_srcs>bar-y := <bar_srcs>

就是这么简单。

ifneq ($(KERNELRELEASE),)

通常,标准的makefile会写成这样:

ifneq ($(KERNELRELEASE),)obj-m  := hello.oelseKDIR ?= /lib/modules/`uname -r`/buildall:$(MAKE) -C $(KDIR) M=$(PWD) modulesclean:$(MAKE) -C $(KDIR) M=$(PWD) cleanendif

为什么要添加一个ifneq,else,all条件判断。

这得从linux内核模块make执行的过程说起:当键入make时,make在当前目录下寻找makefile并执行,KERNELRELEASE在顶层的makefile中被定义,所以在执行当前makefile时KERNELRELEASE并没有被定义,走else分支,直接执行

$(MAKE) -C $(KDIR) M=$(PWD) modules

而这条指令会进入到$(KDIR)目录,调用顶层的makefile,在顶层makefile中定义了KERNELRELEASE变量.

在顶层makefile中会递归地再次调用到当前目录下的makefile文件,这时KERNELRELEASE变量已经非空,所以执行if分支,在可加载模块编译列表添加hello模块,由此将模块编译成可加载模块放在当前目录下。

归根结底,各级子目录中的makefile文件的作用就是先切换到顶层makefile,然后通过obj-m在可加载模块编译列表中添加当前模块,kbuild就会将其编译成可加载模块。

如果是直接编译整个内核源码,就省去了else分支中进入顶层makefile的步骤。

需要注意的一个基本概念是:每一次编译,顶层makefile都试图递归地进入每个子目录调用子目录的makefile,只是当目标子目录中没有任何修改时,默认不再进行重复编译以节省编译时间。

这里同时解决了上面的一个疑问:既然是从顶层目录开始编译,那么只要顶层目录中指定了架构(ARCH)和交叉编译工具链地址(CROSS_COMPILE),各子目录中就不再需要指定这两个参数。

头文件的放置

当编译的目标模块依赖多个头文件时,kbuild对头文件的放置有这样的规定:

  • 直接放置在makefile同在的目录下,在编译时当前目录会被添加到头文件搜索目录。
  • 放置在系统目录,这个系统目录是源代码目录中的include/linux/。
  • 与通用的makefile一样,使用-I$(DIR)来指定,不同的是,代表编译选项的变量是固定的,为ccflag.
    一般的用法是这样的: ccflags-y := -I$(DIR)/include kbuild就会将$(DIR)/includ目录添加到编译时的头文件搜索目录中。

【推荐阅读】

关于如何快速学好,学懂Linux内核。内含学习路线

了解ixgbe网卡驱动— 驱动注册(纯代码分享)

需要多久才能看完linux内核源码?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_39134.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

History、Location

History、Location 学习路线&#xff1a;JavaScript_BOM->Window对象->confirm()、setInterval()、setTimeout()->History、Location->闪烁的灯泡 History History 对象是 JavaScript 对历史记录进行封装的对象。 History 对象的获取 使用 window.history获取&a…

计算机四级网络-网络技术-第六章 网络管理与网络安全

6.1 网络管理技术 CMIP 采用委托监控机制。 CMIP协议是由IS0组织制定的一种管理协议。管理进程根据事件发生时对网络服务影响的大小来划分事件的严重等级&#xff0c;然后再产生相应的故障处理方案。CMIP的所有功能都要映射到应用层的相关协议上实现。操作和事件报告是通过远…

2023 年 10 大 Web 开发趋势

公司的在线形象是最重要的。您使用的平台越多&#xff0c;您就会变得越成功&#xff01;拥有在线形象的困难部分是脱颖而出。如果你没有有趣的东西可以提供&#xff0c;你会迷失在人群中。 除了网站具有的基本功能外&#xff0c;您还需要拥有更多功能才能使您的网站具有可持续…

在RVIZ中显示深度数据

文章目录深入 RVIZ景深图深度云点云置信度视差C中的深度订阅参考深入 RVIZ 在本教程中&#xff0c;您将详细了解如何配置您自己的 RVIZ 会话以仅查看您需要的深度数据。 深度信息可以通过许多不同的方式可视化&#xff1a;2D 深度图像、3D 点云、3D 注册深度云和置信度图像等…

剑指Offer专项突破版(76)—— 数组中的第 k 大的数字

题目 剑指 Offer II 076. 数组中的第 k 大的数字 思路 假设有个划分函数divide&#xff1a; divide&#xff1a;将num在[l,r]范围内&#xff0c;按照nums[l]进行划分&#xff0c;返回一个数组range&#xff0c;划分为&#xff1a; 所有小于nums[l]的数&#xff1a;移动到nu…

[NCTF2019]SQLi

进来就有个弹窗 甚至给了sql语句 sqlquery : select * from users where username and passwd 先扫一下目录&#xff0c;发现有个robots.txt 提示有个hint.txt $black_list "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00…

Kotlin高仿微信-第18篇-单聊-删除单条信息

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

Qt编写视频监控系统67-录像计划(支持64通道7*24录像设置)

一、前言 录像计划这个功能一直挂了很久&#xff0c;之前做的也都有保存视频文件功能&#xff0c;其中还分了三大种&#xff0c;第一种是手动开启和停止录像&#xff1b;第二种是按照指定时长比如10s保存文件&#xff1b;第三种是定时30分钟一个文件一直保存。这三种功能直接写…

opengl,opengl es,egl,glfw,glew

OpenGL ES之GLFW窗口搭建 - Plato - 博客园概述 本章节主要总结如何使用GLFW来创建Opengl窗口。主要包括如下内容&#xff1a; OpenGl窗口创建介绍 GLFW Window版编译介绍 GLFW简单工程源码介绍 OpenGL窗口创建介绍 能用于Ohttps://www.cnblogs.com/feng-sc/p/5093262.htmlOp…

2022-11-30 Github Forking 工作流模式

Forking 工作流 fork 操作是在个人远程仓库新建一份目标远程仓库的副本&#xff0c;流程如下&#xff1a; 比如在 GitHub 上操作时&#xff0c;在项目的主页点击 fork 按钮&#xff08;页面右上角&#xff09;&#xff0c;即可拷贝该目标远程仓库。 假设开发者 A 拥有一个远程仓…

电脑怎么提取图片中的文字?

图片记录着我们生活的点点滴滴&#xff0c;比如各种办公截图、查快递单号、布置的课堂作业等等&#xff0c;都离不开这种便捷的方法。而我们有时难免需要从图片中提取想要的文字&#xff0c;总不能就靠打字打到手软吧&#xff0c;那么电脑怎么提取图片中的文字呢?有需要的朋友…

终于有阿里p8进行了大汇总(Redis+JVM+MySQL+Spring)还有面试题解全在这里了!

Redis特性 Redis是一直基于键值对的NoSQL数据库&#xff1b; Redis支持5种主要数据结构&#xff1a;string、hash、list、set、zset以及bitmaps、hyperLoglog、GEO等特化的数据结构&#xff1b; Redis是内存数据库&#xff0c;因此它有足够好的读写性能&#xff1b; Redis支持…

verilog实现分频(奇数分频和偶数分频,通用版)

大家好&#xff0c;最近写了一些分频器的设计&#xff0c;发现奇数分频和偶数分频是比较常用分频效果&#xff0c;所以写了一个比较简单的分频代码&#xff0c;适用于奇数分频和偶数分频&#xff08;不考虑占空比&#xff09;&#xff0c;代码已经经过测试&#xff0c;需要可自…

如何应对Redis并发访问带来的问题

前言 我们在使用Redis的过程中&#xff0c;难免会遇到并发访问及数据更新的问题。但很多场景对数据的并发修改是很敏感的&#xff0c;比如库存数据如果没有做好并发读取和更新的版本控制&#xff0c;就会导致严重的业务问题。今天就来说说应该如何做好并发访问及数据更新问题。…

ROS2--概述

ROS2概述1 ROS2对比ROS12 ROS2 通信3 核心概念4 ros2 安装5 话题、服务、动作6 参数参考1 ROS2对比ROS1 多机器人系统&#xff1a;未来机器人一定不会是独立的个体&#xff0c;机器人和机器人之间也需要通信和协作&#xff0c;ROS2为多机器人系统的应用提供了标准方法和通信机…

Windows系统--AD域控--DHCP服务器

Windows系统--AD域控--DHCP服务器 虚拟机网络准备 1.将VMware网络编辑器的NAT模式--取消勾选 使用本地DHCP服务器; 从机(win10)将内置网卡的IPv4网络改为 自动获取IP地址、自动获取DNS AD服务器 部署 DHCP服务器

VF01销售开票发票金额控制增强

实施隐式增强 全部代码如下&#xff1a; method IF_EX_BADI_SD_BILLING~INVOICE_DOCUMENT_CHECK. CALL FUNCTION ‘SIPT_DOC_CHECK_SD’ EXPORTING it_xvbrk fxvbrk it_xvbrp fxvbrp it_xkomv fxkomv it_xvbpa fxvbpa IMPORTING ev_bad_data fbad_data. “”“”“”“…

Word控件Spire.Doc 【图像形状】教程(8): 如何借助C#/VB.NET在 Word 中插入艺术字

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

Kotlin高仿微信-第12篇-单聊-图片

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

【JavaEE】MyBatis

文章目录1.MyBatis介绍2.MyBatis快速入门3.Mapper代理开发4.MyBatis核心配置文件5.配置文件完成增删改查5.1 查询5.2 添加/修改5.3 删除6.MyBatis参数传递7.注解完成增删改查1.MyBatis介绍 1.什么是MyBatis? MyBatis是一款优秀的 持久层框架&#xff0c;用于简化JDBC开发MyBat…