Makings of Makefiles 1

The Bare-Bones

September 06, 2022

cover
Source: -Niuy-

We often compile programs with commands like this, which is reasonably long but still a bit annoying to type out every single time:

gcc -std=c11 -Wall -Og -g3 -D LOGGING main.c -o a.out

The tool Make comes to our rescue. With a configuration file, dubbed eponymously as Makefile, set up like this, we can skip the tedious process of typing out everything every time, by instead simply running make:

a.out:
	gcc -std=c11 -Wall -Og -g3 -D LOGGING main.c -o a.out

What we have created is called a rule. We tell Make what we want to make and how to make it. Here we want to make a.out, which is called a target, and we make it by executing the indented command, which is called a recipe.

You can create multiple rules in a Makefile with each having multiple lines of recipes and even multiple targets. When you have multiple rules, you can specify which target you want to make by providing Make with an argument; for example, make a.out, where this argument is called a goal. When you run Make without any goal, the default goal is the first target in the Makefile. (This behavior can be modified and it will be covered later.)

This is how things work in the above example: We have a Makefile with a rule in it properly in place. We run make with no goal, so Make looks for the default goal. It examines the Makefile and finds the first target a.out and its corresponding rule. Then it executes the recipe of that rule. VoilĂ !


Just one more thing to note: The indents in front of recipes must be strictly tabs instead of whitespaces; this is purely for historical reasons. (This requirement can be changed and it will be covered later.)

There you have it! This is what a bare-bones Makefile looks like, acting just as a shortcut to execute complex commands. Now you might wonder why we wouldn’t just use shell functions for that. It is because the power of Make goes well beyond shortcutting.