嵌入式Linux驱动开发系列六:Makefile

Makefile是什么?

gcc hello.c -o hello

gcc aa.c bb.c cc.c dd.c ...

make工具和Makefile

make和Makefile是什么关系?

make工具:找出修改过的文件,根据依赖关系,找出受影响的相关文件,最后按照规则单独编译这些文件。

Makefile文件:记录依赖关系和编译规则。

必须要学精Makefile吗?

嵌入式Linux驱动开发系列六:Makefile_第1张图片

怎么学习Makefile?

Makefile的本质:无论多么复杂的语法,都是为了更好地解决项目文件之间的依赖关系。

 嵌入式Linux驱动开发系列六:Makefile_第2张图片

嵌入式Linux驱动开发系列六:Makefile_第3张图片

嵌入式Linux驱动开发系列六:Makefile_第4张图片

嵌入式Linux驱动开发系列六:Makefile_第5张图片

嵌入式Linux驱动开发系列六:Makefile_第6张图片

 嵌入式Linux驱动开发系列六:Makefile_第7张图片

嵌入式Linux驱动开发系列六:Makefile_第8张图片

嵌入式Linux驱动开发系列六:Makefile_第9张图片

嵌入式Linux驱动开发系列六:Makefile_第10张图片

Makefile三要素

Makefile三要素是什么?

目标、依赖、命令

怎么描述三要素的关系?

目标:依赖的文件或者是其他目标  ( 记得加TAB字符)

命令1 

命令2

...

实验演示

.PHONY:可以指定伪目标

gec@ubuntu:~/makefile/part_1$ sudo vi Makefile
gec@ubuntu:~/makefile/part_1$ sudo make
echo "targetb"
targetb
echo "targetc"
targetc
echo "targeta"
targeta
gec@ubuntu:~/makefile/part_1$ cat Makefile 
#Makefile格式
#目标:依赖的文件或其它目标
#Tab 命令1
#Tab 命令2
#第一个目标,是最终目标及make的默认目标
#目标a,依赖于目标targetc和targetb
#目标要执行的shell命令 ls -lh,列出目录下的内容
targeta: targetb targetc
	echo "targeta"

#目标b,无依赖
#目标要执行的shell命令,使用touch创建test.txt文件
targetb:
	echo "targetb"

#目标c,无依赖
#目标要执行的shell命令,pwd显示当前路径
targetc:
	 echo "targetc"
#目标d,无依赖
#由于abc目标都不依赖于目标d,所以直接make时目标d不会被执行
#可以使用make targetd命令执行
#  targetd:
#  rm -f test.txt
gec@ubuntu:~/makefile/part_1$ 

上图中包含的原理说明如下:

make命令:

在终端上执行make命令时,make会在当前目录下搜索名为“Makefile”或“makefile”的文件,然后 根据该文件的规则解析执行。如果要指定其它文件作为输入规则,可以通过“-f”参数指定输 入文件,如“make -f 文件名”。

此处make命令读取我们的Makefile文件后,发现targeta是Makefile的第一个目标,它会被当成默认目标执行。

又由于targeta依赖于targetc和targetb目标,所以在执行targeta自身的命令之前,会先去完成targetc和targetb。

targetc的命令为pwd,显示了当前的路径。

targetb的命令为touch test.txt ,创建了test.txt文件。

最后执行targeta自身的命令ls -lh ,列出当前目录的内容,可看到多了一个test.txt文件。

.PHONY 是一个在 Makefile 中使用的特殊目标标签(伪目标),用于指示某个目标不对应实际的文件。

通常,Makefile 中的目标都对应着需要生成的文件,而这些目标称为“真实目标”。但有时候,我们需要定义一些在执行 make 命令时需要执行的操作,而这些操作不产生对应的文件。这时就可以使用 .PHONY 来定义这样的目标。

.PHONY 的作用是告诉 make 工具,无论是否存在与之同名的文件,它所标记的目标都应该被认定为需要执行的操作。这样,在执行该目标时,make 将会按照你在 Makefile 中定义的命令来执行相应的操作,而不会检查是否有与之同名的文件存在。

使用 .PHONY 的一个常见场景是在 Makefile 中定义一些常用的操作,比如 clean 来清理临时文件,或者 all 来构建所有的目标。

示例:

.PHONY: clean clean: rm -f *.o

在上述示例中,.PHONY: clean 表示 clean 目标是一个伪目标,不对应任何文件。当执行 make clean 命令时,将会执行 rm -f *.o 命令,删除所有 .o 结尾的临时文件。

总结来说,.PHONY 是用来定义伪目标的,它告诉 make 工具,该目标不对应任何文件,而是需要执行一些特定的操作

 

 

在Makefile的实际应用中,通常会把编译和最终的链接过程分开

嵌入式Linux驱动开发系列六:Makefile_第11张图片

 也就是说,我们的hello_main目标文件本质上并不是依赖hello_main.c和hello_func.c文件,而是依 赖于hello_main.o和hello_func.o,把这两个文件链接起来就能得到我们最终想要的hello_main目 标文件。另外,由于make有一条默认规则,当找不到xxx. o文件时,会查找目录下的同名xxx.c文件进行编译。根据这样 的规则,我们可把Makefile改修改如下。

#Makefile格式
#目标文件:依赖的文件
#Tab 命令1
#Tab 命令2
hello_main: hello_main.o hello_func.o
   gcc -o hello_main hello_main.o hello_func.o
#以下是make的默认规则,下面两行可以不写
#hello_main.o: hello_main.c
# gcc -c hello_main.c

#以下是make的默认规则,下面两行可以不写
#hello_func.o: hello_func.c
# gcc -c hello_func.c

以上代码的第5~6行把依赖文件由C文件改成了.o文件,gcc编译命令也做 了相应的修改。第8~13行分别是hello_main.o文件和hello_func.o文件的依赖和 编译命令,不过由于C编译成同名的.o文件是make的默认规则,所以这部分内容通常不会写上去。

Makefile的变量、模式匹配

变量

系统变量

嵌入式Linux驱动开发系列六:Makefile_第12张图片

自定义变量

=,延迟赋值

嵌入式Linux驱动开发系列六:Makefile_第13张图片

:=, 立即赋值

嵌入式Linux驱动开发系列六:Makefile_第14张图片

?=,空赋值(像const)

只有当这个变量为空时赋值才有效

嵌入式Linux驱动开发系列六:Makefile_第15张图片

+=,追加赋值

当我们用追加赋值给某个变量赋值时,不会覆盖该变量的值,而是在该变量原来的值后面加上新赋的值

 嵌入式Linux驱动开发系列六:Makefile_第16张图片

自动化变量

$<:第一个依赖文件

嵌入式Linux驱动开发系列六:Makefile_第17张图片

$^:全部的依赖文件

嵌入式Linux驱动开发系列六:Makefile_第18张图片

$@:目标

 嵌入式Linux驱动开发系列六:Makefile_第19张图片

优化

嵌入式Linux驱动开发系列六:Makefile_第20张图片

模式匹配

%:匹配任意多个非空字符

shell:*通配符

嵌入式Linux驱动开发系列六:Makefile_第21张图片

默认规则

.o文件默认使用当前目录下对应.c文件来进行编译

嵌入式Linux驱动开发系列六:Makefile_第22张图片

Makefile条件分支

条件分支

如果相等
ifeq (var1,var2)
...
else
...
endif
ifneq (var1,var2)
...
else
...
endif

嵌入式Linux驱动开发系列六:Makefile_第23张图片

Makefile的常用函数

Makefie官方手册:

GNU Make Manual - GNU Project - Free Software Foundation

patsubst:

 文本匹配成新的模式

嵌入式Linux驱动开发系列六:Makefile_第24张图片

notdir:

嵌入式Linux驱动开发系列六:Makefile_第25张图片

  1. $(notdir )
  • 名称:取文件函数——notdir。

  • 功能:从文件名序列  中取出非目录部分。非目录部分是指最後一个反斜杠( / )之后的部分。

  • 返回:返回文件名序列  的非目录部分。

  • 示例: $(notdir src/foo.c hacks) 返回值是 foo.c hacks 。

嵌入式Linux驱动开发系列六:Makefile_第26张图片

wildcard:

嵌入式Linux驱动开发系列六:Makefile_第27张图片

示例:

(wildcard *.c) 

 返回值为当前目录下所有.c 源文件列表。

foreach:

Makefile解决头文件依赖

1、写一个头文件,并把头文件添加到编译器的头文件路径中。

gcc -I +"头文件"

2、实时检查头文件的更新情况,一旦头文件发生变化,应该要重新编译所有相关文件。

gcc -MM

ARCH ?= x86 


ifeq ($(ARCH),x86)
        CC=gcc

else 
        CC=arm-linux-gnueabihf-gcc
endif



TARGET=mp3
#OBJS=main.o mp3.o
BUILD_DIR=build
SRC_DIR=module1 module2
INC_DIR=include
CFLAGS=$(patsubst %,-I%,$(INC_DIR))
INCLUDES=$(foreach dir,$(INC_DIR),$(wildcard $(dir)/*.h))


SOURCES= $(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c))

OBJS=$(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SOURCES)))
VPATH=$(SRC_DIR)




$(BUILD_DIR)/$(TARGET):$(OBJS)
        $(CC) $^ -o $@


#main.o:main.c
#       $(CC) -c main.c -o main.o
#mp3.o:mp3.c
#       $(CC) -c mp3.c -o mp3.o

$(BUILD_DIR)/%.o:%.c $(INCLUDES) | creat_build
        $(CC) -c $< -o $@ $(CFLAGS)

.PHONY:clean creat_build

clean:                                                                                                                                                                                                      
        rm -r $(BUILD_DIR)
creat_build:
        mkdir -p $(BUILD_DIR)

 

你可能感兴趣的:(linux,驱动开发,运维)