Embedded Linux driver development series six: Makefile

What is Makefile?

gcc hello.c -o hello

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

make tool and Makefile

What is the relationship between make and Makefile?

make tool: Find out the modified files, find out the affected related files according to the dependencies, and finally compile these files separately according to the rules.

Makefile: Record dependencies and compilation rules.

Do I have to learn Makefile?

How to learn Makefile?

The essence of Makefile: No matter how complex the syntax is, it is to better resolve the dependencies between project files.

 

 

Three elements of Makefile

What are the three elements of Makefile?

target, dependency, command

How to describe the relationship between the three elements?

Target: dependent files or other targets (remember to add TAB characters)

<tab>command 1 

<tab>command 2

<tab>...

Experiment demonstration

.PHONY: You can specify a pseudo-target

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$ 

The schematic illustration contained in the above diagram is as follows:

make command:

When the make command is executed on the terminal, make will search for a file named "Makefile" or "makefile" in the current directory, and then parse and execute it according to the rules of the file. If you want to specify other files as input rules, you can specify the input file through the "-f" parameter, such as "make -f file name".

After the make command here reads our Makefile, it finds that targeta is the first target of the Makefile, and it will be executed as the default target.

And because targeta depends on targetc and targetb targets, it will complete targetc and targetb before executing its own commands.

The command of targetc is pwd, which shows the current path.

The command of targetb is touch test.txt, and the test.txt file is created.

Finally, execute targeta's own command ls -lh to list the contents of the current directory, and you can see that there is an additional test.txt file.

.PHONYis a special target label (pseudo-target) used in Makefiles to indicate that a target does not correspond to an actual file.

Usually, the targets in the Makefile correspond to the files that need to be generated, and these targets are called "real targets". But sometimes, we need to define some operations that need to be performed when the make command is executed, and these operations do not generate corresponding files. Then you can use .PHONYto define such a target.

.PHONYThe effect of is to tell the make tool that the target it marks should be considered as an operation to be performed regardless of whether a file with the same name exists. In this way, when executing the target, make will execute the corresponding operation according to the command you defined in the Makefile, without checking whether there is a file with the same name as it.

A common scenario for using .PHONYis to define some common operations in the Makefile, such as cleanto clean up temporary files, or allto build all targets.

Example:

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

In the above example, the .PHONY: cleandenoted cleantarget is a pseudo-target that does not correspond to any file. When the command is executed make clean, the command will be executed rm -f *.o, deleting all .otemporary files ending in .

In summary, .PHONYit is used to define a pseudo-target, which tells the make tool that the target does not correspond to any file, but needs to perform some specific operations

 

 

In the actual application of Makefile, the compilation and final linking process are usually separated

 In other words, our hello_main target file does not depend on hello_main.c and hello_func.c files in essence, but depends on hello_main.o and hello_func.o. Linking these two files can get what we want in the end hello_main object file. In addition, because make has a default rule, when the xxx.o file cannot be found, it will search for the xxx.c file with the same name in the directory to compile. According to such rules, we can modify the Makefile as follows.

#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> 的非目录部分。

  • Example:  $(notdir src/foo.c hacks) The return value is  foo.c hacks .

wildcard:

Example:

(wildcard *.c) 

 The return value is a list of all .c source files in the current directory.

foreach:

Makefile resolves header file dependencies

1. Write a header file and add the header file to the header file path of the compiler.

gcc -I + "header file"

2. Check the update status of the header file in real time. Once the header file changes, all related files should be recompiled.

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)

 

Guess you like

Origin blog.csdn.net/qq_51519091/article/details/132146072