Embedded linux development - (2) the use of Makefile

Series Article Directory



foreword

When we compile files, if there are many files, if we only use gcc to compile one file, the efficiency is too slow, and if we change a file, we need to recompile all of them, which is very troublesome. So there is a makefile tool.

1. Examples

We create a small project, which has three C files, main.c, input.c, and calcu.c, and
two header files, input.h, calcu.h. Among them, main.c is the main body, input.c is responsible for receiving the value input from the keyboard, and calcu.c adds any two numbers
, and the content of the main.c file is as follows:

//示例代码 3.3.2.1 main.c 文件代码
#include <stdio.h>
#include "input.h"
#include "calcu.h"
int main(int argc, char *argv[]){
    
    
	int a, b, num; 
	input_int(&a, &b);
	num = calcu(a, b);
	printf("%d + %d = %d\r\n", a, b, num);
}

The content of the input.c file is as follows:

//示例代码 3.3.2.2 input.c 文件代码
#include <stdio.h>
#include "input.h"
void input_int(int *a, int *b){
    
    
	printf("input two num:");
	scanf("%d %d", a, b);
	printf("\r\n");
}

The content of the calcu.c file is as follows:

//示例代码 3.3.2.3 calcu.c 文件代码
#include "calcu.h"
int calcu(int a, int b){
    
    
	return (a + b);
}

The content of the file input.h is as follows:

//示例代码 3.3.2.4 input.h 文件代码
#ifndef _INPUT_H
#define _INPUT_H
void input_int(int *a, int *b);
#endif

The content of the file calcu.h is as follows:

//示例代码 3.3.2.5 calcu.h 文件代码
#ifndef _CALCU_H
#define _CALCU_H
int calcu(int a, int b);
#endif

We use gcc to compile it and enter the command in the terminal:

gcc main.c calcu.c input.c -o main


Figure 1 uses gcc to compile the file

2. Compile with Makefile

Create a Makefile file in the project directory, the name is "Makefile", otherwise it cannot be compiled later.
Enter the code in the Make file:

//示例代码 3.3.2.6 Makefile 文件代码
main: main.o input.o calcu.o 
	gcc -o main main.o input.o calcu.o
main.o: main.c 
	gcc -c main.c
input.o: input.c
	gcc -c input.c
calcu.o: calcu.c
	gcc -c calcu.c 9 

clean:
	rm *.o
	rm main

The blank line in front must use the table key . After editing, use the make command to compile the project: (if you cannot find the command, use sudo apt-get install to install the corresponding package);
insert image description here
Figure 1 uses the make command to compile the file

3. Makefile syntax rules

1. Rule format

目标…... : 依赖文件集合……
命令 1
命令 2
……

For example:

main : main.o input.o calcu.o
 gcc -o main main.o input.o calcu.o

The target of this rule is main, and the dependent files are main.o, input.o and calcu.o. If you want to update the target main, you must first update all its dependent files. If any of the dependent files is updated, Then the object file must also be updated.
Note: Each command in the command list must start with the TAB key, and spaces cannot be used!

2. Makefile variables

Look at a chestnut:

 main: main.o input.o calcu.o
 	gcc -o main main.o input.o calcu.o

After using the variable:

//示例代码 3.4.2.1 Makefile 变量使用
#Makefile 变量的使用
objects = main.o input.o calcu.o 
main: $(objects)
	gcc -o main $(objects)

Assignment character "="

When using "=" to assign a value to a variable, you don't have to use the already defined value, you can also use the value defined later

Assignment character ":="

Variables defined later will not be used, only those defined earlier

Assignment character "?="

"?=" is a very useful assignment character, such as the following line of code:

curname ?= zuozhongkai

The meaning of the above code is that if the variable curname has not been assigned a value before, then this variable is "zuozhongkai",
if it has been assigned a value before, then use the previously assigned value

Variable append "+="

The variables in the Makefile are strings. Sometimes we need to add some strings to the previously defined variables
. At this time, we need to use the symbol "+=", such as the following code:

objects = main.o inpiut.o
objects += calcu.o

At the beginning, the value of the variable objects is "main.o input.o", and later we added a "calcu.o" to it, so
the variable objects becomes "main.o input.o calcu.o", this is Variable addition.

3. Makefile pattern rules

We can use the pattern rules in the Makefile, and through the pattern rules, we can use a rule to compile all .c files into corresponding .o files. When "%" appears in the target, the value represented by "%" in the target determines the value of "%" in the dependency, and the usage method is as follows:

%.o : %.c
	命令

So we can change the example above to:

objects = main.o input.o calcu.o
main: $(objects) 
	gcc -o main $(objects)  
%.o : %.c 
	#命令

clean: 
	rm *.o
	rm main

4. Makefile automation variables

How to write this command after we use the pattern rule? It is necessary to use automation variables. The so-called automation variables are such variables that will automatically take out a series of files defined in the pattern one by one until all the files that conform to the pattern are taken out. Automation variables should only appear in the command of the rule. In Table 1, the commonly used automation variables are shown in Table 1: Table 1 There are three commonly used
automation variables : @ 、 @、
insert image description here@ , < and $^, we use automation variables to complete the Makefile in the sample code, the final complete code looks like this:

//示例代码 3.4.4.1 自动化变量
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects) 
%.o : %.c
	gcc -c $<
clean:
	rm *.o
	rm main

5. Makefile pseudo-target

Makefile has a special target—pseudo-target. The general target name is the file to be generated, and the pseudo-target does not represent the real target name. When executing the make command, specify this pseudo-target to execute the definition of its rules The command.
The use of pseudo-targets is mainly to avoid name conflicts between the targets defined in the Makefile and the actual files in the working directory. Sometimes we need to write a rule to execute some commands, but this rule is not used to create files, such as In the previous "sample code", the following code is used to complete the function of cleaning the project:

clean:
	rm *.o
	rm main

There is no command to create a file clean in the above rules, so the file clean will never exist in the working directory. When we enter "make clean", the following "rm *.o" and "rm main" will always be executed. But if we are "hands-on" and create a file named "clean" in the working directory, it will be different. When "make clean" is executed, the target is considered to be the latest because the rule has no dependent files. , so the following rm command will not be executed, and the function of cleaning up the project that we pre-conceived will not be completed. To avoid this problem, we can declare clean as a pseudo-target in the following way:

.PHONY : clean

Full code:

//示例代码 3.4.5.1 伪目标
objects = main.o input.o calcu.o
main: $(objects)
	gcc -o main $(objects) 4 
.PHONY : clean 
%.o : %.c 
	gcc -c $< 
clean:
	rm *.o
	rm main

Line 5 of the above code declares clean as a pseudo-target. After declaring clean as a pseudo-target, no matter whether there is a file named "clean" in the current directory, if you enter "make clean", the rm command behind the rule will be executed.

Summarize

There are many syntaxes of Makefiles. This article only briefly explains the most basic and commonly used syntaxes. If you want to learn the complete syntaxes, please refer to the explanation of makefile syntaxes in punctual atom development materials.

Guess you like

Origin blog.csdn.net/qq_52608074/article/details/127465847