The foreword 0.
Want to know how to use Makefile to create a project for multiple files and multi-level directory, must arrange!
For an introductory reference article on makefiles, look at this article:
Introduction to Makefile
In order to make everyone have a more intuitive feeling, Ejun will write a small project before, this project is modified on the basis of the project.
The detailed design and code of the project are as follows:
“From 0 to write a” telephone number management system “C entry project [suitable for beginners]
A, files,
All right, here we go!
We put all the function functions of the project into a C file named after the function and into a subdirectory of the corresponding name.
For example, the allfree() function is stored in allFree/allFree.c
The final directory structure is as follows:
Peng @ ubuntu: / MNT/HGFS/code/phone $tree. ├ ─ ─ allfree │ ├ ─ ─ allfree. C │ └ ─ ─ a Makefile ├ ─ ─ the create │ ├ ─ ─ the create. C │ └ ─ ─ Makefile ├ ─ ─ the delete │ ├ ─ ─ the delete. C │ └ ─ ─ a Makefile ├ ─ ─ the display │ ├ ─ ─ the display. The c │ └ ─ ─ a Makefile ├ ─ ─ the include │ ├ ─ ─ a Makefile │ └ ─ ─ phone. H ├ ─ ─ init │ ├ ─ ─ init. C │ └ ─ ─ a Makefile ├ ─ ─ the login │ ├ ─ ─ the login. The c │ └ ─ ─ a Makefile ├ ─ ─ the main │ ├ ─ ─ main. C │ └ ─ ─ The Makefile ├ ─ ─ a Makefile ├ ─ ─ menu │ ├ ─ ─ a Makefile │ └ ─ ─ menu. C ├ ─ ─ scripts │ └ ─ ─ a Makefile └ ─ ─ search ├ ─ ─ a Makefile └ ─ ─ search.c 11 directories, 22 filesCopy the code
Let’s take a look at the result:
peng@ubuntu:/mnt/hgfs/code/phone$ make
make[1]: Entering directory '/mnt/hgfs/code/phone/allfree'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/allfree'
make[1]: Entering directory '/mnt/hgfs/code/phone/create'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/create'
make[1]: Entering directory '/mnt/hgfs/code/phone/delete'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/delete'
make[1]: Entering directory '/mnt/hgfs/code/phone/display'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/display'
make[1]: Entering directory '/mnt/hgfs/code/phone/init'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/init'
make[1]: Entering directory '/mnt/hgfs/code/phone/login'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/login'
make[1]: Entering directory '/mnt/hgfs/code/phone/menu'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/menu'
make[1]: Entering directory '/mnt/hgfs/code/phone/search'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/search'
make[1]: Entering directory '/mnt/hgfs/code/phone/main'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/mnt/hgfs/code/phone/main'
gcc -Wall -O3 -o phone allfree/*.o create/*.o delete/*.o display/*.o init/*.o login/*.o menu/*.o search/*.o main/*.o -lpthread
phone make done!
Copy the code
The running results are as follows:
Makefile Makefile Makefile Makefile
[0] symbols'@' '$' '$$' '-' '-n '
instructions
The '@'
Usually a Makefile prints the command line it executes to the screen before execution. If ‘@’ is appended to the command line, the command will not be made back out. Such as:
@echo--compiling module----; Compiling module----echo--compiling module----; // No @ screen outputecho --compiling module----
Copy the code
The '-'
If a file does not exist or has already been created, you can add -,
- rm dir; - the mkdir aaadir;Copy the code
'$'
The dollar sign $extends variables defined in the makefile
'$$'
The $$symbol extends the shell variables defined in the makefile
[1] wildcard
Note: List all file names in the current directory in the PATTERN format, separated by Spaces. PATTERN uses wildcards recognized by the shell, including? (Single character), asterisk (*) (multi-character). Example:
$(wildcard *.c)
Copy the code
The return value is a list of all. C source files in the current directory.
[2] patsubst
Description: Replace the.c ending words in the string x.c. bar.c with.o ending characters. Example:
$(patsubst %.c,%.o,x.c.c bar.c)
Copy the code
The result of the function is
x.c.o bar.o
Copy the code
[3] notdir
Example of removing path information from a file name:
SRC = ( notdir ./src/a.c )
Copy the code
To remove the path information of file a.c, run notdir./ SRC /a.c to remove the path information of file a.c, run notdir./ SRC /a.c to remove the path information of file a.c, and run notdir./ SRC /a.c to remove the path information of file a.c.
[4] contains the header file path
Example of specifying the path to a compiler’s header file using the -i + header path command:
INCLUDES = -I./inc
Copy the code
$(CC) -c $(INCLUDES) $(SRC)
Copy the code
[5] addsuffix
Function name: suffix function – addsuffix. Grammar:
$(addsuffix SUFFIX, NAMES...).Copy the code
Function The value is NAMES… Add the SUFFIX “SUFFIX” to each filename in. Parameter “NAMES…” A sequence of file names separated by Spaces, with “SUFFIX” appended to the end of each file name in this sequence. Return value: single-space delimited sequence of file names with SUFFIX added. Function description: Example:
$(addsuffix .c,foo bar)
Copy the code
The return value is
foo.c bar.c
Copy the code
[6] includes another file: include
Use the include keyword in a Makefile to include other makefiles, much like C’s #include. The included file is placed exactly where it was included in the current file. Such as command
include file.dep
Copy the code
To expand file.dep in the current Makefile, include the contents of file.dep in the current Makefile
Include can be preceded by blank characters, but it should never start with the [Tab] key.
[7] foreach
The foreach function is very different from other functions. Because this function is used to loop, the syntax is:
$(foreach <var>,<list>,<text> )
Copy the code
This function simply takes the words from the argument and puts them in the variables specified by the argument, and then executes the contained expression.
Each time a string is returned, each string returned by foreach is separated by Spaces during the loop, and at the end of the loop the entire string (separated by Spaces) of each returned string will be the return value of foreach.
Therefore, it is best to have a variable name, which can be an expression, and will normally use this parameter to enumerate the words in sequence.
For example:
names := a b c d
files := $(foreach n,$(names),$(n).o)
Copy the code
In the above example, the words in $(name) are fetched one by one and stored in the variable “n”. “$(n).o” calculates one value from “$(n)” at a time, separated by Spaces, and returned as foreach, so $(files) is “A.O.B.O.C.O.O”.
Note that the parameter in foreach is a temporary local variable. After the foreach function is finished, the parameter’s variable is no longer in effect. Its scope is only in foreach.
[8] call
The “call” function is the only reference function that can create custom argument functions. Use this function to implement user-defined function references. We can define a variable as a complex expression and use the “call” function to expand it with different arguments to get different results.
Function syntax:
$(call variable,param1,param2,...)
Copy the code
The call function has no limit on the number of arguments and may have no parameter values. A call function with no parameter values has no real meaning. At execution time, the variable “variable” is expanded into a temporary variable valid in the function context. The first parameter in the variable definition is “$(1)”, and the first parameter in the function parameter value is assigned to it. The “$(2)” in the variable is assigned to the value of the function’s second argument; And so on (the variable **$(0)** represents the variable “variable” itself). Then calculate the value of the expression of the variable “variable”.
Return value: Parameter value “param” replace “$(1)”, “$(2)”…… Then the expression defined by the variable “variable” is computed.
Function description:
- In functions, “variable” is a variable name, not a variable reference. Therefore, usually “call” functions do not contain “$” in” variable “(unless, of course, the variable name is a computed variable name).
- When the variable “variable” is a function name embedded in make (such as “if”, “foreach”, “strip”, etc.), the use of the “param” argument should be careful, because improper or incorrect arguments will result in an unpredictable return value.
- Multiple params in a function are separated by commas.
- The variable “variable” cannot be defined as a direct expansion! It can only be defined as a recursive expansion.
Function examples:
reverse = $(2)$(1)
foo = $(call reverse,a,b)
all:
@echo "foo=$(foo)"
Copy the code
Execution Result:
foo=ba
Copy the code
So a replaces (1), B replaces (1), B replaces (1),b replaces (2).
Iii. Detailed description of compilation
After executing the make command in the root directory, the detailed steps are as follows:
- Include scripts/Makefile: replace the file to the current location,
- Use the default target all, which depends on
$(Target)
$(Target)
It’s defined in scripts/Makefile, which is phone - while
$(Target)
Depends on the mm - The mm target will be executed
@ $(foreach n,$(Modules),$(call modules_make,$(n)))
Copy the code
Modules is a collection of all directory names. Foreach will iterate over each word in the string $(Modules), assign each word to n, and execute the statement:
call modules_make,$(n)
Copy the code
- Modules_make was
$(MAKE) -C $(1)
Replaced,
$(MAKE) has the default name MAKE -c: go to the subdirectory and execute MAKE $(1) : is $(n) in step 4, that is, each directory name
The final statement in Step 4 is to enter each directory and execute the Makefile in each directory
- Go to a subdirectory and execute the Makefile
The default target is all, depending on Objs
Objs := $(patsubst %.c,%.o,$(Source))
Copy the code
Patsubst replaces the.c ending word in the string $ource with an.o ending character
Source := $(wildcard ./*.c)
Copy the code
Wildcard lists all the.c files in the current directory
So step 6 is finally to compile all the.c files in the subdirectory to generate the corresponding.o files
$(CC) $(CFLAGS) -o $(Target) $(AllObjs) $(Libs)
Copy the code
These variables are defined in the file scripts/Makefile: $(CC) : replace with GCC, make the compiler $(CFLAGS) : replace with -wall-O3, which is the optimization level at compile time -o $(Target) : Generate executable phone $(AllObjs) :
AllObjs := $(addsuffix /*.o,$(Modules))
Copy the code
Addsuffix will append /*.o to all the words in $(Modules), which is all the.o files we compiled in the subdirectory $(Libs) : instead of -lpthread, which is the required dynamic library
So you can use this step to analyze what you do when you make clean
Complete instance procedure public number background reply: telephone number management
Phone Number Management – Makefile version. Rar