+++ title = "µC firmware: a simple Makefile" date = 2023-08-18 +++ --- ### General and basic Makefile for C compilation oriented towards embedded application You'll have to adapt the file, add dependencies and sources on variables. By default, it uses the mold linker with the LDFLAGS `-fuse-ld=mold`. This file is also available in a git repository. ```Make OUTPUT_DIR ?= build OUT ?= main TARGET = $(OUTPUT_DIR)/$(OUT) # Desired outputs: OUTPUTS = $(TARGET).elf \ $(TARGET).hex \ $(TARGET).bin \ $(TARGET).sym \ $(TARGET).lst CROSS ?= CC = $(CROSS)gcc LD = $(CROSS)ld AR = $(CROSS)ar AS = $(CROSS)as OC = $(CROSS)objcopy OD = $(CROSS)objdump NM = $(CROSS)nm RE = $(CROSS)readelf SZ = $(CROSS)size SRC = . SRCS = $(wildcard $(SRC)/*.c) SRCS_PP = $(wildcard $(SRC)/*.cpp) SRCS_AS = $(wildcard $(SRC)/*.S) OBJS = $(SRCS:.c=.o) OBJS_PP = $(SRCS_PP:.cpp=.o) OBJS_AS = $(SRCS_AS:.S=.o) DEP = . DEPS = $(wildcard $(DEP)/*.h) ARCHFLAGS = DEFINES = INCLUDES = -I. LOADS = CPPFLAGS = CFLAGS = $(CPPFLAGS) -std=gnu99 -pedantic -Wall -g3 -Os CFLAGS += $(ARCHFLAGS) ASFLAGS = $(ARCHFLAGS) LDFLAGS = -fuse-ld=mold -Xlinker -Map=$(TARGET).map LDFLAGS += -lc -lgcc NMFLAGS = -n target $(TARGET).bin: OCFLAGS = -Obinary target $(TARGET).hex: OCFLAGS = -Oihex ODFLAGS = -S ARFLAGS = -r VB ?= 0 ifneq ($(VB), 1) V := @ endif # Reminder: # > $@ is the target variable # > $< is the 1st prerequisite # > $^ lists all prerequisites .PHONY: all, clean, deepclean all: $(OUTPUTS) @echo " SIZE $(TARGET).elf" $(V)$(SZ) $(TARGET).elf clean: @echo "Removing files..." -find . -type f -name '*.o' | xargs rm -f -find . -type f -name '*.d' | xargs rm -f -find . -type f -name '*.map' | xargs rm -f -rm -rf $(OUTPUTS) %.o: %.c $(DEPS) @echo " CC $<" $(V)$(CC) $(DEFINES) $(CFLAGS) $(INCLUDES) -o $@ -c $< %.o: %.cpp $(DEPS) @echo " CC $<" $(V)$(CC) $(DEFINES) $(CFLAGS) $(INCLUDES) -o $@ -c $< %.o: %.S @echo " AS $<" $(V)$(AS) $(DEFINES) $(ASFLAGS) $(INCLUDES) -o $@ -c $< $(TARGET).elf: $(OBJS) @echo " LD $@" @mkdir -p $(OUTPUT_DIR) $(V)$(CC) -o $@ $^ $(LOADS) $(LDFLAGS) $(TARGET).sym: $(TARGET).elf @echo " NM $@" $(V)$(NM) $(NMFLAGS) $^ > $@ $(TARGET).lst: $(TARGET).elf @echo " OBJDUMP $@" $(V)$(OD) $(ODFLAGS) $^ > $@ $(TARGET).hex: $(TARGET).elf @echo " OBJCOPY $@" $(V)$(OC) $(OCFLAGS) $^ $@ $(TARGET).bin: $(TARGET).elf @echo " OBJCOPY $@" $(V)$(OC) $(OCFLAGS) $^ $@ $(TARGET).a: $(OBJS) @echo " AR $@" @mkdir -p $(OUTPUT_DIR) $(V)$(AR) $(ARFLAGS) -o $@ $^ ### Embedded specifics PATH := $(HOME)/.ftdi_cpu_prog/:$(PATH) PATH := $(HOME)/.qemu/stm32/arm-softmmu/:$(PATH) FLASHDEV ?= /dev/ttyUSB0 LISTENDEV ?= /dev/ttyUSB0 CROSS_QEMU ?= -system-arm QFLAGS = -M stm32-p103 -serial stdio -serial stdio -serial stdio -kernel .PHONY: flash, listen, qemu flash: $(TARGET).bin stm32flash.sh -w $^ $(FLASHDEV) listen: flash minicom -D $(LISTENDEV) qemu: $(TARGET).bin qemu$(CROSS_QEMU) $(QFLAGS) $^ ```