espressif / esp-idf

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

Linker issue undefined reference to `__ieee754_sqrtf' (IDFGH-1988) #4183

Closed pgreenland closed 5 years ago

pgreenland commented 5 years ago

Environment

Problem Description

Recently updated esp-idf, switching from GCC 5.2 to GCC 8.2 in the process.

I've a project which includes several "pure" cmake library projects, as described in the documentation https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#using-third-party-cmake-projects-with-components. Previously these were building and linking correctly.

After updating to the latest esp-idf I'm struggling to successfully build my project, with linking failing on my pure cmake libraries which make use of math functions. In my case specifically sqrtf, which results in the following linker error:

/home/user/esp/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.2.0/../../../../xtensa-esp32-elf/bin/ld: /home/user/esp/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.2.0/../../../../xtensa-esp32-elf/lib/libm.a(lib_a-wf_sqrt.o): in functionsqrtf': /builds/idf/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/newlib/libm/math/wf_sqrt.c:35: undefined reference to __ieee754_sqrtf'

Without use of math functions from my external projects the project links, flashes and runs correctly (with the exception of incorrect maths).

Expected Behavior

Linking completes without error when linking in external cmake projects consisting of C libraries which make use of math functions contained within math.h.

Actual Behavior

Linking fails with an undefined reference to a symbol I haven't been able to track down, seemingly related to the internal implementation of the sqrtf function.

Steps to repropduce

  1. Attempt to build attached example project. Based on stripped down hello_world example project, with minimal external C library making use of math.

Code to reproduce this issue

See attached file:

minimal_linker_error_example.tar.gz

Debug Logs

Here's the complete output from a failed build, with the complete log attached complete_build_log.txt:

[835/836] Linking CXX executable hello-world.elf
FAILED: hello-world.elf 
: && /home/user/esp/xtensa-esp32-elf/bin/xtensa-esp32-elf-g++   -mlongcalls -Wno-frame-address  -nostdlib CMakeFiles/hello-world.elf.dir/project_elf_src.c.obj  -o hello-world.elf  esp-idf/esp_ringbuf/libesp_ringbuf.a esp-idf/driver/libdriver.a esp-idf/wpa_supplicant/libwpa_supplicant.a esp-idf/efuse/libefuse.a esp-idf/bootloader_support/libbootloader_support.a esp-idf/app_update/libapp_update.a esp-idf/spi_flash/libspi_flash.a esp-idf/nvs_flash/libnvs_flash.a esp-idf/esp_wifi/libesp_wifi.a esp-idf/esp_eth/libesp_eth.a esp-idf/lwip/liblwip.a esp-idf/tcpip_adapter/libtcpip_adapter.a esp-idf/esp_event/libesp_event.a esp-idf/pthread/libpthread.a esp-idf/espcoredump/libespcoredump.a esp-idf/esp32/libesp32.a esp-idf/xtensa/libxtensa.a esp-idf/esp_common/libesp_common.a esp-idf/esp_rom/libesp_rom.a esp-idf/soc/libsoc.a esp-idf/log/liblog.a esp-idf/heap/libheap.a esp-idf/freertos/libfreertos.a esp-idf/vfs/libvfs.a esp-idf/newlib/libnewlib.a esp-idf/cxx/libcxx.a esp-idf/app_trace/libapp_trace.a esp-idf/asio/libasio.a esp-idf/cbor/libcbor.a esp-idf/coap/libcoap.a esp-idf/console/libconsole.a esp-idf/nghttp/libnghttp.a esp-idf/esp-tls/libesp-tls.a esp-idf/esp_adc_cal/libesp_adc_cal.a esp-idf/esp_gdbstub/libesp_gdbstub.a esp-idf/tcp_transport/libtcp_transport.a esp-idf/esp_http_client/libesp_http_client.a esp-idf/esp_http_server/libesp_http_server.a esp-idf/esp_https_ota/libesp_https_ota.a esp-idf/protobuf-c/libprotobuf-c.a esp-idf/protocomm/libprotocomm.a esp-idf/mdns/libmdns.a esp-idf/esp_local_ctrl/libesp_local_ctrl.a esp-idf/esp_websocket_client/libesp_websocket_client.a esp-idf/expat/libexpat.a esp-idf/wear_levelling/libwear_levelling.a esp-idf/sdmmc/libsdmmc.a esp-idf/fatfs/libfatfs.a esp-idf/freemodbus/libfreemodbus.a esp-idf/jsmn/libjsmn.a esp-idf/json/libjson.a esp-idf/libsodium/liblibsodium.a esp-idf/mqtt/libmqtt.a esp-idf/openssl/libopenssl.a esp-idf/spiffs/libspiffs.a esp-idf/ulp/libulp.a esp-idf/unity/libunity.a esp-idf/wifi_provisioning/libwifi_provisioning.a esp-idf/main/libmain.a -Wl,--cref -Wl,--Map=/home/user/esp/hello_world/build/hello-world.map esp-idf/esp_ringbuf/libesp_ringbuf.a esp-idf/driver/libdriver.a esp-idf/wpa_supplicant/libwpa_supplicant.a esp-idf/efuse/libefuse.a esp-idf/bootloader_support/libbootloader_support.a esp-idf/app_update/libapp_update.a esp-idf/spi_flash/libspi_flash.a esp-idf/nvs_flash/libnvs_flash.a esp-idf/esp_wifi/libesp_wifi.a esp-idf/esp_eth/libesp_eth.a esp-idf/lwip/liblwip.a esp-idf/tcpip_adapter/libtcpip_adapter.a esp-idf/esp_event/libesp_event.a esp-idf/pthread/libpthread.a esp-idf/espcoredump/libespcoredump.a esp-idf/esp32/libesp32.a esp-idf/xtensa/libxtensa.a esp-idf/esp_common/libesp_common.a esp-idf/esp_rom/libesp_rom.a esp-idf/soc/libsoc.a esp-idf/log/liblog.a esp-idf/heap/libheap.a esp-idf/freertos/libfreertos.a esp-idf/vfs/libvfs.a esp-idf/newlib/libnewlib.a esp-idf/cxx/libcxx.a esp-idf/app_trace/libapp_trace.a esp-idf/asio/libasio.a esp-idf/cbor/libcbor.a esp-idf/coap/libcoap.a esp-idf/console/libconsole.a esp-idf/nghttp/libnghttp.a esp-idf/esp-tls/libesp-tls.a esp-idf/esp_adc_cal/libesp_adc_cal.a esp-idf/esp_gdbstub/libesp_gdbstub.a esp-idf/tcp_transport/libtcp_transport.a esp-idf/esp_http_client/libesp_http_client.a esp-idf/esp_http_server/libesp_http_server.a esp-idf/esp_https_ota/libesp_https_ota.a esp-idf/esp_http_client/libesp_http_client.a esp-idf/protobuf-c/libprotobuf-c.a esp-idf/protocomm/libprotocomm.a esp-idf/mdns/libmdns.a esp-idf/esp_local_ctrl/libesp_local_ctrl.a esp-idf/esp_websocket_client/libesp_websocket_client.a esp-idf/expat/libexpat.a esp-idf/wear_levelling/libwear_levelling.a esp-idf/sdmmc/libsdmmc.a esp-idf/fatfs/libfatfs.a esp-idf/wear_levelling/libwear_levelling.a esp-idf/sdmmc/libsdmmc.a esp-idf/freemodbus/libfreemodbus.a esp-idf/jsmn/libjsmn.a esp-idf/json/libjson.a esp-idf/libsodium/liblibsodium.a esp-idf/mqtt/libmqtt.a esp-idf/tcp_transport/libtcp_transport.a esp-idf/esp-tls/libesp-tls.a esp-idf/openssl/libopenssl.a esp-idf/spiffs/libspiffs.a esp-idf/ulp/libulp.a esp-idf/unity/libunity.a esp-idf/wifi_provisioning/libwifi_provisioning.a esp-idf/protocomm/libprotocomm.a esp-idf/esp_http_server/libesp_http_server.a esp-idf/nghttp/libnghttp.a esp-idf/protobuf-c/libprotobuf-c.a esp-idf/mdns/libmdns.a esp-idf/console/libconsole.a esp-idf/json/libjson.a esp-idf/main/examplelib/libexamplelib.a esp-idf/cxx/libcxx.a esp-idf/newlib/libnewlib.a esp-idf/freertos/libfreertos.a esp-idf/heap/libheap.a esp-idf/log/liblog.a esp-idf/soc/libsoc.a esp-idf/esp_rom/libesp_rom.a esp-idf/esp_common/libesp_common.a esp-idf/xtensa/libxtensa.a esp-idf/esp32/libesp32.a esp-idf/esp_ringbuf/libesp_ringbuf.a esp-idf/lwip/liblwip.a esp-idf/mbedtls/mbedtls/library/libmbedtls.a esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a esp-idf/mbedtls/mbedtls/library/libmbedx509.a esp-idf/bootloader_support/libbootloader_support.a esp-idf/spi_flash/libspi_flash.a esp-idf/efuse/libefuse.a esp-idf/app_update/libapp_update.a esp-idf/wpa_supplicant/libwpa_supplicant.a esp-idf/nvs_flash/libnvs_flash.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libcoexist.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libcore.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libespnow.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libmesh.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libnet80211.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libphy.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libpp.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/librtc.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libsmartconfig.a esp-idf/esp_event/libesp_event.a esp-idf/tcpip_adapter/libtcpip_adapter.a esp-idf/driver/libdriver.a esp-idf/vfs/libvfs.a esp-idf/esp_wifi/libesp_wifi.a esp-idf/esp_eth/libesp_eth.a esp-idf/app_trace/libapp_trace.a esp-idf/pthread/libpthread.a esp-idf/espcoredump/libespcoredump.a esp-idf/cxx/libcxx.a esp-idf/newlib/libnewlib.a esp-idf/freertos/libfreertos.a esp-idf/heap/libheap.a esp-idf/log/liblog.a esp-idf/soc/libsoc.a esp-idf/esp_rom/libesp_rom.a esp-idf/esp_common/libesp_common.a esp-idf/xtensa/libxtensa.a esp-idf/esp32/libesp32.a esp-idf/esp_ringbuf/libesp_ringbuf.a esp-idf/lwip/liblwip.a esp-idf/mbedtls/mbedtls/library/libmbedtls.a esp-idf/mbedtls/mbedtls/library/libmbedcrypto.a esp-idf/mbedtls/mbedtls/library/libmbedx509.a esp-idf/bootloader_support/libbootloader_support.a esp-idf/spi_flash/libspi_flash.a esp-idf/efuse/libefuse.a esp-idf/app_update/libapp_update.a esp-idf/wpa_supplicant/libwpa_supplicant.a esp-idf/nvs_flash/libnvs_flash.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libcoexist.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libcore.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libespnow.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libmesh.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libnet80211.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libphy.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libpp.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/librtc.a /home/user/esp/esp-idf/components/esp_wifi/lib_esp32/libsmartconfig.a esp-idf/esp_event/libesp_event.a esp-idf/tcpip_adapter/libtcpip_adapter.a esp-idf/driver/libdriver.a esp-idf/vfs/libvfs.a esp-idf/esp_wifi/libesp_wifi.a esp-idf/esp_eth/libesp_eth.a esp-idf/app_trace/libapp_trace.a esp-idf/pthread/libpthread.a esp-idf/espcoredump/libespcoredump.a -u __cxa_guard_dummy -lstdc++ esp-idf/pthread/libpthread.a -u __cxx_fatal_exception esp-idf/newlib/libnewlib.a -u newlib_include_locks_impl -u newlib_include_heap_impl -u newlib_include_syscalls_impl -u newlib_include_pthread_impl -Wl,--undefined=uxTopUsedPriority -L /home/user/esp/esp-idf/components/esp_rom/esp32/ld -T esp32.rom.ld -T esp32.rom.libgcc.ld -T esp32.rom.syscalls.ld -T esp32.rom.newlib-data.ld -T esp32.rom.newlib-funcs.ld -Wl,--gc-sections /home/user/esp/esp-idf/components/xtensa/esp32/libhal.a -L /home/user/esp/hello_world/build/esp-idf/esp32 -T esp32_out.ld -u app_main -L /home/user/esp/hello_world/build/esp-idf/esp32/ld -T esp32.project.ld -L /home/user/esp/esp-idf/components/esp32/ld -T esp32.peripherals.ld -u call_user_start_cpu0 -u ld_include_panic_highint_hdl -u esp_app_desc -u vfs_include_syscalls_impl -L /home/user/esp/esp-idf/components/esp_wifi/lib_esp32 -lgcov -lc -lgcc -u pthread_include_pthread_impl -u pthread_include_pthread_cond_impl -u pthread_include_pthread_local_storage_impl -lm && :
/home/user/esp/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.2.0/../../../../xtensa-esp32-elf/bin/ld: /home/user/esp/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.2.0/../../../../xtensa-esp32-elf/lib/libm.a(lib_a-wf_sqrt.o):(.literal+0x8): undefined reference to `__ieee754_sqrtf'
/home/user/esp/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.2.0/../../../../xtensa-esp32-elf/bin/ld: /home/user/esp/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/8.2.0/../../../../xtensa-esp32-elf/lib/libm.a(lib_a-wf_sqrt.o): in function `sqrtf':
/builds/idf/crosstool-NG/.build/xtensa-esp32-elf/src/newlib/newlib/libm/math/wf_sqrt.c:35: undefined reference to `__ieee754_sqrtf'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
ninja failed with exit code 1
projectgus commented 5 years ago

Hi @pgreenland,

Thanks for the detailed bug report and the example project, it made reproducing this straightforward. Much appreciated.

In gcc 8 __ieee754_sqrtf() is defined in libgcc not libm (I believe the reason for this is that it uses the floating point instructions, and this code lives in native libgcc not libc libm, although there might be some other toolchain-oriented reason).

You can resolve the issue by changing the dependencies line in externallib/CMakeLists.txt as follows:

target_link_libraries(examplelib m gcc)

This moves -lgcc after -lm in the linker arguments list.

If doing this in the external project is not viable, you can also do it in the parent component but only with CMake 3.13 or newer:

add_subdirectory(../examplelib examplelib)

target_link_libraries(${COMPONENT_TARGET} PRIVATE examplelib)
cmake_policy(SET CMP0079 NEW)
target_link_libraries(examplelib m gcc)

I looked to see if we can fix this on the IDF side but it doesn't look CMake will allow us to (we can make a CMake library target depend on specific libraries, but we can't create dependencies between two external libraries like libm & libgcc. For IDF components the order is preserved because we add target_link_libraries ... c m gcc) in a fixed order always, but for external libraries this doesn't necessarily happen and CMake will add the libraries to the link line in the order it sees them.

pgreenland commented 5 years ago

Hey @projectgus,

Thanks for the lightning fast reply.

I'd found one reference to that function in the source for libgcc during a google session - was trying hard not to reveal too many of the magicians secrets though :-P.

Linking against both libm and libgcc, in that order for the correct symbol resolution works nicely for the example project.

Strangely when I do exactly the same thing for my larger project within the library cmake file itself as you describe it doesn't link.

Looking at the command line output on error it appears that both -lm and -lgcc are there, but in the wrong order still. The end of the command line being:

-L /home/user/esp/esp-idf/components/esp_wifi/lib_esp32 -lgcov -lc -lgcc -lm -u pthread_include_pthread_impl -u pthread_include_pthread_cond_impl -u pthread_include_pthread_local_storage_impl

I'm far from an expert at CMake unfortunately, although it's been going well up until now :-P. Other users report that the order of libraries in target_link_libraries should be respected for this sort of reason. For me it doesn't seem to be. I am using the version in the Debian mirrors, which is a tad out of date at 3.7.2.

For now my solution is to bodge via the CMAKE_CXX_LINK_EXECUTABLE variable, which seems to work quite nicely.

set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -lm -lgcc")

With that I'm back in business....while only feeling a little dirty :-P.

Thanks for the help, I'd have been at this for an age without that pointer.

projectgus commented 5 years ago

Hi @pgreenland ,

Glad that this got you going again.

Strangely when I do exactly the same thing for my larger project within the library cmake file itself as you describe it doesn't link.

This might be a CMake bug? It would be interesting to know if also fails on newer CMake.

Clever kludge in any case, I'm glad it's got you up and running again. :)