From aea147ad6a5ac94c2f8c3adb06168fc605dc670a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 10 Aug 2015 15:51:57 +1000 Subject: [PATCH] Add C++ support to Makefile, and proof-of-concept simple.cpp example This is a work in progress based on @mikejac's work. Missing: * No 'new' operator. * I don't think STL is currently supported. --- FreeRTOS/Source/portable/esp8266/port.c | 11 ++++++ common.mk | 14 +++++-- core/sdk_compat.c | 15 +++++++ examples/simple_cplusplus/Makefile | 3 ++ examples/simple_cplusplus/simple.cpp | 52 +++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 examples/simple_cplusplus/Makefile create mode 100644 examples/simple_cplusplus/simple.cpp diff --git a/FreeRTOS/Source/portable/esp8266/port.c b/FreeRTOS/Source/portable/esp8266/port.c index 1632fe1..71c6658 100644 --- a/FreeRTOS/Source/portable/esp8266/port.c +++ b/FreeRTOS/Source/portable/esp8266/port.c @@ -178,6 +178,9 @@ void xPortSysTickHandle (void) //OpenNMI(); } +static bool sdk_compat_initialised; +void sdk_compat_initialise(void); + /* * See header file for description. */ @@ -186,6 +189,14 @@ portBASE_TYPE xPortStartScheduler( void ) _xt_isr_attach(INUM_SOFT, SV_ISR); _xt_isr_unmask(BIT(INUM_SOFT)); + /* ENORMOUS HACK: Call the sdk_compat_initialise() function. + This can be removed happily once we have open source startup code. + */ + if(!sdk_compat_initialised) { + sdk_compat_initialised = true; + sdk_compat_initialise(); + } + /* Initialize system tick timer interrupt and schedule the first tick. */ sdk__xt_tick_timer_init(); diff --git a/common.mk b/common.mk index 00a77dd..7361f70 100644 --- a/common.mk +++ b/common.mk @@ -220,13 +220,15 @@ $(1)_DEFAULT_ROOT := $(dir $(lastword $(MAKEFILE_LIST))) $(1)_ROOT ?= $$($(1)_DEFAULT_ROOT) $(1)_OBJ_DIR = $(call lc,$(BUILD_DIR)$(1)/) ### determine source files and object files ### -$(1)_SRC_FILES ?= $$(foreach sdir,$$($(1)_SRC_DIR), \ - $$(wildcard $$(sdir)/*.c) $$(wildcard $$(sdir)/*.S)) \ +$(1)_SRC_FILES ?= $$(foreach sdir,$$($(1)_SRC_DIR), \ + $$(wildcard $$(sdir)/*.c) $$(wildcard $$(sdir)/*.S) \ + $$(wildcard $$(sdir)/*.cpp)) \ $$($(1)_EXTRA_SRC_FILES) $(1)_REAL_SRC_FILES = $$(foreach sfile,$$($(1)_SRC_FILES),$$(realpath $$(sfile))) $(1)_REAL_ROOT = $$(realpath $$($(1)_ROOT)) # patsubst here substitutes real component root path for the relative OBJ_DIR path, making things short again -$(1)_OBJ_FILES_C = $$(patsubst $$($(1)_REAL_ROOT)%.c,$$($(1)_OBJ_DIR)%.o,$$($(1)_REAL_SRC_FILES)) +$(1)_OBJ_FILES_CXX = $$(patsubst $$($(1)_REAL_ROOT)%.cpp,$$($(1)_OBJ_DIR)%.o,$$($(1)_REAL_SRC_FILES)) +$(1)_OBJ_FILES_C = $$(patsubst $$($(1)_REAL_ROOT)%.c,$$($(1)_OBJ_DIR)%.o,$$($(1)_OBJ_FILES_CXX)) $(1)_OBJ_FILES = $$(patsubst $$($(1)_REAL_ROOT)%.S,$$($(1)_OBJ_DIR)%.o,$$($(1)_OBJ_FILES_C)) # the last included makefile is our component's component.mk makefile (rebuild the component if it changes) $(1)_MAKEFILE ?= $(lastword $(MAKEFILE_LIST)) @@ -244,6 +246,12 @@ $$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.c $$($(1)_MAKEFILE) $(wildcard $(ROOT)* $$($(1)_CC_ARGS) -c $$< -o $$@ $$($(1)_CC_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$< +$$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.cpp $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR) + $(vecho) "C++ $$<" + $(Q) mkdir -p $$(dir $$@) + $$($(1)_CXX_ARGS) -c $$< -o $$@ + $$($(1)_CXX_ARGS) -MM -MT $$@ -MF $$(@:.o=.d) $$< + $$($(1)_OBJ_DIR)%.o: $$($(1)_REAL_ROOT)%.S $$($(1)_MAKEFILE) $(wildcard $(ROOT)*.mk) | $$($(1)_SRC_DIR) $(vecho) "AS $$<" $(Q) mkdir -p $$(dir $$@) diff --git a/core/sdk_compat.c b/core/sdk_compat.c index d141708..b6bb6b3 100644 --- a/core/sdk_compat.c +++ b/core/sdk_compat.c @@ -14,3 +14,18 @@ void IRAM *zalloc(size_t nbytes) { return calloc(1, nbytes); } + +extern void (*__init_array_start)(void); +extern void (*__init_array_end)(void); + +/* Do things which should be done as part of the startup code, but aren't. + + Can be replaced with _start() once we have open source startup code. +*/ +void sdk_compat_initialise() +{ + /* Call C++ constructors or C functions marked with __attribute__((constructor)) */ + void (**p)(void); + for ( p = &__init_array_start; p != &__init_array_end; ++p) + (*p)(); +} diff --git a/examples/simple_cplusplus/Makefile b/examples/simple_cplusplus/Makefile new file mode 100644 index 0000000..717b163 --- /dev/null +++ b/examples/simple_cplusplus/Makefile @@ -0,0 +1,3 @@ +# Simple makefile for simple example +PROGRAM=simple +include ../../common.mk diff --git a/examples/simple_cplusplus/simple.cpp b/examples/simple_cplusplus/simple.cpp new file mode 100644 index 0000000..dada441 --- /dev/null +++ b/examples/simple_cplusplus/simple.cpp @@ -0,0 +1,52 @@ +/* A very basic C++ example, really just proof of concept for C++ + + This sample code is in the public domain. + */ +#include "espressif/esp_common.h" +#include "espressif/sdk_private.h" +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +class Counter +{ +private: + uint32_t _count; +public: + Counter(uint32_t initial_count) + { + this->_count = initial_count; + printf("Counter initialised with count %ld\r\n", initial_count); + } + + void Increment() + { + _count++; + } + + uint32_t getCount() + { + return _count; + } +}; + +static Counter static_counter(99); + +void task1(void *pvParameters) +{ + Counter local_counter = Counter(12); + while(1) { + Counter &counter = rand() % 2 ? static_counter : local_counter; + counter.Increment(); + printf("local counter %ld static counter %ld\r\n", local_counter.getCount(), + static_counter.getCount()); + vTaskDelay(100); + } +} + +extern "C" void user_init(void) +{ + sdk_uart_div_modify(0, UART_CLK_FREQ / 115200); + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + xTaskCreate(task1, (signed char *)"tsk1", 256, NULL, 2, NULL); +}