godotengine / godotengine/godot-cpp
Linking error on macOS with Clang: missing TLS wrapper __ZTW symbols for Wrapped class.
- Dominant language
- C++
- Stars
- 2.7k
- Forks
- 809
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 8
Description
### Godot version
4.5.1.stable.official.f62fdbde1
### godot-cpp version
4.5 commit: da26c1732ee8656ef9ccad587cbdd55acf8637c8
### System information
macOS (Intel x86_64), Clang compiler.
### Issue description
**Linking error on macOS (Clang x86_64): missing TLS wrapper `__ZTW` symbols for `Wrapped` class**
I am encountering a runtime linking error when compiling a GDExtension on macOS (Intel x86_64) using Clang against the latest `godot-cpp` master branch (targeting Godot 4.5.1).
Despite compiling both `godot-cpp` and my extension with `target=template_debug` and ensuring `-fvisibility=default` is set, the linker fails to find the Thread Local Storage (TLS) wrapper functions for the `godot::Wrapped` class variables when loading the dylib.
**Error Message:**
```text
Error: Can't open dynamic library: .../libjrpg_core_sdk.dylib.
Error: dlopen(...): symbol not found in flat namespace '__ZTWN5godot7Wrapped34_constructing_extension_class_nameE'
```
**Investigation & Findings:**
1. I inspected the generated static library `libgodot-cpp.macos.template_debug.x86_64.a` using `nm -a`.
2. The output shows that the `thread_local` variables themselves are present (marked as `S` - data section), but their corresponding TLS wrapper functions (mangled as `__ZTW...`) are **missing entirely**.
3. It appears that the macOS Clang compiler is optimizing out (dead-stripping) these TLS wrapper functions because they are not explicitly called within the `godot-cpp` translation units.
4. Adding `__attribute__((used))` to the variables in `wrapped.cpp` did not fix it.
**Workaround:**
I was only able to make it work by manually implementing the wrapper functions in `wrapped.cpp` via `extern "C"` to match the mangled names expected by the linker:
```cpp
// Manual workaround in wrapped.cpp
extern "C" {
void* __attribute__((visibility("default"))) __attribute__((used))
_ZTWN5godot7Wrapped34_constructing_extension_class_nameE() {
return (void*)&godot::Wrapped::_constructing_extension_class_name;
}
// ... same for _constructing_class_binding_callbacks
}
```
This suggests that `godot-cpp` needs a more robust way to ensure these TLS wrappers are generated and exported in static libraries on macOS/Clang.
### Steps to reproduce
1. Clone `godot-cpp` (master branch).
2. Use Godot 4.5.1 (stable/official) to dump the `extension_api.json`.
3. Compile `godot-cpp` on macOS (Intel x86_64) with Clang:
```bash
scons platform=macos target=template_debug arch=x86_64 use_llvm=yes
```
4. Compile a GDExtension project linking against this library (also using `template_debug` and `clang++`).
5. Run the project in Godot Editor.
6. Observe the `dlopen` error in the console regarding `symbol not found in flat namespace '__ZTW...'`.
### Minimal reproduction project
N/A
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.