Makefile Practical Guide: Start from Scratch for Effortless Code Compilation

Introduction: Are you also a “Command Repeater”?

Every time you compile code, you have to type a long string of commands: gcc -o app main.c tool.c -I./include -L./lib -lm……

Change a line of code, and you have to type it all over again; if you mistype a character, you have to start from scratch — doesn’t it feel like a machine that only repeats commands?

Today, we will talk about Makefile, which is the magic tool to rescue “repeater programmers”! It acts like a “command manager”, storing all the compilation commands so you only need to type make, and it will handle the rest for you. Plus, it’s super easy to get started; you’ll be able to use it after reading this article!

1. First, understand: What is a Makefile?

In simple terms, a Makefile is a **”command script file”** that is filled with “rules” — it tells the make command what files (targets) need to be generated, what files they depend on, and what commands to use for generation.

For example, if you want to cook a dish (target: dish), you need to depend on ingredients (dependency files) and know the cooking steps (commands) — a Makefile is like this “recipe”.

The core format consists of 3 lines, memorize it!

Target: Dependency1 Dependency2 ... (Note: must use Tab, not spaces!) Command

2. Practical demonstration: Writing a Makefile from scratch

Assuming we have a simple C project with the following file structure:

my_project/├── main.c   (main program)├── tool.c   (utility functions)├── include/│   └── tool.h  (header file)└── Makefile    (the file we will write)

1. The most basic Makefile: Compiling

First, write a “working version”. Create a Makefile with the following content:

# Comment: Lines starting with # are comments and will not be executed# Target: Generate executable file appapp: main.c tool.c# Compilation command: -I specifies the header file path, -o specifies the output file namegcc -o app main.c tool.c -I./include  # Compile

After saving, enter the my_project directory in the terminal and type:

make

A miracle happens! The terminal will automatically execute the gcc … command and generate the app executable file. Even if you only change main.c, you can still quickly compile by typing make without retyping the long command!

2. Advanced: Adding a “clean” function

After compilation, an app file will be generated. What if you want to delete it? Add a “clean target” in the Makefile:

# Target 1: Generate app (default first target, executed by typing make)app: main.c tool.c# Target 2: Clean generated files (needs to type make clean to execute)clean:rm -f app   # Force delete, no error if file does not exist

Now try:

Compile: makeClean: make clean

Isn’t it super convenient? No more manually typing rm -f app!

3. Further: Solving the “repeated compilation” problem

The above method has a small drawback: even if you only change main.c, the Makefile will recompile both main.c and tool.c. If the project is large, it will be slow!

The solution: let the Makefile only compile the “modified files” by first generating .o target files (intermediate files):

# Define variables: store the compiler and compilation options, change in one placeCC = gcc          # CompilerCFLAGS = -I./include  # Compilation options (specifying header file path)# Target: Generate app, depends on main.o and tool.oapp: main.o tool.o# Link .o files to generate executable filegcc -o app main.o tool.o# Target: Generate main.o, depends on main.c and tool.hmain.o: main.c include/tool.h$(CFLAGS) -c main.c  # -c: compile only, do not link, generate .o file# Target: Generate tool.o, depends on tool.c and tool.htool.o: tool.c include/tool.h$(CFLAGS) -c tool.c# Clean targetclean:rm -f app *.o  # Delete app and all .o files

Now test:

1. First compilation: make → generates main.o, tool.o, app2. Only modify main.c, then type make → only recompiles main.o, then links to generate app (super fast!)3. Clean: make clean → deletes all generated files

3. Finally, a word of truth

Makefile can compile not only C code but also C++, Python projects (like batch executing scripts)! The core is “defining targets, dependencies, commands”, letting the computer do the repetitive work.

Today’s demonstration only covered the basic usage, but it’s enough to handle daily small projects. If your project is large, you can learn more advanced syntax (like loops, conditional statements), but that’s a topic for another time.

Quickly write a Makefile for your project and say goodbye to the “command repeater”! If you encounter any issues, leave a message in the comments, and we can troubleshoot together!

Leave a Comment