解释下面makefile内容的意思
- # Common part--------------------------------------------------------------------
- DRV_NAME := xxx
- DRV_PATH := xxxxx
-
- # KBuild part of makefile--------------------------------------------------------
- ifneq ($(KERNELRELEASE),)
-
- obj-m := $(DRV_NAME).o
- $(DRV_NAME)-objs += can_init.o
- $(DRV_NAME)-objs += sja1000/sja1000.o
- $(DRV_NAME)-objs += AAAA/AAAA.o
-
- EXTRA_CFLAGS += -std=gnu99
-
- # Normal makefile----------------------------------------------------------------
- else
-
- KVER := $(shell uname -r)
- KSRC ?= /lib/modules/$(KVER)/build
- KMOD ?= /lib/modules/$(KVER)/kernel/drivers/$(DRV_PATH)
-
- all:
- $(MAKE) -w -C $(KSRC) M=$(PWD) modules
这是一个 Linux 内核模块的 Makefile,用于构建一个名为 $(DRV_NAME)
的内核模块。让我解释一下每个部分的含义:
ifneq ($(KERNELRELEASE),)
:这是一个条件语句,检查是否在内核构建阶段。如果 KERNELRELEASE
已定义,说明是在内核构建阶段,将执行下面的代码。obj-m := $(DRV_NAME).o
:定义了要构建的内核模块的目标文件。$(DRV_NAME)-objs += ...
:指定模块的源文件。这里包括 can_init.o
、sja1000/sja1000.o
、AAAA/AAAA.o
。EXTRA_CFLAGS += -std=gnu99
:指定编译模块时要使用的额外编译标志,这里是将 C 语言标准设置为 GNU99。else
:如果不在内核构建阶段,执行下面的代码。KVER := $(shell uname -r)
:获取当前系统的内核版本。KSRC ?= /lib/modules/$(KVER)/build
:指定内核源代码的路径,默认为 /lib/modules/$(KVER)/build
。KMOD ?= /lib/modules/$(KVER)/kernel/drivers/$(DRV_PATH)
:指定模块要安装的位置,默认为 /lib/modules/$(KVER)/kernel/drivers/$(DRV_PATH)
。all:
:定义了一个名为 "all" 的目标,该目标将在执行 make
命令时被调用。$(MAKE) -w -C $(KSRC) M=$(PWD) modules
:这是实际构建模块的命令。它告诉 make
到内核源代码路径 $(KSRC)
下执行构建,并使用当前目录 $(PWD)
中的 Makefile。最终目标是构建内核模块。这个 Makefile 的目的是构建一个名为 $(DRV_NAME)
的内核模块,包括指定的源文件。在构建阶段,它会使用指定的内核源代码路径进行编译。
KMOD ?=xxx的作用是?
在给定的 Makefile 中,KMOD ?= xxx
的作用是定义一个变量 KMOD
,并为其设置默认值为 xxx
。这样的语法通常被用于为变量提供默认值,但允许在执行 make
命令时通过命令行参数进行覆盖。
具体来说:
KMOD ?= /lib/modules/$(KVER)/kernel/drivers/$(DRV_PATH)
设置了变量 KMOD
的默认值。make
命令时未提供对 KMOD
的显式赋值,它将采用默认值。make
命令时通过命令行为 KMOD
赋值,那么该命令行上的值将覆盖默认值。这样做的好处是,它允许用户在不修改 Makefile 的情况下通过命令行参数动态地修改变量的值。例如:
make KMOD=/path/to/custom/directory
在上述命令中,KMOD
将被设置为 /path/to/custom/directory
,而不是默认值。
KDIR := xxx的作用?
在 Linux 内核模块的 Makefile 中,KDIR := xxx
用于指定内核源代码的路径。通常,这是为了告诉 make
在哪里可以找到内核源代码以便编译内核模块。
具体来说:
KDIR
是一个变量,用于存储内核源代码的路径。:=
是 Makefile 中的赋值运算符,表示立即展开,即在执行 make
时,xxx
的值就被赋给 KDIR
。xxx
应该是一个包含内核源代码的路径。举例来说,如果内核源代码位于 /usr/src/linux-headers-$(shell uname -r)
,你可以在 Makefile 中这样设置 KDIR
:
KDIR := /usr/src/linux-headers-$(shell uname -r)
这个路径是一个常见的默认路径,通常包含与当前运行的内核版本匹配的头文件和配置信息。
然后,在 Makefile 中,你可以使用 KDIR
变量来指定内核源代码的位置,比如在编译内核模块时:
- all:
- $(MAKE) -C $(KDIR) M=$(PWD) modules
上述命令告诉 make
在指定的内核源代码路径中进行编译,使用当前目录 ($(PWD)
) 中的 Makefile 编译内核模块。这样可以确保内核模块编译使用了正确版本的头文件和配置。
can_dev 2>/dev/null 这个是什么意思?
这是一个 shell 命令,用于运行名为 can_dev
的可执行文件,并将标准错误流(stderr)重定向到 /dev/null
。
具体来说:
2>
表示将标准错误流重定向。/dev/null
是一个特殊的设备文件,用于丢弃数据。在这里,它用作标准错误流的目标,即将错误信息输出到空设备,从而将其消除。整体来说,这个命令的目的是在运行 can_dev
可执行文件时,忽略掉任何可能产生的错误消息,将错误信息丢弃到 /dev/null
中,而不在终端或日志中显示。这种做法通常用于在脚本中执行命令时,希望保持输出干净,不受错误消息的干扰。
modprobe的作用?
modprobe
是 Linux 系统中用于加载和卸载内核模块的命令。它的作用包括:
加载内核模块: 使用 modprobe
命令可以动态地加载指定的内核模块到系统中,使其成为可用的内核功能。加载模块通常会触发相应的硬件初始化或功能启动。
modprobe module_name
例如,如果要加载名为 my_module
的内核模块,可以运行:
modprobe my_module
自动解决依赖关系: modprobe
会自动解决并加载指定模块所依赖的其他模块,确保加载过程中所有依赖关系都被满足。
卸载内核模块: 除了加载,modprobe
也可以用于卸载已加载的内核模块。
modprobe -r module_name
例如,要卸载名为 my_module
的内核模块,可以运行:
modprobe -r my_module
配置文件查找: modprobe
还会查找配置文件,如 /etc/modprobe.conf
和 /etc/modprobe.d/*
,以获取有关模块加载和相关设置的额外信息。
总体而言,modprobe
提供了一个方便的命令行界面,用于管理系统中的内核模块。
$(shell ! [ -d $(KMOD) ] && mkdir $(KMOD))
这个是啥意思?
这是一个在 Makefile 中使用的 GNU Make 扩展语法,用于检查目录是否存在,如果不存在则创建目录。
让我们解释一下这个命令:
$(shell ...)
是 GNU Make 中用于执行 shell 命令的函数。! [ -d $(KMOD) ]
是一个 shell 条件语句,用于检查 $(KMOD)
是否为一个目录。
-d $(KMOD)
检查目录是否存在。! [ ... ]
表示逻辑取反,即如果目录不存在,则条件为真。mkdir $(KMOD)
用于创建目录 $(KMOD)
。因此,整个命令的意思是,如果目录 $(KMOD)
不存在,则创建它。这种技巧通常用于确保在编译或安装过程中某个目录存在,以避免后续操作出现错误。
$(shell cp -f ./$(DRV_NAME).ko $(KMOD)/ && depmod && modprobe $(DRV_NAME))
这个是啥意思?
这是一个在 Makefile 中使用的 GNU Make 扩展语法,用于执行一系列 shell 命令。让我们逐步解释这个命令:
$(shell ...)
是 GNU Make 中用于执行 shell 命令的函数。
cp -f ./$(DRV_NAME).ko $(KMOD)/
:这个命令使用 cp
命令将当前目录下的 $(DRV_NAME).ko
文件复制到目标目录 $(KMOD)
,并使用 -f
选项强制覆盖目标目录中的同名文件。
depmod
:这个命令用于生成模块依赖关系,通常在安装新的内核模块后运行,以确保内核正确识别和加载模块。
modprobe $(DRV_NAME)
:这个命令用于加载指定的内核模块,其中 $(DRV_NAME)
是模块的名称。
因此,整个命令的意思是,在执行 make 命令时:
$(DRV_NAME).ko
文件复制到目标目录 $(KMOD)
。depmod
以更新模块依赖关系。modprobe $(DRV_NAME)
以加载新的内核模块。这样的命令通常用于在安装或编译过程中自动安装和加载内核模块。
$(shell if grep advsocketcan /proc/modules > /dev/null ; then \ rmmod advsocketcan; fi)
这的意思?
这是一个在 Makefile 中使用的 GNU Make 扩展语法,用于执行一系列 shell 命令。让我们逐步解释这个命令:
$(shell ...)
是 GNU Make 中用于执行 shell 命令的函数。
if grep advsocketcan /proc/modules > /dev/null ; then rmmod advsocketcan; fi
是一个 shell 条件语句,它的作用是:
grep advsocketcan /proc/modules
用于检查 /proc/modules
文件中是否包含字符串 "advsocketcan"。这个文件列出了当前加载的内核模块。
> /dev/null
是将输出重定向到 /dev/null
,即丢弃输出,不显示在终端上。
如果 grep
命令成功找到了 "advsocketcan" 字符串,条件为真,那么 then
后面的命令 rmmod advsocketcan
将卸载名为 "advsocketcan" 的内核模块。
整个命令的目的是在执行 make 命令时,检查系统中是否已经加载了名为 "advsocketcan" 的内核模块,如果已经加载,则使用 rmmod
命令将其卸载。这样的操作通常用于确保在重新安装或编译时,先卸载已加载的模块,以便重新加载新的模块。