A Comprehensive Guide to Makefile: From Basics to Advanced Applications

A Comprehensive Guide to Makefile: From Basics to Advanced Applications

Makefile is a compilation control file widely used for automating project builds. It defines a series of rules to guide the build process. With Makefile, developers can easily manage compilation, linking, cleaning, and other tasks for large projects. This article will start with the basic usage of Makefile and gradually delve into more advanced applications, presenting a comprehensive and detailed manual for using Makefile.

Basic Structure of Makefile

A simple Makefile consists of rules, which are composed of a target, dependencies, and commands:

target: dependencies
    commands

The tab character before the command is mandatory. Here is a simple example:

hello: hello.c
    gcc -o hello hello.c

Using Variables

Declaring variables in Makefile can make our code more concise.

CC=gcc
CFLAGS=-std=c99
LDFLAGS=
OBJ=main.o utils.o

app: $(OBJ)
    $(CC) -o app $(OBJ) $(LDFLAGS)

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

utils.o: utils.c utils.h
    $(CC) $(CFLAGS) -c utils.c

Generic Rules and Pattern Matching

Pattern rules can reduce the workload of repeating the same commands.

%.o: %.c
    $(CC) $(CFLAGS) -c $<

$ is an automatic variable that represents the first item in the dependency list.

Automatic Variables

Makefile provides a series of automatic variables that are very useful in the commands of rules:

  • $@ represents the target file name in the rule;
  • $^ represents the list of all dependency files;
  • $ represents the first dependency file;
  • $? represents the list of all dependencies that are newer than the target.

Using Functions

Many built-in functions in Makefile are available for string operations, file operations, etc.

For example, to get the list of source files:

SRC=$(wildcard *.c)
OBJ=$(patsubst %.c,%.o,$(SRC))

Controlling Make’s Behavior

  • make -B forces recompilation of all targets;
  • make -n shows the commands that will be executed without actually executing them;
  • make -f <file> specifies a Makefile with a different name;
  • make -j allows parallel execution (multi-core compilation).

Advanced Usage – Conditional Statements

Makefile also supports conditional statements, which are very useful when different commands need to be executed in different environments.

ifeq ($(OS),Windows_NT)
    RM=del /Q
else
    RM=rm -f
endif

clean:
    $(RM) *.o

Using Variables and File Includes to Organize Makefile

For large projects, organizing multiple Makefiles is a good approach.

# In the sub-Makefile
include config.mk

Custom Functions

By defining reusable functions, you can make your Makefile more powerful and flexible.

define run-cc
$(CC) $(CFLAGS) -o $@ $^
endef

app: $(OBJ)
    $(call run-cc)

Handling Multiple Targets

Define a rule to batch process multiple files.

FILES := file1 file2 file3

all: $(FILES)

$(FILES):
    touch $@

Using Phony Targets

Phony targets do not represent actual files; they are simply names for actions.

.PHONY: clean

clean:
    rm -f *.o app

Debugging Makefile

You can use make –debug or add comments to help debug Makefile.

app: main.o utils.o
    # This is a linking command
    $(CC) -o app main.o utils.o

Conclusion

Makefile is a powerful tool for build automation, capable of simplifying the build process for small projects while flexibly managing the complex build systems of large applications. Through this detailed discussion and rich examples, you should be able to grasp the skills of Makefile and apply them in practical projects.

I hope the above content helps you deepen your understanding and use of Makefile. Remember, “Practice makes perfect”—writing your own Makefile and trying out these features is the best way to learn.

A Comprehensive Guide to Makefile: From Basics to Advanced Applications

END

Author: Tofu Scholar

Source: One Bite Linux

Copyright belongs to the original author. If there is any infringement, please contact to delete.
Recommended Reading
The Japanese Operating System That Almost Dominated the World…
Modify a Few Lines of Code, For Loop Time Dropped from 3.2 Seconds to 0.3 Seconds
VSCode vs. SourceInsight, Which Is Better for Reading Source Code?

→ Follow for More Updates ←

Leave a Comment