This article comprehensively and deeply explains the make project management tool, which lays a foundation for subsequent reading of complex source codes such as U-Boot and kernel and project development
The principle of Make and the basic knowledge of Makefile
Introduction to Make
Project manager, as its name suggests, refers to managing more files
Make project manager is also an "automatic compilation manager". Here, "automatic" means that it can automatically find updated files according to the file timestamp to reduce the workload of compilation. At the same time, it performs a lot of compilation by reading the contents of Makefile files
Make will compile only the changed code files, not the full compilation.
Makefile basic structure
Makefile is the only configuration file read in by Make
- The target created by the make tool is usually a target file or an executable file
- dependency_file of the target body to be created
- Commands to run when creating each target body
- Note: the command line must be preceded by a TAB key, otherwise the compilation error is: * * * missing separator Stop.
Makefile format
target: dependency_files <TAB> command
example
hello.o: hello.c hello.h gcc –c hello.c –o hello.o
Makefile variable
A more complex example:
-
sunq: kang.o yul.o gcc kang.o yul.o -o sunq kang.o: kang.c kang.h gcc –Wall –O -g –c kang.c -o kang.o yul.o: yul.c gcc - Wall –O -g –c yul.c -o yul.o
notes:
- -Wall allows you to send gcc all useful alarm messages
- -c just compiles without linking and generates the target file o
- -Output o to file
More about using man tools
Create and use variables
Purpose of creating variable: to replace a text string:
- Name of the series file
- Parameters passed to the compiler
- Program to run
- Need to find the directory of source code
- The directory where you need to output information
- Other things you want to do
Two ways to define variables
- Recursive expansion method VAR=var
- Simple method VAR:=var
- Use $(VAR) for variables
- Use $$, then use $$
- Similar to macros in programming languages
The example just now
OBJS = kang.o yul.o CC = gcc CFLAGS = -Wall -O -g sunq : $(OBJS) $(CC) $(OBJS) -o sunq kang.o : kang.c kang.h $(CC) $(CFLAGS) -c kang.c -o kang.o yul.o : yul.c yul.h $(CC) $(CFLAGS) -c yul.c -o yul.o
Recursive expansion method VAR=var; example:
foo = $(bar) bar = $(ugh) ugh = Huh?
The value of $(foo) is?
echo $(foo) to view
- Advantage: it can refer back to variables
- Disadvantages: this variable cannot be extended in any way, for example:
CFLAGS = $(CFLAGS) -O
It will cause a dead cycle
Simple method VAR:=var
m := mm x := $(m) y := $(x) bar x := later echo $(x) $(y) # See what information is printed?
- Variables defined in this way will be expanded according to the current value of the referenced variable at the definition point of the variable
- This way of defining variables is more suitable for large programming projects because it is more like our general programming language
Use= Define variables
dir := /foo/bar FOO ?= bar # FOO is?
-
It means that if FOO has not been defined, the value of variable FOO is bar. If FOO has been defined previously, this phrase will do nothing, which is equivalent to:
ifeq ($(origin FOO), undefined) FOO = bar endif
Add values to variables; You can add a new value to a defined variable with + =
Main=hello.o hello-1.o Main+=hello-2.o
Predefined variables
- The name of the AR library file maintenance program. The default value is ar.
- The name of the as assembler. The default value is as.
- cc is the name of the C compiler. The default value is cc.
- The name of CPP C precompiler. The default value is $(CC) – E.
- The name of CXX C + + compiler. The default value is g + +.
- The name of the FC FORTRAN compiler. The default value is f77
- The name of the RM file deletion program. The default value is rm -f
example:
Hello: main.c main.h <tab> $(CC) –o hello main.c clean: <tab> $(RM) hello
Predefined variables
- There is no default value for the option of ARFLAGS library file maintenance program.
- ASFLAGS assembler option, no default value.
- CFLAGS C compiler options, no default value.
- CPPFLAGS C precompiled option, no default value.
- Cxxflags is an option of the C + + compiler. There is no default value.
- Options of FFLAGS FORTRAN compiler, no default value.
The example just now
-
OBJS = kang.o yul.o CC = gcc CFLAGS = -Wall -O -g sunq : $(OBJS) $(CC) $(OBJS) -o sunq kang.o : kang.c kang.h $(CC) $(CFLAGS) -c kang.c -o kang.o yul.o : yul.c yul.h $(CC) $(CFLAGS) -c yul.c -o yul.o
Automatic variable
- $* target file name without extension
- $+ all dependent files, separated by spaces and in the order of occurrence, may contain duplicate dependent files
- $< name of the first dependent file
- $? All dependent files whose timestamp is later than the target file are separated by spaces
- Full name of $@ target file
- $^ all non duplicate target dependent files, separated by spaces
- $% if the target is an archive member, this variable represents the archive member name of the target
Just now:
OBJS = kang.o yul.o CC = gcc CFLAGS = -Wall -O -g sunq : $(OBJS) $(CC) $^ -o $@ kang.o : kang.c kang.h $(CC) $(CFLAGS) -c $< -o $@ yul.o : yul.c yul.h $(CC) $(CFLAGS) -c $< -o $@
environment variable
- make will automatically read the environment variables currently defined by the system when starting, and will create variables with the same name and value
- If the user defines a variable with the same name in Makefile, the user-defined variable will override the environment variable with the same name
Options of Make command and implicit rules in Makefile
Make use
Run make directly
option
- -C dir reads the Makefile in the specified directory
- -f file read in the file file in the current directory as a Makefile
make -f Makefile.debug
make -f Makefile.debug clean - -i ignore all command execution errors
- -I dir specifies the directory of the included Makefile
- -n print only the commands to be executed, but do not execute them
- -p displays the make variable database and implicit rules
- -s does not display commands when executing commands
- -If make changes the name of the current directory during the printing process
- -j \nproc ` ` compile according to the number of computer cores
Implied rules of Makefile
Implicit rule 1: implicit rules for compiling C programs
- <n>. O's goal dependency goal is automatically derived as < n > C and its generation command is $(CC) -c $(CPPFLAGS) $(CFLAGS)
Implicit rule 2: implicit rules for linking Object files
-
<n> The target depends on < n > o. Run the linker generation (generally ld) by running the C compiler. The generation command is $(CC) (ldflags) < n > o
-
$(LOADLIBES) $(LDLIBS). This rule is valid for projects with only one source file and for multiple Object files (generated from different source files). For example:
-
Rules:
x : x.o y.o z.o -
When x.c, y.c and z.c exist, the implicit rule will execute the following commands:
cc -c x.c -o x.o cc -c y.c -o y.o cc -c z.c -o z.o cc x.o y.o z.o -o x
-
If no source file (such as x.c in the above example) is associated with your target name (such as x in the above example), you'd better write your own generation rules, otherwise, the implicit rules will report an error
-
Example 1:
-
$ ls -R Makefile clean f2.c include Makefile2 f1.c head.h main.c ./include: myinclude.h
-
CFLAGS=-c -Wall -I include f1:f1.o f2.o main.o .PHONY:clean clean: rm *.o f1
Example 2:
-
ls -R Makefile clean f1.c head.h main.c Makefile2 config.mk f2.c include ./include: myinclude.h
OBJS=f1.o f2.o OBJS+=main.o CFLAGS=-c -Wall -I include ~ ~ ~ ~ ~ "config.mk" 3L, 55C
-
#OBJS=f1.o f2.o #OBJS+=main.o #CFLAGS=-c -Wall -I include include config.mk test:$(OBJS) gcc $(OBJS) -o test #f1.o:f1.c #f2.o:f2.c #main.o:main.c .PHONY:clean clean: rm *.o test
VPATH and nested Makefile
Usage of VPATH
VPATH: virtual path
- In some large projects, there are a large number of source files. Our usual practice is to classify these source files and store them in different directories. Therefore, when make needs to find the dependency of the file, you can add a path in front of the file, but the best way is to tell make a path and let make find it automatically.
- The special variable VPTH in the Makefile file is written into this function. If this variable is not specified, make will only find the dependent files and target files in the current directory. If this variable is defined, make will look for files in the specified directory when the current directory cannot be found.
- VPATH = src:../headers
- The above definition specifies two directories, src and/ headers and make will search in this order. Directories are separated by colons. (of course, when the current directory is always the highest priority search place)
Example 3:
-
$ ls -R Makefile Makefile2 main src2 Makefile1 include src1 ./include: head.h myinclude.h ./main: main.c ./src1: f1.c ./src2: f2.c
-
FLAGS=-c -Wall -I include VPATH=src1 src2 main f1:f1.o f2.o main.o .PHONY:clean clean: find ./ -name "*.o" -exec rm {} \;;rm f1
Nested Makefile
Case:
ls -R Makefile f2 main f1 include obj ./f1: Makefile f1.c ./f2: Makefile f2.c ./include: myinclude.h ./main: Makefile main.c ./obj: Makefile
CC=gcc SUBDIRS=f1 \ f2 \ main \ obj OBJS=f1.o f2.o main.o BIN=myapp OBJS_DIR=obj BIN_DIR=bin export CC OBJS BIN OBJS_DIR BIN_DIR all:CHECK_DIR $(SUBDIRS) CHECK_DIR: mkdir -p $(BIN_DIR) $(SUBDIRS):ECHO make -C $@ ECHO: @echo $(SUBDIRS) @echo begin compile CLEAN: @$(RM) $(OBJS_DIR)/*.o @rm -rf $(BIN_DIR)
- We noticed a sentence @ echo $(SUBDIRS)
- @(RM) is not a variable defined by ourselves. Where does it come from?
- make -C $@
- export CC OBJS BIN OBJS_DIR BIN_DIR