Programming in C++

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Programming in C++

Postby kolban » Mon Oct 24, 2016 5:22 am

I am testing out programming in C++ in the ESP-IDF environment and so far so good. Some loose notes that may be of value to others:
  • C++ source files are compiled as such automatically by giving them the file type of ".cpp".
  • The stdc++ lib seems to work (at least for the subset I have tried) by adding COMPONENT_ADD_LDFLAGS=-lstdc++ -l$(COMPONENT_NAME) to the component.mk in the main folder.
  • Include C functions and ESP-IDF include files in extern "C" bracketing.
I am not saying that C++ is a supported or approved language but so far everything seems to be working according to theory.

Update: 2018-03-27 - This post and the follow on thread must be taken in context of when they were written. We are starting to see folks working in 2018 and reading this post from 2016 as the state of play today. While many answers from the past will be useful in the present and the future ... it is also important to realize (especially with problems and early recipes) that things move on and old information and techniques may no longer be relevant (or work). We never want to delete information ... it may have clues for the future ... but please take care and always ask "Is this still relevant?".
Last edited by kolban on Tue Mar 27, 2018 8:55 pm, edited 1 time in total.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: Programming in C++

Postby ESP_igrr » Mon Oct 24, 2016 6:21 am

There is a plan to support C++11 thread/concurrency library by writing appropriate wrappers around FreeRTOS API. But given current progress, i think this is going to be a post-1.0 feature.

The fact that -lstdc++ has to be explicitly added to build flags is a bug, and is on the list to be fixed pre-1.0. (Just adding a flag is not fully sufficient, though. There's a bit more to this).

By the way, nvs_flash component is mostly written in C++.

bengchet
Posts: 3
Joined: Wed Nov 30, 2016 8:20 pm

Re: Programming in C++

Postby bengchet » Wed Nov 30, 2016 8:56 pm

Hi,

Is it possible to use C++ in ESP-IDF environment? I have made a simple class, and include .h and .cpp in the same directory as main file. What I understood is in order to make this work, first main file must be in cpp file type as well, thus I rename main.c to main.cpp but it produces the error below

Code: Select all

make[1]: Entering directory `/home/beng/esp32/esp-idf/projects/myapp/build/main'
xtensa-esp32-elf-c++ -DESP_PLATFORM -Og -g3 -Wpointer-arith -Werror -Wno-error=unused-function -Wno-error=unused-but-set-variable -Wno-error=unused-variable -Wall -ffunction-sections -fdata-sections -mlongcalls -nostdlib -MMD -MP -Og -std=gnu++11 -g3 -fno-exceptions -fstrict-volatile-bitfields -I/home/beng/esp32/esp-idf/projects/myapp/main/include -I/home/beng/esp32/esp-idf/components/bt/include -I/home/beng/esp32/esp-idf/components/driver/include -I/home/beng/esp32/esp-idf/components/esp32/include -I/home/beng/esp32/esp-idf/components/expat/port/include -I/home/beng/esp32/esp-idf/components/expat/include/expat -I/home/beng/esp32/esp-idf/components/freertos/include -I/home/beng/esp32/esp-idf/components/json/include -I/home/beng/esp32/esp-idf/components/json/port/include -I/home/beng/esp32/esp-idf/components/log/include -I/home/beng/esp32/esp-idf/components/lwip/include/lwip -I/home/beng/esp32/esp-idf/components/lwip/include/lwip/port -I/home/beng/esp32/esp-idf/components/lwip/include/lwip/posix -I/home/beng/esp32/esp-idf/components/mbedtls/port/include -I/home/beng/esp32/esp-idf/components/mbedtls/include -I/home/beng/esp32/esp-idf/components/newlib/include -I/home/beng/esp32/esp-idf/components/nghttp/port/include -I/home/beng/esp32/esp-idf/components/nghttp/include -I/home/beng/esp32/esp-idf/components/nvs_flash/include -I/home/beng/esp32/esp-idf/components/spi_flash/include -I/home/beng/esp32/esp-idf/components/tcpip_adapter/include -I/home/beng/esp32/esp-idf/projects/myapp/build/include/  -I. -c /home/beng/esp32/esp-idf/projects/myapp/main/./main.cpp -o main.o
/home/beng/esp32/esp-idf/projects/myapp/main/./main.cpp: In function 'int app_main()':
/home/beng/esp32/esp-idf/projects/myapp/main/./main.cpp:35:5: error: C99 designator 'ssid' outside aggregate initializer
     };
     ^
/home/beng/esp32/esp-idf/projects/myapp/main/./main.cpp:35:5: error: C99 designator 'password' outside aggregate initializer
make[1]: Leaving directory `/home/beng/esp32/esp-idf/projects/myapp/build/main'
make[1]: *** [main.o] Error 1
make: *** [main-build] Error 2
When I try to comment the following code and compile

Code: Select all

    tcpip_adapter_init();
    ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
    wifi_config_t sta_config = {
        .sta = {
            .ssid = "Cytron-Asus",
            .password = "f5f4f3f2f1",
            .bssid_set = false
        }
    };
    ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config) );
    ESP_ERROR_CHECK( esp_wifi_start() );
    ESP_ERROR_CHECK( esp_wifi_connect() );
it gives following error

Code: Select all

/home/beng/esp32/esp-idf/projects/myapp/build/esp32/libesp32.a(cpu_start.o):(.literal.main_task+0x0): undefined reference to `app_main'
/home/beng/esp32/esp-idf/projects/myapp/build/esp32/libesp32.a(cpu_start.o): In function `main_task':
/home/beng/esp32/esp-idf/components/esp32/./cpu_start.c:169: undefined reference to `app_main'
collect2: error: ld returned 1 exit status
make: *** [/home/beng/esp32/esp-idf/projects/myapp/build/DHT22.elf] Error 1
Some libraries I believe they are written in C, so when should I include extern "C" {}?

Attached are the source files in main directory. The whole project I am using basic app-template provided by Espressif.

Hope you guys can enlighten me on how to solve this!
Attachments
testing.zip
(1.71 KiB) Downloaded 1295 times

ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: Programming in C++

Postby ESP_igrr » Wed Nov 30, 2016 11:20 pm

Your problem is that the following bit of code is not valid C++:

Code: Select all

    wifi_config_t sta_config = {
        .sta = {
            .ssid = "Cytron-Asus",
            .password = "f5f4f3f2f1",
            .bssid_set = false
        }
    };
Designated initializers are a C99 thing. C++ doesn't support such syntax.


Regarding app_main error, if you are implementing it in C++ you should declare it as

Code: Select all

extern "C" void app_main(void)
{
    // ...
}
All Espressif libraries in ESP-IDF have 'extern "C"' guards in header files (unlike the 8266 non-OS SDK), so explicit 'extern "C"' guards around include statements shouldn't be necessary in your code.

bengchet
Posts: 3
Joined: Wed Nov 30, 2016 8:20 pm

Re: Programming in C++

Postby bengchet » Thu Dec 01, 2016 12:07 am

Hi,

Thanks for quick reply. I will get back to you with the result. Many thanks again!

rosimildo
Posts: 13
Joined: Fri Nov 11, 2016 7:20 pm

Re: Programming in C++

Postby rosimildo » Thu Dec 01, 2016 12:39 am

There are serious limitations when using C++, specially if you include headers from freeRTOS or lwip components.

Some headers in these components have a huge amount of "defines" macros as function names, and they clash with any method name that equates with one of these "defines" ( macros ).

Example,

If you have a class:

class Foo {

void read();

};

If you include "sockets.h" from lwip component, you can't really use like this, since "read" is defined as macro.

It is not a big deal, but really annoying...

bengchet
Posts: 3
Joined: Wed Nov 30, 2016 8:20 pm

Re: Programming in C++

Postby bengchet » Thu Dec 01, 2016 1:35 am

Hi,

Thanks to ESP_Igrr, now I am able to compile it. Attached is the main.cpp file with few modifications.

Code: Select all

#include "freertos/FreeRTOS.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_event_loop.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "triangle.h"

Triangle polygon(3, 4, 5);  //<--- example class 

esp_err_t event_handler(void *ctx, system_event_t *event)
{
    return ESP_OK;
}

extern "C" int app_main(void)
{
    nvs_flash_init();
    system_init();
    tcpip_adapter_init();
    ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );

    wifi_config_t sta_config;
    sprintf(sta_config.sta.ssid, "Cytron-Asus"); //or strcpy also works
    sprintf(sta_config.sta.password, "f5f4f3f2f1");
    sta_config.sta.bssid_set = false;

    ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config) );
    ESP_ERROR_CHECK( esp_wifi_start() );
    ESP_ERROR_CHECK( esp_wifi_connect() );

    //testing c++ class support

    printf("The area of triangle is %i\r\n", polygon.getArea());

    gpio_set_direction(GPIO_NUM_4, GPIO_MODE_OUTPUT);
    int level = 0;
    while (true) {
        gpio_set_level(GPIO_NUM_4, level);
        level = !level;
        vTaskDelay(300 / portTICK_PERIOD_MS);
    }

    return 0;
}

ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: Programming in C++

Postby ESP_igrr » Thu Dec 01, 2016 3:05 am

rosimildo wrote:There are serious limitations when using C++, specially if you include headers from freeRTOS or lwip components.
Yes, i have encountered this problem as well when porting asio library to the ESP32. I have a few ideas how to resolve the issue with LwIP definitions, but this was somewhat a lower priority until now.

What other conflicts due to preprocessor macros have you met? Which FreeRTOS headers are giving you trouble?

rosimildo
Posts: 13
Joined: Fri Nov 11, 2016 7:20 pm

Re: Programming in C++

Postby rosimildo » Thu Dec 01, 2016 3:55 am

I've not met any issues with freeRTOS, only noticed a lot of defines ( not as all caps like: THIS_IS_A_DEFINE ) or something like that, which could lead to issues. Only noticed a possible for naming clashes due to all macros.

I met issues with the lwip headers.

I apologize, I should not have used the expression "serious limitations", but instead, some limitations.

ESP_igrr
Posts: 2072
Joined: Tue Dec 01, 2015 8:37 am

Re: Programming in C++

Postby ESP_igrr » Thu Dec 01, 2016 7:14 am

Okay, it's clear now. Yes, FreeRTOS does unfortunately use a somewhat lax convention for preprocessor define names.

I'll put the issue with sockets.h on our task list, thanks for reminding about it.

Who is online

Users browsing this forum: Google [Bot] and 422 guests