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

Makefile是什么?

gcc hello.c -o hello

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

make工具和Makefile

make和Makefile是什么关系?

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

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

必须要学精Makefile吗?

怎么学习Makefile?

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

 

 

Makefile三要素

Makefile三要素是什么?

目标、依赖、命令

怎么描述三要素的关系?

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

<tab>命令1 

<tab>命令2

<tab>...

实验演示

.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的实际应用中,通常会把编译和最终的链接过程分开

 也就是说,我们的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的变量、模式匹配

变量

系统变量

自定义变量

=,延迟赋值

:=, 立即赋值

?=,空赋值(像const)

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

+=,追加赋值

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

 

自动化变量

$<:第一个依赖文件

$^:全部的依赖文件

$@:目标

 

优化

模式匹配

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

shell:*通配符

默认规则

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

Makefile条件分支

条件分支

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

Makefile的常用函数

Makefie官方手册:

GNU Make Manual - GNU Project - Free Software Foundation

patsubst:

 文本匹配成新的模式

notdir:

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

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

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

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

wildcard:

示例:

(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)

猜你喜欢

转载自blog.csdn.net/qq_51519091/article/details/132146072