3.4 e Makefile syntax
3.4.1 Introduction to Makefile
The Makefile file is composed of a series of rules, the format is as follows:
target (target file) ...: prerequisites (dependency files) ...
command
...
...
For example, the Makefile rules written in 3.3.2 are:
main.o: main.c
gcc -c main.c
In this rule, main.o is the target file (the file to be generated), main.c is the dependent file (the file required to generate main.o), and "gcc -c main.c" is the command to run to generate main.o. If each line of the script in the e Makefile is indented, you must use the "Tab" key to indent, and remember not to use spaces for indentation (this is the syntax requirement of the e Makefile). Everyone must remember this! Let's analyze the Makefile file written in Figure 3.3.2. The script is as follows:
1 main: main.o calc.o
2 2 gcc -o main main.o calc.o
3 3 main.o: main.c
4 4 gcc -c main.c
5 5 calc.o:calc.c
6 6 gcc -c calc.c
7 7
8 8 clean:
9 9 rm -rf *.o
10 rm -rf main
From the running results in the figure above, you can see that the final result is equal to 10, which is the same as the designed result of our program.
The script has 4 rules in total. Lines 1 and 2 are the first rule, lines 3 and 4 are the second rule, lines 5 and 6 are the third rule, and lines 8, 9, and 10 are the fourth rule. When we run the make command, the rules in the Makefile in the current directory will be parsed. The first rule will be parsed first. The target file in the first rule is main. Once the target file is updated, the function of the entire Makefile will be completed.
It's done. During the first compilation, since the target file main does not exist, the first rule will be parsed. The first rule depends on the files main.o and calc.o. The make command will check whether there are these two .o files in the current directory. After checking, it is found that there are none. Then make will look for rules in the Makefile that target main.o and calc.o respectively (the second and third rules). The file that the second rule depends on is main.c. The make command checks and finds that this file exists in the current directory, and then executes the command "gcc -c main.c" of the second rule to generate the main.o file. Then execute the third rule. The target file of the third rule is calc.o, and the dependent file is calc.c. The make command checks and finds that this file exists in the current directory, and then executes the command "gcc -c calc.c" of the third rule to generate the calc.o file. So far, the two files main.o and calc.o that the first rule depends on have been generated, and then run the command "gcc -o mainmain.o calc.o" of the first rule to generate the main file. Because when the make command is run, it will start parsing from the first rule of the Makefile, and then traverse the "corresponding rules" in the file according to the dependent files of the first rule, and then traverse the "corresponding rules" according to the dependent files of the "corresponding rules". This recursive method will traverse all the rules required to complete the first rule. Let's take a look at the target file of the fourth rule, which is clean. We found that this rule is not related to the first rule, so when we run the make command, we will not traverse this rule. We can enter the "make clean" command in the terminal to run the fourth rule. The fourth rule has no dependent files, so execute the run commands "rm -rf *.o" and "rm -rf main". The function of these two commands is to delete all files ending with .o and delete the file main. Run as shown in the following figure:
From the above figure, we can see that the three files main.o, mcalc.o and main have been deleted. Through this rule, we can clear the files generated by compilation and clean up the project.
Let's summarize the execution process of the make command:
1.The make command will search for a file named Makefile in the current directory
2. Find the Makefile file, compile it according to the rules in the Makefile, and generate the final file
3. When it is found that the target file does not exist or the dependent file is newer than the target file (modification time), the command corresponding to the rule will be executed to update it. We can see that make is a tool that will execute the specific compilation process through the content in the Makefile file.
3.4.2 Makefile variables
The first rule of the Makefile in section 3.3.2 is:
main: main.o calc.o
gcc -o main main.o calc.o
In this rule, we input the two files main.o and calc.o twice. Since our Makefile file has relatively few contents, if the Makefile is complex, this repeated input will take up a lot of time and will be troublesome to modify. To solve this problem, Makefile can use variables. The variable of Makefile is a string. For example, in the above rule, we declare a variable called objects, objs or OBJ. Anyway, no matter what it is, as long as it can represent main.o and calc.o, we modify the above rule
1 objects = main.o calc.o
2 2 main (objects)
3 3 gcc -o main $(objects)
Let's analyze the modified rules. First, in the first line, we define a variable objects and assign it the value "main.o calc.o". The second and third lines use the variable objects. The variable reference method in Makefile is "$(variable name)", and the variable objects is assigned using "=". The variable assignment in Makefile can also use ":=", "?=", and "+=". The differences between these four assignments are as follows:
1. “= = ” assignment operator
We first create a Makefile script in the work directory of the user's root directory and enter the following content:
1 ceshi1 = test
2 ceshi2 = $(ceshi1)
3 ceshi1 = temp
4
5 out:
In the first line, we define the variable and assign the value "test". In the second line, we define the variable ceshi2 and assign the value to the variable ceshi1. In the third line, we modify the value of the variable ceshi1 to "temp". The fifth and sixth lines are the output values of the variable ceshi2. We enter the "make out" command in the terminal, as shown in the following figure:
In the figure above, you can see that the value of the variable ceshi2 is temp, which is the last value assigned to the variable ceshi1.
2. “ := ” assignment operator
We modify the code in the "=" assignment operator, and change the "=" in the second line to ":=". The code is as follows:
1 ceshi1 = test
2 ceshi2 := $(ceshi1)
3 ceshi1 = temp
4
5 out:
6 @echo ceshi2 (ceshi2)
We enter the "make out" command in the terminal, as shown below:
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml10068\wps4.png
We can see that the value of the variable ceshi2 in the running result output above is test, although in the third line we modified the variable ceshi1
Value, through this experiment we can see the function of the ":=" assignment operator.
3. “ ?= ” assignment operator
ceshi ?= test
The function of the “?=” assignment operator is that if the variable ceshi has not been assigned a value before, then the variable will be assigned the value “test”; if it has been assigned a value before, then the previous value will be used.
4. “ += ” assignment operator
objs = main.o
objs += calc.o
In the above script, the value of the variable objs is "main.o calc.o". The function of the "+=" assignment operator is to append variables.
3.4.3 Conditional judgment
Using conditional judgment, make can choose different execution branches according to different runtime situations. The conditional expression can be a comparison of variable values, or a comparison of variables and constant values. There are two syntaxes:
1.
<Condition comparison>
[Script to execute if condition is true]
endif
2.
<Condition comparison>
[Script to execute if condition is true]
else
[Script to execute if condition is false]
endif
The comparison keywords used in conditional comparison are: ifeq, ifneq, ifdef, and ifndef.
ifeq means if the comparison is equal, the syntax is as follows:
ifeq(<parameter 1>, <parameter 2>)
ifneq means if they are not equal, the syntax is as follows:
ifneq(<parameter 1>, <parameter 2>)
ifdef means if a variable is defined, the syntax is as follows:
ifdef <variable name>
ifndef means if the variable is not defined, the syntax is as follows:
ifndef <variable name>
3.4.4 Using functions
In Makefile, we can use functions to process variables, making our commands or rules more flexible and intelligent. There are not many functions supported by make, but they are enough for our operations. After the function is called, the return value of the function can be used as a variable.
The function call is very similar to the use of variables, and is also marked with "$". The syntax is as follows:
$(<function name> <parameter set>)
or:
${<function name> <parameter set>}
The function name and parameter set are separated by spaces, and the parameters of the parameter set are separated by commas. The function call starts with "$", and the function name and parameters are enclosed in parentheses or curly braces. It feels very much like a variable. Parameters in functions can use variables. For the sake of style, it is best to use the same brackets for functions and variables, such as "$(subst a,b,$(x))" instead of "$(subst a,b,${x})".
Because unification will make things clearer and reduce unnecessary trouble.
Next we will introduce several commonly used functions. For other functions, please refer to the document "Write Makefile with Me".
t 1.subst function
$(subst,,)
This function is to convert the stringInReplace the string with, the function returns the replaced string. The following example:
$(substee,EE,feet on the street)
The above script replaces the "ee" string in the string "feet on the street" with the "EE" string.
for "feet on the strEEt".
. 2. t patsubst function
This function is used to findCheck whether the words in the string (words are separated by "space", "Tab" or "carriage return" or "line feed") match the pattern.If it matches, thenReplace. HereThe wildcard character "%" can be included to represent a string of any length.Also contains "%", thenThe "%" in will beThe string represented by the “%” in the string. (You can use “\” to escape, and “\%” to represent the real meaning of the “%” character.) The function returns the string after the replacement. The following example:
$(patsubst %.c,%.o,xc bar.c)
The above script replaces the words in the string "xc bar.c" that match the pattern [%.c] with [%.o], and returns "xo bar.o"
3. strip function
$(strip)
This function is used to removeThe function returns the string value with spaces removed. The following example:
$(strip abc )
The above script removes the leading and trailing spaces from the string "abc", and the result is "abc".
. 4. g findstring function
$(findstring,)
This function is used to convert the stringSearchIf found, return, otherwise it returns an empty string, as shown below
example:
$(findstring a,abc)
$(findstring a,bc)
In the above scripts, the first one returns the string "a" and the second one returns an empty string.
R 5.dir function
$(dir)
This function is used to generate a sequence of file names.The directory part is the part before the last backslash ("/").
If there is no backslash, then "./" is returned. Returns the file name sequenceThe directory part is as follows:
$(dir src/foo.c hacks)
The above script returns "src/".
. 6. r notdir function
$(notdir)
This function is used to generate a sequence of file names.The non-directory part is the part after the last backslash ("/")
The part returns the file name sequenceThe non-directory part is as follows:
$(notdir src/foo.c)
The above script returns the string "foo.c"
. 7. h foreach function
$(foreach ,,)
The function of this function is to pass the parameterThe words in the list are taken out one by one and placed into the variables specified by the parameters, and then executedThe contained expression. Each timeWill return a string, during the loop,Each string returned by will be separated by a space, and finally when the entire loop is completed,The entire string consisting of each string returned (separated by spaces) will be the return value of the foreach function. Therefore, it is best to use a variable name.can be an expression, andThis parameter is generally used to enumerateThe words in . The following example:
names := abcd
files := $(foreach n,$(names),$(n).o)
The above script implements that the words in $(name) will be taken out one by one and stored in the variable "n". "$(n).o" calculates a value based on "$(n)" each time. These values are separated by spaces and finally returned by the foreach function, so the value of $(files) is "ao bo co do". (Note that the parameter in foreach is a temporary local variable. After the foreach function is executed, the parameter variable will no longer be in effect. Its scope is only within the foreach function).
3.4.5 Using wildcards in rules
If we want to define a series of similar files, we naturally think of using wildcards. The make command supports three wildcards: "*", "?" and "[...]", which are the same as Unix's B-Shell. The "~" character also has a special use in file names. If it is "~/test", it means the test file in the current user's root directory. And "~admin/test" means the test file in the user admin's root directory. Wildcards replace a series of files, such as "*.c" means all files with the suffix .c. One thing we need to pay attention to is that if there is a wildcard in our file name, such as: "*", then the escape character "\", such as "\*", can be used to represent the real "*" character, rather than a string of arbitrary length.
Let's look at a few specific examples:
clean:
rm -rf *.o
The above example shows that wildcards can be used in the command of a rule.
print: *.c
The above example shows that wildcards can be used in rule dependencies.
objects = *.o
The above example shows that wildcards can also be used in variables. It does not mean that [*.o] will be expanded and the value of objects will be "*.o". Variables in Makefile are actually macros in C/C++. If you want to expand wildcards in variables, that is, let the value of objects be the set of all [.o] file names, then you can do it like this:
objects := $(wildcard *.o)
This usage is indicated by the keyword "wildcard". For more information about Makefile keywords, please refer to the document "Write Makefile with Me".
This is the end of our introduction to Makefile. This section only gives a basic explanation of Makefile.