2

I'm programming an ARM in C++ with libopencm3. But my Makefile contains errors. Like you can see now!

I have following Makefile:

Q           = @
RM          = @rm -f
MAKE        = make
CC          = arm-none-eabi-gcc
CPP         = arm-none-eabi-g++
LD          = arm-none-eabi-gcc
OBC         = arm-none-eabi-objcopy
OBD         = arm-none-eabi-objdump
SIZ         = arm-none-eabi-size
STFLASH     = st-flash

FIRMWARE    = FIRMWARE
LIBNAME     = opencm3_stm32f1

SRCS        = main.cpp Robot.cpp
OBJS        = $(SRCS:%.cpp=$(OBJ_DIR)/%.o)

OPENCM3_DIR = $(realpath libopencm3)
INCLUDE_DIR = $(OPENCM3_DIR)/include
LIB_DIR     = $(OPENCM3_DIR)/lib
SCRIPT_DIR  = $(OPENCM3_DIR)/scripts
OBJ_DIR     = ./build

LDSCRIPT    = stm32f103c8t6.ld

CPPFLAGS    = -g -Os -Wall
CPPFLAGS    += -Wextra -Wshadow -Wredundant-decls -Weffc++
CPPFLAGS    += -fno-common -ffunction-sections -fdata-sections
CPPFLAGS    += -MD -Wall -Wundef
CPPFLAGS    += -I$(INCLUDE_DIR) -DSTM32F1
CPPFLAGS    += -msoft-float -mfix-cortex-m3-ldrd
CPPFLAGS    += -mthumb -mcpu=cortex-m3

LDFLAGS     = --static -nostartfiles
LDFLAGS     += -L$(LIB_DIR)
LDFLAGS     += -T$(LDSCRIPT)
LDFLAGS     += -Wl,-Map=$(OBJ_DIR)/$(FIRMWARE).MAP
LDFLAGS     += -Wl,--gc-sections
LDFLAGS      += -msoft-float -mfix-cortex-m3-ldrd
LDFLAGS      += -mthumb -mcpu=cortex-m3

LDLIBS      = -l$(LIBNAME)
LDLIBS      += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group

all: bin elf hex

lib:
    $(Q)if [ ! "`ls -A libopencm3`" ] ; then \
        printf "######## ERROR ########\n"; \
        printf "\tPlease run:\n"; \
        printf "\tgit clone https://github.com/libopencm3/libopencm3.git\n"; \
        printf "######## ERROR ########\n"; \
        exit 1; \
        fi
    $(Q)$(MAKE) -C libopencm3

elf: $(OBJ_DIR)/$(FIRMWARE).ELF
bin: $(OBJ_DIR)/$(FIRMWARE).BIN
hex: $(OBJ_DIR)/$(FIRMWARE).HEX

dox:
    $(Q)doxygen Doxyfile

$(OBJ_DIR)/$(FIRMWARE).BIN: $(OBJ_DIR)/$(FIRMWARE).ELF
    $(Q)printf "  OBJCOPY $(OBJ_DIR)/$(FIRMWARE).BIN\n"
    $(Q)$(OBC) -Obinary $(OBJ_DIR)/$(FIRMWARE).ELF $(OBJ_DIR)/$(FIRMWARE).BIN

$(OBJ_DIR)/$(FIRMWARE).HEX: $(OBJ_DIR)/$(FIRMWARE).ELF
    $(Q)printf "  OBJCOPY $(OBJ_DIR)/$(FIRMWARE).HEX\n"
    $(Q)$(OBC) -Oihex $(OBJ_DIR)/$(FIRMWARE).ELF $(OBJ_DIR)/$(FIRMWARE).HEX

$(OBJ_DIR)/$(FIRMWARE).ELF $(OBJ_DIR)/$(FIRMWARE).MAP: $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a
    $(Q)printf "  LD      $(OBJ_DIR)/$(FIRMWARE).ELF\n"
    $(Q)$(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(OBJ_DIR)/$(FIRMWARE).ELF
    $(Q)$(SIZ) $(OBJ_DIR)/$(FIRMWARE).ELF

$(OBJS): $(SRCS)
    $(Q)printf "  CPP     $(*).cpp\n"
    $(Q)$(CPP) $(CPPFLAGS) -o $@ -c $<

flash: $(OBJ_DIR)/$(FIRMWARE).BIN
    $(Q)printf "  FLASH   $(OBJ_DIR)/$(FIRMWARE).BIN\n"
    $(Q)$(STFLASH) write $(OBJ_DIR)/$(FIRMWARE).BIN 0x8000000

libclean:
    $(Q)$(MAKE) -C libopencm3 clean

clean:
    $(Q)printf "  CLEAN\n"
    $(Q)$(RM) $(OBJ_DIR)/*.o
    $(Q)$(RM) $(OBJ_DIR)/*.d

deepclean: clean
    $(Q)$(RM) $(OBJ_DIR)/$(FIRMWARE).*

But the linking (LD) doesn't work. See the Error:

  CPP     build/main.cpp
main.cpp: In function 'int main()':
main.cpp:25:24: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
         for(i = 0; i < 36000000UL; i++)
                        ^
  CPP     build/Robot.cpp
main.cpp: In function 'int main()':
main.cpp:25:24: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
         for(i = 0; i < 36000000UL; i++)
                        ^
  LD      ./build/FIRMWARE.ELF
./build/Robot.o: In function `main':
/home/martin/Dropbox/workspace/electronics/arm/Procyon/main.cpp:15: multiple definition of `main'
./build/main.o:/home/martin/Dropbox/workspace/electronics/arm/Procyon/main.cpp:15: first defined here
collect2: error: ld returned 1 exit status
Makefile:73: recipe for target 'build/FIRMWARE.ELF' failed
make: *** [build/FIRMWARE.ELF] Error 1

Where is the mistake? I don't know what's wrong with the LD, when i used this makefile for C (not C++) it worked fine !?

Maybe is it cause i use gcc instead of g++ for LD'ing?

Thanks, Martin

Sam Protsenko
  • 14,045
  • 4
  • 59
  • 75
Martin Fischer
  • 697
  • 1
  • 6
  • 27
  • 2
    Doesn't it strike you odd your `main.cpp` is clearly being compiled *twice*, including once when you're supposed to be compiling `Robot.cpp` ? Perchance, is there a `#include "main.cpp"` in your `Robot.cpp` ? – WhozCraig Jul 29 '15 at 22:42

1 Answers1

4

You've made each object depend on all sources here

$(OBJS): $(SRCS)

Change it to something like

$(OBJS): $(OBJ_DIR)/%.o: %.cpp

Or simply

$(OBJ_DIR)/%.o: %.cpp
user657267
  • 20,568
  • 5
  • 58
  • 77
  • when i do%.o: %.cpp how can i write the .ofiles into the ./build/ directory instead of where the makefile is? – Martin Fischer Jul 30 '15 at 05:39
  • @MartinFischer Updated. – user657267 Jul 30 '15 at 06:03
  • can you please check my Makefile now if i did the whole makefile well now (like makefile standard) and perfect coded or is there still any mistake, failure or not-perfect part? https://bpaste.net/show/4f911a63003e – Martin Fischer Jul 30 '15 at 06:07
  • @MartinFischer: 1) This works because OBJ_DIR happens to be defined in your makefile `OBJ_DIR = ./build` 2) Don't forget to insure that only *one* file with `main()` is linked at a time! – paulsm4 Jul 30 '15 at 06:07
  • Sure. But now my makefile is ok and doesnt contain any stranges anymore? – Martin Fischer Jul 30 '15 at 06:47
  • @MartinFischer [here](https://bpaste.net/show/6174277ec805) are some suggestions, most of it isn't really that important but there are certain conventions in make. Also I can't guarantee it'll still work because I can't test it. – user657267 Jul 30 '15 at 07:44
  • @user657267 Thanks my friend. I have just 2 questions: #1: Why is := better than = ? #2: Why are with following snippet the SRCS also Added to the OBJS, so OBJS is then all OBJS + SRCS ? SRCS = $(wildcard $(SRC_DIR)/*.cpp) \ $(wildcard $(SRC_DIR)/*.c) OBJS = $(SRCS:$(SRC_DIR)/%.cpp=$(OBJ_DIR)/%.o) \ $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) – Martin Fischer Jul 30 '15 at 07:50
  • @MartinFischer See [here](https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors) for the first question, I'm not sure about what's going on with the second question without a full example, but I have a hunch it has something to do with the answer to #1, try using immediate expansion with `:=` instead. – user657267 Jul 30 '15 at 07:59
  • @user657267 Ok. My current makefile is: https://bpaste.net/show/e41bf6418a4a > now please create a folder called src including some c/cpp files, and then run make clean (this prints the objs) now you see whats my problem is. – Martin Fischer Jul 30 '15 at 08:06
  • @MartinFischer the thing about substitutions is that they return the original string if there's no match, [this](https://bpaste.net/show/dfd195cc8ed7) is one way to do what you want, you can break it down into more commands if the one-liners are too cryptic. – user657267 Jul 30 '15 at 08:18
  • @MartinFischer something like `$(FOO:.cpp=.o)` is just shorthand for `$(patsubst %.cpp,%.o,$(FOO))`, once you understand that it should be simple to understand. You usually use `patsubst` if you need to something more complicated or if you don't have a variable to work on. – user657267 Jul 30 '15 at 08:35
  • @user657267 No there is still one problem. Once the make command successfully build my project, i cant do make again when i changed a file, i need first to make clean the project. Can we fix this? – Martin Fischer Jul 30 '15 at 08:44
  • @MartinFischer Which file? – user657267 Jul 30 '15 at 08:44
  • Robot.hpp, a header file (does it works just on SRC files not on headers?) – Martin Fischer Jul 30 '15 at 08:46
  • @MartinFischer Add `CPPFLAGS += -MMD -MP` somewhere and then `-include $(OBJ_DIR)/*.d` at the end of your Makefile. – user657267 Jul 30 '15 at 08:49
  • Works. But can you explain pls what a .d file is and what `-include $(OBJ_DIR)/*.d` is doing? – Martin Fischer Jul 30 '15 at 08:52
  • 1
    @MartinFischer `-MMD -MP` makes GCC dump dependency (d) files as part of the compilation process, these are just makefile fragments which list the files that are `include`d in the respective source file, so you include them in the main makefile (aka auto dependency generation). – user657267 Jul 30 '15 at 08:53