Makefiles: Part 1 — A Gentle Introduction

Let’s look at the notorious Makefile today!
We will ease into it and keep things clean!

This first part will look at creating a makefile which does not do anything significant. Rather, we will create rules (which actions in makefiles are called) that explain the makefile itself.

It is assumed that you have access to a terminal, and the command make.

Why Use It?

Several reasons!

  • Many cool repositories on a git-hosting website use makefiles, learning to use makefiles means you can use these in your projects!
  • Makefiles offer complete control of your workflow.
  • Makefiles ensure your team is not tied to any one IDE (many IDEs can use makefiles, so the dependency can go the other way).

Creating A Simple Makefile

Let us dive in!

Note: Makefiles require the recipe entries to have tab characters for their indentation.
It will not work otherwise!

Our First Rule

Makefiles consist of rules, and rules are built like so:

TARGET : PREREQUISITES
    RECIPE

The name of the target is what you can call from the command line.
Let us try that!

Example 1: Hello World!

Our first rule will be quite simple.
Put this into a file with the name Makefile:

first_rule:
    echo "Hello World!"

Now, drop out into the terminal and execute make.

The output is:

echo "Hello World!"
Hello World!

Make wants to keep us informed, so it outputs the command it runs.
This leads us to our first trick!

Trick 1: @

Edit Example 1 to be:

first_rule:
    @echo "Hello World!"

Now when running make the output is simply:

Hello World!

We have learned to silence the command being run! Neat.

Our Second Rule

Example 2: Helloer World!

We now introduce a second rule.

Edit our makefile to contain:

first_rule:
    @echo "Hello World!"

second_rule:
    @echo "Helloer World!"

Now run make again. The output is:

Hello World!

Huh! We did not get the output of our second target. This leads us to…

Trick 2: Target Practice (And The Default Target)

Try running make first_rule. As you might suspect, the output is

Hello World!

Now run make second_rule. Aha! It ran the second rule, as the output was now

Helloer World!

We observe two things from this. The first is that we can supply the name of the target we wish to run. Super useful!

The second is that if we supply no name, the top target is executed.

Our Third Rule

Example 3: Lean On Me

Let us expand our makefile. Edit the contents to this:

first_rule:
    @echo "Hello World!"

second_rule:
    @echo "Helloer World!"

third_rule: second_rule
    @echo "Helloest World!"

Now, as we know, we can run our new rule by executing

make third_rule

in the terminal. The output shows:

Helloer World!
Helloest World!

Let’s try going one step further. Edit the second rule now to this:

second_rule: first_rule
    @echo "Helloer World!"

Now we get the output:

Hello World!
Helloer World!
Helloest World!

Trick 3: Dependencies!

From the above we observe that if we put a target into our prerequisites list, it will be executed before the recipe itself.

And if our prerequisites also have prerequisites, the rabbit hole goes deeper!

What Did You Call Me?

If you have seen makefile before, you might have come across this:

.PHONY: <target name(s)>

What is it? In general, targets that produce no output files are phony targets.
All of our rules are of this nature! Why should we care?
Let’s find out.

Revisit our first rule, by simply executing make in the terminal.
The output is as expected:

Hello World!

Now, go to the terminal and make sure you are in the same directory as the Makefile.

Execute touch first_rule to create an empty file with the same name as our target.

Now run make.

The output is:

make: 'first rule' is up to date.

Make sees that our target file (because if it is not a phony target it is a rule that is expected to create a file with the target’s name) exists and is up-to-date, so it does not do unnecessary work.

But we want to run our target recipe anyway!

Trick 4: .PHONY

Edit the makefile such that it contains this:

.PHONY: first_rule second_rule \
    third_rule

Now try running make again. Our output is back! Neat.

We have learned how to specify targets with no output files; phonies!

Trick 5: Long Lines

In Trick 4 we snuck in another useful trick.
Write a backslash and press Return/Enter, and you can continue the list of parameters in your rule.

Until Next Time

Here is our makefile thus far:

.PHONY: first_rule second_rule \
	third_rule

first_rule:
	@echo "Hello World!"

second_rule: first_rule
	@echo "Helloer World!"

third_rule: second_rule
	@echo "Helloest World!"

In the next part, we will get comfortable with some of the more interesting (or confusing?) parts of the make syntax.

Stay tuned!

Related Posts