The writing rules of the Linux makefile Tutorial three [turn]

Source: Internet
Author: User
Tags new set

Writing rules
————

The rule contains two parts, one is a dependency, and the other is the method that generates the target.
In Makefile, the order of the rules is important because, in makefile, there should only be one final goal, and the other targets are associated with this goal, so make sure to know what your ultimate goal is.In general, there may be many goals defined in makefile, but the goal in the first rule will be set as the final goal。 If there are many goals in the first rule, then the first goal will be the final goal. Make accomplishes this goal.

Well, let's take a look at how to write the rules.


I. Examples of rules
FOO.O:FOO.C defs.h # foo Module
Cc-c-G foo.c

See this example, you should not be very strange, the previous also said, FOO.O is our goal, FOO.C and Defs.h is the target depends on the source file, and only one command"Cc-c-G foo.c" (Starts with the TAB key ))。 This rule tells us two things:

1, file dependencies, foo.o dependent on foo.c and defs.h files, if the foo.c and Defs.h file date is newer than the FOO.O file date, or foo.o does not exist, then the dependency occurs.
2. If the foo.o file is generated (or updated). That's the CC command, which explains how to generate the foo.o file. (Of course foo.c files include the Defs.h file)


Ii. Grammar of rules
Targets:prerequisites
Command
...

or this:

Targets:prerequisites; Command
Command
...

targets is a file name, separated by a space, you can use wildcard characters. In general, our goal is basically a file, but it can also be multiple files.
command line, if it is not with "target:prerequisites" in a row, then you must start with [tab], if and prerequisites in a row, you can use a semicolon as a separator. (See above)

Prerequisites is the file (or target) on which the target depends. If one of these files is newer than the target file, the target is considered "obsolete" and is considered to be rebuilt. That's already been said in the front.

if the command is too long, you can use a backslash ('/') as the line break. Make has no limit on how many characters there are on a line. The rules tell make two things, file dependencies and how to become target files.

In general, make executes commands in the UNIX standard shell, which is/bin/sh.


Iii. using wildcard characters in rules

If we want to define a series of similar files, it's natural to think of using wildcard characters.Make supports three wildcard characters: "*", "?" and "[...]"。 This is the same as Unix's B-shell.

The tilde ("~") character also has a more specific purpose in the file name. If it is "~/test", this represents the test directory under the $home directory of the current user. The "~hchen/test" represents the test directory under the host directory of the user Hchen. (These are small knowledge under UNIX, make also support) and in Windows or MS-DOS, the user does not have a host directory, then the wave number refers to the directory according to the environment variable "HOME".

Wildcards replace your series of files, such as "*.c" for files that are later prefixed with C. One of the needs of our attention is thatif we have wildcards in our filenames, such as: "*", then you can use the escape character "/", such as "/*" to represent the real "*" character, rather than as a string of arbitrary length.

Well, let's take a look at some examples:

Clean
Rm-f *.O

I'm not saying much about the above example, which is a wildcard that the operating system shell supports. This is a wildcard character in the command.

Print: *.C
Lpr-p $?
Touch Print

The above example shows that wildcards can also be used in our rules, where the target print depends on all [. c] files. Which of the "$?" is an automation variable that I'll tell you in the back.

objects = *.O

The above example indicates that a wildcard can also be used in a variable. Not that [*.O] will unfold, no! The value of objects is "*.O". The variables in makefile are actually macros in C/s + +. If you want the wildcard to be expanded in a variable, that is, let the objects value be a collection of all [. O] Filenames, then you can:

Objects: = $ (wildcard *.o)

This usage is pointed out by the keyword "wildcard", and we will discuss the key word about makefile later.


Iv. Document Search

In some large projects, there are a large number of source files, we usually do this is to classify many of the source files, and stored in different directories. So, when make needs to find a dependency on a file, you can add a path to the file, but the best way is to give it a path, so it is automatically searched.
The special variable "VPATH" in the makefile file is the completion of this function, and if this variable is not specified, make will only find the dependent and target files in the current directory. If this variable is defined, make will search for the file in the specified directory when the current directory is not found.

VPATH= src:.. /headers

The above definition specifies two directories, "SRC" and ". /headers ", make will search in this order. The directory is delimited by a "colon". (Of course, the current directory is always the highest-priority search place)
Another way to set the file search path is to use theMake 's "vpath" keyword(Note that it is all lowercase), this is not a variable, this is a make keyword, which is similar to the Vpath variable mentioned above, but it is more flexible. It can specify different files in different search directories. This is a very flexible feature. There are three ways to use it:

1, Vpath <pattern> <directories>
Specify search directory <directories> for files that conform to pattern <pattern>.

2. Vpath <pattern>
Clears the search directory for files that conform to the pattern <pattern>.

3, Vpath
Clears all file search directories that have been set up.
The <pattern> need to include the "%" character in the Vapth usage method. "%" means to match 0 or several characters, for example, "%.h" means all files ending with ". h". <pattern> Specifies the set of files to search for, and <directories> specifies the directory to search for the <pattern> set of files. For example:

Vpath%.h. /headers

The statement indicates that make is required in the ".. /headers "directory to search for all files ending with". h ". (If a file is not found in the current directory)
We can use the Vpath statement continuously to specify different search strategies. If the same <pattern&gt appears in successive Vpath statements, or if the <pattern&gt is duplicated, then make performs the search in the order in which the Vpath statements are executed. Such as:

Vpath%.c foo
Vpath% Blish
Vpath%.c Bar
It says ". C" at the end of the file, first in the "foo" directory, then "Blish", and finally the "bar" directory.

Vpath%.c Foo:bar
Vpath% Blish
The above statement says ". C" at the end of the file, first in the "foo" directory, then the "bar" directory, and finally the "Blish" directory.

Five, pseudo-target

In the earlier example, we mentioned a "clean" goal, which is a "pseudo target",
Clean
RM *.O Temp

Just like "clean" in our previous example, when we generate many file-compiling files, we should also provide a "target" to clear them for full recompilation. (Use this target with "make clean")
Because, we do not generate "clean" this file. "Pseudo-target" is not a file, just a label, because "pseudo-target" is not a file, so make cannot generate its dependencies and decide whether it will be executed. We can only let it take effect by indicating the "target" in the show. Of courseThe name "pseudo-target" cannot be the same as the file name, otherwise it loses the meaning of "pseudo-target".
Of coursein order to avoid this situation with duplicate file names, we can use a special tag ". Phony "to show that a target is a" pseudo-target ", to make a statement, whether or not this file, the goal is" pseudo-target. "

. Phony:clean
As long as this statement, regardless of whether there is a "clean" file, to run "clean" the goal, only "make clean" this way. So the whole process can be written like this:

. Phony:clean
Clean
RM *.O Temp
Pseudo-targets generally have no dependent files. However, we can also specify which files are dependent on the pseudo-target. A pseudo-target can also be a "default target", as long as it is placed first. One example is if your makefile needs to generate several executables in one breath, but you want to simply tap a make to finish, and all the target files are written in a makefile, then you can use the "pseudo target" feature:

All:prog1 prog2 Prog3
. Phony:all

PROG1:PROG1.O UTILS.O
Cc-o Prog1 PROG1.O UTILS.O

prog2:prog2.o
Cc-o prog2 PROG2.O

PROG3:PROG3.O SORT.O UTILS.O
Cc-o prog3 prog3.o SORT.O UTILS.O

We know that the first target in makefile will be used as its default target. We declare a pseudo-target of "all", which relies on three other targets. Because the pseudo-target is always executed, the three targets it relies on are not as new as the "all" target. Therefore, the rules of the other three goals will always be resolved. It also achieves our goal of generating multiple goals in one breath. “. Phony:all "All" is declared "pseudo-target".

Incidentally, we can see from the above example that the target can also become a dependency. Therefore, pseudo-targets can also become dependent. Look at the following example:

. Phony:cleanall Cleanobj Cleandiff

Cleanall:cleanobj Cleandiff
RM Program

Cleanobj:
RM *.O

Cleandiff:
RM *.diff

"Make clean" clears all files that are to be purged. The pseudo-targets "cleanobj" and "Cleandiff" are a bit like the meaning of "subroutines". We can enter "make Cleanall" and "makes Cleanobj" and "Do Cleandiff" commands to achieve the purpose of purging different kinds of files.

VI. Multi-Objective

There can be more than one goal in Makefile's rules, which supports multiple targets, and it is possible that our multiple targets depend on a file at the same time, and the commands they generate are roughly similar. So we can merge them together. Of course, the execution commands for multiple target generation rules are the same, which may lead us to trouble, but fortunately we can use an automation variable "[email protected]"(about the automation variable, which will be described later), This variable represents a collection of all the targets in the current rule, which can be very abstract, or an example.

Bigoutput LITTLEOUTPUT:TEXT.G
Generate TEXT.G-$ (subst output,,[email protected]) > [email protected]

The above rules are equivalent to:

Bigoutput:text.g
Generate Text.g-big > Bigoutput
Littleoutput:text.g
Generate Text.g-little > Littleoutput

Where the "$" in-$ (subst Output,,[email protected]) represents a function that performs a makefile, the function is named subst, followed by a parameter. About functions, which are described later. Here the function is to intercept the meaning of the string, "[email protected]" represents the target collection, like an array, "[E-mail protected]" to take out the target, and hold the command.


Seven, static mode

Static mode makes it easier to define multi-objective rules, which can make our rules more resilient and flexible. Let's take a look at the syntax first:

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

It may not be clear to describe these three things, or to give an example to illustrate them. If our <target-parrtern> is defined as "%.o", it means that our <target> collection ends with ". O", and if our <prereq-parrterns> is defined as "%.c", This means that the target set formed by <target-parrtern> is defined two times, which is calculated by taking "%" in the <target-parrtern> mode (that is, removing [. O] end) and adding [. c] A new set of forms.

Therefore, our "target mode" or "dependency mode" should have the "%" character , if you have "%" in the file name, then you can use the backslash "/" to escape, to indicate the real "%" character.

See an example:

objects = FOO.O BAR.O

All: $ (objects)

$ (objects):%.o:%.c
$ (CC)-C $ (CFLAGS) $<-o [email protected]


The above example indicates that our goal is obtained from $object, "%.O" indicates that all targets ending with ". O" are "foo.o bar.o", which is the pattern of the variable $object set, while the dependency pattern "%.c" takes the "%" of the pattern "%.O", that is, " Foo Bar, and add the suffix ". C" to it, so our target is "foo.c bar.c". The command "$<" and "[email protected]" is an Automation variable, "$<" represents all the dependent target set (that is, "foo.c bar.c"), "[email protected]" means the target set (that is, " FOO.O bar.o "). Thus, the above rules are expanded to be equivalent to the following rules:

Foo.o:foo.c
$ (CC)-C $ (CFLAGS) Foo.c-o foo.o
Bar.o:bar.c
$ (CC)-C $ (CFLAGS) Bar.c-o BAR.O

Imagine, if our "%.O" there are hundreds of, that we just use this very simple "static mode rule" can write a bunch of rules, it is too effective rate. The use of static mode rules is flexible, and if used well, it can be a powerful feature. Let's look at an example:

Files = FOO.ELC bar.o lose.o

$ (Filter%.o,$ (Files)):%.O:%.c
$ (CC)-C $ (CFLAGS) $<-o [email protected]
$ (Filter%.elc,$ (Files)):%.ELC:%.el
Emacs-f Batch-byte-compile $<


$ (files) Represents the filter function that calls makefile, filtering the "$filter" set, as long as the schema is "%.O" in the contents of the%.o,$. Its content, I will not have to say it. This example shows the greater elasticity of the makefile.


Viii. Automatic generation of dependencies

In makefile, our dependencies may need to contain a series of header files, for example, if our main.c has a "#include" defs.h "", then our dependency should be:

MAIN.O:MAIN.C Defs.h

However, if it is a relatively large project, you need to know which C files contain which header files, and, when you join or delete the header file, you also have to carefully modify the makefile, which is a very non-maintainable work. In order to avoid this heavy and error-prone thing, we can use a feature compiled by C/C + +. Most C + + compilers support a "-m" option to automatically find the header files contained in the source file and generate a dependency. For example, if we execute the following command:

Cc-m MAIN.C

Its output is:

MAIN.O:MAIN.C Defs.h

The dependencies that are generated automatically by the compiler, so that you do not have to manually write the dependencies of several files, but are generated automatically by the compiler. It should be recalled that if you use the GNU/C + + compiler, you have to use the "-mm" parameter, otherwise the "-m" parameter will include some standard library header files.

The output of the Gcc-m main.c is:

MAIN.O:MAIN.C defs.h/usr/include/stdio.h/usr/include/features.h/
/usr/include/sys/cdefs.h/usr/include/gnu/stubs.h/
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h/
/usr/include/bits/types.h/usr/include/bits/pthreadtypes.h/
/usr/include/bits/sched.h/usr/include/libio.h/
/usr/include/_g_config.h/usr/include/wchar.h/
/usr/include/bits/wchar.h/usr/include/gconv.h/
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h/
/usr/include/bits/stdio_lim.h


The output of the gcc-mm main.c is:

MAIN.O:MAIN.C Defs.h

So how does this function of the compiler relate to our makefile? Because of this, our makefile will also be regenerated based on these source files, so that makefile self-reliance on the source files? This is not a realistic feature, but there are other ways we can do this in a roundabout way. The GNU organization proposes to place the compiler's auto-generated dependencies for each source file in a file, generating a "NAME.D" makefile file for each "name.c" file, and a [. d] file that stores the dependencies for the [. c] File.

So, we can write [. c] Files and [. d] File dependencies, and let make automatically update or own [. d] files and include them in our master makefile, so that we can automate the generation of dependencies for each file.

Here, we give a pattern rule to produce [. d] Files:

%.D:%.c
@set-E; rm-f [email protected]; /
$ (CC)-M $ (cppflags) $< > [email protected]$ $; /
Sed ' s,/($*/)/.o[:]*,/1.o [email protected]:, G ' < [email protected]$ $> [email protected];
Rm-f [email protected]$ $


This rule means that all [. d] files are dependent on [. c] Files, "rm-f [email protected]" means to delete all targets, i.e. [. d] Files, the second line means, for each dependent file "$<", which is the [. c] file that generates the dependent file , "[email protected]" means the mode "%.D" file, if there is a C file is name.c, then "%" is "name", "$ $" means a random number, the second line generates a file may be "name.d.12345", The third line uses the SED command to make a replacement, see the relevant usage documentation for the usage of the SED command. Line four is to delete the temporary file.

All in all, what this pattern does is to add dependency to the [. d] File in the compiler-generated dependency, that is, the dependency relationship:

MAIN.O:MAIN.C Defs.h

Turn into:

MAIN.O main.d:main.c Defs.h

Thus, our [. d] files are automatically updated and automatically generated, and of course, you can add more than just dependencies to this [. d] file, including the generated commands, so that each [. d] file contains a rule that ends. Once we have finished this work, we will then put these automatically generated rules into our master makefile. We can use the makefile "include" command to introduce a different makefile file (mentioned earlier), for example:

Sources = foo.c bar.c

Include $ (SOURCES:.C=.D)

The meaning of ". C=.d" in "$ (SOURCES:.C=.D)" In the above statement is to make a substitution, replacing all [. c] Strings of the variable $ (sources) with [. d], and I'll have a more detailed description of the "replacement" in the following. Of course, you have to pay attention to the order, because include is to load the file at a time, and the target in the first loaded [. d] File becomes the default target.

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.