Make

Build automation tool for compiling and managing project dependencies using Makefiles.

cli
makebuildautomationcompilation

Basic Makefile Structure

# Target: dependencies
#   command
#   command

all: program                # Default target (runs when you type 'make')

program: main.o utils.o     # Target depends on object files
    gcc -o program main.o utils.o  # Link object files

main.o: main.c              # Compile main.c to main.o
    gcc -c main.c

utils.o: utils.c utils.h    # Compile utils.c (depends on header too)
    gcc -c utils.c

clean:                      # Remove built files
    rm -f *.o program

Variables

# Define variables for reusability
CC = gcc                    # Compiler
CFLAGS = -Wall -g          # Compiler flags
LDFLAGS = -lm              # Linker flags
SRC = main.c utils.c       # Source files
OBJ = $(SRC:.c=.o)         # Replace .c with .o

# Use variables in targets
program: $(OBJ)
    $(CC) $(CFLAGS) -o program $(OBJ) $(LDFLAGS)

%.o: %.c                   # Pattern rule: compile any .c to .o
    $(CC) $(CFLAGS) -c $<

Phony Targets

# Declare targets that don't create files
.PHONY: all clean test install

all: build                 # Default target

clean:                     # Clean build artifacts
    rm -rf build/ *.o

test:                      # Run tests
    ./run_tests.sh

install:                   # Install the program
    cp program /usr/local/bin/

Automatic Variables

# Special variables make provides
build: src/main.c
    gcc $< -o $@           # $< = first dependency, $@ = target name

%.o: %.c %.h
    gcc -c $<              # $< = first prerequisite (the .c file)
    
libs: lib1.o lib2.o lib3.o
    ar rcs libmylib.a $^   # $^ = all prerequisites

Conditional Logic

# Conditional compilation
DEBUG ?= 0                 # Default to 0 if not set

ifeq ($(DEBUG), 1)
    CFLAGS += -g -DDEBUG   # Add debug flags
else
    CFLAGS += -O2          # Add optimization
endif

# Check if file exists
ifneq ($(wildcard config.mk),)
    include config.mk      # Include if exists
endif

Common Commands

make                       # Build default target (usually 'all')
make clean                 # Run the 'clean' target
make install               # Run the 'install' target
make -j4                   # Build with 4 parallel jobs
make -n                    # Dry run (show commands without executing)
make -B                    # Force rebuild all targets
make TARGET=value          # Pass variable to makefile

Functions

# Built-in functions
FILES = $(wildcard src/*.c)           # Find all .c files in src/
OBJS = $(patsubst %.c,%.o,$(FILES))  # Replace .c with .o
DIRS = $(shell find . -type d)        # Run shell command

# String manipulation
UPPER = $(shell echo $(VAR) | tr a-z A-Z)  # Convert to uppercase
BASENAME = $(notdir $(FILES))              # Get filename without path

Multi-Directory Project

# Organize larger projects
SRC_DIR = src
BUILD_DIR = build
INC_DIR = include

SOURCES = $(wildcard $(SRC_DIR)/*.c)
OBJECTS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SOURCES))

all: $(BUILD_DIR) program

$(BUILD_DIR):              # Create build directory
    mkdir -p $(BUILD_DIR)

program: $(OBJECTS)
    $(CC) -o $@ $^ -I$(INC_DIR)

$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $@ -I$(INC_DIR)

Dependency Generation

# Auto-generate header dependencies
DEPS = $(OBJECTS:.o=.d)    # .d files track header dependencies

-include $(DEPS)           # Include if they exist

%.o: %.c
    $(CC) $(CFLAGS) -MMD -MP -c $< -o $@  # -MMD generates .d file