C++ STL on the Teensy 4.0 not possible?

Status
Not open for further replies.

teensydude

New member
Because I'm a stubborn jerk, I do not want to use Teensyduino. I want something more low-level for total control over Teensy 4.0, but I love my C++ STL. So, I discovered this nifty project someone kindly put on GitHub with a bare minimum Blinky that compiles straight C code for Teensy 4.0:

https://github.com/blazer82/baremetal-blinky.teensy

So far so good. I was able to alter the Makefile to use g++ to compile cpp files. I can write and compile code with classes, templates and all the fun stuff from C++. Hooray!

But, I cannot for the life of me get any STL code like std::vector to link after compiling. I am pulling my hair out, searching Google like a madman, and tried all of the suggestions (of course I am using -lstdc++ to the linker flags). No dice. I get various linker errors, when I include stdc++ (underfed reference to new, or delete, or exit).

Code:
new_allocator.h:114: undefined reference to `operator new(unsigned int)'

See code attached below:

View attachment baremetal-blinky.teensy.zip

I'm starting to think that the STL might actually not be supported on this thing. Is that true? I couldn't find a clear answer, but I have read a few articles that suggest that STL support with GNU Toolchain for Embedded ARM *does* work.
Has anyone gotten this to work? Would be great if I could find a bare minimum Makefile. Here is what I'm using now:

Code:
CC = arm-none-eabi-gcc
CXX = arm-none-eabi-g++
LD = arm-none-eabi-ld
OBJCOPY = arm-none-eabi-objcopy
OBJDUMP = arm-none-eabi-objdump
SIZE = arm-none-eabi-size
LOADER = teensy_loader_cli

OUTFILE = firmware

BUILD_DIR = ./build
SRC_DIRS ?= ./src ./teensy ./include

SRCS := $(shell find $(SRC_DIRS) -name *.c -or -name *.cpp -or -name *.s)
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)

FLAGS_CPU   := -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16
FLAGS_OPT   := -O3
FLAGS_COM   := -g -Wall -ffunction-sections -fdata-sections -MMD -nostdlib -nostartfiles
FLAGS_LSP   := 

FLAGS_CPP   := -std=c++17 -fno-exceptions -fpermissive -fno-rtti -fno-threadsafe-statics -felide-constructors -Wno-error=narrowing
FLAGS_C     := 
FLAGS_S     := -x assembler-with-cpp
FLAGS_LD    := -Wl,--gc-sections,--print-memory-usage,--relax,-Tteensy/imxrt1062.ld -specs=nosys.specs

INCLUDE_DIRS := $(ARM_NONE_EABI_INCLUDE) $(shell find $(SRC_DIRS) -type d)
FLAGS_INCLUDE := $(addprefix -I,$(INCLUDE_DIRS))

LIB_DIRS := $(ARM_NONE_EABI_LIB)
FLAGS_LIB_DIRS = $(addprefix -L,$(LIB_DIRS))

LIBS := m stdc++_nano gcc g_nano c_nano
FLAGS_LIBS := $(addprefix -l,$(LIBS))

DEFINES     := -D__IMXRT1062__ -DTEENSYDUINO=147 -DARDUINO=10807
DEFINES     += -DF_CPU=600000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH

CPP_FLAGS   := $(FLAGS_CPU) $(FLAGS_OPT) $(FLAGS_COM) $(DEFINES) $(FLAGS_CPP) $(FLAGS_INCLUDE)
C_FLAGS     := $(FLAGS_CPU) $(FLAGS_OPT) $(FLAGS_COM) $(DEFINES) $(FLAGS_C) $(FLAGS_INCLUDE)
S_FLAGS     := $(FLAGS_CPU) $(FLAGS_OPT) $(FLAGS_COM) $(DEFINES) $(FLAGS_S) $(FLAGS_INCLUDE)
LD_FLAGS    := $(FLAGS_CPU) $(FLAGS_OPT) $(FLAGS_LSP) $(FLAGS_LD) $(FLAGS_LIB_DIRS) $(FLAGS_LIBS)
AR_FLAGS    := rcs


$(BUILD_DIR)/$(OUTFILE).hex: $(BUILD_DIR)/$(OUTFILE).elf
	@$(OBJCOPY) -O ihex -R .eeprom build/$(OUTFILE).elf build/$(OUTFILE).hex
	@$(OBJDUMP) -d -x build/$(OUTFILE).elf > build/$(OUTFILE).dis
	@$(OBJDUMP) -d -S -C build/$(OUTFILE).elf > build/$(OUTFILE).lst
	@$(SIZE) build/$(OUTFILE).elf

$(BUILD_DIR)/$(OUTFILE).elf: $(OBJS)
	@$(CXX) $(CPP_FLAGS) -Xlinker -Map=build/$(OUTFILE).map -Tteensy/imxrt1062.ld -o $@ $^
	@echo Linking...

$(BUILD_DIR)/%.s.o: %.s
	@$(MKDIR_P) $(dir $@)
	@$(AS) $(S_FLAGS) -c $< -o $@
	@echo Assembling $<...

$(BUILD_DIR)/%.c.o: %.c
	@$(MKDIR_P) $(dir $@)
	@$(CC) $(C_FLAGS) -c $< -o $@
	@echo Compiling $<...

$(BUILD_DIR)/%.cpp.o: %.cpp
	@$(MKDIR_P) $(dir $@)
	@$(CXX) ${CPP_FLAGS} -c $< -o $@
	@echo Compiling $<...

.PHONY: flash
flash: $(BUILD_DIR)/$(OUTFILE).hex
	$(LOADER) --mcu=TEENSY40 -w -v $<

.PHONY: clean
clean:
	@$(RM) -r $(BUILD_DIR)

MKDIR_P ?= mkdir -p
 
I've not tried C++17 yet, but I know for sure C++14 is supported fairly well by Teensyduino and for a while now so I would start with that to use something with some more maturity on Teensy. I use a couple STL containers in one of my projects. For example, I use <vector>, but I had to add some code in order to get it to work as exceptions are not supported on Teensy I think. When I tried to use <vector> I got warnings about missing functions so I just defined them myself and I've been using STL vectors just fine. Given that you don't have an OS/page table, memory fragmentation is a concern so you should probably stick to containers with a reserve() command and allocate what you need at the start.

See the following for how I added <vector> support to my project.

https://github.com/Blackaddr/TouchMIDI/blob/master/VectorSupport.cpp
 
thanks for this. have you tried the "-fno-exceptions" GCC flag when you compile your code? in your case, I think that flag will remove the necessity for the VectorSupport.cpp file altogether. when I have this flag enabled, I no longer get linker errors for those particular functions.

still though, I can't compile any vector code due to linker not finding "new" and "delete" functions. these are very core STL functions, so I'm wondering what the hell is going on that it is linking all of the stdc++ library functions except these basic ones
 
maybe my next step should be to setup a teensyduino project and see if I can replicate what you've got for teensy 4.0, and then copy GCC options and linker flags to my Makefile. ideally I would like to end up with a simple Makefile project that is not tied to Arduino that has C++ STL support
 
still though, I can't compile any vector code due to linker not finding "new" and "delete" functions. these are very core STL functions, so I'm wondering what the hell is going on that it is linking all of the stdc++ library functions except these basic ones

Are you not saying you wanted to use barmetal (i.e. no TeensyDuino)? So you must write first all the functionality STL expects (here memory management), right?
 
thanks for the heads up, I was able to take the stuff luni showed me by defining these missing symbols:

__exidx_start
__exidx_end

this is resolved by placing the following code at the end of the linker scr

Code:
    .ARM.exidx :
    {
        __exidx_start = .;
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        __exidx_end = .;
        . = ALIGN(4);
    } > RAM

the forum discussion from the post above had > FLASH, which causes all sorts of errors. i was able to make them go away by putting the symbols into RAM with > RAM

the next step was to get rid of the undefined reference to new and delete. although i'm not quite sure why these basic things do not exist in stdc++ library in the arm toolchain, i copied new.h and new.cpp

so i present to you an un-verified bare metal C++ blink example for teensy with C++ 17 & STL support!

The code is here for any who want to mess around. So far I've tested that I can compile std::vector, std::string and std::map without compiler errors. Whether this works or not, I will have to wait for my teensy 4.0 to arrive in the mail to start messing around.

https://github.com/itsermo/baremetal-blinky.teensy
 
Status
Not open for further replies.
Back
Top