Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zig c++ fails to compile for x86_64-linux-gnu: "Undefined symbol: __cxa_thread_atexit_impl" #9412

Closed
TheSpydog opened this issue Jul 18, 2021 · 8 comments · Fixed by #18171
Closed
Labels
arch-x86_64 bug Observed behavior contradicts documented or intended behavior os-linux
Milestone

Comments

@TheSpydog
Copy link

I'm attempting to build a .NET NativeAOT project using zig c++ -target x86_linux-gnu as the system compiler/linker, so that it can build with a low glibc (2.17) instead of my Linux machine's actual libc. So far it seems to be working surprisingly well, but there is one build error that I'm not sure how to properly fix:

ld.lld : error : undefined symbol: __cxa_thread_atexit_impl [/home/calebcornett/dev/flotilla/SpaceShooter/Flotilla.SDL2.Core.csproj]
  >>> referenced by cxa_thread_atexit.cpp
  >>>               /home/calebcornett/.cache/zig/o/9ce5e078b5e6082394b4d462fd77ab1c/cxa_thread_atexit.o:(__cxa_thread_atexit) in archive /home/calebcornett/.cache/zig/o/71710f341d4f94a1eba2a0e167fafa1e/libc++abi.a
  >>> did you mean: __cxa_thread_atexit_impl@GLIBC_2.18
  >>> defined in: /home/calebcornett/.cache/zig/o/fdbd9d71c34a562c7053a91a4cec8d55/libc.so.6

I was able to work around this by #undef'ing HAVE___CXA_THREAD_ATEXIT_IMPL in cxa_thread_atexit.cpp and then removing lines 115-117, but that seems like a terrible hack.

I'm not sure why HAVE__CXA_THREAD_ATEXIT_IMPL is getting defined in the first place, since the targeted glibc doesn't support it. But even if it's not defined, it still tries to use the dynamic __weak__ linkage for the function, which is (apparently?) not supported by clang, so it fails anyway.

@nektro
Copy link
Contributor

nektro commented Jul 18, 2021

set your target to be x86_64-linux-gnu.2.18

@TheSpydog
Copy link
Author

set your target to be x86_64-linux-gnu.2.18

I am intentionally targeting 2.17. This project builds (without zig) on CentOS 7, which has glibc 2.17. The main reason I am interested in compiling with zig in the first place is to avoid having to install a CentOS VM for building this project.

@nektro
Copy link
Contributor

nektro commented Jul 19, 2021

then you have to backport the function from glibc 2.18

  >>> did you mean: __cxa_thread_atexit_impl@GLIBC_2.18
  >>> defined in: /home/calebcornett/.cache/zig/o/fdbd9d71c34a562c7053a91a4cec8d55/libc.so.6

https://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/cxa_thread_atexit_impl.c;h=577ed30931d95a42b5cec67050f90b42e2aecb71;hb=HEAD

@TheSpydog
Copy link
Author

TheSpydog commented Jul 19, 2021

My understanding is that libcxxabi is supposed to polyfill this function for lower glibc versions, by having a backup implementation in case no actual __cxa_thread_atexit_impl function is found. But the polyfill seems to assume that the __weak__ attribute here allows this function to link dynamically at runtime (based on the null check here), which Clang apparently does not support. So instead of checking for the function's existence when the app is run, it checks during the linking process instead and always fails as a result.

Backporting the function doesn't seem like it should be necessary if the polyfill could work as expected.

@howardjohn
Copy link

@howardjohn
Copy link

I ran into the same issue. In my case I didn't really care what version of glibc was used, I just want it to work. I was cross compiling amd64 -> arm64, so it was defaulting to glibc 2.17. When I explicitly used linux-gnu.2.18 target, it worked fine.

I realize the original issue wants to use glibc 2.17 explicitly, just noting that it can be worked around by explicitly using 2.18 (or higher, I assume?)

@felixguendling
Copy link

felixguendling commented Aug 9, 2021

I got the same issue, albeit with the musl target:

zig c++ -target x86_64-linux-musl -static -lc++abi test.cc -o test
ld.lld: error: undefined symbol: __cxa_thread_atexit_impl
>>> referenced by cxa_thread_atexit.cpp
>>>               /home/felix/.cache/zig/o/e64c2abe2575938d980d5fd24527ffd4/cxa_thread_atexit.o:(__cxa_thread_atexit) in archive /home/felix/.cache/zig/o/6ea5fd27b3e32b43954dac6a856968cb/libc++abi.a

Minimal example to reproduce:

#include <thread>
#include <iostream>

struct yeah { ~yeah() { std::cout << "destruct thread local\n"; } };
thread_local yeah x;
int main() { std::thread{ []() { std::cout << "hello\n"; } }.join(); }

The above solution does work for glibc. However, is there also a solution for the musl target?

@andrewrk andrewrk added arch-x86_64 os-linux bug Observed behavior contradicts documented or intended behavior labels Nov 20, 2021
@andrewrk andrewrk added this to the 0.10.0 milestone Nov 20, 2021
@pwaller
Copy link

pwaller commented Oct 21, 2022

I've noticed that the build of libcxxabi on my system always reports LIBCXXABI_HAS_CXA_THREAD_ATEXIT_IMPL:INTERNAL=1 even though this isn't present. The cmake --debug-trycompile option (of the libcxxabi build) shows it produces an archive file which nm reports an U (undefined) reference to __cxa_thread_atexit_impl, but it succeeds in creating this file, and check_library_exists then thinks the symbol is available and subsequently sets HAVE___CXA_THREAD_ATEXIT_IMPL.
https://github.com/llvm/llvm-project/blob/d3f5f330671e718a0e28598c412d09e9a3b54273/libcxxabi/cmake/config-ix.cmake#L102
I conclude the detection logic is broken, it looks like check_library_exists may be the wrong cmake function for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-x86_64 bug Observed behavior contradicts documented or intended behavior os-linux
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants