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

  1. 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
  1. The '-'

If a file does not exist or has already been created, you can add -,

- rm dir; - the mkdir aaadir;Copy the code
  1. '$'

The dollar sign $extends variables defined in the makefile

  1. '$$'

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:

  1. 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).
  2. 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.
  3. Multiple params in a function are separated by commas.
  4. 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:

  1. Include scripts/Makefile: replace the file to the current location,
  2. Use the default target all, which depends on$(Target) $(Target)It’s defined in scripts/Makefile, which is phone
  3. while$(Target)Depends on the mm
  4. 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
  1. 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

  1. 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