Clickthe blue text
Follow us
In the previous article, we discussed some concepts and principles of Makefile. Next, let’s talk about some key points regarding Makefile.
make and make clean
Rules for generating target files (make command):
Executing the make command will generate the corresponding target files based on the rules defined in the Makefile in the current directory.
If the Makefile has a different name, such as makefile.linux, you need to use the make parameters (-f or –file) to execute the corresponding Makefile, for example:
make -f makefile.linux
Rules for cleaning target files (make clean command):
Every Makefile should include a rule to clean target files (such as .o
and other target files), which not only facilitates recompilation but also helps keep the files clean. It is advisable to develop the habit of writing such a rule when creating Makefiles. A common style is:
clean: rm $(obj) *.o
A more robust approach is (reason: if a clean file exists in the current directory, this command will fail), the solution is to add a phony target: .PHONY:clean:
.PHONY:cleanclean: rm $(obj) *.o
Note:
-
<span>clean</span>
rules should not be placed at the beginning of the file; otherwise, it will become the default target for make. Generally, clean is always placed at the end of the file.
Writing Rules
Display rules (@ character):
When using the @ character before a command, that command will not be displayed when executed. For comparison: Example of a command with @ character:
rice@rice:~/rice_file/mkfile$ cat Makefile exec: @echo "rice makefile"rice@rice:~/rice_file/mkfile$ makerice makefile
Example of a command without @ character:
rice@rice:~/rice_file/mkfile$ cat Makefile exec: echo "rice makefile"rice@rice:~/rice_file/mkfile$ makeecho "rice makefile"rice makefile
Note:
Make command parameters <span>-s</span>
or <span>--silent</span>
or <span>--quiet</span>
will completely suppress command display.
Command execution rules:
When a dependent target is newer than the target, make will execute the subsequent commands one by one. To apply the result of the previous command to the next command, use semicolon separation between the two commands, and do not write both commands on the same line.
Example 1:
Makefile:
exec: @cd /home/rice @pwd
Result:
/home/rice/rice_file/mkfile
Example 2:
Makefile:
exec: @cd /home/rice;pwd
Result:
/home/rice
From the above two examples, we can demonstrate the rules of command dependencies.
Command error rules (- symbol):
When a command finishes running, make checks the return code of each command. If the return is successful, make will execute the next command. When all commands return successfully, make completes execution. If a command in a rule fails (non-zero exit code), make will terminate the execution of the current rule, which may terminate the execution of all rules.
Sometimes, a command error does not indicate a failure. For example, the mkdir command creates a directory; if the directory does not exist, mkdir will not produce an error. If the directory already exists, an error will occur. From the example, the error from mkdir does not affect other commands because I only need the directory to exist, so the error from mkdir should not terminate the command rule’s execution.
To solve the above problem, simply add a symbol – before the command in the Makefile, and even if the command fails, subsequent commands will still be executed.
.PHONY:cleanclean: -rm $(obj) *.o
Variables
Variable Definition
Makefile also supports variable definitions, which simplify and make our Makefile more reusable. Variable definitions: generally use uppercase letters, and the assignment method is similar toC language assignment.
DIR = ./src/
Variable value retrieval: use parentheses to enclose the variable and add a dollar sign.
FOO = $(DIR)
Makefile supports other assignment methods besides using ‘=’ such as ‘:=’ and ‘?=’, let’s compare the differences between these methods:
Assignment symbol ‘=’:
PARA = RICECURPARA = $(PARA)PARA = rice
print: @echo $(CURPATA)
Result:
rice
The value of variableCURPARA is not “RICE. Its value isPARA from the last assignment. This indicates that the assignment symbol “=” allows the use of another variable, pushing the real value of the variable to be defined later. The real value of the variable depends on the last effective value of the variable it references.
Assignment symbol ‘:=:
PARA = RICECURPARA := $(PARA)PARA = rice
print: @echo $(CURPATA)
Result:
RICE
The value of variableCURPARA is “RICE. The difference between “=” and “:=” is that “:=” only takes the first assigned value.
Assignment symbol ‘?=’:
PARA = RICEPARA ?= rice
print: @echo $(PATA)
Result:
RICE
If the first line of the above example is removed, the result will be:
rice
This indicates that if the variablePARA has not been assigned a value before, then this variable is “rice. If it has been assigned a value before, then it uses the previously assigned value.
Assignment symbol ‘+=’:In Makefile, variables are strings, and sometimes we need to add some strings to an already defined variable, in this case, we use the symbol “+=” to do so:
OBJ = main1.o main2.oOBJ += main3.o
OBJ will have the value: “main1.o, main2.o, main3.o”. This indicates that “+=” is used for appending to the variable.
Built-in Variables:
Some built-in variables are predefined, usually includingCC, PWD, CLFAG, etc. Some have default values, while others do not. For example:
-
CPPFLAGS: options needed by the preprocessor, such as:-l
-
CFLAGS: parameters used during compilation-Wall
-g -c -
LDFLAGS: options used for linking libraries-L
-l
Among them: default values can be modified, for example, CC has a default value ofcc, but can be changed togcc:CC=gcc
Automatic Variables:
Makefile syntax provides some automatic variables that allow us to complete the writing of Makefile more quickly. These automatic variables can only be used in the commands of rules, and common automatic variables include:
-
$@: the target in the rule
-
$<: the first dependency file in the rule
-
$^: all dependency files in the rule
CC = gccOBJ = main.o add.ooutput: $(OBJ) $(CC) -o $@ $^main.o: main.c $(CC) -c $<add.o: add.c $(CC) -c $<
.PHONY:cleanclean: @rm $(OBJ) output
Pattern Rules
Pattern rules use % in targets and dependencies to match corresponding files. We can still use the previous example in pattern rule format as follows:
CC = gccOBJ = main.o add.ooutput: $(OBJ) $(CC) -o $@ $^%.o: %.c $(CC) -c $<
.PHONY:cleanclean: @rm $(OBJ) output
Where:
main.o is generated from main.c and add.o is generated from add.cFunctions
Makefile provides a large number of functions, among which the two most commonly used functions are(wildcard, patsubst).wildcard function: used to find files of a specified type in a specified directory. Function parameters: directory + file type, usage:
SRC = $(wildcard ./src/*.c)
print: @echo $(SRC)
Result:
./src/add.c ./src/main.c
Indicates: find all files with the suffix.c in the directory./src and assign them to the variableSRC. After the command is executed, the value of SRC variable is:./src/add.c
./src/main.c
patsubst function: used for matching and replacing. Function parameters: original pattern + target pattern + file list, usage::
SRC = $(wildcard ./src/*.c)OBJ = $(patsubst %.c, %.o, $(SRC))
print: @echo $(OBJ)
Result:
./src/add.o ./src/main.o
Indicates: replace all files with the suffix.c in the variable with.o. After the command is executed, the value of OBJ variable is:./src/add.o
./src/main.o
I will continue to update articles and learning materials.
You can add the author’s WeChat to exchange and learn together.
—Author’s WeChat ID: wueroo1314—
To join the discussion group, please add the author’s WeChat
Fan DIY
WeChat ID: Rice_DIY
Technology | Open Source | Sharing
Long press to follow…