Skip to content

Conversation

@iabdalkader
Copy link

@iabdalkader iabdalkader commented Jan 8, 2026

The sketch below fails to link with a loader compiled with/without --debug, with static or dynamic link mode. The errors are multiple definitions of std::__throw_bad_alloc() etc... It seems the specs we're using (picolibc.specs) links libraries compiled with exceptions enabled, which provide those functions. Note that the discard doesn't help here, probably because it comes at a later stage after symbol resolution.

If you simply remove the stubs provided in abi.cpp, the static link mode works, but dynamic fails with errors like the following:

libstdc++.a(eh_arm.o):(.ARM.exidx.text.__cxa_type_match+0x0): undefined reference to `__aeabi_unwind_cpp_pr0'

I think the above proves that exceptions are still enabled, since it's looking for some unwind symbol.

This patch switches to nano.specs, which disables C++ exceptions and provides the needed stubs. I've tested this by building with a loader built with/without --debug and with static/dynamic link modes in each case and all seem to work fine.

#include <memory>
#include <string>
#include <vector>

std::shared_ptr<int> test;
std::string myString;
std::vector<int> myVector;

static void custom_deleter(int *fd) {
    delete fd;
}

void setup() {
    test = nullptr;
    test = std::shared_ptr<int>(nullptr, custom_deleter);

    // Test std::string
    myString = "Hello Arduino";
    myString += " Zephyr!";

    // Test std::vector
    myVector.push_back(1);
    myVector.push_back(2);
    myVector.push_back(3);

    for (auto& val : myVector) {
        val *= 2;
    }
}

void loop() {
}

@iabdalkader
Copy link
Author

For what it's worth, I tested a sketch with nano/pico and I don't see any size difference, which makes sense because most of the savings would be in code that uses stdio functions, memory allocation, math and string functions, which we typically never use. That said, maybe another app/sketch will increase in size slight. So I think it's really a question of when you want this fixed, now or wait for Zephyr/sdk updates.

Note, switching back to pico (when there's one available built with no exceptions) would just require replacing the specs name.

Copy link

@andreagilardoni andreagilardoni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Until we are able to adapt picolibc to our needs and compile it without exceptions I thinks this PR provides a valid solution to our issues

@pillo79
Copy link

pillo79 commented Jan 15, 2026

Ran a full set of build tests using the CI I'm working on, and it indeed fixes the C++ errors on all targets 🥳
However, the run found one tiny new issue only on the unoq:static build:

  /home/runner/.arduino15/packages/zephyr/tools/arm-zephyr-eabi/0.16.8/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld: /home/runner/.arduino15/packages/zephyr/tools/arm-zephyr-eabi/0.16.8/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/lib/thumb/v8-m.main+fp/hard/libm_nano.a(lib_a-w_sqrt.o): in function `sqrt':
  w_sqrt.c:(.text.sqrt+0x3c): undefined reference to `__errno'
  collect2: error: ld returned 1 exit status

(full log here, not much extra detail though)

I suspect the issue is core-wide, but the unoq is the only target where I compiled that function. TBH, not sure how libm and errno interact at all and why it was working before the PR! 👀 🤷‍♂️

@iabdalkader
Copy link
Author

not sure how libm and errno interact at all and why it was working before the PR!

Maybe pico is built with -fno-math-errno? We can just add that.

Copy link

@pillo79 pillo79 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest push fixed it, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std::string doesn't compile

4 participants