Write Makefile with me.

zhaozj2021-02-08  298

V. Define mode rules

You can use the pattern rules to define an implicit rule. A mode rule seems to have a general rule, just in rules, the definition of the target needs to have a "%" character. "%" Means that one or more arbitrary characters. In the dependent target, "%" can also be used, but only the value of "%" in the target is dependent on its objectives.

One thing to note is that the "%" deployment occurs after the expansion of variables and functions, the expansion of variables and functions occurs when Make loads Makefile, while "%" in the mode rule occurs at runtime.

1, mode rule introduction

In the mode rule, at least in the target definition of the rule, "%" is included, otherwise, it is a general rule. The "%" definition in the target represents the matching of the file name, "%" represents any non-empty string of length. For example: "%. C" indicates the file name ending with ".c" (the file name is at least 3), and "s.%. C" is indicated by "s." Start, ". C" ending The file name (the file name is at least 5).

If "%" is defined in the target, then "%" value in the target determines the value of "%" in the target, that is, the "%" "%" in the target determines the dependency target "%" " For example, there is a pattern rule as follows:

% .O:% .c;

Its meaning is, pointing out how to generate the rules of the [.o] file from all [.c] files. If the goal to be generated is "a.o B.O", "% C" is "a.c B.c".

Once the "%" mode in the target is determined, the make will be asked to match all the file names in the current directory. Once the Make is found, the Make will rule, so in the mode rules, the target may be Multiple, if there is a mode matching multiple targets, Make will generate all mode destination. At this time, make cares about the dependencies of the dependent file name and the generation of the target.

2, mode rule example

The following example is expressed, compiling all [.c] files into the [.o] file.

% .O:%. C $ (cc) -c $ (cflags) $ (cppflags) $ <-O $ @

Among them, "$ @" represents all the targets of the target, "$ <" indicates all the values ​​that depend on the target. These strange variables are called "automated variables" and will be detailed later.

There are two objects in this example below:

%. Tab.c% .tab.h:% .y bison -d $

This rule tells Make to perform all [.y] files in "Bison -D .y", then generate " .tab.c" and " .tab.h" files. (Where "" represents an arbitrary string). If our executive program "foo" relies on file "parse.tab.o" and "scan.o", and the file "scan.o" depends on the file "parse.tab.h", if "parse.y" file Updated, then according to the rules described above, "Bison -d Parse.y" will be executed once, so "Parse.tab.o" and "scan.o" dependent files are. (Suppose, "parse.tab.o" is generated by "parse.tab.c", and "scan.o" is generated by "scan.c", and "foo" is generated by "Parse.tab.o" and "SCAN. o "Link generation, and the dependency of the Foo and its [.o] file is also written, then all the goals will be met) 3, automated variables

In the above mode rules, the targets and dependent files are files, so how do we write a command to complete the corresponding goal from different dependency files? Because every time the pattern rule is parsed, it will be different targets and dependencies.

Automated variables are completed. In front, we have already proposed by the automated variables, I believe that you have seen it here has a sense of sensibility. The so-called automated variable is that this variable will automatically remove a series of files defined in the mode until all the modes of matching are finished. This automation variable should only appear in the rule command.

Below is all automation variables and their description:

$ @ Represents the target file set in the rule. In the mode rule, if there are multiple targets, "$ @" is a collection of mode definitions that matches the target.

$% Is only when the goal is in a library file, indicating the target member name in the rule. For example, if a goal is "foo.a (bar.o)", then "$%" is "bar.o", "$ @" is "foo.a". If the target is not a library file (UNIX is [.a], Windows is [.lib] under [.lib]), then its value is empty.

$

$? All collection of new dependent targets than the target. Separate in space.

$ ^ All relying on the target collection. Separate in space. If there are multiple repetitions in the dependent target, the variable will remove the duplicate dependency target, only one copy.

$ This variable is very similar to "$ ^", and it is also a collection of dependent targets. It is just that it does not remove duplicate depends on the target.

$ * This variable indicates "%" and its previous part in the target mode. If the target is "dir / a.foo.b", and the target mode is "a.%. B", then "$ *" value is "Dir / a.foo". This variable is more compared to constructing associated file names. If there is no mode definition in the target, "$ *" cannot be derived, but if the edix of the target file is made by Make, "$ *" is part of the suffix. For example, if the target is "foo.c", because ".c" is the suffix name that make can identify, "$ *" is "foo". This feature is GNU Make, it is likely not compatible with other versions of Make, so you should try to avoid using "$ *", unless you impose rules or static mode. If the suffix in the target is made by Make, "$ *" is a null value. When you want to operate only the updated dependencies, "$?" Is useful in explicit rules, for example, suppose having a library file called "lib", which is updated by several other Object files. Then the more efficient Makefile rules package the Object file package are:

LIB: foo. bar.o lose.o win.o ar r lib $?

In the autointer variables listed above. Four variables ($ @, $ <, $%, $ *) will only have a file when extension, and the other three values ​​are a list of files. These seven automation variables can also obtain the directory name of the file or the file name in the current directory, just match "D" or "F". This is the characteristics of the old version of GNU Make. In the new version, we can use the function "DIR" or "notdir". The meaning of "D" is Directory, which is the directory, "f" meaning is File, that is, the file.

Here is the meaning of "D" or "f" for the seven variables of the above:

$ (@D) represents the directory section of "$ @" (not the end of the slash), if the "$ @" value is "dir / foo.o", then "$ (@d" is "DIR", If there is no slash in "$ @", its value is "." (Current directory).

$ (@ F) means "$ @" file part, if the "$ @" value is "dir / foo.o", then "$ (@ f)" is "foo.o", "$ (@f) "It is equivalent to function" $ (notdir $ @).

"$ (* D)" "$ (* f)" and the same as described above, is also the directory section and file part of the file. For the example above, "$ (* d)" returns "DIR", and "$ (* f)" returns "foo"

"$ (% D)" "$ (% f)" indicates the directory section and the file part of the function package file member. This contains different directories in "Member" in the form of "Archive" forms, "MEMBER". "$ (

"$ (^ D)" "$ (^ f)" represents all directory sections and file parts of the dependencies. (No identical)

"$ ( D)" "$ ( f)" represents all directory sections and file parts of all dependencies. (Can have the same)

"$ (? D)" "$ (? F)" represents the directory section and file part of the updated dependencies.

Finally, I want to remind it that for "$ <", in order to avoid unnecessary trouble, we will add parentheses to the specific characters behind $, for example, "$ (<)" is more than "$ <"It is better.

It is important to note that these variables are only used in rules, and they are generally "Explicit Rules" and "Static Mode Rules" (see chapters of the "Writing Rules"). It doesn't make sense in implicit rules.

4, mode match

In general, a target mode has a "%" with a prefix or suffix, or there is no prefix, which is directly a "%". Because "%" represents one or more characters, in the defined mode, we call the contents of "%" match "stem", such as "% .c", "Test.c" "Test" is "stem". Because when there is "%" in the target and dependent target, "stem" depends on the target will pass to the target, and "stem" in the target.

When a mode match contains a file with a slash (actually not often included), then the directory portion will be first removed, then matched, then add the directory back. When the transmission of "stem", we need to know this step. For example, there is a mode "E% T", the file "src / EAT" matches this mode, so "SRC / A" is its "stem", if this mode is defined in the dependent target, and is dependent on this mode There is also a mode "C% R", then the target is "src / car". ("Stem" is transmitted)

5, overload built-in implicit rules

You can overruun built-in implicit rules (or define a new), for example, you can re-construct and build different hidden rules, such as:

% .O:% .C $ (CC) -C $ (CPPFLAGS) $ (cflags) -d $ (date)

You can cancel the built-in implicit rules, as long as you don't write the command later. Such as:

% .O:% .s

Similarly, you can also redefine a new implicit rule, which in the hidden rules depends on where you write this rule. The front position is before.

Sixth, "suffix rules"

Suffix rules are a comparison method for implicit rules. Suffix rules will be gradually replaced by mode rules. Because pattern rules are stronger clearer. GNU Make is equally compatible with the old version of Makefile. There are two ways to suffix rules: "Double Suffix" and "Single Human Supper". Double complications define a pair of suffixes: the suffix of the target file and the suffix on the destination (source file). Such as ".c.o" is equivalent to "% o:% C". Single suffix rules only define a suffix, that is, the suffix of the source file. Such as ".c" is equivalent to "%:% .c".

The suffix defined in the suffix rule should be made by Make. If a suffix is ​​made by Make, then this rule is a single binding rule, and if the two consecutive suffixes are recognized by Make, it is a double suffix rule. For example: ". C" and ".o" are made by Make. Thus, if you define a rule is ".c.o" then it is the two suffix rules, meaning ".c" is the suffix of the source file, ". O" is the suffix of the target file. The following example:

.c.o: $ (CC) -C $ (CFLAGS) $ (CPPFLAGS) -O $ @ $ <

Suffix rules do not allow any dependencies, if there is a dependent file, it is not a suffix rule, and those subjectedures are considered to be file names, such as:

.c.o: foo.h $ (cc) -c $ (cflags) $ (cppflags) -o $ @ $ <

This example, that is, the file ".c.o" depends on the file "foo.h" instead of what we want:

% .O:% .c foo.h $ (cc) -c $ (cflags) $ (cppflags) -o $ @ $ <

In the suffix rule, it is meaningless if there is no command. Because he doesn't remove the built-in implicit rules.

To let Make know some specific suffixes, we can use pseudo-target ".suffixes" to define or delete, such as:

. Suffixes: .hack .win

Add a suffix .hack and .win Add to the end of the suffix list.

.Suffixes: # Deletes the default suffix.suffixes: .c .o .h # Defines your suffix

First clear the default suffix, define your own suffix list.

Make's parameters "-r" or "-no-builtin-rules" also use the default suffix list empty. The variable "SUFFIXE" is used to define the default suffix list, you can use ".suffixes" to change the suffix list, but do not change the value of the variable "suffixe".

Seven, implicit rules search algorithm

For example, we have a target called T. Below is an algorithm for searching for the rules of target T. Note that in the following, we did not mention the suffix rule, because all suffix rules were converted into a pattern rule when Makefile was loaded into memory. If the target is "Archive (MEMBER)" function library file mode, then this algorithm will run twice, the first time I find the target T. If I haven't found it, then I will enter the second time, I will put "Member" Take T comment.

1. Separate T 's directory part. Call D, and the remaining part is called N. (, If T is "src / foo.o", then D is "src /", n is "foo.o") 2, create all the schema rules that matches T or N.

3. If there is a mode in which all files are matched in the pattern rule list, such as "%", remove other modes from the list.

4. Remove the rules that have no commands in the list.

5. For the first mode rule in the list: 1) derive its "stem" S, S should be t or n matched in "%" non-empty portions in the mode. 2) Calculate dependencies. Replace "%" in the dependency file into "stem" S. If there is no flap character in the target mode, the D is added to the beginning of the first dependency file. 3) Test if all dependencies are exist or are existed. (If there is a file being defined as a target file for another rule, or an explicit rule dependent file, then this file is called "reasonable") 4) If all dependencies exists or correct, or There is no dependency file. Then this rule will be adopted and exit the algorithm.

6. If you have passed through step 5, there is no mode rule to be found, then you will do something a further search. For the first mode rule existing in the list: 1) If the rule is termination rule, then ignore it, continue the next mode rule. 2) Calculate dependencies. (Step 5) 3) Test if all dependencies exist or correct. 4) For non-existent dependent files, recursive calls this algorithm lookup that he can be found by implicit rules. 5) If all dependencies exists or properly, or there is no dependency file. Then this rule is used to exit the algorithm.

7. If there is no implicit rule, you can use, view ".default" rules, if there is, use, use the ".default" command to T.

Once the rules are found, they will execute their quite commands, while this time, our automation variables will be generated.

<- Previous Next -> (All rights reserved, please indicate the author and source)

转载请注明原文地址:https://www.9cbs.com/read-1156.html

New Post(0)