Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Writing Effective Makefiles for Software Builds

Tech 1

Kernel Module Build Configuration

obj-m := module_driver.o
# multi_files := component1.o component2.o
KERNEL_PATH := /usr/src/linux
MODULE_SRC := $(shell pwd)
build:
	$(MAKE) -C $(KERNEL_PATH) SUBDIRS=$(MODULE_SRC) modules
	@rm -f *.mod.* .*.cmd *.o Module.*
clean:
	rm -f *.ko

Core Makefile Concepts

Targets: Can be actual files (programs, libraries) or phony targets (build, clean)

Dependencies: Files or other targets required to build the current target

Commands: Operations executed to generate targets, typically compilation or linking instructions

Makefile Structure Compoennts

Variable declarations, target rules, phony targets, and cleanup rules

Variable Definitions

Using variables enhances maintainability and flexibility

# Compiler configuration
COMPILER = gcc
COMPILE_FLAGS = -Wall -g
LINK_FLAGS = -lm

Target Rule Syntax

Each target consists of a name, dependencies, and commands (indented with TAB)

# target: dependencies
#	commands
application: main.o helper.o
	$(COMPILER) -o application main.o helper.o $(LINK_FLAGS)

Target: application Dependencies: main.o helper.o Command: $(COMPILER) -o application main.o helper.o $(LINK_FLAGS)

Phony Targets

Phony targets represent actions rather than files. Common examples include build and clean

.PHONY: build clean
build: application
clean:
	rm -f *.o application

.PHONY declaration prevents conflicts with actual files

Complete Build System Example

CURRENT_DIR := .
EXECUTABLE = hardware_controller

USER_COMPILE_FLAGS += $(BUILD_FLAGS)
USER_COMPILE_FLAGS += $(EXTRA_FLAGS)
USER_LINK_FLAGS += $(LINK_BUILD_FLAGS)

# Directory structure
INCLUDE_DIR = -I$(CURRENT_DIR)/include
SOURCE_DIR = $(CURRENT_DIR)/src
OBJECT_DIR = $(CURRENT_DIR)/objects
LIBRARY_DIR = $(CURRENT_DIR)/libraries
BINARY_DIR = $(CURRENT_DIR)/bin

SOURCE_FILES = $(wildcard $(SOURCE_DIR)/*.c *.cpp)
OBJECT_FILES = $(patsubst $(SOURCE_DIR)/%.c,$(OBJECT_DIR)/%.o,$(patsubst $(SOURCE_DIR)/%.CPP,$(OBJECT_DIR)/%.o,$(SOURCE_FILES)))

$(OBJECT_DIR)/%.o: $(SOURCE_DIR)/%.c
	$(COMPILER) $(USER_COMPILE_FLAGS) $(INCLUDE_DIR) -c $< -o $@

build: setup $(EXECUTABLE)

setup: $(OBJECT_DIR)

LIBRARIES = -L$(LIBRARY_DIR)/

$(EXECUTABLE): $(OBJECT_FILES)
	$(COMPILER) -o $(BINARY_DIR)/$(EXECUTABLE) $^ $(USER_LINK_FLAGS) $(LIBRARIES) -lpthread -lrt -lm

$(OBJECT_DIR):
	@mkdir -p $(OBJECT_DIR)
	@mkdir -p $(LIBRARY_DIR)
	@mkdir -p $(BINARY_DIR)

clean:
	rm -rf $(OBJECT_DIR)/*
	rm -f $(BINARY_DIR)/$(EXECUTABLE)

Auotmatic Variables

  • $@: Target filename
  • $<: First dependency filename
  • $^: All dependency filenames (duplicates removed)
  • $?: All dependencies newer than target

Note: Automatic variables are only valid within rule commands

Built-in Variables

  • CC: C compiler (gcc)
  • CPPFLAGS: C preprocessor flags (-I)
  • CFLAGS: C compiler flags (-Wall -g -c -O2)
  • LDFLAGS: Linker flags (-L -l)

Common Functions

wildcard: Find files matching pattern

source_files = $(wildcard *.c)

patsubst: Pattern substitution

object_files = $(patsubst %.c,%.o,$(source_files))

Basic Project Makefile

COMPILER = gcc
COMPILE_FLAGS = -Wall -Wextra
OUTPUT = myprogram
SOURCE_DIR = src
BUILD_DIR = build

# Source files
SOURCES = $(wildcard $(SOURCE_DIR)/*.c)
# Object files
OBJECTS = $(SOURCES:$(SOURCE_DIR)/%.c=$(BUILD_DIR)/%.o)

# Default target
build: $(BUILD_DIR)/$(OUTPUT)

# Create executable
$(BUILD_DIR)/$(OUTPUT): $(OBJECTS)
	$(COMPILER) $(COMPILE_FLAGS) $^ -o $@

# Compile source to object files
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c
	$(COMPILER) $(COMPILE_FLAGS) -c $< -o $@

# Clean build artifacts
clean:
	rm -f $(BUILD_DIR)/*.o $(BUILD_DIR)/$(OUTPUT)

.PHONY: build clean

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.