1

I'm an electrical engineer who's gotten into embedded C at a beginner/intermediate level. I've found Geoffery Brown's "Discovering the STM32 Microcontroller" to be an excellent beginner embedded resource after having gone through Steve Oualline's Practical C Programming. I very much recommend that path to anyone wanting to learn embedded C.

To my question: The author of Discovering STM32 provides a Makefile scheme that includes a project-specific Makefile as well as a Makefile common (Makefile.common) to all project directories that gets included. I really want to organize my code into src, inc, obj and bin directories but the author did not provide this functionality in the makefile templates. After reading up on Makefiles and trying a few things out, I'm at a loss as to how to do it with the author-provided structure. My goal is to retain the same Makefile/Makefile.common scheme while having my code be organized into separate bin, src, inc and obj directories within my project subfolder after my .elf is built.

More simply, I want my directory structure / folders to look like :

DiscoveringSTM32
    Makefile.common
    ProjectA
        src
            main.c
            stuff.c
            whateverelse.c
            Makefile
        inc
            stuff.h
            whateverelse.h
        bin
            ProjectA.elf
        obj
            stuff.o
            whateverelse.o

Context / what I'm working with: FWIW, my full DiscoveringSTM32 repo is here. The project-specific (e.g. "ProjectA") author provided Makefile looks like this:

TEMPLATEROOT = ..

# compilation flags for gdb

CFLAGS  = -O1 -g 
ASFLAGS = -g 
LDLIBS += -lm

# object files

OBJS =  $(STARTUP) main.o
OBJS += foo.o bar.o
OBJS += baz.o fee.o 
OBJS += fo.o fum.o

# include common make file
include $(TEMPLATEROOT)/Makefile.common

While the author provided Makefile.common looks like

# name of executable

ELF=$(notdir $(CURDIR)).elf                    

# Tool path

TOOLROOT="C:\Users\Robert\OneDrive\Documents\GNU_ARM_TOOLS\9-2020-q2-update\bin"

# Library path

LIBROOT="C:\Users\Robert\OneDrive\Documents\DiscoveringSTM32\STM32F10x_StdPeriph_Lib_V3.5.0"

# Tools

CC=$(TOOLROOT)/arm-none-eabi-gcc
LD=$(TOOLROOT)/arm-none-eabi-gcc
AR=$(TOOLROOT)/arm-none-eabi-ar
AS=$(TOOLROOT)/arm-none-eabi-as

# Code Paths

DEVICE=$(LIBROOT)/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x
CORE=$(LIBROOT)/Libraries/CMSIS/CM3/CoreSupport
PERIPH=$(LIBROOT)/Libraries/STM32F10x_StdPeriph_Driver

# Search path for standard files

vpath %.c $(TEMPLATEROOT)

# Search path for perpheral library

vpath %.c $(CORE)
vpath %.c $(PERIPH)/src
vpath %.c $(DEVICE)

# Search path for Library

vpath %.c $(TEMPLATEROOT)/Library/ff9/src
vpath %.c $(TEMPLATEROOT)/Library/ff9/src/option
vpath %.c $(TEMPLATEROOT)/Library

#  Processor specific

#PTYPE = STM32F10X_MD_VL 
PTYPE = STM32F10X_MD #try this for blue pill
LDSCRIPT = $(TEMPLATEROOT)/stm32f100.ld
STARTUP= startup_stm32f10x.o system_stm32f10x.o 

# Compilation Flags

FULLASSERT = -DUSE_FULL_ASSERT 

LDFLAGS+= -T$(LDSCRIPT) -mthumb -mcpu=cortex-m3 
CFLAGS+= -mcpu=cortex-m3 -mthumb 
CFLAGS+= -I$(TEMPLATEROOT) -I$(DEVICE) -I$(CORE) -I$(PERIPH)/inc -I.
CFLAGS+= -D$(PTYPE) -DUSE_STDPERIPH_DRIVER $(FULLASSERT)
CFLAGS+= -I$(TEMPLATEROOT)/Library/ff9/src -I$(TEMPLATEROOT)/Library

# Build executable 

$(ELF) : $(OBJS)
    $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

# compile and generate dependency info

%.o: %.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(CC) -MM $(CFLAGS) $< > $*.d

%.o: %.s
    $(CC) -c $(CFLAGS) $< -o $@

clean:
    rm -f $(OBJS) $(OBJS:.o=.d) $(ELF) startup_stm32f* $(CLEANOTHER)

debug: $(ELF)
    arm-none-eabi-gdb $(ELF)


# pull in dependencies

-include $(OBJS:.o=.d)

I think I understand the jist of what's going on here where we define our object files (i.e. main.o from main.c, foo.o from foo.c) and we have rules to create the object files from their dependencies, ultimately building my flashable ELF file.

Things I've tried

After some googling and reading some online tutorials I've tried defining my directories like so:

BINDIR = bin
SRCDIR = src
OBJDIR = obj
INCDIR = inc

and then wildcarding all my .c's and .o's

# name of executable

ELF:= $(BINDIR)/$(notdir $(CURDIR)).elf
SRC := $(wildcard $(SRCDIR)/*.c)
OBJ = $(SRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
OBJ += $(STARTUP)

I +='d in $(STARTUP) and thus the associated files defined by STARTUP as I've run into "error: no rule to make target startup_stm32f10x.o".

The farthest I've got with this endeavor is successfully creating a bin directory with the .elf file in it in my specific project directory (e.g. Documents/DiscoveringStm32/projectA). Getting there involved keeping the author-provided += object file scheme and modifying the ELF definition in makefile.common to be:

ELF:= $(BINDIR)/$(notdir $(CURDIR)).elf

I tried doing:

$(ELF) : $(OBJDIR)/$(OBJS)
    $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)

# compile and generate dependency info

$(OBJDIR)/%.o: $(SRCDIR)/%.c
    $(CC) -c $(CFLAGS) $< -o $@
    $(CC) -MM $(CFLAGS) $< > $*.d

%.o: %.s
    $(CC) -c $(CFLAGS) $< -o $@

but this threw errors.

I've come to have an appreciation for the complexities of Makefiles through all this. I'm sure I'll have learned quite a bit more about writing them once this is figured out.

Thanks for the help in advance!

RobGah
  • 21
  • 2
  • Do you really say that with the **Things I've tried** scenario the Makefile was, as indicated in the first code block, in the `src` directory? – Armali Mar 14 '21 at 15:58
  • There is no `ProjectA` in your _DiscoveringSTM32 repo_, so of what use is the link? – Armali Mar 14 '21 at 16:01
  • How could you get to _successfully creating … the .elf file_ **before** doing something with the effect of `$(OBJDIR)/%.o: $(SRCDIR)/%.c $(CC) -c $(CFLAGS) $< -o $@`? – Armali Mar 14 '21 at 16:41
  • (With the above, were the sources still in `ProjectA`?) – Armali Mar 14 '21 at 16:48
  • "ProjectA" is just a placeholder for the other project directory names. I'm saying that what I want is to structure my directories as I've shown for ProjectA. To your second question - I believe that when I did get the bin directory w/ the .elf I had something to the effect of `$(OBJDIR)/%.o: $(SRCDIR)/%.c $(CC) -c $(CFLAGS) $< -o $@.` for my rule for the ELF file. – RobGah Mar 14 '21 at 17:09

1 Answers1

0

In order to allow the source files to reside in src, you can use VPATH = $(SRCDIR) along with your definition of SRCDIR. To place the object files in obj, you have to add the directory to the filenames in OBJS, e. g. with OBJS := $(OBJS:%.o=$(OBJDIR)/%.o). The compile rule head is then $(OBJDIR)/%.o: %.c.

Armali
  • 18,255
  • 14
  • 57
  • 171