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:

  • 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

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


Comments

Popular posts from this blog

bb.utils.contains yocto

Difference between RDEPENDS and DEPENDS in Yocto

make config vs oldconfig vs defconfig vs menuconfig vs savedefconfig