Page 1 of 1

Multiple definition linker issue

Posted: Sat Dec 09, 2023 9:49 pm
by TheWillderness
Hello all,

I would be grateful to get help with this issue. I am running into a multiple definition issue when linking my ESP-IDF project and cannot figure out why. I am using external CMake libraries and linking them to a custom ESP-IDF component called "Device". Then, my main component depends on "Device" component.

Here is the CMakeLists.txt for the "Device" component:

[Codebox]
SET(PROJECT_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../../..)
SET(DEVICE_SRC ${PROJECT_SRC}/Device/)
SET(DEVICE_HAL_SRC ${DEVICE_SRC}/src/Hal/Esp32)
SET(SHARED_SRC ${PROJECT_SRC}/Shared/)
SET(LIB_SRC ${PROJECT_SRC}/lib/)

idf_component_register()

add_subdirectory(${DEVICE_SRC}/src/Core ../../mylib/Device)
add_subdirectory(${SHARED_SRC}/Core ../../mylib/Shared)
add_subdirectory(${LIB_SRC}/nanopb ../../mylib/nanopb)
add_subdirectory(${LIB_SRC}/arduinojson ../../mylib/arduinojson)
add_subdirectory(${LIB_SRC}/Fusion ../../mylib/Fusion)

target_link_libraries(${COMPONENT_LIB} INTERFACE
DeviceLib
)
[/Codebox]

Here is the external "DeviceLib" library's CMakeLists.txt:

[Codebox]
add_library(DeviceLib)

target_link_libraries(DeviceLib SharedLib Fusion)

add_subdirectory(Autopilot)
add_subdirectory(Comm)
add_subdirectory(Device)
add_subdirectory(Hal)
add_subdirectory(Managers)
add_subdirectory(Sensors)
add_subdirectory(Util)

target_include_directories(DeviceLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
[/Codebox]

Note it is linked to "SharedLib".

Here is the CMakeLists.txt for the "main" component:

[Codebox]
SET(PROJECT_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
SET(DEVICE_SRC ${PROJECT_SRC}/Device/)
SET(DEVICE_HAL_SRC ${DEVICE_SRC}/src/Hal/Esp32)
SET(SHARED_SRC ${PROJECT_SRC}/Shared/)
SET(LIB_SRC ${PROJECT_SRC}/lib/)

idf_component_register(
SRCS
${DEVICE_SRC}/src/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DeviceInit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Esp32Device.cpp

${DEVICE_HAL_SRC}/Esp32DeviceBaseHal.cpp
${DEVICE_HAL_SRC}/Esp32I2CConnection.cpp
${DEVICE_HAL_SRC}/Esp32Logging.cpp
${DEVICE_HAL_SRC}/Esp32PwmConnection.cpp
${DEVICE_HAL_SRC}/Esp32SerialConnection.cpp
${DEVICE_HAL_SRC}/Esp32Util.cpp

INCLUDE_DIRS
"."
${DEVICE_HAL_SRC}

REQUIRES driver esp_timer
PRIV_REQUIRES Device
)
[/Codebox]

What I think is happening is that when I call add_subdirectory() in the "Device" component and link the external libraries to the component, somehow those external libraries are also included in the "main" lib, leading to multiple definition issues. Here is the output of building my project:

[Codebox]

[0/1] Re-running CMake...
-- Building ESP-IDF components for target esp32
-- Project sdkconfig file C:/MyProjects/FoxtrotFC/Device/Esp32/sdkconfig
Loading defaults file C:/MyProjects/FoxtrotFC/Device/Esp32/sdkconfig.defaults...
-- App "Esp32" version: 1d896d2-dirty
-- Adding linker script C:/MyProjects/FoxtrotFC/Device/Esp32/build/esp-idf/esp_system/ld/memory.ld
-- Adding linker script C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_system/ld/esp32/sections.ld.in
-- Adding linker script C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_rom/esp32/ld/esp32.rom.ld
-- Adding linker script C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_rom/esp32/ld/esp32.rom.api.ld
-- Adding linker script C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_rom/esp32/ld/esp32.rom.libgcc.ld
-- Adding linker script C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_rom/esp32/ld/esp32.rom.newlib-data.ld
-- Adding linker script C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_rom/esp32/ld/esp32.rom.syscalls.ld
-- Adding linker script C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_rom/esp32/ld/esp32.rom.newlib-funcs.ld
-- Adding linker script C:/Espressif/frameworks/esp-idf-v5.0.1/components/soc/esp32/ld/esp32.peripherals.ld
CMake Warning (dev) at C:/MyProjects/FoxtrotFC/Device/src/Core/CMakeLists.txt:1 (add_library):
ADD_LIBRARY called with SHARED option but the target platform does not
support dynamic linking. Building a STATIC library instead. This may lead
to problems.
This warning is for project developers. Use -Wno-dev to suppress it.

CMake Warning (dev) at C:/MyProjects/FoxtrotFC/Shared/Core/CMakeLists.txt:1 (add_library):
ADD_LIBRARY called with SHARED option but the target platform does not
support dynamic linking. Building a STATIC library instead. This may lead
to problems.
This warning is for project developers. Use -Wno-dev to suppress it.

CMake Warning (dev) at C:/MyProjects/FoxtrotFC/lib/nanopb/CMakeLists.txt:1 (add_library):
ADD_LIBRARY called with SHARED option but the target platform does not
support dynamic linking. Building a STATIC library instead. This may lead
to problems.
This warning is for project developers. Use -Wno-dev to suppress it.

CMake Warning (dev) at C:/MyProjects/FoxtrotFC/lib/Fusion/CMakeLists.txt:3 (add_library):
ADD_LIBRARY called with SHARED option but the target platform does not
support dynamic linking. Building a STATIC library instead. This may lead
to problems.
This warning is for project developers. Use -Wno-dev to suppress it.

-- Components: Device app_trace app_update bootloader bootloader_support bt cmock console cxx driver efuse esp-tls esp_adc esp_app_format esp_common esp_eth esp_event esp_gdbstub esp_hid esp_http_client esp_http_server esp_https_ota esp_https_server esp_hw_support esp_lcd esp_local_ctrl esp_netif esp_partition esp_phy esp_pm esp_psram esp_ringbuf esp_rom esp_system esp_timer esp_wifi espcoredump esptool_py fatfs freertos hal heap
http_parser idf_test ieee802154 json log lwip main mbedtls mqtt newlib nvs_flash openthread partition_table perfmon protobuf-c protocomm pthread sdmmc soc spi_flash spiffs tcp_transport ulp unity usb vfs wear_levelling wifi_provisioning wpa_supplicant xtensa
-- Component paths: C:/MyProjects/FoxtrotFC/Device/Esp32/components/Device C:/Espressif/frameworks/esp-idf-v5.0.1/components/app_trace C:/Espressif/frameworks/esp-idf-v5.0.1/components/app_update C:/Espressif/frameworks/esp-idf-v5.0.1/components/bootloader C:/Espressif/frameworks/esp-idf-v5.0.1/components/bootloader_support C:/Espressif/frameworks/esp-idf-v5.0.1/components/bt C:/Espressif/frameworks/esp-idf-v5.0.1/components/cmock C:/Espressif/frameworks/esp-idf-v5.0.1/components/console C:/Espressif/frameworks/esp-idf-v5.0.1/components/cxx C:/Espressif/frameworks/esp-idf-v5.0.1/components/driver C:/Espressif/frameworks/esp-idf-v5.0.1/components/efuse C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp-tls C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_adc C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_app_format C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_common C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_eth C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_event C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_gdbstub C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_hid C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_http_client C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_http_server C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_https_ota C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_https_server C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_hw_support C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_lcd C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_local_ctrl C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_netif C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_partition C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_phy C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_pm C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_psram C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_ringbuf C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_rom C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_system C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_timer C:/Espressif/frameworks/esp-idf-v5.0.1/components/esp_wifi C:/Espressif/frameworks/esp-idf-v5.0.1/components/espcoredump C:/Espressif/frameworks/esp-idf-v5.0.1/components/esptool_py C:/Espressif/frameworks/esp-idf-v5.0.1/components/fatfs C:/Espressif/frameworks/esp-idf-v5.0.1/components/freertos C:/Espressif/frameworks/esp-idf-v5.0.1/components/hal C:/Espressif/frameworks/esp-idf-v5.0.1/components/heap C:/Espressif/frameworks/esp-idf-v5.0.1/components/http_parser C:/Espressif/frameworks/esp-idf-v5.0.1/components/idf_test C:/Espressif/frameworks/esp-idf-v5.0.1/components/ieee802154 C:/Espressif/frameworks/esp-idf-v5.0.1/components/json C:/Espressif/frameworks/esp-idf-v5.0.1/components/log C:/Espressif/frameworks/esp-idf-v5.0.1/components/lwip C:/MyProjects/FoxtrotFC/Device/Esp32/main C:/Espressif/frameworks/esp-idf-v5.0.1/components/mbedtls C:/Espressif/frameworks/esp-idf-v5.0.1/components/mqtt
C:/Espressif/frameworks/esp-idf-v5.0.1/components/newlib C:/Espressif/frameworks/esp-idf-v5.0.1/components/nvs_flash C:/Espressif/frameworks/esp-idf-v5.0.1/components/openthread C:/Espressif/frameworks/esp-idf-v5.0.1/components/partition_table C:/Espressif/frameworks/esp-idf-v5.0.1/components/perfmon C:/Espressif/frameworks/esp-idf-v5.0.1/components/protobuf-c C:/Espressif/frameworks/esp-idf-v5.0.1/components/protocomm C:/Espressif/frameworks/esp-idf-v5.0.1/components/pthread C:/Espressif/frameworks/esp-idf-v5.0.1/components/sdmmc C:/Espressif/frameworks/esp-idf-v5.0.1/components/soc C:/Espressif/frameworks/esp-idf-v5.0.1/components/spi_flash
C:/Espressif/frameworks/esp-idf-v5.0.1/components/spiffs C:/Espressif/frameworks/esp-idf-v5.0.1/components/tcp_transport C:/Espressif/frameworks/esp-idf-v5.0.1/components/ulp C:/Espressif/frameworks/esp-idf-v5.0.1/components/unity C:/Espressif/frameworks/esp-idf-v5.0.1/components/usb C:/Espressif/frameworks/esp-idf-v5.0.1/components/vfs C:/Espressif/frameworks/esp-idf-v5.0.1/components/wear_levelling C:/Espressif/frameworks/esp-idf-v5.0.1/components/wifi_provisioning C:/Espressif/frameworks/esp-idf-v5.0.1/components/wpa_supplicant C:/Espressif/frameworks/esp-idf-v5.0.1/components/xtensa
-- Configuring done
-- Generating done
-- Build files have been written to: C:/MyProjects/FoxtrotFC/Device/Esp32/build
[1/6] Performing build step for 'bootloader'
[1/1] cmd.exe /C "cd /D C:\MyProjects\FoxtrotFC\Device\Esp32\build\bootloader\esp-idf\esptool_py && C:\Espressif\python_env\idf5.0_py3.8_env\Scripts\python.exe C:/Espressif/frameworks/esp-idf-v5.0.1/components/partition_table/check_sizes.py --offset 0x8000 bootloader 0x1000 C:/MyProjects/FoxtrotFC/Device/Esp32/build/bootloader/bootloader.bin"
Bootloader binary size 0x6710 bytes. 0x8f0 bytes (8%) free.
[2/4] Linking CXX executable Esp32.elf
FAILED: Esp32.elf
cmd.exe /C "cd . && C:\Espressif\tools\xtensa-esp32-elf\esp-2022r1-11.2.0\xtensa-esp32-elf\bin\xtensa-esp32-elf-g++.exe -mlongcalls -Wno-frame-address @CMakeFiles\Esp32.elf.rsp -o Esp32.elf && cd ."
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::init()':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:27: multiple definition of `ILoraRadio::init()'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x64): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::ILoraRadio(Hal::SerialConnection&, unsigned short, unsigned short)':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:15: multiple definition of `ILoraRadio::ILoraRadio(Hal::SerialConnection&, unsigned short, unsigned short)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x0): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::ILoraRadio(Hal::SerialConnection&, unsigned short, unsigned short)':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:15: multiple definition of `ILoraRadio::ILoraRadio(Hal::SerialConnection&, unsigned short, unsigned short)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x0): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::~ILoraRadio()':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:22: multiple definition of `ILoraRadio::~ILoraRadio()'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x38): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::~ILoraRadio()':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:22: multiple definition of `ILoraRadio::~ILoraRadio()'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x38): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::~ILoraRadio()':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:22: multiple definition of `ILoraRadio::~ILoraRadio()'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x4c): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::getError(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:71: multiple definition of `ILoraRadio::getError(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x49c): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::expectResponse(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned long)':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:122: multiple definition of `ILoraRadio::expectResponse(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&, unsigned long)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x79c): first
defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::readData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:32: multiple definition of `ILoraRadio::readData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0x70): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(ILoraRadio.cpp.obj): in function `ILoraRadio::sendData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned short)':
C:/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp:43: multiple definition of `ILoraRadio::sendData(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned short)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Device/src/Core/Sensors/ILoraRadio.cpp.obj:ILoraRadio.cpp:(.text+0xd4): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(BlobUtils.cpp.obj): in function `BlobUtils::getProtoSize(_JsonBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
C:/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp:184: multiple definition of `BlobUtils::getProtoSize(_JsonBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp.obj:BlobUtils.cpp:(.text+0x908): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(BlobUtils.cpp.obj): in function `BlobUtils::encodeProto(unsigned char*, unsigned int, _JsonBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
C:/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp:172: multiple definition of `BlobUtils::encodeProto(unsigned char*, unsigned int, _JsonBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp.obj:BlobUtils.cpp:(.text+0x8bc): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(BlobUtils.cpp.obj): in function `BlobUtils::getBlobFromProto(_CmdBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
C:/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp:252: multiple definition of `BlobUtils::getBlobFromProto(_CmdBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp.obj:BlobUtils.cpp:(.text+0xb2c): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(BlobUtils.cpp.obj): in function `BlobUtils::getBlobFromProto(_NtfnBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
C:/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp:215: multiple definition of `BlobUtils::getBlobFromProto(_NtfnBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp.obj:BlobUtils.cpp:(.text+0x9ac): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(BlobUtils.cpp.obj): in function `BlobUtils::getBlobFromProto(_JsonBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
C:/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp:196: multiple definition of `BlobUtils::getBlobFromProto(_JsonBlobProto const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp.obj:BlobUtils.cpp:(.text+0x958): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(BlobUtils.cpp.obj): in function `BlobUtils::getStringFromBlob(JsonBlob const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
C:/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp:16: multiple definition of `BlobUtils::getStringFromBlob(JsonBlob const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp.obj:BlobUtils.cpp:(.text+0x0): first defined here
c:/espressif/tools/xtensa-esp32-elf/esp-2022r1-11.2.0/xtensa-esp32-elf/bin/../lib/gcc/xtensa-esp32-elf/11.2.0/../../../../xtensa-esp32-elf/bin/ld.exe: esp-idf/main/libmain.a(BlobUtils.cpp.obj): in function `BlobUtils::getBlobFromString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
C:/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp:31: multiple definition of `BlobUtils::getBlobFromString(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'; CMakeFiles/Esp32.elf.dir/C_/MyProjects/FoxtrotFC/Shared/Core/Blobs/BlobUtils.cpp.obj:BlobUtils.cpp:(.text+0x98): first defined here
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

[/Codebox]

I see there are warning at the top that I am suspicious about, but I am not sure that building a static library would cause this issue. Here is the warning: "ADD_LIBRARY called with SHARED option but the target platform does not
support dynamic linking. Building a STATIC library instead. This may lead
to problems."

Any help would be very much appreciated! Thank you!

Re: Multiple definition linker issue

Posted: Sun Dec 10, 2023 3:39 am
by TheWillderness
Update: I have figured it out.

The main issue was the following line:

target_link_libraries(${COMPONENT_LIB} INTERFACE
DeviceLib)

INTERFACE should not be used. It needs to be PRIVATE linkage. However, with PRIVATE linkage, the "main" component does not receive the required headers. So what I ended up doing was removing the "Device" component entirely and instead linking "main" directly to my external libraries. The "main" component's CMakeLists.txt ends up looking like the following, with PRIVATE linkage to "DeviceLib":

SET(PROJECT_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
SET(DEVICE_SRC ${PROJECT_SRC}/Device/)
SET(DEVICE_HAL_SRC ${DEVICE_SRC}/src/Hal/Esp32)
SET(SHARED_SRC ${PROJECT_SRC}/Shared/)
SET(LIB_SRC ${PROJECT_SRC}/lib/)

idf_component_register(
SRCS
${DEVICE_SRC}/src/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DeviceInit.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Esp32Device.cpp

${DEVICE_HAL_SRC}/Esp32DeviceBaseHal.cpp
${DEVICE_HAL_SRC}/Esp32I2CConnection.cpp
${DEVICE_HAL_SRC}/Esp32Logging.cpp
${DEVICE_HAL_SRC}/Esp32PwmConnection.cpp
${DEVICE_HAL_SRC}/Esp32SerialConnection.cpp
${DEVICE_HAL_SRC}/Esp32Util.cpp

INCLUDE_DIRS
"."
${DEVICE_HAL_SRC}

REQUIRES driver esp_timer
)

add_subdirectory(${DEVICE_SRC}/src/Core ../build/Device)
add_subdirectory(${SHARED_SRC}/Core ../build/Shared)
add_subdirectory(${LIB_SRC}/nanopb ../build/nanopb)
add_subdirectory(${LIB_SRC}/arduinojson ../build/arduinojson)
add_subdirectory(${LIB_SRC}/Fusion ../build/Fusion)

target_link_libraries(${COMPONENT_LIB} PRIVATE
DeviceLib
)


This article discusses PUBLIC, PRIVATE, and INTERFACE linking: https://cmake.org/pipermail/cmake/2016-May/063400.html