GNU Make: Part 1 — An introduction

whosayn
3 min readApr 3, 2022

As a software engineer who primarily works on developing cross-platform applications in multiple programming languages, one of the most useful, but complicated, tools I frequently use is the GNU make tool, but I found that most of my software engineering training made no effort in training me for it, and I’m here to fix that! As I’m delving deeper into GNU make, I’m writing this to allow people to follow along with my journey.

This article serves to give a brief tutorial on some useful things one should know about GNU make in order to effectively understand its usage, and to improve one’s ability to effective build software. This will be the first part of a series of articles showing said useful features of make and how to use them.

Installation

In this tutorial, I’m going to assume you have make version ≥ 3.81 installed on your linux/unix machine. You can first check for the presence of the make program on your machine by running the following command

which make

After you confirm the presence of make on you machine, you can find the version of make by running the command

make --version

If you happen to not have make v3.81+ installed on your machine, you can find the necessary instructions here https://www.gnu.org/software/make/.

Variables

One of the most important things to know about in constructing a Makefile, is variable assignment. There are two ways of assigning variables in make, that is either using the simple operator (:=) or the recursive operator (=).

When you use the simple operator, like in this example,

FOO := $(shell find $(HOME) -name "*.c")

FOO gets evaluated straight away as a single fixed value for all references to it, but when you use the recursive operator like in this example,

FOO = $(shell find $(HOME) -name "*.c")

The FOO variable has to be evaluated every time the variable is used, which could lead to some performance issues, especially if it’s evaluated from and an expensive computation.

Given the above, you’d think that the using the simple operator (:=) is always better, but it also can present some issues. Since they’re evaluated straight away, the order of defining dependent variables can affect the value of what the simple operator evaluates the variable to, which may affect the correctness of your instructions. Always try to weight the potential costs of using one operator over the other before settling on one!

Hooray! Now you can define a variable in make, but in order to know if you correctly defined said variable you need a way to print it out. A good way to do this is by using the info command. You can print the contents of a variable with

$(info $(VARIABLE_NAME))

An important thing to know about variables in Makefiles is the hierarchy of importance of variable origins (where they’re defined). It goes like this:

override > command-line (eg., make VAR=val) > environment override (eg., make -e VAR=val) > file > environment

While it’s always a good practice to have unique variable names, you could find yourself in a place where you want to extract some important variable information from the environment or the user, but if you mistakenly define it in your file, you may have a hard time evaluating what the necessary value is. Try to keep in mind the relative importance of where variables are defined, so that you don’t use the wrong values in your instructions. You can find the origin of a variable with the command:

$(info $(origin VARIABLE_NAME))

Thats all for today. I’m going to be talking about some useful functions in make next time, so follow me to stay updated. Bye.

--

--