前言

该 Makefile 已经通过基于内核 Linux5.4 版本验证通过。

因为编写这通用驱动 Makefile 时遇到了头文件指定路径失败的问题。使用过 ccflags-y 、INCDIR 、EXTRA_CFLAGS 、-L 等等参数都无效。就是因为我使用了 $(shell pwd)。导致这些参数的路径都为内核源码路径下,而非模块路径。后面重新查看内核文档,看内核的推荐写法才解决了,使用 $(src) 来获取模块源码路径。正确指向自定义的头文件路径。所以有以下建议:

  • 建议:对于不同的 Linux 内核,应该去该内核文档看看 makefielKbuild 的语法及特点。(Documentation/kbuild)**

1. 特点

  1. 支持编译多目录Linux内核驱动
  2. 支持多目录源文件及头文件编译
  3. 兼容性高,修改接口宏即可

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 的

目标

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)

最新文章

  1. Android Stuido 常用快捷键
  2. salesforce 零基础学习(四十三)运算取余
  3. CSS的样式表基本概念
  4. HTML5的学习--performance
  5. Gym 100801E Easy Arithmetic (思维题)
  6. 在本地环境用虚拟机win2008 sever搭建VS2013 + SVN 代码版本控制环境
  7. shell小技巧
  8. thickbox关闭子页后ajax局部刷新父页
  9. .net项目IIS、VS 附加进程调试
  10. Dubbo入门实例 本地伪集群测试Demo
  11. 理解 Web 中的Session
  12. uniGUI -- Web 应用框架 Delphi + Ext JS
  13. 《Linux就该这么学》今天开课了-Linux的发展,起源
  14. SOA与微服务的区别
  15. No appenders could be found for logger
  16. 【CAS单点登录视频教程】 第01集-- 认识CAS
  17. FFT节省资源的思路
  18. 【遥感影像】Python GDAL 像素与坐标对应
  19. githug-54-git练习
  20. Expression Blend实例中文教程(3) - 布局控件快速入门Grid

热门文章

  1. Leetcode(29)-两数相除
  2. c# 类(2)
  3. js camelCase formatter
  4. 关于Google Chrome的使用小技巧!
  5. .NET 面试题: C# override && overloading (C# 覆写 && 重载)
  6. React Hooks: useState All In One
  7. how to import a SQL file in MySQL command line
  8. XPath in Action
  9. CSS border gradient color All In One
  10. Java & Maven & Spring & Spring Boot