Friday 16 October 2015

Makefile

The make utility automatically determines which pieces of a large program need to be recompiled, and issues commands to recompile them.
To prepare to use make, you must write a file called the makefile that describes the relationships among files in your program and provides commands for updating each file.
In a program, typically, the executable file is updated from object files, which are in turn made by compiling source files. Once a suitable makefile exists, each time you change some source files, this simple shell command:
make

You can provide command line arguments to make to control which files should be recompiled, or how.

A simple makefile consists of “rules” with the following shape:
target ... : prerequisites ...
             recipe
             ...
             ...
 
A target is usually the name of a file that is generated by a program; examples of targets are executable or object files. A target can also be the name of an action to carry out, such as ‘clean’.

A prerequisite is a file that is used as input to create the target. A target often depends on several files.

A recipe is an action that make carries out. A recipe may have more than one command, either on the same line or each on its own line.
Please note: you need to put a tab character at the beginning of every recipe line!

If you prefer to prefix your recipes with a character other than tab, you can set the .RECIPEPREFIX variable to an alternate character.

.RECIPEPREFIX
The first character of the value of this variable is used as the character make assumes is introducing a recipe line. If the variable is empty (as it is by default) that character is the standard tab character. For example, this is a valid
makefile:
.RECIPEPREFIX = >
all:
> @echo Hello, world

The value of .RECIPEPREFIX can be changed multiple times; once set it stays in effect for all rules parsed until it is modified.
The .RECIPEPREFIX is only supported since v3.82.

Usually a recipe is in a rule with prerequisites serves to create a target file if any of the prerequisites change.
However, the rule that specifies a recipe for the target may not need to have prerequisites. For example, the rule containing the delete command associated with the target ‘clean’ does not have prerequisites.
 
Rule, then, explains how and when to remake certain files which are the targets of the particular rule. make carries out the recipe on the prerequisites to create or update the target.
A rule can also explain how and when to carry out an action.

A rule appears in the makefile and says when and how to remake certain files, called the rule’s targets (most often only one per rule). It lists the other files that are the prerequisites of the target, and the recipe to use to create or update the target.
The order of rules is not significant, except for determining the default goal: the target for make to consider, if you do not otherwise specify one. The default goal is the target of the first rule in the first makefile. If the first rule has multiple targets, only the first target is taken as the default.


.DEFAULT_GOAL

Sets the default goal to be used if no targets were specified on the command line.
The .DEFAULT_GOAL variable allows you to discover the current default goal, restart the default goal selection algorithm by clearing its value, or to explicitly set the default goal.

The following examples illustrates these cases:

Note that assigning more than one target name to .DEFAULT_GOAL is invalid and will result in an error.


Phony Targets:
A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request. There are two reasons to use a phony target:
1) To avoid a conflict with a file of the same name, and 
2) To improve performance.

If you write a rule whose recipe will not create the target file, the recipe will be executed every time the target comes up for remaking. Here is an example:
clean:
    rm *.o temp

Because the rm command does not create a file named clean, probably no such file will ever exist. Therefore, the rm command will be executed every time you say ‘make clean’.
In this example, the clean target will not work properly if a file named clean is ever created in this directory. Since it has no prerequisites, clean would always be considered up to date and its recipe would not be executed. To avoid this problem you can explicitly declare the target to be phony by making it a prerequisite of the special target .PHONY
For example:
.PHONY: clean
clean:
    rm *.o temp
 
Once this is done, ‘make clean’ will run the recipe regardless of whether there is a file named clean.
Phony targets are also useful in conjunction with recursive invocations of make.


Rules without Recipes or Prerequisites:
If a rule has no prerequisites or recipe, and the target of the rule is a nonexistent file, then make imagines this target to have been updated whenever its rule is run. This implies that all targets depending on this one will always have their recipe run.
An example will illustrate this:
clean: FORCE
    rm $(objects)
FORCE:

Here the target ‘FORCE’ satisfies the special conditions, so the target clean that depends on it is forced to run its recipe. There is nothing special about the name ‘FORCE’, but that is one name commonly used this way.
As you can see, using ‘FORCE’ this way has the same results as using ‘.PHONY: clean’. Using ‘.PHONY’ is more explicit and more efficient. However, other versions of make do not support ‘.PHONY’; thus ‘FORCE’ appears in many makefiles.


Using Variables in Recipes:
To substitute a variable’s value, write a dollar sign followed by the name of the variable in parentheses or braces: either ‘$(foo)’ or ‘${foo}’ is a valid reference to the variable foo.

if you want a dollar sign to appear in your recipe, you must double it (‘$$’). For shells like the default shell, that use dollar signs to introduce variables, it’s important to keep clear in your mind whether the variable you want to reference is a make variable (use a single dollar sign) or a shell variable (use two dollar signs).
For example:
LIST = one two three
print:
    for i in $(LIST); do \
      echo $$i; \
    done
 
#Command:
#    make print
#Output:
#    one
#    two
#    three
Variable references work by strict textual substitution.


Environment variables can be accessed by using both $ (a single dollar sign) and $$ (two dollar signs).
For example:
.PHONY: display
display:
    echo $(HOME)
    echo $$HOME
 
#Command:
#    make display
#Output:
#     /home/sagar.shah
#     /home/sagar.shah

Generally in most of the shells HOME is predefined environment variable.
But if make file also has (locally defined) variable with same name then locally defined value has high priority.
HOME = /home/sagar.shah/docs
.PHONY: display_home
display_home:
    echo $(HOME)
    echo $$HOME
 
#Command:
#    make display_home
#Output:
#     /home/sagar.shah/docs
#     /home/sagar.shah/docs


Automatic Variables:

$@
The file name of the target of the rule. If the target is an archive member, then ‘$@’ is the name of the archive file. In a pattern rule that has multiple targets, ‘$@’ is the name of whichever target caused the rule’s recipe to be run.

$%
The target member name, when the target is an archive member. For example, if the target is foo.a(bar.o) then ‘$%’ is bar.o and ‘$@’ is foo.a.
‘$%’ is empty when the target is not an archive member.

$<
The name of the first prerequisite.
If the target got its recipe from an implicit rule, this will be the first prerequisite added by the implicit rule.

$?
The names of all the prerequisites that are newer than the target, with spaces between them.
For prerequisites which are archive members, only the named member is used.

$^
The names of all the prerequisites, with spaces between them.
For prerequisites which are archive members, only the named member is used.
A target has only one prerequisite on each other file it depends on, no matter how many times each file is listed as a prerequisite. So if you list a prerequisite more than once for a target, the value of $^ contains just one copy of the name.
This list does not contain any of the order-only prerequisites; for those see the ‘$|’ variable, below.

$+
This is like ‘$^’, but prerequisites listed more than once are duplicated in the order they were listed in the makefile. This is primarily useful for use in linking commands where it is meaningful to repeat library file names in a particular order.

$|
The names of all the order-only prerequisites, with spaces between them.

S(MAKE)

The value of this variable is the file name of Makefile.
For Example:
.PHONY:create_dir
create_dir:
    mkdir -p dir

.PHONY:create
create:
    touch file.txt
    $(MAKE) create_dir
 
#Command:
#    make create
#Output:
#     Directory named "dir" and File named "file.txt" will be created


Multiple Targets in a Rule:
A rule with multiple targets is equivalent to writing many rules, each with one target, and all identical aside from that. The same recipe applies to all the targets, but its effect may vary because you can substitute the actual target name into the recipe using ‘$@’. The rule contributes the same prerequisites to all the targets also.
For Example:
bigoutput littleoutput : text.g
    generate text.g -$(subst output,,$@) > $@

is equivalent to

bigoutput : text.g
    generate text.g -big > bigoutput
littleoutput : text.g
    generate text.g -little > littleoutput



Conditional Parts of Makefiles:
A conditional directive causes part of a makefile to be obeyed or ignored depending on the values of variables. Conditionals can compare the value of one variable to another, or the value of a variable to a constant string.

This conditional uses three directives: one ifeq, one else and one endif.

The ifeq directive begins the conditional, and specifies the condition. It contains two arguments, separated by a comma and surrounded by parentheses. Variable substitution is  performed on both arguments and then they are compared. The lines of the makefile following the ifeq are obeyed if the two arguments match; otherwise they are ignored.

The else directive causes the following lines to be obeyed if the previous conditional failed. In the example above, this means that the second alternative linking command is used whenever the first alternative is not used. It is optional to have an else in a conditional.

The endif directive ends the conditional. Every conditional must end with an endif.

The syntax of a simple conditional with no else is as follows:
conditional-directive
    text-if-true
endif

The text-if-true may be any lines of text, to be considered as part of the makefile if the condition is true. If the condition is false, no text is used instead.
The syntax of a complex conditional is as follows:
conditional-directive
    text-if-true
else
    text-if-false
endif

or:
conditional-directive-one
    text-if-one-is-true
else conditional-directive-two
    text-if-two-is-true
else
    text-if-one-and-two-are-false
endif
There can be as many “else conditional-directive” clauses as necessary. Once a given condition is true, text-if-true is used and no other clause is used; if no condition is true then text-if-false is used. The text-if-true and text-if-false can be any number of lines of text.

The syntax of the conditional-directive is the same whether the conditional is simple or complex; after an else or not.
There are four different directives that test different conditions.
ifeq (arg1, arg2)
ifeq ’arg1’ ’arg2’
ifeq "arg1" "arg2"
ifeq "arg1" ’arg2’
ifeq ’arg1’ "arg2"

Expand all variable references in arg1 and arg2 and compare them. If they are identical, the text-if-true is effective; otherwise, the text-if-false, if any, is effective.

Often you want to test if a variable has a non-empty value. When the value results from complex expansions of variables and functions, expansions you would consider empty may actually contain white-space characters and thus are not seen as empty.
However, you can use the strip function to avoid interpreting white-space as a non-empty value.
For example:
ifeq ($(strip $(foo)),)
  text-if-empty
endif

will evaluate text-if-empty even if the expansion of $(foo) contains white-space characters.

ifneq (arg1, arg2)
ifneq ’arg1’ ’arg2’
ifneq "arg1" "arg2"
ifneq "arg1" ’arg2’
ifneq ’arg1’ "arg2"

Expand all variable references in arg1 and arg2 and compare them. If they are different, the text-if-true is effective; otherwise, the text-if-false, if any, is effective.


ifdef variable-name

The ifdef form takes the name of a variable as its argument, not a reference to a variable. The value of that variable has a non-empty value, the text-if-true is effective; otherwise, the text-if-false, if any, is effective.
Variables that have never been defined have an empty value.
The text variable-name is expanded, so it could be a variable or function that expands to the name of a variable.
For example:
bar = true
foo = bar
ifdef $(foo)
  frobozz = yes
endif


The variable reference $(foo) is expanded, yielding bar, which is considered to be the name of a variable. The variable bar is not expanded, but its value is examined to determine if it is non-empty.
Note that ifdef only tests whether a variable has a value. It does not expand the variable to see if that value is nonempty.
Consequently, tests using ifdef return true for all definitions except those like foo =.
To test for an empty value, use ifeq ($(foo),).
For example,
bar =
foo = $(bar)
ifdef foo
  frobozz = yes
else
  frobozz = no
endif
sets ‘frobozz’ to ‘yes’,

while:
foo =
ifdef foo
  frobozz = yes
else
  frobozz = no
endif

sets ‘frobozz’ to ‘no’.


ifndef variable-name
If the variable variable-name has an empty value, the text-if-true is effective; otherwise, the text-if-false, if any, is effective. The rules for expansion and testing of variable-name are identical to the ifdef directive.

The other two directives that play a part in a conditional are else and endif. Each of these directives is written as one word, with no arguments. Extra spaces are allowed and ignored at the beginning of the line, and spaces or tabs at the end. Extra spaces are allowed and ignored at the beginning of the conditional directive line, but a tab is not allowed. (If the line begins with a tab, it will be considered part of a recipe for a rule.)

A comment starting with ‘#’ may appear at the end of the line.


Makefile variable assignment types:
Basically there are four types of assignment:
1)  =  for creating recursive variables.
Values within variables are recursively expanded when the variable is used, not when it's declared.

2) :=  for creating simple variables.
Setting of a variable with simple expansion of the values inside - values within it are expanded at declaration time.

3) ?=  for conditional assignment.
Setting of a variable only if it doesn't have a value

4) +=  for appending text to a variable.
Appending the supplied value to the existing value (or setting to that value if the variable didn't exist), important feature when recursive variables are used.


Recipe Echoing:
Normally make prints each line of the recipe before it is executed. We call this echoing because it gives the appearance that you are typing the lines yourself.
When a line starts with ‘@’, the echoing of that line is suppressed. The ‘@’ is discarded before the line is passed to the shell. Typically you would use this for a command whose only effect is to print something, such as an echo command to indicate progress through the makefile:
    @echo About to make distribution files

When make is given the flag ‘-n’ or ‘--just-print’ it only echoes most recipes, without executing them. In this case even the recipe lines starting with ‘@’ are printed. This flag is useful for finding out which recipes make thinks are necessary without actually doing them.

The ‘-s’ or ‘--silent’ flag to make prevents all echoing, as if all recipes started with ‘@’. A rule in the makefile for the special target .SILENT has the same effect.


Errors in Recipes:
After each shell invocation returns, make looks at its exit status. If the shell completed successfully (the exit status is zero), the next line in the recipe is executed in a new shell; after the last line is finished, the rule is finished.
If there is an error (the exit status is nonzero), make gives up on the current rule, and perhaps on all rules. Sometimes the failure of a certain recipe line does not indicate a problem.
For example,
you may use the mkdir command to ensure that a directory exists. If the directory already exists, mkdir will report an error, but you probably want make to continue regardless.
To ignore errors in a recipe line, write a ‘-’ at the beginning of the line’s text (after the initial tab). The ‘-’ is discarded before the line is passed to the shell for execution.
For example,
clean:
    -rm -f *.o

This causes make to continue even if rm is unable to remove a file.

When you run make with the ‘-i’ or ‘--ignore-errors’ flag, errors are ignored in all recipes of all rules. A rule in the makefile for the special target .IGNORE has the same effect.


Table of all the options make understands:

‘-i’
‘--ignore-errors’

Ignore all errors in recipes executed to remake files.

‘-n’
‘--just-print’
‘--dry-run’
‘--recon’

Print the recipe that would be executed, but do not execute it (except in certain circumstances)

‘-q’
‘--question’
“Question mode”
 
Do not run any recipes, or print anything; just return an exit status that is zero if the specified targets are already up to date, one if any remaking is required, or two if an error is encountered.

‘-s’
‘--silent’
‘--quiet’

Silent operation; do not print the recipes as they are executed.

‘-v’
‘--version’

Print the version of the make program plus a copyright, a list of authors, and a notice that there is no warranty; then exit.

‘-t’
‘--touch’

Marks targets as up to date without actually running any recipes.
Touch files (mark them up to date without really changing them) instead of running their recipes. This is used to pretend that the recipes were done, in order to fool future invocations of make.

No comments:

Post a Comment