1. Defining Command Packages
If some of the same sequence of commands appear in Makefile, you can define a variable for these same command sequences. The syntax for defining this sequence of commands begins with "define" and ends with "endef", such as:
define RUN-YACC
Yacc $ (firstword $^)
MV Y.TAB.C [email protected]
Endef
here, "Run-yacc" is the name of the command pack, not the same as the variable in makefile. The two lines in "define" and "endef" are command sequences. The first command in this command package is to run the YACC program, because the YACC program always generates "Y.TAB.C" files, so the second line of the command is to change the name of the file. Put this command package in an example.
Foo.c:foo.y
$ (RUN-YACC)
You can see that you want to use this command package as if you were using a variable. In the use of this command package, "$^" in the command package "RUN-YACC" is "foo.y", "[email protected]" is "foo.c" (for this special variable beginning with "$" will be described later), make when executing the command package, Each command in the command pack is executed independently.
the variable defined in makefile, like a macro in the C + + language, represents a text string that, when executed in makefile, automatically expands to the original mode as it is used. It differs from C/s + + in that you can change its value in makefile. In makefile, variables can be used in "targets", "dependent targets", "commands" or other parts of makefile.
variable names can contain characters, numbers, underscores (which can be the beginning of a number), but should not contain ":", "#", "=", or null characters (spaces, carriage returns, and so on). The variables are case-sensitive, and "foo", "foo", and "foo" are three different variable names. The traditional makefile variable name is all-uppercase naming, but it is recommended to use the variable name of the case, such as: Makeflags. This avoids collisions with the system's variables, and unexpected things happen.
Some variables are very strange strings, such as "$<", "[email protected]" and so on, these are the automation variables, will be described later.
2. Basics of variables
Variables need to be given an initial value at declaration, and when used, they need to be preceded by a "$" symbol in the name of the variable, but it is best to include the variable with the parentheses "()" or the curly brace "{}". If you want to use the real "$" character, you need to say "$$".
Variables can be used in many places, such as "target", "dependent", "command", and new variables in the rules. Let's look at an example:
objects = PROGRAM.O foo.o UTILS.O
Program: $ (objects)
Cc-o Program $ (objects)
$ (objects): Defs.h
The variable expands exactly where it is used, just like a macro in C + +, such as:
Foo = c
prog.o:prog.$ (foo)
$ (foo) $ (foo)-$ (foo) prog.$ (foo)
Expanded to get:
Prog.o:prog.c
Cc-c prog.c
Of course, do not do this in your makefile, here is just an example to show that the variables in the makefile are used to unfold the actual appearance. It can be seen as an "alternative" principle.
In addition, the parentheses are used to make the variable more secure, and in the example above, if you do not want to add parentheses to the variable, you can.
3. Variables in variables
When you define the value of a variable, you can use other variables to construct the value of the variable. In makefile, there are two ways to define the value of a variable in a variable.
(1) simply use the "=" sign, the left side of "=" is a variable, the right side is the value of the variable, the value of the right variable can be defined at any place in the file, that is, the right side of the variable is not necessarily a defined value, it can also use the value defined later. such as:
Foo = $ (bar)
Bar = $ (ugh)
ugh = Huh?
All:
Echo $ (foo)
Execute "make all" will be typed the value of the variable $ (foo) is "Huh?" The value of ($ (foo) is $ (bar), the value of $ (bar) is $ (ugh), and the value of $ (ugh) is "Huh?" Visible, variables can be defined using the following variables.
This feature has a good place, there are bad places, the good thing is, we can push the real value of the variable to be defined later, such as:
CFLAGS = $ (include_dirs)-O
Include_dirs =-ifoo-ibar
When "CFLAGS" is expanded in the command, it will be "-ifoo-ibar-o". But this form also has a bad place, that is, the recursive definition, such as:
CFLAGS = $ (CFLAGS)-O
or:
A = $ (b)
B = $ (A)
This makes make into infinity Variable expansion process, of course, our make is capable of detecting such a definition and will error. What's more, if you use a function in a variable, that way makes our make run very slow and, worse, he will use the two make function "wildcard" and "shell" to cause unpredictable errors. Because you don't know how many times these two functions will be called.
To avoid this approach, we can use the other method of make to define variables using variables.
(2) Use the ": =" operator, such as:
x: = foo
Y: = $ (x) bar
x: = Later
It is equivalent to:
Y: = foo bar
x: = Later
In this way, the preceding variables cannot use the following variables, only the variables that have been defined previously. If this is the case:
Y: = $ (x) bar
x: = foo
So, the value of y is "bar", not "foo bar".
Here are some of the more simple variables used to see a complex example, including the use of make functions, conditional expressions, and a system variable "Makelevel":
Ifeq (0,${makelevel})
Cur-dir: = $ (shell pwd)
WHOAMI: = $ (Shell whoami)
Host-type: = $ (Shell arch)
Make: = ${make} host-type=${host-type} Whoami=${whoami}
endif
As for the conditional expressions and functions, we'll say later, for the system variable "makelevel", which means that if our make has a nested execution (see the previous "nesting use make"), then this variable will record the number of calls to our current makefile.
The following is a description of the two definition variables need to know, please first look at an example, if we want to define a variable, its value is a space, then you can:
NullString: =
Space: = $ (nullstring) # End of the line
NullString is an empty variable, where nothing is, and the value of our space is a space. Because it is difficult to describe a space on the right side of the operator, the technique used here is very useful, first using an empty variable to indicate the value of the variable, and then using the "#" notation to denote the termination of the variable definition, so that we can define a variable whose value is a space. Note here about the use of "#", The Notation "#" which deserves our attention if you define a variable like this:
Dir: =/foo/bar # directory to put the frobs in
Dir The value of this variable is "/foo/bar", followed by 4 spaces, if we use such a variable to specify a different directory-"$ (dir)/file" then it is finished.
There is also a more useful operator is "? =", first look at the example:
FOO? = Bar
The implication is that if Foo is not defined, then the value of the variable foo is "bar", and if Foo was previously defined, then the phrase will do nothing, which is equivalent to:
Ifeq ($ (Origin FOO), undefined)
FOO = Bar
endif
4. Advanced usage of variables
Here are some advanced ways to use the two variables:
(1) The first is the substitution of variable values.
You can replace a common part of a variable in the format "$ (var:a=b)" or "${var:a=b}", which means replacing all "a" in the variable "var" with "a" in the "a" string to "B" string. The "end" here means "space" or "Terminator".
Let's look at an example:
Foo: = A.O b.o C.O
Bar: = $ (FOO:.O=.C)
In this example, we first define a "$ (foo)" Variable, and the second line means to replace all ". O" Strings with ". C" in "$ (foo)", so our value for "$ (bar)" is "A.C B.C c.c".
Another technique for variable substitution is defined in "static mode" (see previous chapters), such as:
Foo: = A.O b.o C.O
Bar: = $ (FOO:%.O=%.C)
This depends on the same pattern in the substituted string, and the pattern must contain a "%" character, and this example also allows the value of the $ (bar) variable to be "A.C B.C c.c".
(2) The second advanced usage is to "take the value of a variable again as a variable".
Let's look at an example:
x = y
y = Z
A: = $ ($ (x))
In this example, the value of $ (x) is "Y", so $ ($ (x)) is $ (y), so the value of $ (a) is "Z". (Note that it is "x=y", not "x=$ (y)")
We can also use more layers:
x = y
y = Z
z = u
A: = $ ($ ($ (x)))
The value of $ (a) here is "U".
To get a little more complicated, use the first way of "using variables in variable definitions" to see an example:
x = $ (y)
y = Z
z = Hello
A: = $ ($ (x))
The $ ($ (x)) here is replaced by $ ($ (y)), because the $ (Y) value is "Z", so the end result is: a:=$ (z), which is "Hello".
More complicated, let's add the function:
x = Variable1
Variable2: = Hello
y = $ (subst 1,2,$ (x))
z = y
A: = $ ($ ($ (z)))
In this example, "$ ($ ($ ($))" expands to "$ ($ (Y))" and is again extended to "$ ($ (subst 1,2,$ (x))"). The value of $ (x) is "Variable1", and the SUBST function replaces all "1" strings in "Variable1" with the "2" string, so that "variable1" becomes "variable2" and then takes its value, so finally, the value of $ (a) is $ ( VARIABLE2) The value-"Hello".
In this way, or you can use multiple variables to form the name of a variable, and then take its value:
First_second = Hello
A = First
B = Second
All = $ ($a _$b)
The "$a _$b" here consists of "First_second", so the value of $ (all) is "Hello".
Take a look at examples of the first technique:
A_objects: = A.O b.o C.O
1_objects: = 1.o 2.o 3.o
Sources: = $ ($ (A1) _OBJECTS:.O=.C)
In this example, if the value of $ (A1) is "A", then the value of $ (sources) is "A.C B.C c.c", and if the value of $ (A1) is "1", then the value of $ (sources) is "1.c 2.c 3.c".
Take another look at this technique and the example used with "function" and "conditional statement":
Ifdef do_sort
Func: = sort
Else
Func: = Strip
endif
Bar: = a d b g Q c
Foo: = $ ($ (func) $ (bar))
In this example, if "Do_sort" is defined, then: foo: = $ (sort a d B g Q C), so the value of $ (foo) is "a b c D g Q", and if "do_sort" is not defined, then: foo: = $ (sort a d b g Q c ), the strip function is called.
Of course, the technique of "using the value of a variable again as a variable" can also be used on the left side of the operator:
DIR = foo
$ (dir) _sources: = $ (Wildcard $ (dir)/*.c)
Define $ (dir) _print
LPR $ ($ (dir) _sources)
Endef
In this example, three variables are defined: "dir", "Foo_sources" and "Foo_print".
5. Append variable values
You can use the "+ =" operator to append a value to a variable, such as:
objects = MAIN.O foo.o bar.o utils.o
Objects + = ANOTHER.O
As a result, the $ (objects) value becomes: "MAIN.O foo.o bar.o utils.o another.o" (ANOTHER.O is appended)
Using the "+ =" operator, you can simulate this example for the following:
objects = MAIN.O foo.o bar.o utils.o
Objects: = $ (objects) ANOTHER.O
The difference is that "+ =" is more concise.
If the variable is not defined before, then "+ =" will automatically become "=", if there is a variable definition, then "+ =" will inherit from the previous operation of the assignment. If the previous time is ": =", then "+ =" will be ": =" as its assignment, such as:
Variable: = value
Variable + = more
Equivalent to:
Variable: = value
Variable: = $ (variable) more
But if this is the case:
Variable = value
Variable + = more
Since the previous assignment is "=", so "+ =" will also be assigned as "=", then it will not occur the variable is defined, it is very bad, so make will automatically solve the problem, do not worry about this problem.
6. Override indicator
If a variable is set by the command-line argument of make, the assignment to the variable in makefile is ignored. If you want to set the values of such parameters in makefile, you can use the "override" indicator. Its syntax is:
Override <variable> = <value>
Override <variable>: = <value>
Of course, you can also add:
Override <variable> + = <more text>
For multi-row variable definitions, use the Define indicator, which can also be used before the define indicator, as in the case of the ovveride indicator, such as:
Override define Foo
Bar
Endef
7. Multi-line variables
There is also a way to set the value of a variable by using the Define keyword. The use of the Define keyword to set the value of a variable can have a newline, which facilitates the definition of a series of commands (the technique of "command package" mentioned above is the use of this keyword).
The define indicator is followed by the name of the variable, and the value of the variable is defined by a line that ends with the ENDEF keyword. It works the same way as the "=" operator. The value of a variable can contain functions, commands, literals, or other variables. Because the command needs to start with the [tab] key, if the command variable defined with define does not start with the [tab] key, then make does not think of it as a command.
The following example shows the use of define:
Define Two-lines
echo Foo
echo $ (BAR)
Endef
8. Environment Variables
The system environment variables of the make runtime can be loaded into the makefile file while the makes is running, but if the variable is already defined in makefile, or if the variable is brought in by the Make command line, the value of the system's environment variable will be overwritten. (If make specifies the "-e" parameter, the system environment variable overrides the variable defined in makefile.)
Therefore, if you set the "CFLAGS" environment variable in the environment variable, you can use this variable in all makefile. This is a great benefit for us to use uniform compilation parameters. If cflags is defined in makefile, then the variable in makefile is used, and if there is no definition then the value of the system environment variable is used, a commonality and a unity of personality, much like the attributes of "global variables" and "local variables".
When make nested calls, the variables defined in the upper makefile are passed to the lower makefile as a system environment variable. Of course, by default, only variables that are set through the command line are passed. Variables defined in the file, if passed to the lower makefile, need to be declared using the Exprot keyword.
9. Target Variables
The variables defined in makefile above are all "global variables", which we can access throughout the file. Of course, except for "automation variables", such as "$<", such as the amount of automation variables such as "Regular variable", the value of this variable depends on the goal of the rule and the definition of dependent targets.
Of course, you can also set a local variable for a target, which is called "Target-specific Variable", and it can have the same name as "global variable" because its scope is only in this rule and the rules, so its value is only valid within the scope of the action. The values of global variables other than the rule chain are not affected.
Its syntax is:
<target ...>: <variable-assignment>
<target ...>: Overide <variable-assignment>
<variable-assignment> can be a variety of assignment expressions previously mentioned, such as "=", ": =", "+ =" or "? = ". The second syntax is for variables that are brought into the make command line, or for system environment variables.
This feature is very useful when we set up a variable that will act on all the rules that are thrown by the target. Such as:
Prog:cflags = g
PROG:PROG.O foo.o BAR.O
$ (CC) $ (CFLAGS) PROG.O foo.o BAR.O
Prog.o:prog.c
$ (CC) $ (CFLAGS) prog.c
Foo.o:foo.c
$ (CC) $ (CFLAGS) foo.c
Bar.o:bar.c
$ (CC) $ (CFLAGS) bar.c
In this example, regardless of the global value of $ (CFLAGS), the value of $ (BAR.O) is "-G" in the prog target, and in all the rules that it throws (PROG.O foo.o CFLAGS rule).
10. Mode variables
In GNU make, schema variables (pattern-specific Variable) are also supported, and through the target variables above, we know that variables can be defined on a target. The advantage of a pattern variable is that we can give a "pattern" that defines a variable in all targets that conform to that pattern.
The "mode" of make usually contains at least one "%", so we can define the target variable for all targets ending with [. O] as follows:
%.o:cflags =-O
Similarly, the syntax of a pattern variable is the same as the "Target variable":
<pattern ...>: <variable-assignment>
<pattern ...>: Override <variable-assignment>
Override is also for variables passed in to the system environment, or variables specified by the Make command line.
The middle variable of makefile