:=
(立即赋值)
定义变量并立即展开右侧表达式,例如:
BUILD_DIR := build # BUILD_DIR 值为 "build"
+=
(追加赋值)
向变量追加新值,例如:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
=
(延迟赋值)
变量值在引用时才会展开,例如:
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
$(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"
$(wildC++ard pattern)
通配符匹配文件,例如:
$(wildcard *.c) # 返回所有 .c 文件的列表
$(shell command)
执行 Shell 命令并返回结果,例如:
PWD := $(shell pwd) # 获取当前目录路径
ifneq (a,b)
/ ifeq (a,b)
比较两个值是否不等/相等,例如:
ifneq ($(KERNELRELEASE),) # 如果 KERNELRELEASE 非空
$(if condition,then-part,else-part)
条件函数,例如:
$(if $(wildcard dir),,mkdir dir) # 目录不存在则创建
目标-依赖规则
target: dependency
command # 命令必须以 Tab 开头
示例:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
0
.PHONY
伪目标
声明目标不代表实际文件,例如:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
1
%
(通配符)
模式匹配,例如:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
2
$@
、$<
、$^
(自动变量)
$@
:当前目标名(如 install
)。$<
:第一个依赖文件名。$^
:所有依赖文件列表。$(foreach var,list,text)
遍历列表并执行操作,例如:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
3
多行命令
使用 \
换行或直接换行(需保持缩进),例如:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
4
.PHONY
)的作用。:=
、=
、?=
、+=
)。subst
、wildcard
、foreach
)。ifdef
、ifeq
、ifneq
。$(if)
。%
的使用。.c
→ .o
)。$(info ...)
或 $(warning ...)
输出变量值。make -n
查看命令但不执行。从简单项目入手
编写一个编译多文件 C 项目的 Makefile,逐步添加变量和条件。
示例:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
5
分析现有 Makefile
动手调试
$(info VAR=$(VAR))
打印变量值。make -p
查看内置规则和变量。abspath
或 realpath
避免相对路径问题。RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
6
build
目录中创建符号链接,保持与源码相同的目录结构。$(foreach i,...)
遍历 MODULE_SRC
列表中的每个文件路径 i
。$(if $(wildcard ...))
检查目标目录是否存在,若不存在则执行 mkdir -p
。$(shell ln -s ...)
创建软链接,使编译时能正确找到源文件。RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
7
路径与编译选项:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
8
条件分支:
RTSDK_CFLAGS += -D__KERNEL__ # 在原有 CFLAGS 后添加宏定义
9
link_file_local
目标:
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
0
安装:
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
1
清理:
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
2
设置变量(在 Makefile 或命令行中):
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
3
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
4
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
5
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
6
问题现象 | 原因与解决方案 |
---|---|
No such file or directory |
OSS_LINUX_PATH 未定义或路径错误:在 Makefile 或命令行中指定正确路径。 |
模块编译后无法加载 | 内核版本与模块不匹配:确保 OSS_LINUX_PATH 指向与目标内核一致的源码目录。 |
符号链接未正确生成 | link_file_local 执行失败:检查 MODULE_SRC 变量是否包含有效源文件路径。 |
权限不足导致安装失败 | 使用 sudo 或确保 LKM_INSTALL_PATH 对当前用户可写。 |
VAR = $(shell date) # 每次引用 VAR 时才会执行 date 命令
7
OSS_LINUX_PATH
、ROOT_PATH
等变量与实际源码路径匹配。make menuconfig
并编译内核。uname -r
查看)。通过以上步骤,可高效管理内核模块的构建、安装与维护。