espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.37k stars 7.21k forks source link

Linking asio fails when using ESP-IDF in Custom CMake Projects (IDFGH-4818) #6617

Open haffmans opened 3 years ago

haffmans commented 3 years ago

Environment

Problem Description

Trying to use the asio component in a custom CMake project fails to compile in multiple ways. This can be reproduced by adapting the protocols/asio/tcp_echo_server example to follow the custom CMake approach (but it also occurs with real projects using asio).

The first issue is that the ESP_PLATFORM definition is required when including asio.hpp, otherwise the wrong asio config is loaded (specifically, ESP's configuration is not included). It would be helpful if ESP_PLATFORM is either added as PUBLIC definition on the idf::asio CMake target (or actually __idf_asio):

# Fix 1: add ESP_PLATFORM definition to the interface of idf::asio
target_compile_definitions(__idf_asio INTERFACE ESP_PLATFORM)

After this, compilation works until the linking stage fails with the following error that I haven't been able to resolve yet (full output below):

~/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: CMakeFiles/asio_tcp_echo_server.elf.dir/main/echo_server.cpp.obj:(.rodata._ZTIN4asio6detail30execution_context_service_baseINS0_23reactive_socket_serviceINS_2ip3tcpEEEEE[typeinfo for asio::detail::execution_context_service_base<asio::detail::reactive_socket_service<asio::ip::tcp> >]+0x8): undefined reference to `typeinfo for asio::execution_context::service'

The exact same program code works when using idf.py to build the example. Given that the compile stage works

Expected Behavior

The asio component is usable from custom CMake projects.

Actual Behavior

Compilation and linking fails.

Steps to reproduce

  1. Copy the protocols/asio/tcp_echo_server examples to a writable location
  2. Change the CMakeLists.txt contents to the version below
  3.  mkdir build
     cd build
     cmake -DCMAKE_TOOLCHAIN_FILE=${IDF_PATH}/tools/cmake/toolchain-esp32.cmake -G Ninja ..
     ninja

Code to reproduce this issue

cmake_minimum_required(VERSION 3.12)

project(asio_tcp_echo_server)

include($ENV{IDF_PATH}/tools/cmake/idf.cmake)
idf_build_component($ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
idf_build_process(esp32 freertos esptool_py nvs_flash asio protocol_examples_common lwip)

add_executable(${CMAKE_PROJECT_NAME}.elf main/echo_server.cpp)
target_link_libraries(${CMAKE_PROJECT_NAME}.elf idf::newlib idf::protocol_examples_common idf::nvs_flash idf::lwip idf::asio)
idf_build_executable(${CMAKE_PROJECT_NAME}.elf)

target_compile_definitions(${CMAKE_PROJECT_NAME}.elf PRIVATE "CONFIG_EXAMPLE_PORT=\"1337\"")

# Fix 1: add ESP_PLATFORM definition to the interface of idf::asio
target_compile_definitions(__idf_asio INTERFACE ESP_PLATFORM)

Debug Logs

Complete log attached. output.log

FAILED: asio_tcp_echo_server.elf
: && $HOME/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-g++ -mlongcalls -Wno-frame-address  CMakeFiles/asio_tcp_echo_server.elf.dir/main/echo_server.cpp.obj -o asio_tcp_echo_server.elf  esp-idf/newlib/libnewlib.a  esp-idf/protocol_examples_common/libprotocol_examples_common.a  esp-idf/nvs_flash/libnvs_flash.a  esp-idf/lwip/liblwip.a  esp-idf/asio/libasio.a  -fno-rtti  -fno-lto  esp-idf/newlib/libnewlib.a  esp-idf/nvs_flash/libnvs_flash.a  esp-idf/lwip/liblwip.a  esp-idf/cxx/libcxx.a  esp-idf/freertos/libfreertos.a  esp-idf/esp_hw_support/libesp_hw_support.a  esp-idf/heap/libheap.a  esp-idf/log/liblog.a  esp-idf/soc/libsoc.a  esp-idf/hal/libhal.a  esp-idf/esp_rom/libesp_rom.a  esp-idf/esp_common/libesp_common.a  esp-idf/esp_system/libesp_system.a  esp-idf/esp32/libesp32.a  esp-idf/esp_netif/libesp_netif.a  esp-idf/spi_flash/libspi_flash.a  esp-idf/mbedtls/libmbedtls.a  esp-idf/vfs/libvfs.a  esp-idf/esp_wifi/libesp_wifi.a  esp-idf/esp_eth/libesp_eth.a  esp-idf/tcpip_adapter/libtcpip_adapter.a  esp-idf/pthread/libpthread.a  esp-idf/app_trace/libapp_trace.a  esp-idf/esp_timer/libesp_timer.a  esp-idf/efuse/libefuse.a  esp-idf/espcoredump/libespcoredump.a  esp-idf/esp_ipc/libesp_ipc.a  esp-idf/esp_pm/libesp_pm.a  esp-idf/ulp/libulp.a  esp-idf/esp_http_client/libesp_http_client.a  esp-idf/esp_http_server/libesp_http_server.a  esp-idf/bootloader_support/libbootloader_support.a  esp-idf/app_update/libapp_update.a  esp-idf/wpa_supplicant/libwpa_supplicant.a  esp-idf/esp_serial_slave_link/libesp_serial_slave_link.a  esp-idf/esp-tls/libesp-tls.a  esp-idf/esp_https_ota/libesp_https_ota.a  esp-idf/esp_gdbstub/libesp_gdbstub.a  esp-idf/driver/libdriver.a  esp-idf/xtensa/libxtensa.a  esp-idf/perfmon/libperfmon.a  esp-idf/mbedtls/mbedtls/library/libmbedtls.a  esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a  esp-idf/mbedtls/mbedtls/library/libmbedx509.a  esp-idf/esp_event/libesp_event.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libcoexist.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libcore.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libespnow.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libmesh.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libnet80211.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libpp.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libsmartconfig.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libwapi.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libphy.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/librtc.a  esp-idf/nghttp/libnghttp.a  esp-idf/tcp_transport/libtcp_transport.a  esp-idf/sdmmc/libsdmmc.a  esp-idf/esp_ringbuf/libesp_ringbuf.a  esp-idf/newlib/libnewlib.a  esp-idf/nvs_flash/libnvs_flash.a  esp-idf/lwip/liblwip.a  esp-idf/cxx/libcxx.a  esp-idf/freertos/libfreertos.a  esp-idf/esp_hw_support/libesp_hw_support.a  esp-idf/heap/libheap.a  esp-idf/log/liblog.a  esp-idf/soc/libsoc.a  esp-idf/hal/libhal.a  esp-idf/esp_rom/libesp_rom.a  esp-idf/esp_common/libesp_common.a  esp-idf/esp_system/libesp_system.a  esp-idf/esp32/libesp32.a  esp-idf/esp_netif/libesp_netif.a  esp-idf/spi_flash/libspi_flash.a  esp-idf/mbedtls/libmbedtls.a  esp-idf/vfs/libvfs.a  esp-idf/esp_wifi/libesp_wifi.a  esp-idf/esp_eth/libesp_eth.a  esp-idf/tcpip_adapter/libtcpip_adapter.a  esp-idf/pthread/libpthread.a  esp-idf/app_trace/libapp_trace.a  esp-idf/esp_timer/libesp_timer.a  esp-idf/efuse/libefuse.a  esp-idf/espcoredump/libespcoredump.a  esp-idf/esp_ipc/libesp_ipc.a  esp-idf/esp_pm/libesp_pm.a  esp-idf/ulp/libulp.a  esp-idf/esp_http_client/libesp_http_client.a  esp-idf/esp_http_server/libesp_http_server.a  esp-idf/bootloader_support/libbootloader_support.a  esp-idf/app_update/libapp_update.a  esp-idf/wpa_supplicant/libwpa_supplicant.a  esp-idf/esp_serial_slave_link/libesp_serial_slave_link.a  esp-idf/esp-tls/libesp-tls.a  esp-idf/esp_https_ota/libesp_https_ota.a  esp-idf/esp_gdbstub/libesp_gdbstub.a  esp-idf/driver/libdriver.a  esp-idf/xtensa/libxtensa.a  esp-idf/perfmon/libperfmon.a  esp-idf/mbedtls/mbedtls/library/libmbedtls.a  esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a  esp-idf/mbedtls/mbedtls/library/libmbedx509.a  esp-idf/esp_event/libesp_event.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libcoexist.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libcore.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libespnow.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libmesh.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libnet80211.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libpp.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libsmartconfig.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libwapi.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libphy.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/librtc.a  esp-idf/nghttp/libnghttp.a  esp-idf/tcp_transport/libtcp_transport.a  esp-idf/sdmmc/libsdmmc.a  esp-idf/esp_ringbuf/libesp_ringbuf.a  esp-idf/newlib/libnewlib.a  esp-idf/nvs_flash/libnvs_flash.a  esp-idf/lwip/liblwip.a  esp-idf/cxx/libcxx.a  esp-idf/freertos/libfreertos.a  esp-idf/esp_hw_support/libesp_hw_support.a  esp-idf/heap/libheap.a  esp-idf/log/liblog.a  esp-idf/soc/libsoc.a  esp-idf/hal/libhal.a  esp-idf/esp_rom/libesp_rom.a  esp-idf/esp_common/libesp_common.a  esp-idf/esp_system/libesp_system.a  esp-idf/esp32/libesp32.a  esp-idf/esp_netif/libesp_netif.a  esp-idf/spi_flash/libspi_flash.a  esp-idf/mbedtls/libmbedtls.a  esp-idf/vfs/libvfs.a  esp-idf/esp_wifi/libesp_wifi.a  esp-idf/esp_eth/libesp_eth.a  esp-idf/tcpip_adapter/libtcpip_adapter.a  esp-idf/pthread/libpthread.a  esp-idf/app_trace/libapp_trace.a  esp-idf/esp_timer/libesp_timer.a  esp-idf/efuse/libefuse.a  esp-idf/espcoredump/libespcoredump.a  esp-idf/esp_ipc/libesp_ipc.a  esp-idf/esp_pm/libesp_pm.a  esp-idf/ulp/libulp.a  esp-idf/esp_http_client/libesp_http_client.a  esp-idf/esp_http_server/libesp_http_server.a  esp-idf/bootloader_support/libbootloader_support.a  esp-idf/app_update/libapp_update.a  esp-idf/wpa_supplicant/libwpa_supplicant.a  esp-idf/esp_serial_slave_link/libesp_serial_slave_link.a  esp-idf/esp-tls/libesp-tls.a  esp-idf/esp_https_ota/libesp_https_ota.a  esp-idf/esp_gdbstub/libesp_gdbstub.a  esp-idf/driver/libdriver.a  esp-idf/xtensa/libxtensa.a  esp-idf/perfmon/libperfmon.a  esp-idf/mbedtls/mbedtls/library/libmbedtls.a  esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a  esp-idf/mbedtls/mbedtls/library/libmbedx509.a  esp-idf/esp_event/libesp_event.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libcoexist.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libcore.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libespnow.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libmesh.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libnet80211.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libpp.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libsmartconfig.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libwapi.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libphy.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/librtc.a  esp-idf/nghttp/libnghttp.a  esp-idf/tcp_transport/libtcp_transport.a  esp-idf/sdmmc/libsdmmc.a  esp-idf/esp_ringbuf/libesp_ringbuf.a  esp-idf/newlib/libnewlib.a  esp-idf/nvs_flash/libnvs_flash.a  esp-idf/lwip/liblwip.a  esp-idf/cxx/libcxx.a  esp-idf/freertos/libfreertos.a  esp-idf/esp_hw_support/libesp_hw_support.a  esp-idf/heap/libheap.a  esp-idf/log/liblog.a  esp-idf/soc/libsoc.a  esp-idf/hal/libhal.a  esp-idf/esp_rom/libesp_rom.a  esp-idf/esp_common/libesp_common.a  esp-idf/esp_system/libesp_system.a  esp-idf/esp32/libesp32.a  esp-idf/esp_netif/libesp_netif.a  esp-idf/spi_flash/libspi_flash.a  esp-idf/mbedtls/libmbedtls.a  esp-idf/vfs/libvfs.a  esp-idf/esp_wifi/libesp_wifi.a  esp-idf/esp_eth/libesp_eth.a  esp-idf/tcpip_adapter/libtcpip_adapter.a  esp-idf/pthread/libpthread.a  esp-idf/app_trace/libapp_trace.a  esp-idf/esp_timer/libesp_timer.a  esp-idf/efuse/libefuse.a  esp-idf/espcoredump/libespcoredump.a  esp-idf/esp_ipc/libesp_ipc.a  esp-idf/esp_pm/libesp_pm.a  esp-idf/ulp/libulp.a  esp-idf/esp_http_client/libesp_http_client.a  esp-idf/esp_http_server/libesp_http_server.a  esp-idf/bootloader_support/libbootloader_support.a  esp-idf/app_update/libapp_update.a  esp-idf/wpa_supplicant/libwpa_supplicant.a  esp-idf/esp_serial_slave_link/libesp_serial_slave_link.a  esp-idf/esp-tls/libesp-tls.a  esp-idf/esp_https_ota/libesp_https_ota.a  esp-idf/esp_gdbstub/libesp_gdbstub.a  esp-idf/driver/libdriver.a  esp-idf/xtensa/libxtensa.a  esp-idf/perfmon/libperfmon.a  esp-idf/mbedtls/mbedtls/library/libmbedtls.a  esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a  esp-idf/mbedtls/mbedtls/library/libmbedx509.a  esp-idf/esp_event/libesp_event.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libcoexist.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libcore.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libespnow.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libmesh.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libnet80211.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libpp.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libsmartconfig.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libwapi.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/libphy.a  /opt/esp-idf-sdk/components/esp_wifi/lib/esp32/librtc.a  esp-idf/nghttp/libnghttp.a  esp-idf/tcp_transport/libtcp_transport.a  esp-idf/sdmmc/libsdmmc.a  esp-idf/esp_ringbuf/libesp_ringbuf.a  -lm  esp-idf/newlib/libnewlib.a  -u newlib_include_heap_impl  -u newlib_include_syscalls_impl  -u newlib_include_pthread_impl  -u __cxa_guard_dummy  -lstdc++  esp-idf/pthread/libpthread.a  -u __cxx_fatal_exception  -Wl,--undefined=uxTopUsedPriority  -u app_main  -L /opt/esp-idf-sdk/components/esp_rom/esp32/ld  -T esp32.rom.ld  -T esp32.rom.api.ld  -T esp32.rom.libgcc.ld  -T esp32.rom.newlib-data.ld  -T esp32.rom.syscalls.ld  -T esp32.rom.newlib-funcs.ld  -T esp32.rom.newlib-time.ld  -Wl,--gc-sections  -u ld_include_panic_highint_hdl  -u start_app  -u start_app_other_cores  -lgcc  -L /tmp/tcp_echo_server/build/esp-idf/esp32  -T esp32_out.ld  -L /tmp/tcp_echo_server/build/esp-idf/esp32/ld  -T esp32.project.ld  -L /opt/esp-idf-sdk/components/esp32/ld  -T esp32.peripherals.ld  -u call_user_start_cpu0  -Wl,--wrap=mbedtls_mpi_exp_mod  -u vfs_include_syscalls_impl  -L /opt/esp-idf-sdk/components/esp_wifi/lib/esp32  -u pthread_include_pthread_impl  -u pthread_include_pthread_cond_impl  -u pthread_include_pthread_local_storage_impl  esp-idf/app_trace/libapp_trace.a  -lgcov  esp-idf/app_trace/libapp_trace.a  -lgcov  -lc  -u esp_app_desc  /opt/esp-idf-sdk/components/xtensa/esp32/libxt_hal.a && :
$HOME/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: CMakeFiles/asio_tcp_echo_server.elf.dir/main/echo_server.cpp.obj:(.rodata._ZTIN4asio6detail30execution_context_service_baseINS0_23reactive_socket_serviceINS_2ip3tcpEEEEE[typeinfo for asio::detail::execution_context_service_base<asio::detail::reactive_socket_service<asio::ip::tcp> >]+0x8): undefined reference to `typeinfo for asio::execution_context::service'
collect2: error: ld returned 1 exit status

Other items if possible

N/A

haffmans commented 3 years ago

Turns out the final executable needs to be built with the -fno-rtti flag enabled to work around this.

I think it makes sense to add this to the CXX_Flags in the shipped toolchain file (tools/cmake/toolchain-esp32.cmake), but adding it to a custom toolchain file works too:

set(CMAKE_SYSTEM_NAME Generic)

set(CMAKE_C_COMPILER xtensa-esp32-elf-gcc)
set(CMAKE_CXX_COMPILER xtensa-esp32-elf-g++)
set(CMAKE_ASM_COMPILER xtensa-esp32-elf-gcc)

set(CMAKE_C_FLAGS "-mlongcalls -Wno-frame-address" CACHE STRING "C Compiler Base Flags")
set(CMAKE_CXX_FLAGS "-mlongcalls -Wno-frame-address -fno-rtti" CACHE STRING "C++ Compiler Base Flags")

Another alternative work-around is adding it to the interface compile options of the __idf_asio target:

target_compile_options(__idf_asio INTERFACE -fno-rtti)

david-cermak commented 3 years ago

Hi @haffmans

Thanks for making us aware of this problem on passing a configuration to the components and the project when building using custom CMake.

As for the asio, it could be build with rtti both on and off. Let me add some more to the list of your workarounds:

We could also check directly if the compiler's rtti is enabled in asio:

diff --git a/components/asio/port/include/esp_asio_config.h b/components/asio/port/include/esp_asio_config.h
index cba316527e..ebff60c806 100644
--- a/components/asio/port/include/esp_asio_config.h
+++ b/components/asio/port/include/esp_asio_config.h
@@ -14,9 +14,9 @@
 #  define ASIO_NO_EXCEPTIONS
 # endif   // CONFIG_COMPILER_CXX_EXCEPTIONS

-# ifndef CONFIG_COMPILER_RTTI
+# ifndef __GXX_RTTI
 #  define ASIO_NO_TYPEID
-# endif   // CONFIG_COMPILER_RTTI
+# endif   // __GXX_RTTI

 //
 // LWIP compatibility inet and address macros/functions