"Linux Network Programming" makefile file

Source: Internet
Author: User

"Linux Network Programming" (Second Edition) 2nd chapter of some reading notes ↓

Makefile: In a project with more files, define a series of rules that specify the order in which the files are compiled and can be used to manage the project.

MAKEFILE specifies which source files in the project need to be compiled, how to compile, how to create those library files, how to create these library files, and how to eventually produce the executable file we want. The benefit of writing makefile for engineering is the ability to use a single line of commands to automate compilation, and the only thing you need to do to compile the entire project is to enter the make command at the shell prompt, and the entire project is automatically compiled.

First look at the GCC under Linux (GNU Compiler Collection): This is a toolset that contains GCC (unlike uppercase), g++ and other toolsets such as compilers and AR, NM.

The GCC compiler has 4 stages of compiling a program: Compile -to-build and optimize-to-assemble links , compiled with C code as an example:

Source code (*.C) "precompiled-E" pre-preprocessed code (*.I) "Compile and optimize-S" Assembler Code (*.S) "Assembler-C" target file (*.O) "link" executable file

The precompilation process is to include the header file referenced in the program into the source code and replace some macros

compilation and optimization are usually translated into assembly language, and the assembly is a one-to-a-kind relationship between machine opcode

A target file is a CPU-readable binary code that is compiled and compiled by the compiler, but some of these function procedures do not have instructions and instructions, so they are not generally executed

The target file needs to be combined in some way to run, which is the link

Some command options (assuming the file name is HELLO.C):

GCC hello.c/* Generates an executable file named Default a.out. GCC can be followed not only by the *.c file, but also by *.O or others, as long as the stage of the processed file can be preceded by the stage of the file generation */

Gcc-o Hello hello.c/* Generates the executable file, named after-O, which is hello */

GCC-E hello.c/* Pre-compiled process, default name format, generated HELLO.I */

Gcc-s hello.c/* has been pre-compiled and compiled to optimize the process, the name is the default HELLO.S */

Gcc-c hello.c/* (commonly used) has been pre-compiled and compiled to optimize and compile the process, resulting in the target file, the name is the default HELLO.O */

Other options:

GCC-D macro name, Gcc-dos_linux is equivalent to adding a #define os_linux when precompiled, that is, when a #ifdef os_linux occurs, the condition is met

Gcc-idir (uppercase I), expands the search path of the header file, including the Dir directory (which is used later)

Gcc-ldir, expand the link library search path to use when linking, including the Dir directory, GCC takes precedence over shared libraries

Gcc-static, use only static libraries for linking

Gcc-on,n is a number, optimizes program execution speed and occupies space (also increases compile speed), commonly 2,gcc-o2

After understanding some basic options, give an example of a small project, using manual compilation and Makefile "automated compilation" to illustrate:

Directory structure:

project/    main.c    add/        add_int.c        add_float.c    sub/        sub_int.c        sub_float.c

MAIN.C: It can be noted that add.h and sub.h do not have the same level directory with MAIN.C, it is necessary to use the Gcc-i directory options, expand the header file search path, only to find the real *.h. For non-defined functions such as add_int, you need to include a specific. o file at the time of the link.

/* MAIN.C */#include <stdio.h> #include "add.h" #include "sub.h" int main (void) {int a = ten, b = 12;float x = 1.23456, y = 9.87654321;printf ("int a+b is:%d\n", Add_int (A, b));p rintf ("int A-a is:%d\n", Sub_int (A, b));p rintf ("Float a+b is:%f\n" , Add_float (x, y));p rintf ("float A-B is:%f\n", Sub_float (x, y)); return 0;}

Add/add.h

/* add.h */#ifndef __add_h__#define __add_h__extern int add_int (int a, int b); extern float add_float (float A, float b); #en Dif

Add/add_int.c

/* add_int.c */int add_int (int a, int b) {return a+b;}

Add/add_float.c

/* add_float.c */float add_float (float A, float b) {return a+b;}

Sub directory slightly.

According to the code in the book, the C file is converted to the target file and then linked. Where, if in the compilation of Main.c, because the header files can not be found, so must be added to-iadd and-isub to be able to find, the book example is wrong.

As you can see, compiling a small project requires so many steps:

Gcc-o add/add_int.o-c add/add_int.c gcc-o add/add_float.o-c add/add_float.c gcc-o sub/sub_float.o-c sub/sub_float.c Gcc-o sub/sub_int.o-c sub/sub_int.c gcc-o main.o-c main.c-iadd-isubgcc-o cacu add/add_int.o add/add_float.o sub/sub _INT.O sub/sub_float.o MAIN.O./cacu

Although you can use the default rules for GCC, you can also generate executables using the following command:

Gcc-o cacu1 add/add_int.c add/add_float.c sub/sub_int.c sub/sub_float.c main.c-iadd-isub

However, it becomes very difficult to compile directly with GCC when the source files are frequently modified or when there are more files in the project and the relationship is more complex.

Therefore, we should use the makefile file to write, through the make command to compile multiple files into an executable file.

Make by parsing the rules in the makefile file, you can automatically execute the corresponding script, and here is a simple makefile file:

# The first line of item ":" To the left of the make command after the correct operation of the default generated files, it generates CACU2, depending on ":" to the right of the file. # Every item is a rule # in the process of scanning from left to right, if a file does not exist, skip to the rule that generates it # Note the bottom line, which starts with the TAB key, cannot be a space, indicates that all dependencies are met, executes those lines of instruction CACU2:ADD_INT.O add _FLOAT.O sub_int.o sub_float.o main.ogcc-o cacu2 add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o main.oadd_ int.o:add/add_int.c add/add.hgcc-o add/add_int.o-c add/add_int.cadd_float.o:add/add_float.c add/add.hgcc-o add/add_ Float.o-c add/add_float.csub_int.o:sub/sub_int.c sub/sub.hgcc-o sub/sub_int.o-c sub/sub_int.csub_float.o:sub/sub_ float.c sub/sub.hgcc-o sub/sub_float.o-c sub/sub_float.cmain.o:main.c add/add.h sub/sub.hgcc-o main.o-c Main.c-iadd- isub# cleanup Rules, you can use make clean to proactively execute clean:rm-f cacu2 add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o MAIN.O

, in the case where make is installed, after writing the makefile, the system automatically executes some GCC commands, generates the CACU2 executable file, and then makes clean, then deletes the content created by the make.

Back in the makefile file, in fact, by default, make executes the first rule directly, the CACU2 rule. The system checks for dependencies first and executes the following commands after success:

$ (CC)-  o  $ (TARGET) $ (  objs)  $ (CFLAGS)

How to understand? The above command is actually equivalent to the following one, but only with the variable extension

Gcc-o cacu2 add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o Main.o-iadd-isub-o2

CC = gcc, TARGET = cacu2, Objs = add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o main.o, CFLAGS =-iadd-is Ub-o2

Similarly, the make clean command is this:

-$ (RM)  $ (TARGET)  $ (OBJS)

Equivalent to rm-f cacu2 add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o MAIN.O, notice that the RM variable is preceded by a "-" sign, which indicates that the command continues execution when the operation fails without an error.

Summarize the points to note:

    1. The makefile is made up of several rules, and the first is executed by default, and the basic format of the rule is:
      TARGET ...:D ependeds (dependent)    ... COMMAND    ...    ... # one line, if a command line is not enough to write, you need to use a backslash section

        

    2. The command line must start with the TAB key (not a space), and the make program handles all successive tab-start lines that appear after a rule as the command line
    3. The order of dependencies is checked or executed from left to right, and if no such file is checked, you need to jump to the corresponding (same name) rule to generate the file, but if there is no such rule, an error is given.
    4. When the make command executes, it determines whether the relevant command is executed based on the timestamp of the file and executes the rules that depend on it. For example, to modify only the Main.c file after a make, and then compile it again with the build command, it compiles only main.c and executes the rules, reconnecting the program.
    5. Execute non-default rule: Make XXX (rule name), such as Make Cacu
    6. Pattern matching (using automatic variables to simplify rule writing), as mentioned later, here is an example:
      MAIN.O:MAIN.C    gcc-o main.o-c main.c-iadd-isub# can be replaced by the following wording main.o:%o:%c    gcc-o [email protected]-C $<-iadd- isub#%o:%c indicates that the target domain's extension is replaced by a. C,[email protected] representing the contents of the target domain,$< represents the result of the dependency

        

Use variables in makefile:

Why introduce variables? It is inconvenient to add a dependency to a rule, both in the dependency and in the command line.

There are 3 types of variables:

1. Predefined variables: variables already defined in makefile, users can directly use these variables without having to define them. (Figure from this link) using the same method as a custom variable, see 3

    

2, automatic variables: In the compilation of statements, the target file and dependent files will often appear, automatic variables on behalf of these target files and dependent files.

    

3. User-defined variables:

Definition method: Variable name = value. eg, objs = add_int.o add_float.o ... # a row represents a variable

How to use: $ (variable name). Eg, $ (OBJS)

/* Rewrite a copy here Makefile */

# define some variables cc = Gcccflags =-iadd-isub-o2target = Cacu3objs = add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o m ain.o# $ (cc)-O $ (target) $ (OBJS) $ (CFLAGS) $ (target): $ (OBJS) $ (cc)-O $ (TARGET) $ (OBJS) $ (CFLAGS) $ (OBJS):%o:%c$ (CC)-O [em AIL protected]-C $< $ (CFLAGS) clean:-$ (RM) $ (TARGET) $ (OBJS)

The method of defining variables is used here to simplify the maintenance of text.

$ (CC)-o [email protected]-C $< $ (CFLAGS) uses the so-called "static mode" rule, which is equivalent to multiple rules, as shown above.

Search Path:

In large systems, there are many directories, hand-I method to add directories inconvenient, so the use of the Vpath variable, it can automatically find the directory of the specified file and add to the file.

How to use: VPATH = path1:path2: ...:.

Separated by a colon (:), remember to add the current directory at the end.

This will cause a problem: The target file will be placed in the current directory, polluting the environment! So, customize a variable, create a directory with the name of the variable, and put the *.o file in.

/* Rewrite a copy of makefile here * *

# found a serious error, because makefile file line at the end of no terminator, so it is best not to blindly put comments in the back, but should be wrapped. # define some variables and introduce VPATHCC = Gcccflags =-iadd-isub-o2# Place all the target files in this folder Objsdir = Objsvpath = add:sub:. TARGET = cacu4# Objs = add/add_int.o add/add_float.o sub/sub_int.o sub/sub_float.o main.oobjs = ADD_INT.O ADD_FLOAT.O sub_ INT.O SUB_FLOAT.O main.o# defines the Vpath, the folder name in the OBJS does not have to be written # first check that the directory exists $ (target): $ (Objsdir) $ (OBJS) $ (CC)-O $ (TARGET) $ ( Objsdir)/*.O $ (CFLAGS) $ (OBJS):%o:%c$ (CC)-O $ (objsdir)/[email protected]-C $< $ (CFLAGS) # Mkdir-p Create all lost parent directories $ ( Objsdir): Mkdir-p./[email protected]clean:-$ (RM) $ (TARGET) $ (objsdir)/*.O

Automatic derivation rules: When using command make to compile C language files with the extension C, the compilation rules of the source files are not explicitly given. According to the default rules, find the corresponding. c file by using the. o file in the dependency to compile it into a target file to satisfy the dependency.

# when using command make to compile C language files with the extension C, the compilation rules for the source files are not explicitly given. (a default compilation rule is used)--make's implied rule cc = Gcccflags =-iadd-isub-o2vpath = add:sub:. target = CACU5OBJS = ADD_INT.O add_float.o sub_int.o sub_float.o main.o$ (target): $ (OBJS) $ (CC)-O $ (TARGET) $ (OBJS) $ (cflag S) clean:-$ (RM) $ (TARGET) $ (OBJS)

Recursive make:

When more than one person is developing a program in multiple directories, and everyone is responsible for a module, and the file is in a relatively separate directory, the compilation of the same makefile maintenance code can be very lame.

1. Recursive invocation: The make command has the function of recursive invocation, which can recursively invoke the makefile of each subdirectory.

If you have makefile in the directory Add and sub, you can use the following two methods (the second is better):

Add:    CD add && $ (make)
Add:    $ (make)-C add

All means go to the Add directory and execute the make command

2, General control makefile: Call $ (make)-C can. If some of the variables in the master makefile need to be passed to the lower makefile, you can use the Export command.

The following is a general-controlled makefile code implementation:

Export CC = Gcccflags =-iadd-isub-o2target = Cacu6export Objsdir = ${shell pwd}/objs$ (TARGET): $ (Objsdir) main.o$ (make) -C add$ (make)-C sub$ (CC)-O $ (TARGET) $ (objsdir)/*.omain.o:main.c$ (cc)-O $ (objsdir)/[email protected]-C $^ $ (CFLAGS) $ (o Bjsdir): Mkdir-p $ (objsdir) clean:-$ (RM) $ (TARGET) $ (objsdir)/*.O

The above code is different from the book, note that CC needs to export to the sub-makefile, otherwise it will default to CC instead of GCC

${shell pwd} indicates that the PWD command in the shell is executed, that is, getting the current path

The resulting target files (*.O) are all placed in the OBJS directory of the project directory

Here is the subdirectory makefile:

Add/makefile:

OBJS = ADD_INT.O add_float.oall:$ (OBJS) $ (OBJS):%o:%c$ (CC)-O $ (objsdir)/[email protected]-C $<-o2clean:-$ (RM) $ ( OBJS)

Sub/makefile:

OBJS = SUB_INT.O sub_float.oall:$ (OBJS) $ (OBJS):%o:%c$ (CC)-O $ (objsdir)/[email protected]-C $<-o2clean:-$ (RM) $ ( OBJS)

Results such as:

3. Functions in Makefile

    • Gets the filename of the matching pattern wildcard: Finds all the file names in the current directory that conform to pattern patterns, and the return value is a space-delimited list of file names that conform to the pattern. Prototype: $ (wildcard PATTERN), such as: $ (wildcard *.c)
    • The pattern substitution function Patsubst: equivalent to the Replace function, looking for words separated by spaces in the text of the string, replacing the pattern-conforming string with another string. Prototype: $ (patsubst pattern, replacement, text), such as: $ (Patsubst%.c,%.O, $ (wildcard *.c))
    • Loop function foreach: Takes out each var word separated by a space in the list, then executes the text expression, processing the output after the end. Prototype: $ (foreach VAR, LIST, TEXT), such as: $ (foreach dir, $ (DIRS), $ (wildcard $ (dir)/*.c))

The following is a function-based makefile file that is rewritten according to the makefile file in the book:

CC = Gcccflags =-iadd-isub-o2target = Cacu7dir = Add Sub.  FILES = $ (foreach dir, $ (dir), $ (wildcard $ (dir)/*.c)) Objs = $ (Patsubst%c,%o, $ (FILES)) $ (TARGET): $ (OBJS) main.o$ (CC)-O [Email protected] $^-o2$ (OBJS):%o:%c$ (CC)-o [email protected]-C $< $ (CFLAGS) clean:-$ (RM) $ (TARGET) $ (OBJS)

-----Split Line-----

The above makefile examples and the entire project code can be found in: Tyruschin-github

"Linux Network Programming" makefile file

Related Article

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.