My notes on Makefile
'make' utility is a powerful tool that allows you to manage compilation of multiple modules into an executable.
A makefile contains a set of dependencies and rules.A dependency has a target (a file to be created) and set of source files upon which it is dependent.The rules defines how to create a target from the dependent files.
It reads a specification file called : makefile or Makefile, that describes how the modules of a software system depend on each other. If you want to use a non standard name, you can pass '-f' option to specify that name.
Make utility uses the time when various modules modified, to only recompile those modules.
structure of Makefile:
target: dependency1 dependency2 dependency3
command
Target: Name of the executable to be build
dependency1, dependency2, dependency3: Name of the files on which target depends (.c and .h files)
command: shell command to create the target from dependencies
Simple Makefile Ex1:
hello:hello.o
gcc hello.o -o hello
hello.o:hello.c
gcc hello.c -c hello.o
The above makefile contains two rules(hello, hello.o).
hello depends on hello.o. Uses the 'gcc hello.o -o hello' command to generate hello
hello.o depends on hello.c. Uses the 'gcc hello.c -c hello.o' command to generate hello.o
Running make second time, will says 'hello is up to data'
How this happens?
Each file on the system has three timestamps:
1. Access time
2. Modified time
3. Change time (ownership time)
You can use 'stat <filename>' to get the above details
If you modify the timestamps using touch command, make will again try to compile as the timestamp has changed.
In makefile a rule is defined as follows:
hello:hello.c
cc hello.c -o hello
Now assume that file 'hello' is a text file containing some data, which was created after 'hello.c' file. So the modification (or creation) time-stamp of 'hello' will be newer than that of the 'hello.c'. So when we will invoke 'make hello' from command line, it will print as:
make: `hello' is up to date.
make will always try to build for the first target.
A comment in the Makefile starts with # and goes till the end of the line
Makefile example 2:
#comment
app: sub.o div.o mul.o add.o app.o
gcc sub.o div.o mul.o add.o app.o -o app
sub.o: sub.c
gcc -c sub.c
div.o: div.c
gcc -c div.c
mul.o: mul.c
gcc -c mul.c
add.o: add.c
gcc -c add.c
app.o: app.c
gcc -c app.c
The sequence of execution depends on the order in which the dependencies are written
Options to Make:
-f : By default make looks for makefile then Makefile in the current directory. To tell make uses a different file, use '-f' provided by the filename
-n: To tell make to print out what it would have done without actually doing it
-k: Tells make to continue even there is any error. You can use this to find out which sources files there are error in a single go.
Multiple Targets in a Makefile:
A makefile can have multiple targets, We can call makefile with the name of a particular target.
To tell make to build a particular target, pass the target name to the make as a parameter.
Many programmers specify all as the first target in the Makefile and then list the other targets as being a dependency for 'all'.
Phony Target: A phony target is a target without dependency list. Some important phony targets are clean, install, uninstall.
clean:
-@rm -f *.o
When there is no .o files in the current directory and you run make, it will give an error. To ignore error, while executing a command, we proceed the command with a hyphen as done above. Moreover make print the command to stdout before executing. If we want to tell make not to print the command to stdout before executing use @ character.
-,@ are special characters in Makefile
Makefile example 3:
#comment
app: sub.o div.o mul.o add.o app.o
gcc sub.o div.o mul.o add.o app.o -o app
sub.o: sub.c
gcc -c sub.c
div.o: div.c
gcc -c div.c
mul.o: mul.c
gcc -c mul.c
add.o: add.c
gcc -c add.c
app.o: app.c
gcc -c app.c
clean:
rm -f *.o
install: app
cp app /usr/bin
chmod a+x /usr/bin/app
uninstall:
rm /usr/bin/app
Multiple Makefiles in a Project:
app: sub.o div.o mul.o add.o app.o proj1/mymod.o
gcc sub.o div.o mul.o add.o app.o proj1/mymod.o -o app
sub.o: sub.c
gcc -c sub.c
div.o: div.c
gcc -c div.c
mul.o: mul.c
gcc -c mul.c
add.o: add.c
gcc -c add.c
app.o: app.c
gcc -c app.c
include ./proj1/makefile
clean:
rm -f *.o
install: app
cp app /usr/bin
chmod a+x /usr/bin/app
uninstall:
rm /usr/bin/app
Use of Macros in Makefile
A makefile allows you to use macros or variables, so that we can write it in a more generalized form. Variables allows a text string to be defined once and substituted in multiple places later.
We can define macros/variables in Makefile as:
MACRONAME=value
We can access the macros as $(MACRONAME)
Eg: We can use a macro to give options to the compiler
CFLAGS = std=c11 -O0 -ggdb -Wall
gcc -c hello.c $(CFLAGS)
Special Internal Macros:
Each of the following four macros is expanded just before it is used. So the meaning of the macro may vary as the makefile progresses
$? List of dependencies changed more recently than the current target
$@ Name of the current target
$< Name of the current dependency
$* Name of the current dependency without extension
For example, consider the following declaration:
all: library.cpp main.cpp
In this case:
$@ evaluates to all
$< evaluates to library.cpp
$^ evaluates to library.cpp main.cpp
References:
https://stackoverflow.com/questions/2145590/what-is-the-purpose-of-phony-in-a-makefile
https://stackoverflow.com/questions/3220277/what-do-the-makefile-symbols-and-mean
https://www.youtube.com/watch?v=8hG0MTyyxMI&t=1308s
A makefile contains a set of dependencies and rules.A dependency has a target (a file to be created) and set of source files upon which it is dependent.The rules defines how to create a target from the dependent files.
It reads a specification file called : makefile or Makefile, that describes how the modules of a software system depend on each other. If you want to use a non standard name, you can pass '-f' option to specify that name.
Make utility uses the time when various modules modified, to only recompile those modules.
structure of Makefile:
target: dependency1 dependency2 dependency3
command
Target: Name of the executable to be build
dependency1, dependency2, dependency3: Name of the files on which target depends (.c and .h files)
command: shell command to create the target from dependencies
Simple Makefile Ex1:
hello:hello.o
gcc hello.o -o hello
hello.o:hello.c
gcc hello.c -c hello.o
The above makefile contains two rules(hello, hello.o).
hello depends on hello.o. Uses the 'gcc hello.o -o hello' command to generate hello
hello.o depends on hello.c. Uses the 'gcc hello.c -c hello.o' command to generate hello.o
Running make second time, will says 'hello is up to data'
How this happens?
Each file on the system has three timestamps:
1. Access time
2. Modified time
3. Change time (ownership time)
You can use 'stat <filename>' to get the above details
If you modify the timestamps using touch command, make will again try to compile as the timestamp has changed.
In makefile a rule is defined as follows:
hello:hello.c
cc hello.c -o hello
Now assume that file 'hello' is a text file containing some data, which was created after 'hello.c' file. So the modification (or creation) time-stamp of 'hello' will be newer than that of the 'hello.c'. So when we will invoke 'make hello' from command line, it will print as:
make: `hello' is up to date.
make will always try to build for the first target.
A comment in the Makefile starts with # and goes till the end of the line
Makefile example 2:
#comment
app: sub.o div.o mul.o add.o app.o
gcc sub.o div.o mul.o add.o app.o -o app
sub.o: sub.c
gcc -c sub.c
div.o: div.c
gcc -c div.c
mul.o: mul.c
gcc -c mul.c
add.o: add.c
gcc -c add.c
app.o: app.c
gcc -c app.c
The sequence of execution depends on the order in which the dependencies are written
Options to Make:
-f : By default make looks for makefile then Makefile in the current directory. To tell make uses a different file, use '-f' provided by the filename
-n: To tell make to print out what it would have done without actually doing it
-k: Tells make to continue even there is any error. You can use this to find out which sources files there are error in a single go.
Multiple Targets in a Makefile:
A makefile can have multiple targets, We can call makefile with the name of a particular target.
To tell make to build a particular target, pass the target name to the make as a parameter.
Many programmers specify all as the first target in the Makefile and then list the other targets as being a dependency for 'all'.
Phony Target: A phony target is a target without dependency list. Some important phony targets are clean, install, uninstall.
clean:
-@rm -f *.o
When there is no .o files in the current directory and you run make, it will give an error. To ignore error, while executing a command, we proceed the command with a hyphen as done above. Moreover make print the command to stdout before executing. If we want to tell make not to print the command to stdout before executing use @ character.
-,@ are special characters in Makefile
Makefile example 3:
#comment
app: sub.o div.o mul.o add.o app.o
gcc sub.o div.o mul.o add.o app.o -o app
sub.o: sub.c
gcc -c sub.c
div.o: div.c
gcc -c div.c
mul.o: mul.c
gcc -c mul.c
add.o: add.c
gcc -c add.c
app.o: app.c
gcc -c app.c
clean:
rm -f *.o
install: app
cp app /usr/bin
chmod a+x /usr/bin/app
uninstall:
rm /usr/bin/app
Multiple Makefiles in a Project:
- Project source divided into multiple directories
- Different developers involved
- Multiple Makefiles
- Top Level makefile uses include directive
Include Directive: Tells make to suspend reading the current makefile and read one or more makefiles before continuing
include ./project1/makefile ./project2/makefile
Example 4 Makefile
app: sub.o div.o mul.o add.o app.o proj1/mymod.o
gcc sub.o div.o mul.o add.o app.o proj1/mymod.o -o app
sub.o: sub.c
gcc -c sub.c
div.o: div.c
gcc -c div.c
mul.o: mul.c
gcc -c mul.c
add.o: add.c
gcc -c add.c
app.o: app.c
gcc -c app.c
include ./proj1/makefile
clean:
rm -f *.o
install: app
cp app /usr/bin
chmod a+x /usr/bin/app
uninstall:
rm /usr/bin/app
Use of Macros in Makefile
A makefile allows you to use macros or variables, so that we can write it in a more generalized form. Variables allows a text string to be defined once and substituted in multiple places later.
We can define macros/variables in Makefile as:
MACRONAME=value
We can access the macros as $(MACRONAME)
Eg: We can use a macro to give options to the compiler
CFLAGS = std=c11 -O0 -ggdb -Wall
gcc -c hello.c $(CFLAGS)
Special Internal Macros:
Each of the following four macros is expanded just before it is used. So the meaning of the macro may vary as the makefile progresses
$? List of dependencies changed more recently than the current target
$@ Name of the current target
$< Name of the current dependency
$* Name of the current dependency without extension
For example, consider the following declaration:
all: library.cpp main.cpp
$@ evaluates to all
$< evaluates to library.cpp
$^ evaluates to library.cpp main.cpp
References:
https://stackoverflow.com/questions/2145590/what-is-the-purpose-of-phony-in-a-makefile
https://stackoverflow.com/questions/3220277/what-do-the-makefile-symbols-and-mean
https://www.youtube.com/watch?v=8hG0MTyyxMI&t=1308s
Comments
Post a Comment