文章目录
前言
上一篇我们讲完了,驱动在内核如何运行,我们输出了一个hello kernel的打印,但如果阅读者是不太那么懂的新手,可能对于某些名词,比如makefile、config、GLP协议等,我们就抽出一节来,单独讲一下这些内容。也巩固一下笔者的基础。这节主要是makeifle,下节config,下下节GPL。慢慢的学习Linux的内容。
makefile
makefile是什么呢,我是这样理解他的,比如windows的bat、linux的shell,当然bat里面还可以调用bat、shell里面还可以调用shell。当然makefile里可以调用makefile,甚至shell里面调用makefile,反之亦然。这种错综复杂,到融汇贯通的东西。只有亲自经历大量的项目就明白了,非常简单。
概念: makefile就是方便我们构建编译规则的一个脚本语法,根据它的语法,我们方便组织我们的代码。
语法指令就三个。
目标(Target) :规则中要生成的文件或执行的操作名称,例如可执行文件或中间目标文件。
依赖(Prerequisites) :生成目标所需的文件或其他目标,若依赖文件更新,目标会重新生成。
命令(Recipe):以 Tab 键开头的命令行操作,用于从依赖生成目标。
makefile
target: prerequisites
<Tab>recipe
示例:编译 C 程序
makefile
hello: hello.c
gcc -o hello hello.c
常用变量与符号
变量定义:
makefile
CC = gcc
CFLAGS = -Wall
使用变量:
makefile
hello: hello.c
$(CC) $(CFLAGS) -o hello hello.c
自动变量
- $@:当前目标名(如 hello)。
- $^:所有依赖文件(如 hello.c)。
- $<:第一个依赖文件。
高级功能
模式规则:通配符简化重复规则,例如编译所有 .c 文件:
makefile
%.o: %.c
$(CC) -c $< -o $@
伪目标:声明不生成文件的操作(如 clean):
makefile
.PHONY: clean
clean:
rm -f *.o hello
讲解上一篇内核的makefile细节
makefile
# 外层:把 lianxi/ 当成一个子模块目录交给内核 Kbuild
obj-m += lianxi/
# 与 QEMU 里跑的自编内核对齐(你文档里的 linux-6.19.11)
KDIR ?= /home/jiaju/learn/Linux/Linux_src/linux-6.19.11
# 若要在「当前宿主机」上 insmod 做实验,可改用:
# KDIR ?= /lib/modules/$(shell uname -r)/build
.PHONY: all clean
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
obj-m不要被名字吓到,他只是一个变量而已,通过这个变量使用追加等于(+=)的方式赋值给obj-m,追加等于也就是说不会破坏之前obj-m这个变量已经有的值,因为内核模块不仅仅只有我们这个模块,肯定之前会有,之后也会有新增的,所以使用obj-m的方式把我们的目录添加进来。
后面随着深入在内核配合Kconfig可能会见到obj-$(CONFIG_A)之类的,所以他只是个给内核编译用的变量而已
在 Linux 内核模块编译的 Makefile 中,obj-m += lianxi/ 表示将 lianxi 目录作为一个模块进行编译。
那么下一行的KDIR ?= /home/jiaju/learn/Linux/Linux_src/linux-6.19.11 是什么意思,KDIR也是一个变量,通过?=的方式赋值,如果这个在这之前有定义,那么这里就不会赋值,相反如果是第一次定义这个变量,之前没见过,那么这里就会定义这个变量并赋值后面的目录。
.PHONY: all clean 说明我们makefile 可以在命令行输入俩种参数,make all ,make clean,输入哪一个就进入那一个规则进行执行。
比如我们输入make all,makefile会由上到下执行定义一些我们提前写好的变量比如obj-m,KDIR然后找到我们指定的规则all进行执行命令。
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
$(MAKE)的意思是,我再次调用了make,例如shell里面调用了另一个shell一样,-C指定目录,我make是哪个文件夹下的makefile,然后后面是我们的变量,变量的使用方式也是$(变量名),也就用的是/home/jiaju/learn/Linux/Linux_src/linux-6.19.11这个目录,相当于在这个目录下又执行了一次make 然后运行什么规则呢? modules,回过头来原来是用的内核的makefile去编译我们的模块啊,我们只是包装了一层罢了。
是不是很绕呢?哈哈,这算简单的啦~,经过上面这层套壳我们知道了,其实还是用的内核本身的规则去编译模块,所以我们在makefile里面注释:与 QEMU 里跑的自编内核对齐(你文档里的 linux-6.19.11)
提问为什么我们懂了shell已经很不容易了,为什么不直接用shell编写规则呢?
答案:略。自行找理由查找~
结束
这节作为补充makefile相关细节一点的基础和操作。
其实makefile知识点无非就是这些,规则、命令、依赖。以及变量的几种定义和赋值方式,?= (定义赋值), :=(立即赋值) , =(延时赋值),以及发明makefile的人,懒得写变量使用$@(当前目标名),$^(所有依赖) ,$<(第一个依赖)。
剩下一些突入其来的函数,和一些高级的使用方式见的多了,自然而然就明白了。
希望能够引发你们的思考,和进步。所以说看似上节简单的代码,背后其实有绝对硬核的基础进行支撑。我们下一节来聊聊config。