godotengine / godotengine/godot-cpp

Linking error on macOS with Clang: missing TLS wrapper __ZTW symbols for Wrapped class.

Open
#1,892 2 comments 2 reactions 0 assignees View on GitHub
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.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.