Makefile 中一些常用语法讲解

 解释下面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.osja1000/sja1000.oAAAA/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 系统中用于加载和卸载内核模块的命令。它的作用包括:

  1. 加载内核模块: 使用 modprobe 命令可以动态地加载指定的内核模块到系统中,使其成为可用的内核功能。加载模块通常会触发相应的硬件初始化或功能启动。

    modprobe module_name

    例如,如果要加载名为 my_module 的内核模块,可以运行:

    modprobe my_module
  2. 自动解决依赖关系: modprobe 会自动解决并加载指定模块所依赖的其他模块,确保加载过程中所有依赖关系都被满足。

  3. 卸载内核模块: 除了加载,modprobe 也可以用于卸载已加载的内核模块。

    modprobe -r module_name

    例如,要卸载名为 my_module 的内核模块,可以运行:

    modprobe -r my_module

  4. 配置文件查找: 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 命令。让我们逐步解释这个命令:

  1. $(shell ...) 是 GNU Make 中用于执行 shell 命令的函数。

  2. cp -f ./$(DRV_NAME).ko $(KMOD)/:这个命令使用 cp 命令将当前目录下的 $(DRV_NAME).ko 文件复制到目标目录 $(KMOD),并使用 -f 选项强制覆盖目标目录中的同名文件。

  3. depmod:这个命令用于生成模块依赖关系,通常在安装新的内核模块后运行,以确保内核正确识别和加载模块。

  4. 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 命令将其卸载。这样的操作通常用于确保在重新安装或编译时,先卸载已加载的模块,以便重新加载新的模块。

你可能感兴趣的:(linux常用操作,驱动开发,linux驱动开发,linux,运维,服务器)