PlatformIO Community

Possible to use C++17

I noticed a thread where someone was able to compile with C++17 using the latest toolchain.

I changed my platformio.ini to,

...
build_flags =
    -DARDUINO=10800
    -DESP32=1
    -DARDUINO_ARCH_ESP32=1
    -DBOARD_HAS_PSRAM
    -std=c++17
    -std=gnu++17
build_unflags =
    -std=gnu++11

[esp32]
platform_packages =
    toolchain-gccarmnoneeabi @ https://dl.bintray.com/platformio/dl-packages/toolchain-gccarmnoneeabi-darwin_x86_64-1.90201.191206.tar.gz
    framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git

[env:planter]
board = esp32doit-devkit-v1
framework = arduino
platform = espressif32
platform_packages =
    ${esp32.platform_packages}
lib_deps =
    ${common.lib_deps}
build_flags =
    ${common.build_flags}
build_unflags =
upload_port = /dev/cu.SLAB_USBtoUART
upload_speed = 921600

I then tried to use an optional but it doesn’t resolve,

lib/spiffs/SpiffsUtils.cpp:57:6: error: 'optional' in namespace 'std' does not name a template type
 std::optional<String> SpiffsUtils::read_file(const char * path){...

Any ideas?

This is the GCC-ARM-None-Eabi compiler for ARM targets. You’re having an XTensa32 target, the ESP32.

Let me check if it works when using the right toolchain.

I see,

So I changed to,

platform_packages =
    ; toolchain-gccarmnoneeabi-darwin_x86_64-1.80201.181220.tar.gz
    toolchain-xtensa32 @ https://dl.bintray.com/platformio/dl-packages/toolchain-xtensa32-darwin_x86_64-2.80200.200226.tar.gz
    framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git

now I’m seeing,

/Users/tmillar/.platformio/packages/toolchain-xtensa32@src-d6a97b83f94cf8cd271a11c0b1a39af0/xtensa-esp32-elf/include/c++/8.2.0/xtensa-esp32-elf/no-rtti/bits/gthr-default.h:781:12: error: 'pthread_mutex_timedlock' was not declared in this scope
     return __gthrw_(pthread_mutex_timedlock) (__mutex, __abs_timeout);
            ^~~~~~~~

Ideas?

Unfortunately the newest XTensa compiler does not work for me. The repo has Xtensa32-GCC 8.2.0 as the newest, which is xtensa-esp32-elf-g++ (crosstool-NG esp-2019r2) 8.2.0 (also referenced in esp-idf), but building with it fails fatally with internal G++ errors.

For reference my platformio.ini

[platformio]
default_envs = planter


[esp32]
; upgrade XTensa32 GCC/G++ compiler to 8.2.0
; use bleeding edge arduino-esp32
platform_packages =
    toolchain-xtensa32 @ 2.80200.200226
    framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git

[common]
build_flags =
; do not redefine arduino
;    -DARDUINO=10800 
    -DESP32=1
    -DARDUINO_ARCH_ESP32=1
    -DBOARD_HAS_PSRAM
    -std=c++17
    -std=gnu++17
build_unflags =
    -std=gnu++11

[env:planter]
board = esp32doit-devkit-v1
framework = arduino
platform = espressif32
platform_packages =
    ${esp32.platform_packages}
; not given in examples
;lib_deps =
;    ${common.lib_deps}
build_flags =
    ${common.build_flags}
build_unflags =
	${common.build_unflags}

and sample code

#include <Arduino.h>

void setup() {

}

void loop() {
}

fails to compile .

Compiling .pio\build\planter\FrameworkArduino\FunctionalInterrupt.cpp.o
In file included from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\xtensa-esp32-elf\no-rtti\bits\gthr.h:151,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\ext\atomicity.h:35,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\bits\basic_string.h:39,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\string:52,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\stdexcept:39,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\array:39,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\tuple:39,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\functional:54,
                 from C:\Users\Maxi\.platformio\packages\framework-arduinoespressif32@src-537c58760dafe7fcc8a1d9bbcf00b6f6\cores\esp32\FunctionalInterrupt.h:11,
                 from C:\Users\Maxi\.platformio\packages\framework-arduinoespressif32@src-537c58760dafe7fcc8a1d9bbcf00b6f6\cores\esp32\FunctionalInterrupt.cpp:8:
c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\xtensa-esp32-elf\no-rtti\bits\gthr-default.h: In function 'int __gthread_mutex_timedlock(__gthread_mutex_t*, const __gthread_time_t*)':
c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\xtensa-esp32-elf\no-rtti\bits\gthr-default.h:783:12: error: 'pthread_mutex_timedlock' was not declared in this scope
     return __gthrw_(pthread_mutex_timedlock) (__mutex, __abs_timeout);
            ^~~~~~~~
c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\xtensa-esp32-elf\no-rtti\bits\gthr-default.h:783:12: note: suggested alternative: 'pthread_mutex_trylock'
In file included from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\cstdlib:75,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\ext\string_conversions.h:41,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\bits\basic_string.h:6391,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\string:52,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\stdexcept:39,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\array:39,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\tuple:39,
                 from c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\include\c++\8.2.0\functional:54,
                 from C:\Users\Maxi\.platformio\packages\framework-arduinoespressif32@src-537c58760dafe7fcc8a1d9bbcf00b6f6\cores\esp32\FunctionalInterrupt.h:11,
                 from C:\Users\Maxi\.platformio\packages\framework-arduinoespressif32@src-537c58760dafe7fcc8a1d9bbcf00b6f6\cores\esp32\FunctionalInterrupt.cpp:8:
c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\sys-include\stdlib.h: At global scope:
c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\sys-include\stdlib.h:155:44: error: expected initializer before '__result_use_check'
 void *reallocarray(void *, size_t, size_t) __result_use_check __alloc_size(2)
                                            ^~~~~~~~~~~~~~~~~~
c:\users\maxi\.platformio\packages\toolchain-xtensa32\xtensa-esp32-elf\sys-include\stdlib.h:340:52: error: expected initializer before '__alloc_align'
 void * aligned_alloc(size_t, size_t) __malloc_like __alloc_align(1)
                                                    ^~~~~~~~~~~~~
*** [.pio\build\planter\FrameworkArduino\FunctionalInterrupt.cpp.o] Error 1

There seems to be some misconfiguration regarding pthreads / mutexes and internal __result_use_check and __alloc_align stuff…

This exact error has already been reported at https://github.com/espressif/esp-at/issues/215 but no solution was found other than “go back to 5.2.0”, which doesn’t have C++17 support.

I’ll open an issue at ESP-IDF and see what I can do.

I’ll open an issue at ESP-IDF and see what I can do.

Thanks Max…when you do can you reply with that Issue link

Opened at https://github.com/espressif/arduino-esp32/issues/3778 instead ESP-IDF, because the error is related to compiling Arduino-ESP32 and can’t open an issue in https://github.com/espressif/crosstool-NG anyways >.<

2 Likes

See updated issue. When using the right branch it goes through and C++17 std::optional features are usuable. I copied the example from the cppreference page and it produces the expected output.

Full platformio.ini:

[esp32]
; upgrade XTensa32 GCC/G++ compiler to 8.2.0
; use bleeding edge arduino-esp32
platform_packages =
    toolchain-xtensa32 @ 2.80200.200226
    framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0

[common]
build_flags =
; do not redefine arduino
;    -DARDUINO=10800 
    -DESP32=1
    -DARDUINO_ARCH_ESP32=1
    -DBOARD_HAS_PSRAM
    -std=c++17
; only use C++17 now not GNU++17. This is an either-or relation.
;    -std=gnu++17
build_unflags =
    -std=gnu++11

[env:planter]
board = esp32doit-devkit-v1
framework = arduino
platform = espressif32
platform_packages =
    ${esp32.platform_packages}
; not given in examples
;lib_deps =
;    ${common.lib_deps}
build_flags =
    ${common.build_flags}
build_unflags =
	${common.build_unflags}

main.cpp

#include <Arduino.h>
#include <string>
#include <functional>
#include <iostream>
#include <optional>


// optional can be used as the return type of a factory that may fail
std::optional<std::string> create(bool b) {
    if (b)
        return "Godzilla";
    return {};
}

// std::nullopt can be used to create any (empty) std::optional
auto create2(bool b) {
    return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}

// std::reference_wrapper may be used to return a reference
auto create_ref(bool b) {
    static std::string value = "Godzilla";
    return b ? std::optional<std::reference_wrapper<std::string>>{value}
             : std::nullopt;
}

int main2()
{
    std::cout << "create(false) returned "
              << create(false).value_or("empty") << '\n';

    // optional-returning factory functions are usable as conditions of while and if
    if (auto str = create2(true)) {
        std::cout << "create2(true) returned " << *str << '\n';
    }

    if (auto str = create_ref(true)) {
        // using get() to access the reference_wrapper's value
        std::cout << "create_ref(true) returned " << str->get() << '\n';
        str->get() = "Mothra";
        std::cout << "modifying it changed it to " << str->get() << '\n';
    }
    return 0;
}

void setup() {
	Serial.begin(115200);
	main2();
}

void loop() {
}

Produces

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:1364
load:0x40078000,len:12656
load:0x40080400,len:3512
entry 0x40080624
create(false) returned empty
create2(true) returned Godzilla
create_ref(true) returned Godzilla
modifying it changed it to Mothra

So it should be all fine now. Since this uses bleeding-edge version of the Arduino-ESP32’s idf-release/v4.0 branch I can’t say much about the stability of this branch, but I’m sure some time later a stable version will be released as an update…

2 Likes

Great job! Thanks for your help.

I just added these changes in my project. Other than a third party library giving some c++17 warnings, ArduinoLog, I have no other warnings, nothing! :partying_face:

1 Like

None of this worked on Linux to get C++17 to work with Platform.IO and ESP32

Eventually after lots of tinkering, the latest xtensa and v4.0 of arduino-espressif worked well…

** Note - you have to unflag the useless gnu++11 and add propper c++17 support…

; un-flaging gnu++11 (it really sucks) and using proper C++17
build_unflags =-std=gnu++11
build_flags =-std=c++17

; need latest toolchains and frameworks to make C++17 work
platform_packages =
     toolchain-xtensa32 @ 3.80200.200512
     framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#idf-release/v4.0