Makefile usage Analysis
in the Linux development, the application compiles basically uses the GNU make tool, and made with the makefile to realize the project code compiles, in the larger complex project,the more powerful place is obvious. After you have used make for a period of time, analyze its usage. This article is in the study of Chenhao "with me to learn Makefile" article, the summary of their own learning.
A. A simple example
now, we have a C + + projects need to be compiled, the project contains 3 header files, 3. cpp files, respectively, Main.cpp,main.h,read.cpp,read.h,write.cpp,write.h, the following is our makefile:
The goal we need to generate is the executable file test,test by the intermediate target file. O-Link, the. o file is compiled from the corresponding header file and the. cpp source file According to the dependencies, and pseudo-target clean is used to clear the target file and the. o file.
in my Makefile, we found that the compiler tool CC even if not specified as g++ can also be compiled normally, but if the target file is not specified in the link, there will be a hint to find the relevant library, that CC is based on what to choose the compiler tool? By consulting the data and testing found that the compiler cc is generally the default is GCC, when we compile the source file, for. c files, gcc and g++ are identified as C and C + + programs, for. cpp files, both are recognized as C + + programs, So at compile time we can use the default cc to compile the. C and. cpp files (of course, for other platforms or embedded, to specify the corresponding compilation tools to prevent errors). However, when linking, you need to generate an executable program for the. O Intermediate File link library, g++ will link the C + + library, GCC link C's library, so if you need to indicate the compiler when linking. In normal use, the easy-to-maintain and error-prevention considerations are unified to indicate that compiled and linked compilers are g++.
Okay, through this . Makefile realized our functional requirements, but we found that this makefile although logic is simple, but once the project volume is very large, write makefile will be a very painful thing, need to write hundreds of intermediate target file dependencies, OK, don't worry, GNU make is powerful, and it can be deduced automatically through cryptic rules.
two. Cryptic rules and automatic derivation
The GNU make tool has a cryptic rule, As soon as make sees an. o file, he will default to the corresponding. C or. cpp (discussed later in the. c file) file added to the dependency relationship, such as if there is a main.o, then he will default to add MAIN.C to their dependencies, and make will automatically deduce it, including the file dependencies and the following 's command. So, we can get a new makefile again.
so we get a more concise look . Makefile, we don't have to write the compilation instructions for each intermediate target file, because make is automatically deduced, but it seems to only partially reduce our labor force, for hundreds of source file programs, We still need to write out the dependencies of each file's cryptic rules, although we don't have to write the compilation instructions, but it's a lot, and this Makefile is not very general, if we write a different test program, this Makefile We still need to change a lot,OK, make this tool's static mode and automatic variable can help us solve this problem.
three. static mode and automatic variables
The syntax for the static mode in Make is as follows:
<targets: <target-pattern>: <prereq-patterns ...>
<commands>
....
The targets defines a series of target files, which can have wildcard characters. is a collection of targets.
Target-parrtern is the pattern that indicates the targets, that is, the target set pattern.
Prereq-parrterns is the dependent pattern of the target, which is the definition of a dependent target for the pattern formed by Target-parrtern.
For example, the previous objects target set,<target-parrtern> defined as "%.O", meaning that all of our <target> collections End with ". O", And if our <prereq-parrterns> is defined as "%.c", it means two definitions of the target set formed by <target-parrtern>, which is calculated by taking < The "%" in the target-parrtern> mode(i.e. the end of [. O] is removed), and a new set is added to the end of [. c]. A dependent target such as MAIN.O through the pattern is the main.c file. Static mode helps us to represent hundreds of source files in a common pattern, so we don't have to write out the dependencies of all the intermediate files, as long as a static mode is OK.
Then there is a problem, in the above pattern rules, the target and dependent files are a series of files, then how do we write a command to complete the corresponding target from different dependent files? Because every time you parse a schema rule, it will be a different target and dependent file. This requires an automation variable for make.
The automation variable for make. The so-called automation variable, that is, this variable will be defined in the pattern of a series of files automatically removed, until all the matching mode of the file is finished. This automation variable should only appear in the command of the rule.
Here are all the automation variables and their descriptions:
[email protected]
represents a set of target files in a rule. In a pattern rule, if there are multiple targets, then"[email protected]" is matched to
The collection of schema definitions in the target.
$%
represents the target member name in a rule only if the target is in a function library file. For example, if a target is "FOO.A (BAR.O)", then "$%" is "BAR.O", "[email protected]" is "FOO.A". If the target is not a function library file (under UNIX is [. lib] under [. a],windows]), then its value is null.
$<
the first target name in a dependent target. If the dependent target is defined in a pattern (that is, "%"), then "$<" will be a series of file sets conforming to the pattern. Note that it is taken out one by one.
$?
A collection of all new dependent targets than the target. separated by a space.
$^
A collection of all dependent targets. separated by a space. If there are multiple duplicates in the dependent target, that variable will remove the duplicate dependent target and keep only one copy.
$+
This variable is much like "$^" and is also a collection of all dependent targets. It's just that it does not remove duplicate dependent targets.
$*
this variable represents "%" in the target pattern and its previous part. If the target is "DIR/A.FOO.B" and the target's pattern is "a.%.b", then the value of "$*" is "Dir/a.foo". This variable is more relative to the file name that is associated with the construct. If there is no schema definition in the target, then "$*" cannot be deduced, but if the suffix of the target file is recognized by make, then "$*" is the part of the suffix. For example, if the target is "foo.c" because ". C" is the suffix name that make can recognize, the value of "$*" is "foo". This feature is GNU make and most likely not compatible with other versions of makes, so you should try to avoid using "$*" unless it is in implied rules or static mode. If the suffix in the target is not recognized by make, then "$*" is a null value.
after the updated Makefile as follows:
Ok Here, our makefile main.o dependencies include main.cpp main.h read.h write.h When the first compilation, the dependency will find the corresponding header file, but then if a header file is modified, then the header file is not updated again, so this method is missing the header file dependencies, One workaround is to empty the previous compilation target file on the ok .c file dependencies (write next time).
The second problem is that we've found that we're still going to write out all of the target file sets, and again, it's a headache for projects with hundreds of intermediate files, and we can solve this problem with wildcards and some functions.
Our requirement is for make to find all the source files in the current directory, and to compile the source files according to their dependencies for complete automation. First we need to use a wildcard * to find all the source files, and corresponding to generate all the source files corresponding to the intermediate target file, which is mainly through the patsubst function to achieve, This function is a pattern string substitution function (for all functions that can query the following function table), which helps us to generate. o files for all source files that depend on the target set .
Makefile write here, should be concise and universal is relatively high, but now the Makefile In actual availability is not high, because the actual project source files are often placed in multiple folders, A number of compilation parameters are also set, so the following will write a makefile that reflects the complexity of the source file structure and compiler parameters .
Four. Compiler parameters
now, let's assume that our read.cpp,read.h is in the read directory of the current directory , write.cpp and Write.h in the current directory under the write directory, then our new makefile is baked.
The original wildcard is to match all the source files in the current directory, but there are multiple folders, it will not match, so here we can use the variable VPATH (this the variables identified by make are used to find files in the current directory when they are not found, default to the VPATH path, and a function Forreachis required. Because this only matches the source file, the location of the corresponding header file is not included, so you need to include a header file.
OK, here, it seems that we have written a better Makefile, but the actual compilation parameters we have not covered, the following specific analysis,GNU Compile parameters for the compilation tool under the
Five. link library
Sometimes we need to link to a third-party library, so how to link the library, how to use the function in the library?
First, in the source code, we need the header file containing the interface function of the library being used;
Second, in In Makefile , we need to add the path to the header files and libraries separately in the search path of the header files and libraries. Assuming that the header files for the libraries and libraries are under path /mnt/hgfs/share/miniupnp/miniupnpc-1.9.20160209, the Include method
header file:-i/mnt/hgfs/share/miniupnp/miniupnpc-1.9.20160209// Join header file path
Library:-l/mnt/hgfs/share/miniupnp/miniupnpc-1.9.20160209// Join library file path
if the name of the library is LIBMINIUPNPC.A, then the parameter at the time of the link is -LMINIUPNPC
Similar to:
End.
Makefile Study Summary