In a makefile, we can generate specified target files from our source code based on a series of rules defined in the makefile. This helps us automate various operations such as compiling and packaging programs.
1 Basic Principles of Makefile: Any version of the shell will include the make command. When we execute the make command, make will operate the commands defined in the makefile.
2 Basic Format for Writing a Makefile: target():dependence
command
(1) Declare Target (target): Specify the name of the target to be built and its dependencies. Targets can be executable files, library files, intermediate files, etc.
(2) Define Dependencies (Dependences): Specify the source files, header files, or other targets that each target depends on.
(3) Define Build Rules (Build Rules): For each target, define build rules that describe how to generate the target from its dependencies. This includes commands for compiling source files, linking target files, etc.
3 About the Format of Phony Targets: .PHONY:target prevents us from creating a target named clean in the makefile if there is also a file or folder named clean in the directory. Executing make clean will result in a clean: up to date error (when there is a file with the same name in the directory, executing the make command will result in an error).
4 Adding Variables to Makefile: Variable: dependencies
5 Pattern Matching: Use pattern matching to optimize scripts.
(1) % represents each one, * represents all.
(2) $@ represents the target, $^ represents all dependencies, $< represents the first dependency.
6 Two Functions (Two commonly used functions in makefile):
wildcard function $(wildcard ./*.cpp) retrieves all .cpp files in the current directory.
patsubst function $(patsubst %.cpp, %.o, ./*.cpp) replaces all corresponding .cpp file names with .o file names.
Below is a simple code demonstration, using the generation of a dynamic library as an example. Based on the simple explanation of makefile above, interpret the code in the image, and please point out any errors.
target = libsub.so
cc = g++
src = $(wildcard *.cpp)
obj = $(patsubst %.cpp, %.o, $(src))
lib_local = ../lib
$(target): $(obj)
$(cc) -shared $^ -o $@
mv $(target) $(lib_local)/
%.o: %.cpp
$(cc) -fPIC -c $^
.PHONY: clean
clean:
rm $(obj) $(lib_local)/$(target)
Explanation of the above code:
target = libsub.so: Defines the target file as libsub.so.
cc = g++: Specifies the compiler as g++.
src = $(wildcard *.cpp): Uses the wildcard function to match all .cpp files in the current directory and assigns the result to the src variable.
obj = $(patsubst %.cpp, %.o, $(src)): Replaces .cpp file names in src with corresponding .o file names to obtain the list of compiled target files.
lib_local = ../lib: Specifies the local path for the library file as ../lib.
$(target): $(obj): Specifies that generating the libsub.so target file depends on the target files in obj.
$(cc) -shared $^ -o $@: Uses the g++ compiler to link all target files into a shared library file, where $@ represents the target file in the current rule, which is libsub.so. This part tells the compiler to link all .o files into a shared library file named libsub.so.
mv $(target) $(lib_local)/: Moves the generated libsub.so file to the specified library file directory.
%.o: %.cpp: Defines the rule for compiling .cpp files into .o files.
$(cc) -fPIC -c $^: Uses the g++ compiler to compile and generate .o files.
.PHONY: clean: Declares clean as a phony target.
clean: rm $(obj) $(lib_local)/$(target): Defines the clean rule to delete the generated target files and library file target.
That concludes a simple introduction to makefile, I hope it is helpful to you.