makefile
Makefile.lkm 语法解析与学习指南一、Makefile.lkm 涉及的语法与符号详解
1. 变量定义与赋值
[*]:=(立即赋值)
定义变量并立即展开右侧表达式,比方:
BUILD_DIR := build# BUILD_DIR 值为 "build"
[*]+=(追加赋值)
向变量追加新值,比方:
RTSDK_CFLAGS += -D__KERNEL__# 在原有 CFLAGS 后添加宏定义
[*]=(延迟赋值)
变量值在引用时才会展开,比方:
VAR = $(shell date)# 每次引用 VAR 时才会执行 date 命令
2. 特殊变量与函数
[*]$(subst from,to,text)
字符串更换函数,比方:
$(subst $(ROOT_PATH)/,,src/root/module.c)# 输出 "src/module.c"
[*]$(addprefix prefix,names)
为每个名称添加前缀,比方:
$(addprefix build/, a.o b.o)# 输出 "build/a.o build/b.o"
[*]$(wildcard pattern)
通配符匹配文件,比方:
$(wildcard *.c)# 返回所有 .c 文件的列表
[*]$(shell command)
实行 Shell 下令并返回结果,比方:
PWD := $(shell pwd)# 获取当前目录路径
3. 条件判断
[*]ifneq (a,b) / ifeq (a,b)
比较两个值是否不等/相称,比方:
ifneq ($(KERNELRELEASE),)# 如果 KERNELRELEASE 非空
[*]$(if condition,then-part,else-part)
条件函数,比方:
$(if $(wildcard dir),,mkdir dir)# 目录不存在则创建
4. 规则与下令
[*]目标-依赖规则
target: dependency
command# 命令必须以 Tab 开头示例:
modules: link_file_local
$(MAKE) -C ...# 构建模块前先执行 link_file_local
[*].PHONY 伪目标
声明目标不代表实际文件,比方:
.PHONY: install clean# install 和 clean 是动作而非文件
5. 通配符与自动变量
[*]%(通配符)
模式匹配,比方:
%.o: %.c# 所有 .o 文件依赖对应的 .c 文件
[*]
<strong>$@、$ 函数 > 条件/循环。
[*]实践建议:从单一文件编译开始,逐步扩展到多目次、多条件项目。
$(foreach i,$(MODULE_SRC), ln -s $i ...)# 为每个源文件创建符号链接总结:Makefile.lkm 内容与 Linux 内核模块编译流程
一、Makefile.lkm 焦点内容解析
1. 变量定义
[*]路径与编译选项:
link_file_local:
$(foreach i,$(MODULE_SRC), \
$(shell ln -s ...))# 使用 \ 换行
2. 内核模块构建规则
[*]条件分支:
CC = gcc
CFLAGS = -Wall
OBJ = main.o utils.o
app: $(OBJ)
$(CC) $(CFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $<
3. 符号链接与目次管理
[*]link_file_local 目标:
# 生成符号链接到 build 目录
link_file_local:
$(foreach i,$(MODULE_SRC), \
$(if $(wildcard $(dir $(BUILD_DIR)/...)),, \
$(shell mkdir -p ...)) \
$(shell ln -s $i ...))
4. 安装与清理规则
[*]安装:
################################################################################
#
#
# Rules for building Linux Kernel Module
################################################################################
BUILD_DIR := build
LKM_INSTALL_PATH := $(ROOTFS_PATH)/lib/modules
RTSDK_CFLAGS += -D__KERNEL__
OUTPUT_MODULE_OBJ := $(addprefix $(BUILD_DIR)/,$(subst $(ROOT_PATH)/,,$(MODULE_OBJ)))
EXTRA_CFLAGS += $(RTSDK_CFLAGS)
EXTRA_LDFLAGS += $(RTSDK_LDFLAGS)
ifneq ($(KERNELRELEASE),)
obj-m := $(MODULE_NAME).o
$(MODULE_NAME)-objs := $(OUTPUT_MODULE_OBJ)
else
PWD := $(shell pwd)
modules: link_file_local
$(MAKE) -C $(OSS_LINUX_PATH) $(MAKEOPT) M=$(PWD) ARCH=$(RTSDK_ARCH) "CROSS_COMPILE=$(CROSS_COMPILE)" "CC=$(CC)" "LD=$(LD)" "AR=$(AR)" modules
endif
.PHONY: install
install:
ifeq ($(MODULE_NAME).ko, $(wildcard $(MODULE_NAME).ko))
$(if $(wildcard $(LKM_INSTALL_PATH)),,mkdir -p $(LKM_INSTALL_PATH))
$(STRIP) --strip-debug -R .note -R .comment $(MODULE_NAME).ko
cp $(MODULE_NAME).ko $(LKM_INSTALL_PATH)
@echo "$(MODULE_NAME).ko installed"
endif
clean distclean clean_all:
if [ -d $(BUILD_DIR) -a -d $(OSS_LINUX_PATH) ]; then $(MAKE) -C $(OSS_LINUX_PATH) M=$(PWD) "CC=$(CC)" "LD=$(LD)" "AR=$(AR)" clean; fi
@find \( -name '*.' -o -name 'Module.symvers' -o -name 'modules.order' \) -type f -print | xargs rm -rf
rm -rf $(BUILD_DIR)
link_file_local:
$(foreach i,$(MODULE_SRC),$(if $(wildcard $(dir $(BUILD_DIR)/$(subst $(ROOT_PATH),,$i))),,$(shell mkdir -p $(dir $(BUILD_DIR)/$(subst $(ROOT_PATH),,$i)))))
$(foreach i,$(MODULE_SRC),$(if $(wildcard $(BUILD_DIR)/$(subst $(ROOT_PATH),,$i)),,$(shell ln -s $i $(BUILD_DIR)/$(subst $(ROOT_PATH),,$i))))
[*]清理:
BUILD_DIR := build # 构建输出目录
LKM_INSTALL_PATH := $(ROOTFS_PATH)/lib/modules# 模块安装路径
RTSDK_CFLAGS += -D__KERNEL__ # 内核模块编译必选宏
OUTPUT_MODULE_OBJ := $(addprefix $(BUILD_DIR)/,$(subst $(ROOT_PATH)/,,$(MODULE_OBJ)))# 对象文件路径映射
二、Linux 内核模块编译流程
1. 准备环境
[*]设置变量(在 Makefile 或下令行中):
ifneq ($(KERNELRELEASE),)# 在内核构建系统中被调用时
obj-m := $(MODULE_NAME).o
$(MODULE_NAME)-objs := $(OUTPUT_MODULE_OBJ)
else# 用户态执行时
modules: link_file_local# 依赖符号链接创建
$(MAKE) -C $(OSS_LINUX_PATH) M=$(PWD) ... modules# 调用内核构建系统
endif
2. 编译模块
link_file_local:
# 创建构建目录结构,并为源文件创建符号链接到 build/ 目录
$(foreach i,$(MODULE_SRC), mkdir -p ... && ln -s ...)3. 安装模块
install:# 安装内核模块到根文件系统
$(STRIP) --strip-debug ...# 剥离调试符号
cp $(MODULE_NAME).ko $(LKM_INSTALL_PATH)4. 清理构建文件
clean distclean clean_all:# 删除构建产物
make -C $(OSS_LINUX_PATH) clean# 清理内核构建中间文件
rm -rf $(BUILD_DIR) ... # 删除本地构建目录三、常见问题与解决
问题现象原因与解决方案No such file or directoryOSS_LINUX_PATH 未定义或路径错误:在 Makefile 或下令行中指定正确路径。模块编译后无法加载内核版本与模块不匹配:确保 OSS_LINUX_PATH 指向与目标内核一致的源码目次。符号链接未正确生成link_file_local 实行失败:检查 MODULE_SRC 变量是否包含有效源文件路径。权限不足导致安装失败利用 sudo 或确保 LKM_INSTALL_PATH 对当前用户可写。四、完整编译流程图
# 示例:Realtek SDK 环境变量
export OSS_LINUX_PATH=/home/jiangzhiguo/SDK4_V4.4.1.55661/build/oss/linux-4.4.153
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-五、关键留意事项
[*]路径一致性:确保 OSS_LINUX_PATH、ROOT_PATH 等变量与实际源码路径匹配。
[*]内核配置:若修改内核选项(如添加驱动支持),需重新实行 make menuconfig 并编译内核。
[*]版本匹配:模块与运行中的内核版本必须一致(通过 uname -r 查看)。
通过以上步调,可高效管理内核模块的构建、安装与维护。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]