Conditions for using makefile variables and usage

Source: Internet
Author: User

Use Variables
----

Variables defined in makefile are like Macros in C/C ++. They represent a text string, when executed in makefile, the original mode is automatically expanded in the used place. Unlike C/C ++, you can change the value in makefile. In makefile, variables can be used in "target", "dependency target", "command", or other parts of makefile.

The name of a variable can contain characters, numbers, and underscores (can start with a number), but cannot contain ": "," # "," = ", or an empty character (space, carriage return, etc ). Variables are case sensitive. "foo", "foo", and "foo" are three different variable names. In traditional makefile, variable names are all named in uppercase. However, we recommend that you use a combination of uppercase and lowercase variables, such as makeflags. This avoids conflicts with system variables and unexpected events.

Some variables are very strange strings, such as "$ <" and "$ @". These are automated variables. I will introduce them later.

I. Basics of Variables

When declaring a variable, you need to give the initial value. When using the variable, you need to add the "$" symbol before the variable name, but it is best to use parentheses "() or braces "{}" to include the variable. If you want to use the true "$" character, you need to use "$" to represent it.

Variables can be used in many places, such as the "target", "dependency", "Command" in the rule, and new variables. Let's take a look at an example:

Objects = program. O Foo. O utils. o
Program: $ (objects)
CC-O program $ (objects)

$ (Objects): defs. h

Variables are precisely expanded where they are used, like Macros in C/C ++. For example:

Foo = C
Prog. O: Prog. $ (FOO)
$ (FOO)-$ (FOO) Prog. $ (FOO)

Expand and get:

Prog. O: Prog. c
CC-C Prog. c

Of course, do not do this in your makefile. Here is an example to show how variables in makefile are actually expanded in use. It can be seen that it is an alternative principle.

In addition, brackets are added to variables to make it safer to use them. In the above example, if you do not want to add parentheses to variables, you can also, however, I strongly recommend that you add parentheses to the variables.

2. Variables in Variables

When defining the value of a variable, we can use other variables to construct the value of the variable. There are two methods in makefile to define the value of the variable.

First, let's look at the first method, that is, simply using the "=" sign, on the left side of "=" is the variable, and on the right side is the value of the variable, the value of the variable on the right can be defined in any part of the file. That is to say, the variable on the right is not necessarily a defined value. It can also use the value defined later. For example:

Foo = $ (bar)
Bar = $ (ugh)
Ugh = huh?

ALL:
Echo $ (FOO)

When we execute "make all", the value of the variable $ (FOO) is "huh ?" ($ (FOO) is $ (bar), $ (bar) is $ (ugh), and $ (ugh) is "huh ?") It can be seen that variables can be defined using the following variables.

This function has both good and bad features. The good thing is that we can push the real value of the variable to the end for definition, such:

Cflags = $ (include_dirs)-O
Include_dirs =-ifoo-Ibar

When "cflags" is expanded in the command, it will be "-ifoo-Ibar-o ". But there is also a bad thing about this form, that is, recursive definition, such:

Cflags = $ (cflags)-O

Or:

A = $ (B)
B = $ ()

This will bring make into the infinite variable expansion process. Of course, our make is capable of detecting such a definition and reporting an error. In addition, if a function is used in a variable, this method will slow our make runtime. What's worse, he will use two make functions "wildcard" and "shell" to make unpredictable errors. Because you don't know how many times these two functions will be called.

To avoid this method, we can use another method in make to define variables. This method uses the ": =" operator, for example:

X: = foo
Y: = $ (x) bar
X: = later

It is equivalent:

Y: = Foo bar
X: = later

It is worth mentioning that, in this method, the preceding variables cannot use the following variables, but can only use the previously defined variables. If so:

Y: = $ (x) bar
X: = foo

Then, the value of Y is "bar" instead of "foo bar ".

The above are some simple variables used. Let's take a look at a complicated example, including the make function, conditional expression, and the use of 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

We will talk about conditional expressions and functions later. For the system variable "makelevel", it means, if make has a nested execution action (see the previous "use make nested"), this variable records the number of calls to the current makefile.

Next we need to know about two variables. Let's take a look at an example. If we want to define a variable whose value is a space, we can do this:

Nullstring: =
Space: = $ (nullstring) # End of the line

Nullstring is an empty variable with nothing in it, and our space value is a space. It is difficult to describe a space on the right side of the operator. The technology used here is very useful. First, use an empty variable to indicate the value of the variable, the "#" annotator is used later to indicate the termination of variable definition. In this way, we can define a variable whose value is a space. Please note that the usage of "#" here is worth noting for the feature of the annotator "#". If we define a variable like this:

Dir: =/Foo/bar # directory to put the frobs in

The value of the Dir variable is "/Foo/bar", followed by four spaces. If we use this variable to specify another directory -- "$ (DIR) /file.

Another useful operator is "? = ", First look at the example:

Foo? = Bar

The meaning is that if Foo has not been defined, the value of the variable foo is bar. If Foo has been previously defined, then this language will do nothing, which is equivalent:

Ifeq ($ (origin Foo), undefined)
Foo = bar
Endif

Iii. Advanced variable usage

This section describes the advanced usage of the two variables. The first is the replacement of the variable value.

We can replace the common parts of the variable in the format of "$ (VaR: A = B)" or "$ {var: a = B}", which means, replace all "a" in the variable "var" with "B" string ending with ". Here the "end" 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 put all the values in "$ (FOO)" as ". O "string" end "is replaced with". C ", so the value of" $ (bar) "is". c B. c. C ".

Another technique for variable replacement is defined as "static mode" (see the previous section), for example:

Foo: = A. o B. O C. O
Bar: = $ (FOO: %. O = %. c)

This relies on the same pattern in the replaced string. The pattern must contain a "%" character. In this example, the value of the $ (bar) variable is also set to ". c B. c. C ".

The second advanced usage is to "treat the value of a variable as a variable ". Let's take a 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 is "Z ". (Note: "x = y" instead of "X = $ (y )")

We can also use more layers:

X = y
Y = z
Z = u
A: =$ ($ (X )))

Here, the value of $ (a) is "U". Let the readers do the derivation.

Let's make it more complicated. Let's look at an example using the first method of "using variables in variable definition:

X = $ (y)
Y = z
Z = Hello
A: =$ ($ (x ))

Here $ (x) is replaced with $ (y), because the $ (y) value is "Z", the final result is:: = $ (z), that is, "hello ".

To be more complex, we add the following functions:

X = variable1
Variable2: = Hello
Y = $ (SUBST 1, 2, $ (x ))
Z = y
A: =$ ($ (z )))

In this example, "$ (z)" is extended to "$ (y ))", it is expanded to "$ (SUBST, $ (x)" again )))". The value of $ (X) is "variable1". The SUBST function replaces all "1" strings in "variable1" with "2". Therefore, "variable1" is changed to "variable2 ", then, the value of $ (a) is the value of $ (variable2) -- "hello ". (Oh, It's hard)

In this way, you can use multiple variables to form the name of a variable, and then obtain its value:

First_second = Hello
A = first
B = Second
All = $ ($ A _ $ B)

Here, "$ A _ $ B" forms "first_second", so the value of $ (all) is "hello ".

Let's take a look at the example of combining the first Technology:

A_objects: = A. o B. O C. O
Export 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 ". c B. c. C "; if the value of $ (A1) is" 1 ", then the value of $ (sources) is" 1.C 2.c 3. C ".

Let's take a look at an example of this technology and the use of "functions" and "conditional statements:

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), then $ (FOO) the value 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 technology of "taking the value of a variable 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 ".

Iv. append variable values

We can use the "+ =" operator to append a value to the variable, for example:

Objects = Main. O Foo. O Bar. O utils. o
Objects + = another. o

So our $ (objects) value is changed to "Main. O Foo. O Bar. O utils. o another. O" (another. O is appended)

Using the "+ =" operator, we can simulate the following example:

Objects = Main. O Foo. O Bar. O utils. o
Objects: = $ (objects) Another. o

The difference is that "+ =" is more concise.

If the variable has not been defined before, "+ =" is automatically changed to "=". If there is a variable definition before, "+ =" is inherited from the value assignment of the previous operation. If the previous value is ": =", "+ =" uses ": =" as its value assignment, for example:

Variable: = Value
Variable + = more

It is equivalent:

Variable: = Value
Variable: = $ (variable) More

However, in this case:

Variable = Value
Variable + = more

Because the previous value assignment is "=", "+ =" will also use "=" as the value assignment, so it is difficult to implement the progressive population definition of variables, so make will automatically solve this problem for us and we don't have to worry about it.

V. Override indicator

If a variable is set by the command line parameter of make, the value of this variable in makefile is ignored. If you want to set the value of this type of parameter in makefile, you can use the "Override" indicator. Its syntax is:

Override <variable >=< value>

Override <variable >:= <value>

Of course, you can also append:

Override <variable> + = <more text>

For variable definitions of multiple rows, we use the define indicator. We can also use the ovveride indicator before the define indicator, for example:

Override define foo
Bar
Endef

6. multiline Variables
 
Another way to set the variable value is to use the define keyword. You can use the define keyword to set variable values with line breaks, which helps to define a series of commands (the "command package" technology we mentioned earlier is to use this keyword ).

The define indicator is followed by the variable name, and the variable value is defined in a new line. The definition ends with the endef keyword. It works in the same way as the "=" operator. Variable values can include functions, commands, text, or other variables. Because the command must start with the [Tab] key, if the command variable defined by define does not start with the [Tab] key, make will not regard it as a command.

The following example shows how to use define:

Define two-Lines
Echo foo
Echo $ (bar)
Endef

VII. Environment Variables

The system environment variable during the make operation can be loaded into the MAKEFILE file when make starts running. However, if the makefile has defined this variable, or the variable is imported by the make command line, then the system environment variable value will be overwritten. (If make specifies the "-e" parameter, the system environment variable overwrites the variable defined in makefile)

Therefore, if we set the "cflags" environment variable in the environment variable, we can use this variable in all makefiles. This is of great benefit to the use of unified compilation parameters. If cflags is defined in makefile, this variable in makefile will be used. If no definition is made, the value of the system environment variable will be used, which is a unity of commonality and individuality, it is similar to the features of "global variables" and "local variables.

When you make a nested call (see the previous "nested call" section), the variables defined in the upper makefile are passed to the lower makefile as system environment variables. Of course, by default, only variables set through the command line will be passed. Variables defined in files must be declared using the exprot keyword if they are to be passed to lower-level makefile. (See the previous chapter)

Of course, I do not recommend defining many variables in the system environment. In this way, when we execute makefiles that are not used, some of them have the same set of system variables, this may cause more trouble.

8. target variables

The variables defined in makefile are all "global variables", which can be accessed throughout the file. Of course, except for "automation variables", for example, "$ <" and other types of automation variables belong to "rule variables ", the value of this variable depends on the rule's target and the target's definition.

Of course, I can also set a local variable for a target. This variable is called "target-specific variable" and can have the same name as "global variable, because its scope is only in this rule and associated rules, its value is only valid within the scope. The value of global variables other than the rule chain is not affected.

Its syntax is:

<Target...>: <variable-assignment>

<Target...>: overide <variable-assignment>

<Variable-assignment> can be a variety of value assignment expressions, such as "=", ": =", "+ =", or "? = ". The second syntax is for variables or system environment variables brought in by the make command line.

This feature is very useful. When we set such a variable, it will apply to all the rules caused by this target. For example:

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, no matter what the global $ (cflags) value is. O Foo. O Bar. O rules), $ (cflags) values are "-G"

9. Mode Variables

In GNU make, pattern-specific variable is also supported. Through the above target variables, we know that variables can be defined on a specific target. The advantage of pattern variables is that we can give a "pattern" to define variables on all targets that conform to this pattern.

We know that the "pattern" of make generally contains at least one "%", so we can define the target variable for all targets ending with [. O] in the following way:

%. O: cflags =-o

Similarly, the syntax of pattern variables is the same as that of "target variables:

<Pattern... >:< variable-assignment>

<Pattern...>: override <variable-assignment>

Override is also for variables passed in the system environment or variables specified by the make command line.
 

Condition Determination
------

Conditional judgment allows make to select different execution branches based on different running conditions. A conditional expression can be used to compare the value of a variable or a constant.

I. Example

In the following example, determine whether the $ (CC) variable is "GCC". If yes, use the GNU function to compile the target.

Libs_for_gcc =-lgnu
Normal_libs =

Foo: $ (objects)
Ifeq ($ (CC), GCC)
$ (CC)-O Foo $ (objects) $ (libs_for_gcc)
Else
$ (CC)-O Foo $ (objects) $ (normal_libs)
Endif

It can be seen that in the rule in the above example, the target "foo" can select different function libraries based on the variable "$ (CC)" value to compile the program.

From the preceding example, we can see three keywords: ifeq, else, And endif. Ifeq indicates the start of a Condition Statement and specifies a condition expression. The expression contains two parameters separated by commas (,). The expression is enclosed in parentheses. Else indicates that the conditional expression is false. Endif indicates the end of a condition statement. Any condition expression should end with endif.

When the $ (CC) value of our variable is "GCC", the rule for the target foo is:

Foo: $ (objects)
$ (CC)-O Foo $ (objects) $ (libs_for_gcc)

When the value of $ (CC) is not "GCC" (for example, "cc"), the rule for the target foo is:

Foo: $ (objects)
$ (CC)-O Foo $ (objects) $ (normal_libs)

Of course, we can also write the above example more concisely:

Libs_for_gcc =-lgnu
Normal_libs =

Ifeq ($ (CC), GCC)
Libs = $ (libs_for_gcc)
Else
Libs = $ (normal_libs)
Endif

Foo: $ (objects)
$ (CC)-O Foo $ (objects) $ (libs)

Ii. Syntax

The syntax of the conditional expression is:

<Conditional-Directive>
<Text-if-true>
Endif

And:

<Conditional-Directive>
<Text-if-true>
Else
<Text-if-false>
Endif

<Conditional-Directive> indicates the condition keyword, for example, "ifeq ". There are four keywords.

The first one is the "ifeq" we have seen before"

Ifeq (<arg1>, <arg2>)
Ifeq '<arg1> ''<arg2>'
Ifeq "<arg1>" "<arg2>"
Ifeq "<arg1>" '<arg2>'
Ifeq '<arg1>' "<arg2>"

Compare whether the values of "arg1" and "arg2" are the same. Of course, we can also use the make function in parameters. For example:

Ifeq ($ (Strip $ (FOO )),)
<Text-if-empty>
Endif

In this example, the "Strip" function is used. If the returned value of this function is empty, <text-if-empty> takes effect.

The second condition keyword is "ifneq ". Syntax:

Ifneq (<arg1>, <arg2>)
Ifneq '<arg1> ''<arg2>'
Ifneq "<arg1>" "<arg2>"
Ifneq "<arg1>" '<arg2>'
Ifneq '<arg1>' "<arg2>"

The comparison parameters "arg1" and "arg2" have the same values. If they are different, they are true. Similar to "ifeq.

The third condition keyword is "ifdef ". Syntax:

Ifdef <variable-Name>

If the value of variable <variable-Name> is not empty, the expression is true. Otherwise, the expression is false. Of course, <variable-Name> can also be the return value of a function. Note that ifdef only tests whether a variable has a value and does not extend the variable to the current position. Let's look at two examples:

Example 1:
Bar =
Foo = $ (bar)
Ifdef foo
Frobozz = Yes
Else
Frobozz = No
Endif

Example 2:
Foo =
Ifdef foo
Frobozz = Yes
Else
Frobozz = No
Endif

In the first example, the value of "$ (frobozz)" is "yes", and the second value is "no ".

The fourth condition keyword is "ifndef ". Its syntax is:

Ifndef <variable-Name>

I will not say much about this. It is the opposite of "ifdef.

On the <conditional-Directive> line, extra spaces are allowed, but cannot start with the [Tab] Key (otherwise it is considered a command ). The annotator "#" is also safe. The same is true for "else" and "endif", as long as it does not start with the [Tab] key.

Note that make calculates the value of the conditional expression when reading makefile and selects the statement based on the value of the conditional expression, you 'd better not put automation variables (such as "$ @") into conditional expressions, because automation variables are available at runtime.

In addition, to avoid confusion, make does not allow the entire Condition Statement to be divided into two parts and placed in different files.

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.