一个通用驱动Makefile-V2-支持编译多目录
前言
该 Makefile 已经通过基于内核 Linux5.4 版本验证通过。
因为编写这通用驱动 Makefile 时遇到了头文件指定路径失败的问题。使用过 ccflags-y 、INCDIR 、EXTRA_CFLAGS 、-L 等等参数都无效。就是因为我使用了 $(shell pwd)。导致这些参数的路径都为内核源码路径下,而非模块路径。后面重新查看内核文档,看内核的推荐写法才解决了,使用 $(src) 来获取模块源码路径。正确指向自定义的头文件路径。所以有以下建议:
- 建议:对于不同的 Linux 内核,应该去该内核文档看看 makefiel 和 Kbuild 的语法及特点。(Documentation/kbuild)**
1. 特点
- 支持编译多目录Linux内核驱动
- 支持多目录源文件及头文件编译
- 兼容性高,修改接口宏即可
2. 分析
2.1 简要原理
由于驱动程序中包含了很多来自内核的头文件,编译驱动程序时需要指定板子所用的同一版本的内核源码(编译后,以下无特别说明也是编译后)路径。
简要原理其实是主要由内核源码中的 Makefile 来进行编译并生成驱动文件。所以当前 Makefile 只需要提供参数和跳转到内核源码路径执行其顶层 Makefile 即可。
2.2 具体分析
内核路径:
KERNEL_DIR = /home/lss/work/kernel/imx6/ebf-buster-linux/build_image/build:指出编译后的内核源码路径。
架构及编译器:
ARCH = arm:提供架构名称。
CROSS_COMPILE = arm-linux-gnueabihf-:提供交叉编译器名称。
CC = $(CROSS_COMPILE)gcc:用于测试用例APP使用的编译器(无测试用例可屏蔽)。
export ARCH CROSS_COMPILE:共享架构名称及交叉编译器名称到 sub-Makefile,这里即是内核源码中的顶层Makefile及其sub-Makefile。
路径变量:
PWD := $(shell pwd):运行时的 make 路径。并不是当前文件路径。
MODDIR := $(src):当前模块的顶层路径。
- 内核源码原话:$(src) provides the absolute path by pointing to the directory where the currently executing kbuild file is located.
- Kbuild可以看作Makefile。(虽然不严谨)
- $(src) 是由内核 Makefile 提供的。为当前被执行的 子Makefile 的绝对路径。在这里也可以看出 M= 的路径。
- 因为当内核顶层 Makefile 使用 -C 跳到内核顶层 Makefile ,如果使用
$(shell pwd)的话,该命令的值为 内核顶层 Makefile 的绝对路径,而不是内核顶层 Makefile 的路径。( $(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules 中的 M=$(CURDIR) 例外,因为它在当前 Makefile 生效后再跳转到 -C 的 )
- 因为当内核顶层 Makefile 使用 -C 跳到内核顶层 Makefile ,如果使用
目标:
TARGET_DRV := led_device_driver:模块目标名称。
TARGET_APP := led_app:测试用例目标名称。
资源文件和模块目标定义
$(TARGET_DRV)-y += led_module.o:目标模块所需源文件。
$(TARGET_DRV)-y += ./device/led_dev_a.o:目标模块所需源文件。
$(TARGET_DRV)-y += ./driver/led_drv.o:目标模块所需源文件。
obj-m := $(TARGET_DRV).o:目标。告诉内核要编译成模块。
- obj-y:编译驱动到内核。 obj-m:编译驱动为模块。 obj-n:不编译。
- 驱动模块的多源文件编译:obj-m := $(TARGET).o 是告诉 makefile 最总的编译目标。而 $(TARGET)-y 则是告诉 makefile 该总目标依赖哪些目标文件。(为固定格式,如总目标为
xxx.o,那么它依赖的源文件应该这样指定xxx-y +=)(也可以使用 xxx-objs)
编译参数:
ccflags-y := -I$(MODDIR)/include:指定自定义头文件路径。这里只能使用 $(src) 来获取模块文件路径。
- External modules tend to place header files in a separate include/ directory where their source is located, although this is not the usual kernel style. To inform kbuild of the directory, use either ccflags-y or CFLAGS_.o.
目标 all:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules:原型是 make modules,即是编译模块目标,其它都是参数。
- -C $(KERNEL_DIR):把工作目录跳转到内核源码中。
- M=$(CURDIR):表示编译模块时,可以到该路径寻找模块源码进行编译。
- 推荐:观看内核文档 Documentation/kbuild/modules.rst
3. 源码
# @file Makefile
# @brief 驱动。
# @details led 驱动模块 Makefile 例程。
# @author lzm
# @date 2021-03-14 10:23:03
# @version v1.1
# @copyright Copyright By lizhuming, All Rights Reserved
#
# ********************************************************
# @LOG 修改日志:
# ********************************************************
# 编译后内核路径
KERNEL_DIR = /home/lss/work/kernel/imx6/ebf-buster-linux/build_image/build
# 定义框架
# ARCH 为 x86 时,编译链头为
# ARCH 为 arm 时,编译链头为 arm-linux-gnueabihf-
ARCH = arm
ifeq ($(ARCH),x86)
CROSS_COMPILE = # 交叉编译工具头,如:
else
CROSS_COMPILE = arm-linux-gnueabihf-# 交叉编译工具头,如:arm-linux-gnueabihf-
endif
CC = $(CROSS_COMPILE)gcc # 编译器,对 C 源文件进行编译处理,生成汇编文件
# 共享到sub-Makefile
export ARCH CROSS_COMPILE
# 路径
PWD := $(shell pwd)
# 当前模块路径
# $(src) 是内和文件定义并传过来的当前模块 M= 的路径。
MODDIR := $(src)
# 注意:驱动目标不要和文件名相同
TARGET_DRV := led_device_driver
TARGET_APP := led_app
# 本次整个编译需要源 文件 和 目录
# 这里的“obj-m” 表示该模块不会编译到zImage ,但会生成一个独立的xxx.ko 静态编译(由内核源码顶层Makefile识别)
# 模块的多文件编译:obj-m 是告诉 makefile 最总的编译目标。而 $(TARGET)-y 则是告诉 makefile 该总目标依赖哪些目标文件。(也可以使用 xxx-objs)
$(TARGET_DRV)-y += led_module.o
$(TARGET_DRV)-y += ./device/led_dev_a.o
$(TARGET_DRV)-y += ./driver/led_drv.o
obj-m := $(TARGET_DRV).o
# obj-m += $(patsubst %.c,%.o,$(shell ls *.c))
# 编译条件处理
# 指定头文件 由于该文件是 -C 后再被调用的,所以部分参数不能使用 $(shell pwd)
# $(src) 是内和文件定义并传过来的当前模块 M= 的路径。
ccflags-y := -I$(MODDIR)/include
ccflags-y += -I$(MODDIR)/device
ccflags-y += -I$(MODDIR)/driver
# 第一个目标 CURDIR 是该makefile内嵌变量,自动设置为当前目录
all :
@$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules
# make mobailes 就是是编译模块,上面是其添加参数的指令
# $(CROSS_COMPILE)gcc -o $(TARGET_APP) $(TARGET_APP).c
# 清理
.PHONY:clean
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
# rm $(TARGET_APP)
一个通用驱动Makefile-V2-支持编译多目录的更多相关文章
- 编写一个通用的Makefile文件
1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...
- Linux C编程学习之开发工具3---多文件项目管理、Makefile、一个通用的Makefile
GNU Make简介 大型项目的开发过程中,往往会划分出若干个功能模块,这样可以保证软件的易维护性. 作为项目的组成部分,各个模块不可避免的存在各种联系,如果其中某个模块发生改动,那么其他的模块需要相 ...
- 一个通用的Makefile(二)
1.各级子目录的Makefile: obj-y += file.o obj-y += subdir/ “obj-y += file.o” 表示把当前目录下的file.c编进程序里. “obj-y += ...
- 14、编写一个通用的Makefile
编译test_Makefile的方法:a. gcc -o test a.c b.c对于a.c: 预处理.编译(C文件转换成汇编).汇编(汇编转换成机器码)对于b.c:预处理.编译.汇编最后链接优点:命 ...
- 一步一步写一个简单通用的makefile(四)--写一个通用的makefile编译android可执行文件
通常要把我们自己的的代码编译成在android里面编译的可执行文件,我们通常是建一个文件夹 . ├── Android.mk ├── Application.mk ├── convolve.cl ├─ ...
- 一个通用的Makefile (转)
据http://bbs.chinaunix.net/thread-2300778-1-1.html的讨论,发现还是有很多人在问通用Makefile的问题,这里做一个总结.也作为以后的参考. ...
- 我所使用的一个通用的Makefile模板
话不多说,请看: 我的项目有的目录结构有: dirls/ ├── include │ └── apue.h ├── lib │ ├── error.c │ ├── error.o │ ...
- 一个简单的makefile,一次性编译本文件夹下所有的cpp文件
代码: CXX := g++ CFLAGS := -g TARGET := xxx.exe SRCS := $(wildcard *.cpp) OBJS := $(patsubst %cpp,%o,$ ...
- 一个通用的makefile(一)
最近在编写Android编译系统时,需要遍历每一个目录下每一个文件夹下的makefile,网上的方法有些繁琐 :就直接贴上自己遍历子目录深度为1:(for temporary)(之后会继续更新) 下 ...
随机推荐
- 洛谷p1966 火柴排队 (逆序对变形,目标排序
题目描述 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2 其中 ai 表示 ...
- mssql 2005安装
SQL Server 2005详细安装过程及配置 说明:个人感觉SQL Server 2005是目前所有的SQL Server版本当中最好用的一个版本了,原因就是这个版本比起其它版本来说要安装简单 ...
- Keras读取保存的模型时, 产生错误[ValueError: Unknown activation function:relu6]
Solution: from keras.utils.generic_utils import CustomObjectScope with CustomObjectScope({'relu6': k ...
- js & document.execCommand
js & document.execCommand click copy document.execCommand 已废弃 过时的 此功能已过时.尽管它可能在某些浏览器中仍然可以使用,但不建议 ...
- 一个最简单 node.js 命令行工具
一个最简单 node.js 命令行工具 node.js cli $ node cli.js xyz # OR $ node cli xyz 接受参数 process.argv js "use ...
- 算法型稳定币USDN有什么魔力引发市场热潮?
最近比特币重新突破了8万大关,区块链行业又再次火爆起来,吸引了圈内圈外人的火热讨论,而这其中市场投资者讨论最频繁的就要属算法型稳定币USDN了. USDN是基于NGK.IO区块链中的稳定币, 1枚US ...
- 加州金融专访NGK,就NGK DeFi+展开讨论
近日,加利福尼亚金融日报联合数家知名媒体就DeFi+行业专访了NGK团队代表特德惠斯基. 首先,加利福尼亚金融日报专栏记者迈尔斯表示,目前区块链领域,去中心化金融(DeFi+)的概念是目前市场上面最火 ...
- 如何使用irealtime.js实现一个基于websocket的同步画板
同步画板演示 同时打开2个tab,分别在画布上写下任意内容,观察演示结果,同时可设置画笔颜色及线条宽度.演示地址 初始化画布 <canvas id="drawBoard" w ...
- sun公司和apache使用ftpclient的区别
最近因为使用FTP实现上传下载,因为已经有前辈使用了,照着敲了一遍(绝对没有复制粘贴啊,发誓).但是今天突然发现FTPClient还不一样,仔细看了看,一个是sun.net.ftp.FtpClient ...
- 创建AD域之后设置DNS服务访问外网
AD域内需要有DNS服务器,用于解析域内的计算机名,域内的计算解析公网的域名需要设置一个转发器(Forwarder). 一定要设置好自己的默认网关.DNS因为部署在AD服务器上,直接loopback地 ...