From cb2876ff4e4f1a78223e7f075badc4ad694a1929 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 4 Sep 2018 10:20:29 +0800 Subject: [PATCH] examples: add C++ exception handling example --- docs/en/api-guides/error-handling.rst | 1 + examples/system/cpp_exceptions/Makefile | 9 +++ examples/system/cpp_exceptions/README.md | 41 ++++++++++++++ .../system/cpp_exceptions/example_test.py | 28 ++++++++++ .../system/cpp_exceptions/main/component.mk | 4 ++ .../main/exception_example_main.cpp | 56 +++++++++++++++++++ .../system/cpp_exceptions/sdkconfig.defaults | 3 + 7 files changed, 142 insertions(+) create mode 100644 examples/system/cpp_exceptions/Makefile create mode 100644 examples/system/cpp_exceptions/README.md create mode 100644 examples/system/cpp_exceptions/example_test.py create mode 100644 examples/system/cpp_exceptions/main/component.mk create mode 100644 examples/system/cpp_exceptions/main/exception_example_main.cpp create mode 100644 examples/system/cpp_exceptions/sdkconfig.defaults diff --git a/docs/en/api-guides/error-handling.rst b/docs/en/api-guides/error-handling.rst index 284bcc753..b3e88a06f 100644 --- a/docs/en/api-guides/error-handling.rst +++ b/docs/en/api-guides/error-handling.rst @@ -119,4 +119,5 @@ Enabling exception handling normally increases application binary size by a few If an exception is thrown, but there is no ``catch`` block, the program will be terminated by ``abort`` function, and backtrace will be printed. See :doc:`Fatal Errors ` for more information about backtraces. +See :example:`system/cpp_exceptions` for an example of C++ exception handling. diff --git a/examples/system/cpp_exceptions/Makefile b/examples/system/cpp_exceptions/Makefile new file mode 100644 index 000000000..bbca3f716 --- /dev/null +++ b/examples/system/cpp_exceptions/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := cpp_exceptions_example + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/system/cpp_exceptions/README.md b/examples/system/cpp_exceptions/README.md new file mode 100644 index 000000000..0ff49f352 --- /dev/null +++ b/examples/system/cpp_exceptions/README.md @@ -0,0 +1,41 @@ +# Example: C++ exception handling + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example demonstrates usage of C++ exceptions in ESP-IDF. + +By default, C++ exceptions support is disabled in ESP-IDF. It can be enabled using `CONFIG_CXX_EXCEPTIONS` configuration option. + +In this example, `sdkconfig.defaults` file sets `CONFIG_CXX_EXCEPTIONS` option. This enables both compile time support (`-fexceptions` compiler flag) and run-time support for C++ exception handling. + +Example source code declares a class which can throw exception from the constructor, depending on the argument. It illustrates that exceptions can be thrown and caught using standard C++ facilities. + +## How to use example + +### Configure the project + +Run `make menuconfig` and set serial port under Serial Flasher Options. + +### Build and Flash + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +make -j4 flash monitor +``` + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +app_main starting +In constructor, arg=42 +In constructor, arg=0 +In destructor, m_arg=42 +Exception caught: Exception in constructor +app_main done +``` + diff --git a/examples/system/cpp_exceptions/example_test.py b/examples/system/cpp_exceptions/example_test.py new file mode 100644 index 000000000..29a132428 --- /dev/null +++ b/examples/system/cpp_exceptions/example_test.py @@ -0,0 +1,28 @@ +from __future__ import print_function +import os +import sys + +test_fw_path = os.getenv('TEST_FW_PATH') +if test_fw_path and test_fw_path not in sys.path: + sys.path.insert(0, test_fw_path) + +import TinyFW +import IDF + +@IDF.idf_example_test(env_tag='Example_WIFI') +def test_examples_system_cpp_exceptions(env, extra_data): + dut = env.get_dut('cpp_exceptions_example', 'examples/system/cpp_exceptions') + # start test + dut.start_app() + lines = ['app_main starting', + 'In constructor, arg=42', + 'In constructor, arg=0', + 'In destructor, m_arg=42', + 'Exception caught: Exception in constructor', + 'app_main done' + ] + for line in lines: + dut.expect(line, timeout=2) + +if __name__ == '__main__': + test_examples_system_cpp_exceptions() diff --git a/examples/system/cpp_exceptions/main/component.mk b/examples/system/cpp_exceptions/main/component.mk new file mode 100644 index 000000000..a98f634ea --- /dev/null +++ b/examples/system/cpp_exceptions/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/system/cpp_exceptions/main/exception_example_main.cpp b/examples/system/cpp_exceptions/main/exception_example_main.cpp new file mode 100644 index 000000000..24ada9de6 --- /dev/null +++ b/examples/system/cpp_exceptions/main/exception_example_main.cpp @@ -0,0 +1,56 @@ +/* C++ exception handling example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include + +using std::cout; +using std::endl; +using std::runtime_error; + +/* A simple class which may throw an exception from constructor */ +class Throwing +{ +public: + Throwing(int arg) + : m_arg(arg) + { + cout << "In constructor, arg=" << arg << endl; + if (arg == 0) { + throw runtime_error("Exception in constructor"); + } + } + + ~Throwing() + { + cout << "In destructor, m_arg=" << m_arg << endl; + } + +protected: + int m_arg; +}; + +/* Inside .cpp file, app_main function must be declared with C linkage */ +extern "C" void app_main() +{ + cout << "app_main starting" << endl; + + try { + /* This will succeed */ + Throwing obj1(42); + + /* This will throw an exception */ + Throwing obj2(0); + + cout << "This will not be printed" << endl; + } catch (const runtime_error &e) { + cout << "Exception caught: " << e.what() << endl; + } + + cout << "app_main done" << endl; +} diff --git a/examples/system/cpp_exceptions/sdkconfig.defaults b/examples/system/cpp_exceptions/sdkconfig.defaults new file mode 100644 index 000000000..e9d7fca37 --- /dev/null +++ b/examples/system/cpp_exceptions/sdkconfig.defaults @@ -0,0 +1,3 @@ +# Enable C++ exceptions and set emergency pool size for exception objects +CONFIG_CXX_EXCEPTIONS=y +CONFIG_CXX_EXCEPTIONS_EMG_POOL_SIZE=1024