### 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
在 Linux 内核的发展历程中,从版本 2.4 到 2.6 的过渡是一个重要的里程碑。这一时期的内核不仅在性能、稳定性和安全性方面有了显著提升,而且在模块化支持上也做了很多改进。这些改进对于设备驱动程序的开发有着深远的影响。
#### 1. 取得内核版本并判断兼容性
在同时支持多个内核版本(例如 2.4 和 2.6)的场景下,了解如何获取内核版本以及根据版本选择不同的编译选项是非常重要的。为了实现这一点,通常会使用宏 `LINUX_VERSION_CODE` 来判断当前内核的版本号,并据此选择合适的代码路径。
例如:
```c
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
#define LINUX26
#endif
#ifdef LINUX26
// code specific to the 2.6 kernel
#else
// code specific to the 2.4 kernel
#endif
```
这段代码通过 `KERNEL_VERSION` 宏定义了一个内核版本的值,并与 `LINUX_VERSION_CODE` 进行比较,从而决定执行哪部分代码。这种方法使得开发者能够轻松地编写兼容不同内核版本的代码。
#### 2. 模块编译方式的变化
从 2.4 版本到 2.6 版本,Linux 内核在模块编译方面发生了很大的变化。在 2.4 内核中,模块编译主要依赖于自定义的 Makefile 文件,而在 2.6 版本中,则引入了 kbuild,这是一个更加灵活和强大的构建系统,可以更好地管理和自动化模块的构建过程。
##### 2.4 版本的 Makefile 示例
在 2.4 版本中,Makefile 文件的结构比较简单,通常包含以下几个部分:
1. **获取内核版本**:使用 `uname -r` 命令来获取当前运行的内核版本。
2. **设置内核目录**:定义 `KDIR` 变量指向内核的 build 目录。
3. **编译目标和源文件**:定义 `OBJS` 变量来指定要编译的源文件。
4. **编译选项**:通过 `CFLAGS` 变量设置编译器的选项。
5. **编译规则**:定义 `all` 规则来触发编译过程。
示例 Makefile 如下所示:
```make
KVER=$(shell uname -r)
KDIR=lib/modules/$(KVER)/build
OBJS=mymodule.o
CFLAGS=-D__KERNEL__ -I$(KDIR)/include -DMODULE -D__KERNEL_SYSCALLS__ -DEXPORT_SYMTAB -O2 -ffunction-sections -fdata-sections -fomit-frame-pointer -Wall -DMODVERSIONS -include $(KDIR)/include/linux/modversions.h
all: $(OBJS)
mymodule.o: file1.o file2.o
ld -r -o $@ $^
```
##### 2.6 版本的 Makefile 示例
到了 2.6 版本,Makefile 文件变得更加简洁和高效,主要依赖于 kbuild 系统。kbuild 通过一系列规则和变量自动处理模块的编译过程。
示例 Makefile 如下所示:
```make
ifneq ($(KERNELRELEASE),)
# kbuild syntax.
mymodule-objs := file1.o file2.o
obj-m += mymodule.o
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD)
clean:
rm -rf .*.cmd *.o *.mod.c *.ko *.tmp_versions
endif
```
在 2.6 版本中,通过 `KERNELRELEASE` 变量来区分是否是在内核构建环境中运行。如果是,则使用 kbuild 语法;如果不是,则手动调用 `$(MAKE) -C $(KDIR) M=$(PWD)` 来构建模块。
#### 结论
从 2.4 到 2.6 的过渡期间,Linux 内核在模块机制上进行了大量的改进,这些改进提高了模块的灵活性和可维护性,同时也降低了设备驱动程序开发者的负担。通过采用新的构建系统和技术,内核开发者能够更加高效地管理模块,并确保它们能够无缝地集成到内核中。这对于推动 Linux 系统的整体发展起到了积极的作用。