Practical make best practices

Source: Internet
Author: User

I. Preface

The most important and basic function of the make tool is to describe the source through the MAKEFILE file.ProgramAnd automatically maintain the compilation work. The MAKEFILE file needs to be compiled according to a certain syntax. The file must describe how to compile each source file and generate an executable file, and define the dependency between the source files.

However, the make command "profound blog" is daunting for beginners.ArticleInstead of making, you can only compile and use the practical makefile.

In Linux, if you use GCC to compile the source code one by one, it is very cumbersome, especiallySource codeThis is even more complicated. Many people, including me, have very simple requirements. They only need to put the header file and CPP or C file in the current directory or other directories, A command can be compiled directly, but there are too many make commands, which is quite a blow to the confidence of beginners.

There are not many frequently-used make commands. You can just use them. Next, I will explain how to write the practical makefile. After reading this, you can directly download the make project and compile it with a make command.

Related Environment: RedHat 5.5 + G ++ version 4.1.2 + GNU make 3.81

G ++ supports CPP file compilation. GCC may cause some problems when compiling CPP files. Therefore, G ++ is used here.

 

Ii. makefile rules

 
Target...: prerequisites...
Command
...
...

If comman and target are not in the same row, Type \ t in the second row and then type command.

Target is a target file, which can be an object file or an execution file. It can also be a label)

This is the dependency of a file. That is to say, one or more target files depend on the files in prerequisites, and their generation rules are defined in command.

If more than one prerequisites file is newer than the target file, the command defined by the command will be executed. This is the makefile rule. That is, the core content in makefile.

 

3. Use make to compile sources one by oneCode

Suppose we write a simple program with the source code in/usr/make/Main. cpp. The Code is as follows:

//Main. cpp
# Include <stdio. h>
IntMain (IntArgc,Char** Argv ){
Printf ("APP Startup \ n");
Printf ("APP stop \ n");
Return 0;
}

The biggest benefit of make is automatic compilation, So we create/usr/make/makefile. The content of makefile is as follows:

 
Main: Main. o
G ++ main. O-o main
Main. O: Main. cpp
G ++-C main. cpp-O main. o
Clean:
Rm-RF *. O main

After saving the file, run make directly to generate the main. O target file, which is the main executable file.

However, this program is actually thin, so we need to add an app class to control the entire program startup and shutdown cycle.

Create a new/usr/make/APP. h file. The Code is as follows:

 
# Ifndef app_h
# DefineApp_h

ClassAPP {
Public:
StaticAPP & getinstance ();
BoolStart ();
BoolShutdown ();

Private:
APP ();
APP (ConstAPP &);
APP &Operator= (ConstAPP &);
BoolM_stopped;
};

# Endif

Create the/usr/make/APP. cpp file with the following code:

# Include " App. h  " 

# Include <stdio. h>
# Include <unistd. h>
APP & App: getinstance (){
Static APP;
Return APP;
}

APP: APP (){
M_stopped = False ;
}

Bool APP: Start (){
Printf ( " APP Startup \ n " );
While (! M_stopped ){
Printf ( " APP run \ n " );
Sleep ( 5 );
}
Return True ;
}

Bool APP: Shutdown (){
If (M_stopped = False ){
M_stopped = True ;
}
Return True ;
}

Modify the/usr/make/Main. cpp file with the following code:

//Main. cpp
# Include <stdio. h>

# Include"App. h"

IntMain (IntArgc,Char** Argv ){
APP & App = app: getinstance ();

If(! App. Start ()){
Printf ("APP start fail \ n");
}

App. Shutdown ();
Return 0;
}

Modify/usr/make/makefile with the following content:

Main: Main. O app. o
G ++ main. O app. O-o main
Main. O: Main. cpp
G ++-C main. cpp-O main. o
App. O: App. cpp
G ++-C app. cpp-O app. o
Clean:
Rm-RF *. O main

Execute make,./main, and find that the background prints "app run" every five seconds, only Ctrl + C can end.

Later, we modified main. CPP, app. CPP, app. after the H file, we only need to input make to automatically compile the file, without having to execute the complicated compilation process each time using G ++ commands.

In this way, every time we add a source code file, we need to manually modify the content of the makefile, add dependencies and commands, and it still does not appear automatic.

Download makeprojectv1

 

4. Use make to automatically derive and compile

GNU make is very powerful. It can automatically deduce the commands behind the file and file dependency, so we do not need to go to every [. o] The files are all written with similar commands, because our make will automatically identify and deduce the commands by ourselves.

Our new makefile is released again:

Cpp_sources = $ (wildcard *. cpp)
Cpp_objs =$ (patsubst %. cpp, %. O, $ (cpp_sources ))

Default: Compile

$ (Cpp_objs): %. O: %. cpp
G ++-C $ <-o $ @

Compile: $ (cpp_objs)
G ++ $ ^-O main

Clean:
Rm-F $ (cpp_objs)
Rm-F Main
 
Next we will parse the makefie syntax step by step.
 
Initialization:
 
The wildcard function is used to expand a list Of all file names that match the description of the parameter. Files are separated by spaces. In this example, a list of all files are generated '. CPP, and then save the variable cpp_sources.
 
The patsubst function is a matching and replacement function with three parameters. The first parameter is a pattern to be matched, and the second parameter is used to replace it, the third is a space-separated word column to be processed. In this example
 
The extension of cpp_sources is the CPP file list, which is replaced with the file list with the extension of O.
 
Generate the target file
 
$ (Cpp_objs): %. O: %. cpp
G ++-C $ <-o $ @

In the above example, we specify that our target is obtained from $ (cpp_objs), "%. O "indicates that you want all ". O "The end of the target, that is," Main. O app. O ", that is, the mode of the variable $ (cpp_objs) set.
The dependency mode "%. CPP "indicates the mode" %. O "" % ", that is," main app ", with the suffix" CPP ". therefore, our dependency goal is "Main. CPP app. CPP ".
In the command, "$ <" and "$ @" are automation variables. "$ <" indicates all dependent target sets (that is, "Main. CPP app. CPP ")," $ @ "indicates the target set (that is," Main. o cpp. O ").

After expansion:

 
Main. O: Main. cpp
G ++-C main. cpp-O main. o
Main. O: App. cpp
G ++-C app. cpp-O app. o

Link

The above default target is the first target of makefile, which depends on compile. The compile object does not exist or does not exist. Therefore, the compile object will be executed.

Default and compile are only common rules for makefile.

 
Compile: $ (cpp_objs)
G ++ $ ^-O main

"$ <" Indicates all dependent target sets, indicating main. O app. o

After expansion

 
Compile: Main. O app. o
G ++ main. O app. O-o main

In this way, when we add a CPP file to the current directory, we do not need to change the makefile any more. Just type the make command to complete the entire compilation process. At this time, we can feel the convenience of automatic compilation of make.

Download makeprojectv2

 

V. Improvement of practical makefile

Although we have used the automatic derivation of makefile, this makefile still has some shortcomings:

1. Only CPP files are supported. c files are not supported.

2. The generated target files are all stored in the current directory, causing confusion in the current directory.

3. The H file and the CPP file or the c file are not separated, resulting in a double explosion of source code files in the directory, and multi-directory is not supported.

4. Third-party library files, including include files and Lib files, are not supported.

Therefore, a complete makefile is as follows:

Target = Main
Obj_path = objs

Cc = g ++
Cflags =-wall-werror-G
Linkflags =

# Includes =-I include/myinclude-I include/otheradede1-I include/otheradede2
Includes =-I include
# Srcdir = src/mysrcdir src/othersrc1 src/othersrc2
Srcdir = SRC
# Libs =-llib-lcurl-llib-lmysqlclient-llib-llog4cpp
Libs =

C_srcdir = $ (srcdir)
C_sources = $ ( Foreach D, $ (c_srcdir), $ (wildcard $ (d)/*. c ))
C_objs =$ (patsubst %. C, $ (obj_path)/%. O, $ (c_sources ))

Cpp_srcdir = $ (srcdir)
Cpp_sources = $ ( Foreach D, $ (cpp_srcdir), $ (wildcard $ (d)/*. cpp ))
Cpp_objs = $ (patsubst %. cpp, $ (obj_path)/%. O, $ (cpp_sources ))

Default : Init compile

$ (C_objs): $ (obj_path)/%. O: %. c
$ (CC)-C $ (cflags) $ (DES) $ <-o $ @

$ (Cpp_objs): $ (obj_path)/%. O: %. cpp
$ (CC)-C $ (cflags) $ (DES) $ <-o $ @

Init:
$ ( Foreach D, $ (srcdir), mkdir-p $ (obj_path)/$ (d );)

Compile: $ (c_objs) $ (cpp_objs)
$ (CC) $ ^-o $ (target) $ (linkflags) $ (libs)

Clean:
Rm-RF $ (obj_path)
Rm -F $ (Target)

Install: $ (target)
CP $ (target) $ (prefix_bin)

Uninstall:
Rm -F $ (Prefix_bin)/$ (target)

Rebuild: Clean compile

The makefile function is to scan the C and CPP files in the SRC folder for compilation. The compiled command is g ++ and the compilation option is-wall-werror-G, indicates to print the error message as much as possible. If there is an error or warning, the compilation is stopped and debugging information is generated. In the production environment, remove-G. Finally, connect all target files to main. If all c files and CPP files do not have the main function entry, an error is reported during the link.

When using this makefile, note the following variables:

 
Target indicates the name of the last generated executable file. The default generated main executable file is in the current working directory.
Obj_path indicates the directory where the target file generated during the compilation process is stored. By default, the file is generated under the objs directory of the current directory, which is automatically generated without manual mkdir.
 
CC is g ++ by default. If GCC is used, modify it. However, after GCC compiles the CPP file, problems may occur during the link.
 
The Directory of the header file configured with the pair des. The default directory is the include directory. If you want to put the file in the current directory, you can change it to "pair des =.". If you want to configure multiple include directories, follow the annotations and configure them by yourself.
 
Srcdir configures the directory of the C and CPP files. The default directory is the src directory. If you prefer to put it in the current directory, you can change it to "srcdir =. ", if you want to configure multiple source code directories, you can follow the notes and configure them yourself.
 
Libs configures third-party Dynamic and Static link libraries. When a program uses a third-party library, we compile to configure a third-party header file directory. When linking, We need to configure the Linked Library file, for details about libs configuration, refer to the comments. If you are not clear about the libs configuration, refer to the "frequently used GCC commands" article in my blog.

Download makeprojectv3

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.