As you already know,  a major part of the projects are managed using Make tool. The Make it's a nice tool which controls the generation of executables based on rules. In this post I will share some of things that I found useful when you begin a project using Makefile.

So, let's say that we will create a project that it's called MyProject and in this project we have two folder folder_1 and folder_2

mkdir MyProject
cd MyProjet
mkdir folder_1 folder_2

Now we will create a Makefile on top of the project (the Mekefile it's a text file so you can use whatever text editor you want to create and edit it). At this stage we have:

bash$ ls

folder_1 folder_2 Makefile

DEBUG Makefile

There is not a special tool that allow to debug a Makefile, as is the case with a GNU Debugger that allow to check your program. But you can use @echo to display useful information when you develop your Makefile. For example let's write this rule, called debug,  in the Makefile.

Makefile:

.PHONY: debug
debug:

 @echo "This is the debug rule"

Bash:

bash$ make debug

This is the debug rule

Note: .PHONY it's a word that it's good to be added in front of rules to avoid conflict with a file of the same name. For example if a file named debug exists, this will not work properly.

TOP DIRECTORY

Sometime it's necessary to know the working directory where the project is located. The Make allow to execute command form shell,  we can use pwd(print working directory) to know the working directory or we can use the CURDIR variable.

Makefile:

#WORKDIR := ${shell pwd}
WORKDIR :=$(CURDIR)

.PHONY: debug
debug:

@echo "This is the debug rule"
@echo $(WORKDIR)

Bash:

bash$make debug

This is the debug rule
/home/miti/Desktop/MyProject

INCLUDE / -INCLUDE

To organize better the project, Makefile allow to include others makefiles or file, using include directive. If you want to include a file but you don't want to show error, in the case the file don't exists, then use this -include.  Let's suppose that in the folder_1 we have the compiler configuration named Toolchain.conf.

Toolchain.conf:

AR = ar
CC = gcc
CPP = g++
NM = nm
OBJCOPY = objcopy
OBJDUMP = objdump

Makefile:

WORKDIR := ${shell pwd}

include $(WORKDIR)/folder_1/Toolchain.conf

.PHONY: debug
debug:

@echo "This is the debug rule"
@echo $(WORKDIR)
@echo $(CC)

Bash:

bash$make debug

This is the debug rule
/home/miti/Desktop/MyProject
gcc

WILDCARD

Wildcard it's a very useful command that allow to get all the files found in a folder. This command can be useful when we use recursive Makefile. Let's say that the folder_2 has the following file: file_1.c, file_2.c and file_3.c

Makefile:

WORKDIR := ${shell pwd}

include $(WORKDIR)/folder_1/Toolchain.conf

CC_SRCS ?= $(wildcard folder_2/*.c)

.PHONY: debug
debug:

@echo "This is the debug rule"
@echo $(WORKDIR)
@echo $(CC)
@echo $(CC_SRCS)

Bash:

bash$ make debug

This is the debug rule
/home/miti/Desktop/MyProject
gcc
folder_2/file_2.c folder_2/file_3.c folder_2/file_1.c

=   :=   ::=    ?=

Often we see  in makefile that a variable in set with one of the symbol "=" , ":=" , "::=" or "?=" , but what is the difference between them?

Variable defined with "=" are recursively expanded variables.
Variable defined with ":=" or "::=" are simply expanded variables.
Variable defined with "?=" will be set only if the variable was not already set.

Categories: Makefile

Leave a Reply

Your email address will not be published. Required fields are marked *