Alexis Draussin


µC firmware: a simple Makefile

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.

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) $^