Undefined reference errors using pre-compiled class

Testing use of pre-compiled library. I'm getting an "undefined reference" error. The .a file was created in ESP-IDF as a test case. Eventually I need to create a class there because of some issues with the USB-HOST support for an ESP32-S3.

Appreciate any help.

library.properties

name=Hello
version=0.0.1
author=Nomlas
sentence=Testing precompiled library from ESP-IDF
paragraph=
category=Communication
url=https://github.com/Salmon
architectures=*
dot_a_linkage=true
precompiled=full

The .a file was compiled from these. Tested fine within ESP-IDF.
Header

#pragma once
class Hello
{
public:
    Hello();
    void sayHello();
};

Implementation

#include "Hello.h"
#include "esp_log.h"

static const char *TAG = "HelloSays";

Hello::Hello()
{
    ESP_LOGI(TAG, "Constructed Hello...");
}

void Hello::sayHello()
{
    ESP_LOGI(TAG, "Hi there1");
}

Test case

#include "Hello.h"
void setup() {
     Hello speak;
     speak.sayHello();
}

void loop() {}

Errors

 undefined reference to Hello::Hello()
 undefined reference to Hello::sayHello()
 in function `setup()':

Make that global?

Thanks for responding. It should be, but since I'm only referencing the object in setup it's OK.

It seems that the Arduino build system is finding your header fine, but it’s not actually linking your libHello.a into the final binary, which is why you would get the “undefined reference” errors.

Did you call the library libHello.a ?

Is it in the right place ? I think it has to live inside src/ in your library folder: libraries/Hello/src/libHello.a and how did you compile it (did you target the S3?)

AFAIR a private (project specific) library also can reside in a library folder inside the sketch folder.

Right - could be there too I guess

Thank you both. The compile did target the S3 and name is libHello.a. I've tried placing a copy at every level I could find any references to in my private library and the one in \arduino15\libraries.

C:\dev\SKETCHBOOK\libraries\ **Hello** >tree
Folder PATH listing for volume Windows
Volume serial number is 34E4-1A1F
C:.
└───src
   └───esp32
       └───esp32s3
C:/Users/Chuck/AppData/Local/Arduino15/packages/esp32/tools/esp-x32/2411/bin/../lib/gcc/xt
C:\dev\SKETCHBOOK\Precompile_test/Precompile_test.ino:4:(.text._Z5setupv+0x6): undefined r
C:/Users/Chuck/AppData/Local/Arduino15/packages/esp32/tools/esp-x32/2411/bin/../lib/gcc/xt
**collect2.exe: error: ld returned 1 exit status**
Multiple libraries were found for "Hello.h"
 Used: C:\dev\SKETCHBOOK\libraries\Hello
 Not used: C:\Users\Chuck\AppData\Local\Arduino15\libraries\Hello
**Using library Hello in folder: C:\dev\SKETCHBOOK\libraries\Hello (legacy)**

I interpret this to mean that the linker is finding the correct library but having finding the actual .a file, or finding the file and not finding the class declaration in the... we used to call it symbol table, in the object module.

Maybe it's some kind of extern / name-mangling thing? I guess I could try and find a way to dump the object module, but that's something I haven't done since the 60's on s/360 systems! I did run an ar command and it shows the .o file is in the "archive".

Update ---- I tried deleting the .a file and I get exactly the same messages, so it seems the loader really isn't finding it and not a problem with its contents.

can you check what's inside the library - something like

xtensa-esp32s3-elf-ar t libHello.a

you should verify it actually contains Hello.o with C++ symbols

xtensa-esp32s3-elf-nm libHello.a | grep Hello

also - I think the Arduino IDE only looks one level deep for architecture-specific precompiled archives, not two so this might be an issue

in your library properties, can you try this (changed architectures)

name=Hello
version=0.0.1
author=Nomlas
sentence=Testing precompiled library from ESP-IDF
paragraph=
category=Communication
url=https://github.com/Salmon
architectures=esp32
dot_a_linkage=true
precompiled=full

and organize the code as this

libraries/Hello/
└───library.properties
└───src/
└───── Hello.h
└───── esp32/
└───────── libHello.a

Seems OK. But, per last experiment, I don't think it's ever finding it to process.

C:\dev\SKETCHBOOK\libraries\Hello>xtensa-esp32s3-elf-nm libHello.a | grep Hello                           
Hello.cpp.obj:
00000000 T _ZN5Hello8sayHelloEv
00000000 T _ZN5HelloC1Ev
00000000 T _ZN5HelloC2Ev

Yes - that confirms your archive is fine. The symbols like _ZN5HelloC1Ev and _ZN5Hello8sayHelloEv are the mangled names for Hello::Hello() and Hello::sayHello() , and the T indicates they are defined in the text section.

You should try next the layout - may be it's just that...

Tried your suggestion - getting closer. Can't quite figure out this message.

C:/Users/Chuck/AppData/Local/Arduino15/packages/esp32/tools/esp-x32/2411/bin/../lib/gcc/xtensa-esp-elf/14.2.0/../../../../xtensa-esp-elf/bin/ld.exe: cannot find C:\Users\Chuck\AppData\Local\arduino\sketches\994B45CE06D93F6B3F616DE99D8489C4\libraries\Hello\Hello.a: No such file or directory

Tried with and without the linker flags - same result.

    name=Hello
    version=0.0.1
    author=Nomlas
    sentence=Testing precompiled library from ESP-IDF
    paragraph=
    category=Communication
    url=https://github.com/Salmon
    architectures=esp32
    dot_a_linkage=true
    precompiled=full
    ldflags=-lHello

The oddly named folder in the error message exists, but is empty. I guess some previous step failed to build it?

Just to confirm your file structure:

The main folder is

C:/Users/Chuck/Documents/Arduino/libraries/Hello/

Inside that folder, you have library.properties containing:

name=Hello
version=0.0.1
author=Nomlas
sentence=Testing precompiled library from ESP-IDF
paragraph=
category=Communication
url=https://github.com/Salmon
architectures=esp32
precompiled=full
dot_a_linkage=true
ldflags=-lHello

Then a src folder containing
Hello.h ➜ the header needed by your sketch
then a subdirectory esp32 in which you have libHello.a ➜ the precompiled library compiled for the ESP32 architecture

So the full paths are:

C:/Users/Chuck/Documents/Arduino/libraries/Hello/
C:/Users/Chuck/Documents/Arduino/libraries/Hello/src/Hello.h
C:/Users/Chuck/Documents/Arduino/libraries/Hello/src/esp32/libHello.a

is that what you have?

can you also duplicate the libHello.a file next to Hello.h?

Except for sketchbook location, I think it's what you suggested. Copying the .a made no difference. This is going to be something really stupid I've done.... thanks for staying with me.

C:\dev\SKETCHBOOK\libraries\Hello>ls
library.properties  src

C:\dev\SKETCHBOOK\libraries\Hello>cat library.properties
    name=Hello
    version=0.0.1
    author=Nomlas
    sentence=Testing precompiled library from ESP-IDF
    paragraph=
    category=Communication
    url=https://github.com/Salmon
    architectures=esp32
    dot_a_linkage=true
    precompiled=full
    ldflags=-lHello

C:\dev\SKETCHBOOK\libraries\Hello>ls src
Hello.h  esp32

C:\dev\SKETCHBOOK\libraries\Hello>ls src\esp32
libHello.a

Bingo! I changed the directory to esp32s3 and it worked! Apparently it has to be the exact name as in the boards.txt file. I'm not getting any output, but that's a new battle.

Thank you very much for working with me. I'd been fighting this for 3 days and desperately needed the focus you supplied.

Since you mentioned it

Adding word wrap and an additional indent to the very long linker command will make it easier to see the paths and files. (Don't know what the equivalent of sed is on Windows)

$ pbpaste | sed 's/ /\n /g' | sed 's/\(sketches\/[0-9A-Z]*\)/\1\n\t/g'
/Users/kenb4/Library/Arduino15/packages/esp32/tools/esp-x32/2302/bin/xtensa-esp32-elf-g++
 @/Users/kenb4/Library/Arduino15/packages/esp32/tools/esp32-arduino-libs/idf-release_v5.1-632e0c2a/esp32/flags/ld_flags
 @/Users/kenb4/Library/Arduino15/packages/esp32/tools/esp32-arduino-libs/idf-release_v5.1-632e0c2a/esp32/flags/ld_scripts
 -Wl,--Map=/private/var/folders/rf/_lcbkycs7pld4c0vk5xd53sr0000gn/T/arduino/sketches/EA243980B16EE70D070DC90BE93C5103
	/sketch_aug16b.ino.map
 -L/Users/kenb4/Library/Arduino15/packages/esp32/tools/esp32-arduino-libs/idf-release_v5.1-632e0c2a/esp32/lib
 -L/Users/kenb4/Library/Arduino15/packages/esp32/tools/esp32-arduino-libs/idf-release_v5.1-632e0c2a/esp32/ld
 -L/Users/kenb4/Library/Arduino15/packages/esp32/tools/esp32-arduino-libs/idf-release_v5.1-632e0c2a/esp32/qio_qspi
 -Wl,--wrap=esp_panic_handler
 -Wl,--start-group
 /private/var/folders/rf/_lcbkycs7pld4c0vk5xd53sr0000gn/T/arduino/sketches/EA243980B16EE70D070DC90BE93C5103
	/sketch/sketch_aug16b.ino.cpp.o
 /private/var/folders/rf/_lcbkycs7pld4c0vk5xd53sr0000gn/T/arduino/sketches/EA243980B16EE70D070DC90BE93C5103
	/libraries/ArduinoMqttClient/MqttClient.cpp.o
 /private/var/folders/rf/_lcbkycs7pld4c0vk5xd53sr0000gn/T/arduino/cores/29338a0067ee74818556beb73ef33b63/core.a
 @/Users/kenb4/Library/Arduino15/packages/esp32/tools/esp32-arduino-libs/idf-release_v5.1-632e0c2a/esp32/flags/ld_libs
 -Wl,--end-group
 -Wl,-EL
 -o
 /private/var/folders/rf/_lcbkycs7pld4c0vk5xd53sr0000gn/T/arduino/sketches/EA243980B16EE70D070DC90BE93C5103
	/sketch_aug16b.ino.elf

Builds happen on a temp directory tree. (This is a Mac, so it's deep under /private/var)

  • arduino
    • sketches
      • per-sketch hash (with uppercase letters)
        • sketch
          • object file for sketch: .ino.cpp.o
        • libraries
          • each library
            • each .o
            • and apparently each .a
        • resulting .ino.elf also ends up here
    • cores
      • per-core hash (with lowercase letters -- guess it was done separately)
        • core.a

Thanks for that. I'm getting a new appreciation for the complexity of build systems now that I've worked with Arduino, PlatformIO, and ESP-IDF. So hard to grok messages with the ridiculously long paths.

Glad you solved it !