Makefile Structure

It is just a plain text file named "Makefile" under a folder.

Bascially the structure is as follows:

target: dependencies
[tab] system command

For example, to compile all files,

all: 
    gcc -o main main.c add_int.c multi_int.c

Then you can type make in the terminal and main executable will be produced.

make

You can see calling make will invoke the target "all". make will run the first target as default.


Dependencies

By spliting the targets, modifying a single file will not recompile everything in the project. What you need to do is to specify the dependencies:


all: main

main: add_int.o multi_int.o main.o
    gcc add_int.o multi_int.o main.o -o main

add_int.o: add_int.c
    gcc -c add_int.c

multi_int.o: multi_int.c
    gcc -c multi_int.c

main.o: main.c
    gcc -c main.c

clean:
    rm *.o main

Now you can see that the target all contains only a dependency. In order to fulfill the target all, it will go through the another dependency main and so on and finally all dependencies are fulfilled and compilation can take place.

The last target clean is a target to call rm to delete all compiled file.


PHONY Target

In the last example you can see a new target clean. Actually it is not a file target, instead it is a name that user wants to execute a particular command, like rm.

However, in rare case if the directory has a file called clean, make will be confused. As the file called clean exists, the target dependency is fulfilled and nothing will be run.

make: 'clean' is up to date.

In order to tell make clean is not a file target, you can explicitly declare the target to be "phony"

.PHONY: clean
all: main

main: add_int.o multi_int.o main.o
    gcc add_int.o multi_int.o main.o -o main

add_int.o: add_int.c
    gcc -c add_int.c

multi_int.o: multi_int.c
    gcc -c multi_int.c

main.o: main.c
    gcc -c main.c

clean:
    rm *.o main

You can try, now make clean can be run successfully even if the file clean is here.


Variables

You can use variables in the Makefile to save time and get rid of repeated statements.

CC=gcc
CFLAGS=-Wall -c

all: main

main: add_int.o multi_int.o main.o
    $(CC) add_int.o multi_int.o main.o -o main

add_int.o: add_int.c
   $(CC) $(CFLAGS) add_int.c

multi_int.o: multi_int.c
    $(CC) $(CFLAGS) multi_int.c

main.o: main.c
    $(CC) $(CFLAGS) main.c

clean:
    rm *.o main

In this case, we can specify the options for the compiler more easily.


Implicit Rule

In some cases, you can omit the command elements in the Makefile, and the make can automagically do the action for you.


CC=gcc
CFLAGS=-Wall

EXE=main
OBJ=add_int.o multi_int.o main.o

all: $(EXE)

main: $(OBJ)

clean:
        rm -f $(OBJ) $(EXE)

In the target main, you can see only dependencies are declared. However, make can do all the compilation jobs. It is because there are implicit rules.

From the manual, it states:

n.o is made automatically from n.c with a recipe of the form ‘$(CC) $(CPPFLAGS) $(CFLAGS) -c’.

Therefore, add_int.o is made by using the above-mentioned rule automatically.


The brief introduction of Makefile stops here. Of course there are even more advanced features, please always refer to the Make documentation for more information.

results matching ""

    No results matching ""