1

I am trying to set up a makefile project using the mbed library for use in a larger project I am wanting to do later on. I have the project directory set up like this...

.
|-- Doxyfile
|-- NUCLEO_F446RE.mk
|-- Nucleo_blink.map
|-- asm
|-- attach.gdb
|-- debug
|-- gdb-pipe.cfg
|-- lib
|   `-- mbed
|       |-- AnalogIn.h
|       |-- ...
|       |-- TARGET_NUCLEO_F446RE
|       |   |-- TARGET_STM
|       |   |   `-- TARGET_STM32F4
|       |   |       |-- PeripheralPins.h
|       |   |       |-- TARGET_NUCLEO_F446RE
|       |   |       |   |-- PeripheralNames.h
|       |   |       |   |-- PinNames.h
|       |   |       |   |-- PortNames.h
|       |   |       |   |-- device.h
|       |   |       |   `-- objects.h
|       |   |       `-- gpio_object.h
|       |   |-- TOOLCHAIN_GCC_ARM
|       |   |   |-- STM32F446XE.ld
|       |   |   |-- board.o
|       |   |   |-- ...
|       |   |   `-- system_stm32f4xx.o
|       |   |-- arm_common_tables.h
|       |   |-- ...
|       |   `-- system_stm32f4xx.h
|       |-- Ticker.h
|       |-- ...
|       `-- wait_api.h
|-- makefile
|-- obj
|-- release
`-- src
    `-- main.cc

Specifically, my error is in lib/mbed/platform.h, which tries to include device.h. I have a makefile that should add it to the include path, but g++ still seems to be unable to find it. Here is the exact error...

arm-none-eabi-g++    -c -o main.o source/main.cc
In file included from source/../lib/mbed/mbed.h:21:0,
                from source/main.cc:1:
source/../lib/mbed/platform.h:21:20: fatal error: device.h: No such file or directory
#include "device.h"
                    ^
compilation terminated.
<builtin>: recipe for target 'main.o' failed
make: *** [main.o] Error 1

Line 1 of main.cc is #include "../lib/mbed/mbed.h"

NUCLEO_F446RE.mk defines the device-specific include path I am using, and I hope to be able to be able to choose the .mk file to use based on a variable I pass to the makefile, so that I can easily use a different mbed board if I want. Here are the contents of NUCLEO_F446RE.mk...

HARDFP = 1

LIBRARY_PATHS = -L./lib/mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM 

CPU = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=$(FLOAT_ABI)

LINKER_SCRIPT = ./lib/mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM/STM32F446XE.ld

CC_SYMBOLS = -DTARGET_M4 -DMBED_BUILD_TIMESTAMP=1453683815.81 -DTOOLCHAIN_GCC_ARM -DTOOLCHAIN_GCC -DTARGET_RTOS_M4_M7 -DTARGET_FF_MORPHO -DTARGET_CORTEX_M -D__FPU_PRESENT=1 -DTARGET_FF_ARDUINO -DTARGET_STM32F446RE -DTARGET_NUCLEO_F446RE -D__MBED__=1 -DTARGET_STM -DTARGET_STM32F4 -D__CORTEX_M4 -DARM_MATH_CM4

INCLUDE_PATHS = -I./lib/ -I./lib/mbed/ \
-I./lib/mbed/TARGET_NUCLEO_F446RE/ \
-I./lib/mbed/TARGET_NUCLEO_F44\6RE/TARGET_STM/ \
-I./lib/mbed/TARGET_NUCLEO_F446RE/TARGET_STM/TARGET_STM32F4/ \
-I./lib/mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM/ \
-I./lib/mbed/TARGET_NUCLEO_F446RE/TARGET_STM/TARGET_STM32F4/TARGET_NUCLEO_F446RE/ #<--device.h is here

SYS_OBJECTS = ./lib/mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM/stm32f4xx_hal_flash_ramfunc.o \
./lib/mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM/board.o \
...

For good measure, here is my makefile. I have been trying to keep everything as neat as possible.

#Project parameters
PROJECT = Nucleo_blink
OBJECTS = main.o
DEST    = debug
VPATH   = src lib $DEST
TARGET  = NUCLEO_F446RE

#Compilation options
DEBUG = 1

#Tools
AS      = $(GCC_BIN)arm-none-eabi-as
CC      = $(GCC_BIN)arm-none-eabi-gcc
CXX     = $(GCC_BIN)arm-none-eabi-g++
LD      = $(GCC_BIN)arm-none-eabi-gcc
OBJCOPY = $(GCC_BIN)arm-none-eabi-objcopy
OBJDUMP = $(GCC_BIN)arm-none-eabi-objdump
SIZE    = $(GCC_BIN)arm-none-eabi-size 

include $(TARGET).mk

CFLAGS = $(INCLUDE_PATHS) $(CC_SYMBOLS) $(CPU) -c -g -fno-common -fmessage-length=0 -Wall -Wextra -fno-exceptions -ffunction-sections -fdata-sections -fomit-frame-pointer -MMD -MP

ifeq ($(HARDFP),1)
        FLOAT_ABI = hard
else
        FLOAT_ABI = softfp
endif

ifeq ($(DEBUG), 1)
        CFLAGS += -DDEBUG -O0
else
        CFLAGS += -DNDEBUG -Os
endif

LD_FLAGS = $(CPU) -Wl,--gc-sections --specs=nano.specs -u _printf_float -u _scanf_float -Wl,--wrap,main -Wl,-Map=$(PROJECT).map,--cref
LD_SYS_LIBS = -lstdc++ -lsupc++ -lm -lc -lgcc -lnosys

LIBRARIES = -lmbed 

.PHONY: all clean lst size

all: $(PROJECT).bin $(PROJECT).hex

clean:
        rm -f debug/* obj/* asm/* $(DEPS)

obj/%.o: %.c #<---Attempt to fix target error mentioned by @user657267
        $(CC)  $(CC_FLAGS) $(CC_SYMBOLS) -std=c99 $(INCLUDE_PATHS) -o obj/$@ $<

obj/%.o: %.cc
        $(CXX) $(CC_FLAGS) $(CC_SYMBOLS) -std=c++98 -fno-rtti $(INCLUDE_PATHS) -o obj/$@ $<

obj/%.o: %.cpp
        $(CXX) $(CC_FLAGS) $(CC_SYMBOLS) -std=c++98 -fno-rtti $(INCLUDE_PATHS) -o obj/$@ $<

obj/%.o: %.asm
        $(CC) $(CPU) -c -x assembler-with-cpp -o asm/$@ $<

$(PROJECT).elf: $(OBJECTS) $(SYS_OBJECTS)
        $(LD) $(LD_FLAGS) -T$(LINKER_SCRIPT) $(LIBRARY_PATHS) -o $(DEST)/$@ $^ $(LIBRARIES) $(LD_SYS_LIBS) $(LIBRARIES) $(LD_SYS_LIBS)

$(PROJECT).bin: $(PROJECT).elf
        $(OBJCOPY) -O binary $< $@

$(PROJECT).hex: $(PROJECT).elf
        @$(OBJCOPY) -O ihex $< $@

$(PROJECT).lst: $(PROJECT).elf
        @$(OBJDUMP) -Sdh $< > $@

lst: $(PROJECT).lst

size: $(PROJECT).elf
        $(SIZE) $(PROJECT).elf

DEPS = $(OBJECTS:.o=.d) $(SYS_OBJECTS:.o=.d)
-include $(DEPS)

A lot of the code I have here is based on the output from the online mbed IDE after exporting a simple project to a makefile. However, the export had everything in a single directory, and that will be extremely messy as I start doing larger projects and possibly add more libraries. The strange part is that this project compiles without any errors when I use the single-directory exported version. What is going on here? Why is g++ not seeing device.h in my multi-directory version?

EDITS 2016-05-09: Minor tweaks to makefile, same error.

Caleb Reister
  • 263
  • 1
  • 2
  • 9

1 Answers1

0
%.o: %.cc %.cpp

This pattern rule is (probably) incorrect, you're telling make to apply this rule if and only if both the .cc and .cpp files exist (or can be made by other rules). As main.cpp presumably doesn't exist make will fall back to its built-in implicit rule, which obviously won't know about INCLUDE_PATHS or any other of the unconventional variables you're using for flags.

You can fix this by making the two rules separate

%.o: %.cc
    $(CXX) $(CC_FLAGS) $(CC_SYMBOLS) -std=c++98 -fno-rtti $(INCLUDE_PATHS) -o obj/$@ $<
%.o: %.cpp
    $(CXX) $(CC_FLAGS) $(CC_SYMBOLS) -std=c++98 -fno-rtti $(INCLUDE_PATHS) -o obj/$@ $<

These rules are still broken however, as when one of them matches something like ./lib/mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM/stm32f4xx_hal_flash_ramfunc.o you're going to place it into obj/./lib/mbed/TARGET_NUCLEO_F446RE/TOOLCHAIN_GCC_ARM/stm32f4xx_hal_flash_ramfunc.o, which means make will always recompile the object because it won't be where you've said it should be (check out the informal Rules of Makefiles, specifically 2).

user657267
  • 20,568
  • 5
  • 58
  • 77
  • I fixed the `%.o` problem, and I tried removing all the `./`'s from `NUCLEO_F446RE.mk`. It is still giving me the same error. Do I need to create separate rules to handle the mbed object files? – Caleb Reister May 09 '16 at 05:48
  • @CalebReister A typo perhaps? I'm guessing `-include $(TARGET)_mbed.mk` should be `include $(TARGET).mk`, and get rid of the `-` it was masking the error. Removing the `./` won't help with the second issue, the problem is you are outputting the objects to `obj/$@` but your rule says you output them to `%.o` (which is `$@`). – user657267 May 09 '16 at 06:43
  • I fixed the first problem and fixed a syntax error in `$(TARGET).mk`. The second issue is proving to be more complicated. I will update my post with some new information. – Caleb Reister May 09 '16 at 15:45
  • @CalebReister That's not to do with your makefile, but [this](http://stackoverflow.com/questions/19419782/exit-c-text0x18-undefined-reference-to-exit-when-using-arm-none-eabi-gcc) seems to be the same thing. – user657267 May 09 '16 at 21:22
  • Thanks for the input. However, I am still confused about the obj/ part. I made the rule look for object files in `obj/%.o`, but I am still getting the same error. Could it have something to do with the fact that the library objects are in a different location? Do I need a rule to handle them? Why would the header files be used that late in the compilation process? – Caleb Reister May 10 '16 at 04:28
  • @CalebReister Like I said your new error has nothing to do with your makefile, this is a linking issue, read the link I posted. – user657267 May 10 '16 at 04:52
  • Sorry about the confusion. I was talking about the original error, not the new one, which I should probably delete. – Caleb Reister May 10 '16 at 06:35
  • @CalebReister Please do, and make sure the error in the question is exactly how it appears now. – user657267 May 10 '16 at 06:37
  • @CalebReister Set `OBJECTS = obj/main.o` – user657267 May 10 '16 at 09:11
  • Thanks for all your help. That problem appears to be solved, even though I still have the other error. I'll have to fix that when I have more time. I set `OBJECTS`, but I also had to change `obj/$@` back to `$@` in the `obj/%.o` targets. – Caleb Reister May 10 '16 at 17:03