In the Flatpak the MinGW sysroot is the host's /usr, which puts glibc's headers on the Windows include path #43

Closed
opened 2026-10-31 17:59:06 +00:00 by jorijnvdgraaf · 0 comments

Summary

Inside the Flatpak, a MinGW C++ program that uses std::shared_ptr doesn't link:

ld.lld: error: undefined symbol: __libc_single_threaded

The MinGW sysroot crafter-build picks there is the host's /usr, and clang's MinGW driver adds <sysroot>/include whenever --sysroot is given. That puts the host's glibc headers last on the include path of a Windows build. libstdc++'s <ext/atomicity.h> checks __has_include(<sys/single_threaded.h>), finds glibc's copy, and has shared_ptr's reference counting read ::__libc_single_threaded, which nothing on Windows defines.

Line numbers refer to 909e027. Seen with crafter-build 4.0.0 (clang 23.1.2) on an Arch host with mingw-w64 14.0.0 and mingw-w64-gcc 16.2.0.

Details

  • implementations/Crafter.Build-Toolchain.cpp:138-144: without CRAFTER_MINGW_DIR, a sandboxed run sets mingwSysroot = hostRoot / "usr" when the host has /usr/x86_64-w64-mingw32.
  • It becomes --sysroot for C (implementations/Crafter.Build-Clang.cpp:931-933) and C++ (implementations/Crafter.Build-Platform.cpp:867), and -DCMAKE_SYSROOT for CMake externals (implementations/Crafter.Build-External.cpp:152).
  • The search list for clang++ --target=x86_64-w64-mingw32 -stdlib=libstdc++ --sysroot=/run/host/usr ends with the host's own headers:
 /run/host/usr/x86_64-w64-mingw32/include/c++/16.2.0
 /run/host/usr/x86_64-w64-mingw32/include/c++/16.2.0/x86_64-w64-mingw32
 /run/host/usr/x86_64-w64-mingw32/include/c++/16.2.0/backward
 /app/lib/clang/23/include
 /run/host/usr/x86_64-w64-mingw32/include
 /run/host/usr/include

MinGW's own headers come first, so only headers MinGW lacks resolve to Linux's. A __has_include of a Linux-only header then answers yes for Windows. sys/single_threaded.h is the case that breaks the link.

Reproduction

In flatpak run --command=sh net.catcrafts.CrafterBuild:

#include <memory>
#include <string>
#include <cstdio>
int main() { auto p = std::make_shared<std::string>("hi"); std::puts(p->c_str()); }

clang++ --target=x86_64-w64-mingw32 -stdlib=libstdc++ -fuse-ld=lld --sysroot=/run/host/usr t.cpp -o t.exe fails with the error above.

In practice it stops Crafter.Graphics' Win32 executables. Crafter.Asset's GLB loader includes nlohmann/json, whose shared_ptr code in Crafter.Asset-GLB_impl.o ended up in every one built so far: the PointerWin32 and TextWin32 tests, and examples/HelloUI. Those tests have needed an archive defining char __libc_single_threaded = 0; to link.

Suggested fix

Pass a sysroot that has MinGW's layout without the host's include/. A directory holding only two symlinks did it here:

<dir>/x86_64-w64-mingw32 -> /run/host/usr/x86_64-w64-mingw32
<dir>/lib/gcc            -> /run/host/usr/lib/gcc

With --sysroot=<dir>, clang found the same libstdc++ and MinGW headers, sys/single_threaded.h was no longer visible, and the program above linked. crafter-build could make that directory in its cache once and use it wherever mingwSysroot goes now.

Two simpler options don't work. --sysroot=/run/host/usr/x86_64-w64-mingw32 loses libstdc++'s versioned header directory, so <string> is not found. --gcc-toolchain= and --gcc-install-dir= are ignored for this target ("argument unused during compilation").

## Summary Inside the Flatpak, a MinGW C++ program that uses `std::shared_ptr` doesn't link: ``` ld.lld: error: undefined symbol: __libc_single_threaded ``` The MinGW sysroot crafter-build picks there is the host's `/usr`, and clang's MinGW driver adds `<sysroot>/include` whenever `--sysroot` is given. That puts the host's glibc headers last on the include path of a Windows build. libstdc++'s `<ext/atomicity.h>` checks `__has_include(<sys/single_threaded.h>)`, finds glibc's copy, and has `shared_ptr`'s reference counting read `::__libc_single_threaded`, which nothing on Windows defines. Line numbers refer to `909e027`. Seen with crafter-build 4.0.0 (clang 23.1.2) on an Arch host with mingw-w64 14.0.0 and mingw-w64-gcc 16.2.0. ## Details - `implementations/Crafter.Build-Toolchain.cpp:138-144`: without `CRAFTER_MINGW_DIR`, a sandboxed run sets `mingwSysroot = hostRoot / "usr"` when the host has `/usr/x86_64-w64-mingw32`. - It becomes `--sysroot` for C (`implementations/Crafter.Build-Clang.cpp:931-933`) and C++ (`implementations/Crafter.Build-Platform.cpp:867`), and `-DCMAKE_SYSROOT` for CMake externals (`implementations/Crafter.Build-External.cpp:152`). - The search list for `clang++ --target=x86_64-w64-mingw32 -stdlib=libstdc++ --sysroot=/run/host/usr` ends with the host's own headers: ``` /run/host/usr/x86_64-w64-mingw32/include/c++/16.2.0 /run/host/usr/x86_64-w64-mingw32/include/c++/16.2.0/x86_64-w64-mingw32 /run/host/usr/x86_64-w64-mingw32/include/c++/16.2.0/backward /app/lib/clang/23/include /run/host/usr/x86_64-w64-mingw32/include /run/host/usr/include ``` MinGW's own headers come first, so only headers MinGW lacks resolve to Linux's. A `__has_include` of a Linux-only header then answers yes for Windows. `sys/single_threaded.h` is the case that breaks the link. ## Reproduction In `flatpak run --command=sh net.catcrafts.CrafterBuild`: ```cpp #include <memory> #include <string> #include <cstdio> int main() { auto p = std::make_shared<std::string>("hi"); std::puts(p->c_str()); } ``` `clang++ --target=x86_64-w64-mingw32 -stdlib=libstdc++ -fuse-ld=lld --sysroot=/run/host/usr t.cpp -o t.exe` fails with the error above. In practice it stops Crafter.Graphics' Win32 executables. Crafter.Asset's GLB loader includes nlohmann/json, whose `shared_ptr` code in `Crafter.Asset-GLB_impl.o` ended up in every one built so far: the `PointerWin32` and `TextWin32` tests, and `examples/HelloUI`. Those tests have needed an archive defining `char __libc_single_threaded = 0;` to link. ## Suggested fix Pass a sysroot that has MinGW's layout without the host's `include/`. A directory holding only two symlinks did it here: ``` <dir>/x86_64-w64-mingw32 -> /run/host/usr/x86_64-w64-mingw32 <dir>/lib/gcc -> /run/host/usr/lib/gcc ``` With `--sysroot=<dir>`, clang found the same libstdc++ and MinGW headers, `sys/single_threaded.h` was no longer visible, and the program above linked. crafter-build could make that directory in its cache once and use it wherever `mingwSysroot` goes now. Two simpler options don't work. `--sysroot=/run/host/usr/x86_64-w64-mingw32` loses libstdc++'s versioned header directory, so `<string>` is not found. `--gcc-toolchain=` and `--gcc-install-dir=` are ignored for this target ("argument unused during compilation").
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Catcrafts/Crafter.Build#43
No description provided.