Part 3 makefile project organization

Source: Internet
Author: User
Tags automake
++ The third part is the project organization of makefile. ++

Preface:
If Library 1 depends on library 2 and the user only uses lib1, I haven't seen it yet. How can I avoid using-l library 2. That is to say, at the same time as-l database 1,-l database 2 must be compiled. All I can think of now is to add the. PC file with PKG-config, so that users do not know what to rely on.

The standard engineering organization of automake (autotools) is introduced above. The following comparison shows how to organize the project by writing makefile on your own to accomplish similar work and understand why autotools is needed.
I. Why do we need autotools?
The first two reasons are as follows:
1. How to port it?
Compilers on different platforms have different parameters, and makefile must specify these parameters. This is a great learning and memory burden for people who maintain multiple platforms. The configure of autotools does all this for you. In addition, automake is embedded with libtool to unify the compilation library exceptions on various platforms.
2. How to create an installation package?
(1) It is clear that autotools is conducive to making installation packages released by source code, because the principle of writing makefile. Am is to assign values to variables, greatly simplifying the preparation of makefile.
(2) rows ).
(3) for users who get the installation package, it can use configure to determine many parameters and adjust the compilation and installation methods. ── That is, it is painful for the user to change the makefile. The parameter is specified with./configure. This makes your installation package more friendly.

After learning about the advantages of autotools, you will know what kind of "simple" package can be hand-written makefile, and what kind of best use of autotools.

II. For more information about the makefile project, see:
1. makefile principle: ── ─ the general principle is: makefile is a write Rule, compared to makefile. am is a write value!
(1) make-C subdir and export variables for makefile at the non-source file layer:
Make-C subdir: Enter subdir to execute make (makefile must be included ). If there is a dependency between sub-directories, adjust the order to make-C.
Export variable: if there are upper-layer makefile variables that you want to pass to make-C subdir, The makefile of subdir must be given using export. It may be used to pass the absolute path of the top-level directory to the lower-level directory, because the lower-level directory may want to find something like this.
(2) write "Display rules" and "abstract rules" at the source file layer and "self-contained ":
1) explicit rules: it is a library or program that depends on which objects and what actions are then taken. All objects must be listed. Generally, make built-in functions or embedded shell are used to help us list them.
2) abstract rule: it is the. c. o rule. See the example file below.
3) Self-contained: for example, if you want to reference another header file under the same level as subdir, you can write these header files to the upper-level makefile and use export everywhere, then many makefiles in the lower layer are used directly. You can also maintain this in the lower makefile. I select the latter, because this allows sub-directories to be made separately without using the upper-layer makefile. But what I gave in the example is export on the upper layer.

Description ── ─ why not use implicit rules to generate. O:
Implicit rules, such as $ (CC) $ (cflags) $ (cppflags) $ (target_arch)-C $ <-o $ @,
Implicit rules are not enough! Because its rules, such as main. O, only depend on Main. C, rather than the header file contained in Main. C and the header file included in the header file... In this way, if your header file is modified, it will not cause re-make. To this end, we have introduced gcc-MD-MF $ *. d parameter. This parameter enables compilation of a main. c, a main. d, which contains main. O all dependencies, including all header files and header files referenced in the header file! Then, use "include those. D files" in makefile to include the dependency! This completes the final makefile. To introduce-MD-MF $ *. D, you need to write the. C->. o rule by yourself, that is,. c. O: rule. The syntax is as follows.

2. tips:
(1) All things should be defined with variables before reference:
For example, if the library name you want to generate is libhello. A, first use lib_name: = libhello. A to give it, and then use $ (lib_name) to reference it.
(2) Use an embedded shell to avoid memorizing the built-in functions of makefile:
For example, to list all objects dependencies, because all. O comes from. C, you can:
Objs: = $ (shell ls | grep '/. c' | SED's //. C ///. O/G ')
If you use the make built-in function, you need to use $ (wildcard...) and $ (patsubst ...)
(3) Use-to avoid ignoring errors:
The above mentioned "include those. d ", but when you make the first time, make will obviously improve the makefile first, it will see this include and will try to put. d, but GCC has not been called yet. Of course not. d, so make will exit. Unless you use-before include, this error will be ignored. Then, when the second make operation is performed, the. d rule is enabled and the rule introduced by. D takes effect.
(4) avoid printing information:
In the make action, for example, you write @ mkdir-p $ (build_dir) to avoid printing this information during the action execution.
(5) Try $ @ $ <and $ ^:
The following example shows a lot of advantages, especially in the makefile of vpath.

3. Example
In this example, there is a total makefile on the top layer, followed by a src directory and build directory.
Put the source code in SRC. If you make all or make clean on the top layer, it is for the src directory.
The build directory is the make that demonstrates vpath. If you make all-vpath or make clean-vpath on the top layer, it is for the build directory.

Overall makefile (same directory as SRC and build ):
# Makefile for the project
# It's intened to make everything you like, for example the src dir or other non-code things

Export top_dir: = $ (shell PWD) # This is used in lower-layer makefile
Src_dir: = SRC
Build_dir: = build

. Phony: All clean
ALL:
@ Make-C $ (src_dir)
Clean:
@ Make-C $ (src_dir) clean

All-vpath:
@ Make-C $ (build_dir)
Clean-vpath:
@ Make-C $ (build_dir) clean

(1) src directory:
-------- Src/makefile :-------------
# Makeflags: =-S
Src_dir: = $ (shell PWD)

Primary des: =-I $ (src_dir)/libhello # use primary des to contain-I (Notice: these names are made by me)
Ldflags: =-L $ (src_dir)/libhello/build # Use ldflags to contain-l
Myflags: =-wall-g-O3 # Use myflags to contain other flags
Export cflags: = $ (includes) $ (ldflags) $ (myflags) # Use cflags to contain all flags passed to GCC
Export header_dir: = $ (src_dir)/libhello # Just For subdir makefile convenience
Export libs_dir: = $ (src_dir)/libhello/build # Just For subdir makefile convenience

. Phony: All clean
ALL:
@ Echo '===== building libhello =====' # Build libhello first, then Bin
Make-C $ (src_dir)/libhello
@ Echo
@ Echo '==== building binary ===='
Make-C $ (src_dir)/bin
Clean:
@ Echo '==== cleaning libhello ===='
Make-C $ (src_dir)/libhello clean
@ Echo
@ Echo '===== cleaning binary ===='
Make-C $ (src_dir)/bin clean

-------- Src/libhello/makefile :---------
Lib_name: = libhello.
Objs: = $ (shell ls | grep '/. c' | SED's //. C //. o/G') # list all possible. O files 'names for using in "explicit rule"
Deps: = $ (shell ls | grep '/. c' | SED's //. C //. d/G') # list all possible. D files 'names for using in "include"

# The place to keep build process files
Build_dir: = build

# Use vpath to let make find. A and. O in $ (build_dir), when "explicit rule" are checked by make,
# Because *. O are in the $ (build_dir) Dir and not in the Dir where make enters (where makefile exits)
# Vpath is used to find target and dependence files. But has no effect on the command line files
Vpath: = $ (build_dir)

# "Explicit rule"
$ (Lib_name): $ (objs)
CD $ (build_dir) & ar RCS $ @ $ (objs) # cd $ (build_dir) because in. c. o we moved *. O to $ (build_dir)
# "Abstract rule"
. C. O:
@ Mkdir-p $ (build_dir) # avoid failure if no $ (build_dir) exists.
$ (CC) $ (cflags)-MD-MF $ *. D-C $ <-o $ @ # produce. d. o files
@ MV $ *. d $ *. o $ (build_dir) # Move them to $ (build_dir) to make source dir clean.

# Include. O <-. C &. h dependence
-Include $ (addprefix $ (build_dir)/, $ (deps ))

# Phony target
. Phony: clean
Clean:
Rm-RF $ (build_dir)

---------- Src/libhello/hello1.c hello2.c hello. H is the same as the automake example above -------

---------- Src/bin/makefile ------------
# For this file is similiar to that in libhello, we omit submit comments.
Prog: = kid
Objs: = $ (shell ls | grep '/. c' | SED's //. C ///. O/G ')
Deps: = $ (shell ls | grep '/. c' | SED's //. C ///. d/G ')
Libs: = $ (shell ls $ (libs_dir)/*.)
L_libs: =-lhello-LM

# The place to keep build process files
Build_dir: = build

# Vpath to let make find. A and. O in $ (build_dir)
Vpath: = $ (build_dir)

$ (Prog): $ (objs) $ (libs)
CD $ (build_dir) & $ (CC) $ (objs)-o $ @ $ (cflags) $ (l_libs)
. C. O:
@ Mkdir-P build
$ (CC) $ (cflags)-MD-MF $ *. D-C $ <-o $ @
@ MV $ *. d $ *. o $ (build_dir)

-Include $ (addprefix $ (build_dir)/, $ (deps ))

. Phony: clean
Clean:
Rm-RF $ (build_dir)

---------- Src/bin/Main. c is the same as the example in automake above ----------

(2) Build directory:
First, you need to explain what you need to do to support vpath:
A. Create a directory tree structure with the same levels of makefile in build and SRC, and put the similar makefile. The changes are as follows:
B. Use vpath to specify the location of the dependences directory in SRC in "Display rules" and "abstract rules. In this way, target: a row of Object
C. For other files that need to be found, such as-I, you still need to write it yourself. It is useless to rely on vpath.

--------- Build/makefile -----------
. Phony: All clean
ALL:
Make-C SRC
Clean:
Make-c src clean

-------- Build/src/makefile ---------
# Makeflags: =-S

Includes: =-I $ (top_dir)/src/libhello
Ldflags: =-L $ (top_dir)/build/src/libhello
Myflags: =-wall-g-O3
Export cflags: = $ (DES) $ (ldflags) $ (myflags)

. Phony: All clean
ALL:
@ Echo '==== building libhello ===='
Make-C libhello
@ Echo
@ Echo '==== building binary ===='
Make-C Bin
Clean:
@ Echo '==== cleaning libhello ===='
Make-C libhello clean
@ Echo
@ Echo '===== cleaning binary ===='
Make-C bin clean

---------- Build/src/libhello/makefile ---------
Lib_name: = libhello.
Src_dir: = $ (top_dir)/src/libhello
Objs: = $ (shell ls $ (src_dir) | grep '/. c' | SED's //. C ///. O/G ')
Deps: = $ (shell ls $ (src_dir) | grep '/. c' | SED's //. C ///. d/G ')

# The place to keep build process files
Build_dir: = build

# Vpath to let make find. O in $ (src_dir) when executing "Explicit" and "abstract" rule.
# Vpath is used to find target and dependence files. But has no effect on the command line files
Vpath: = $ (src_dir)

# Explicit rule
$ (Lib_name): $ (objs)
Ar RCS $ @ $ ^
# Abstract rule
. C. O:
$ (CC) $ (cflags)-MD-MF $ *. D-C $ <-o $ @

# Include. O <-. C &. h dependence
-Include $ (deps)

# Phony target
. Phony: clean
Clean:
Rm-RF *. O *. d $ (lib_name)

----------- Build/src/bin/makefile ------------
Prog: = kid
Src_dir: = $ (top_dir)/src/bin
Objs: = $ (shell ls $ (src_dir) | grep '/. c' | SED's //. C ///. O/G ')
Deps: = $ (shell ls $ (src_dir) | grep '/. c' | SED's //. C ///. d/G ')
Libs: = $ (shell ls $ (top_dir)/build/src/libhello/*.)
L_libs: =-lhello-LM

# Vpath to let make find. O in $ (src_dir) When
# Executing "Explicit" and "abstract" rule.
Vpath: = $ (src_dir)

# Explicit rule
$ (Prog): $ (objs) $ (libs)
$ (CC) $ ^-o $ @ $ (cflags) $ (l_libs)
# Abstract rule
. C. O:
$ (CC) $ (cflags)-MD-MF $ *. D-C $ <-o $ @

-Include $ (deps)

. Phony: clean
Clean:
Rm-RF *. O *. d $ (Prog)

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.