Re: Request to update libc++ related packages for current Clang/LLVM toolchain

Takashi Yano via Cygwin <[email protected]>
Newsgroups gmane.os.cygwin
Message-ID <[email protected]>
Hi Tomohiro,

On Fri, 23 Jan 2026 12:28:51 +0000
kikairoya via Cygwin <[email protected]> wrote:
> 
> 2026122 17:20:03 (+09:00) Takashi Yano via Cygwin :
> 
> > >
> > > If you are planning to provide a package built with compiler-rt, especially
> > > one that contains a DLL, I would say, "Please don't do that." It's very
> > > different if someone decides to build their own application with compiler-rt
> > > and takes responsibility for doing so. Before providing such a package, the
> > > implementation of native TLS in cygwin1.dll is needed, as well as an update
> > > to the toolchains to use it (and, I guess, it is impossible to switch with
> > > keeping ABI). That changes the fundamental design of the distribution.
> > 
> > I attempted to build the entire compiler-rt (builtins) as a shared library,
> > similar to the suggestions in:
> > https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/emutls.c#L388-L389
> > , and could successfully solve the problem.
> > Could you please try 21.1.4-2 (Test)?
> > 
> 
> 
> Im concerned this makes the situation worse than providing a static library. I guess
> that the upstream has never built it as a shared library. Consequently, that configuration
> appears to be largely untested.
> And then, what is the benefit of "specifying -rtlib=compiler-rt makes us cyggcc_s.dll free but
> requires a dependency on cygclang_rt.builtins-21-x86_64.dll" ? Is there another benefit?

I don't think I could get your point. The benefit of this test version is
solving the broken thread local variable reference between dlls and executable,
of course.

> Furthermore, if you really intend to provide a DLL linked with compiler-rt, the
> DLL comes with limitations that are hard to notice.
> (If this is not what you are planning, please feel free to ignore this.)
> - Linking the DLL without -rtlib=compiler-rt breaks the EmuTLS functionality silently. There is
>   no way to know that the linking needs compiler-rt except inspecting the DLL with ldd or objdump.

Why? If -rtlib=compiler-rt is not specified, the program uses libgcc_s
which is a shared library. Therefore, emutls works as expected except
for a bug in libstdc++:
https://cygwin.com/pipermail/cygwin/2025-November/258943.html

> - GCC doesn't support -rtlib=compiler-rt. That effectively enforces the use of clang.
> - A single module (EXE or DLL) can link against only one of the TLS implementations, either the
>   one from libgcc_s or the one from compiler-rt. A TLS variable that relies on the other
>   implementation would be broken (again, silently).

These are not related to the aproach whether compiler-rt provides shared
library or not, I think. Even if compiler-rt provides static library,
above two problems still exist.

> Of course that might not matter if EmuTLS is never used, however, I worry about the
> assumptions that are not enforced or validators automatically would be broken silently.
> 
> Therefore, my conclusion remains unchanged -- "Please don't do that."

I have uploaded compiler-rt 21.1.4-3 (Test), where the shared library
is used only for __emutls_get_address(), and programs that do not use
emutls will be linked with compiler-rt statically.

> Just to note, we're now focusing on compiler-rt because my original attention is about
> EmuTLS, but the same discussion is applicable to libc++. A DLL that exports C++ interfaces
> and linked to libc++ (if such a DLL were to be provided, would it be cygLLVM-X.dll?) can't be
> linked together with another libstdc++-ed C++ library (e.g., boost).

No. cygLLVM-x.dll is a part of llvm package. The shared library in libc++
package is cygc++-1.dll. Anyway, I don't understand what is the problem
in that case.

$ clang++ -stdlib=libc++ -unwindlib=libunwind -rtlib=compiler-rt emutlstest.cc -o emudll.dll -DDLL=1 -shared && clang++ -stdlib=libstdc++ -unwindlib=libunwind -rtlib=compiler-rt emutlstest.cc -o emuexe.exe -DEXE=1 emudll.dll && ./emuexe.exe
1 0xa00000538 0xa00000538
1 0xa000268a8 0xa000268a8
$ clang++ -stdlib=libstdc++ -unwindlib=libunwind -rtlib=compiler-rt emutlstest.cc -o emudll.dll -DDLL=1 -shared && clang++ -stdlib=libc++ -unwindlib=libunwind -rtlib=compiler-rt emutlstest.cc -o emuexe.exe -DEXE=1 emudll.dll && ./emuexe.exe
1 0xa00000538 0xa00000538
1 0xa000109c8 0xa000109c8
$ clang++ -stdlib=libc++ -unwindlib=libgcc -rtlib=libgcc emutlstest.cc -o emudll.dll -DDLL=1 -shared && clang++ -stdlib=libstdc++ -unwindlib=libgcc -rtlib=libgcc emutlstest.cc -o emuexe.exe -DEXE=1 emudll.dll && ./emuexe.exe
1 0xa00000538 0xa00000538
1 0xa000269c8 0xa000269c8
$ clang++ -stdlib=libstdc++ -unwindlib=libgcc -rtlib=libgcc emutlstest.cc -o emudll.dll -DDLL=1 -shared && clang++ -stdlib=libc++ -unwindlib=libgcc -rtlib=libgcc emutlstest.cc -o emuexe.exe -DEXE=1 emudll.dll && ./emuexe.exe
1 0xa00000538 0xa00000538
1 0xa00010ae8 0xa00010ae8

Of course, the cases bellow do not work because executable and DLL
call different __emutls_get_address().

$ clang++ -stdlib=libc++ -unwindlib=libunwind -rtlib=compiler-rt emutlstest.cc -o emudll.dll -DDLL=1 -shared && clang++ -stdlib=libc++ -unwindlib=libgcc -rtlib=libgcc emutlstest.cc -o emuexe.exe -DEXE=1 emudll.dll && ./emuexe.exe
0 0xa00000538 0xa00000558
0 0xa00010ba8 0xa00010c58
$ clang++ -stdlib=libc++ -unwindlib=libgcc -rtlib=libgcc emutlstest.cc -o emudll.dll -DDLL=1 -shared && clang++ -stdlib=libc++ -unwindlib=libunwind -rtlib=compiler-rt emutlstest.cc -o emuexe.exe -DEXE=1 emudll.dll && ./emuexe.exe
0 0xa00000538 0xa00000558
0 0xa00010b18 0xa00010c58


Furthermore, the following test case also works.

$ cat hello.cc
#include <iostream>
#ifdef DLL
void func()
{
        std::cout << "Hello(dll)" << std::endl;
}
#endif
#ifdef EXE
extern void func();
int main()
{
        std::cout << "Hello(main)" << std::endl;
        func();
        return 0;
}
#endif
$ clang++ -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL hello.cc -shared -o hello.dll && clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DEXE hello.cc hello.dll -o hello.exe && ./hello.exe
Hello(main)
Hello(dll)
$ clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DDLL hello.cc -shared -o hello.dll && clang++ -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -DEXE hello.cc hello.dll -o hello.exe && ./hello.exe
Hello(main)
Hello(dll)

-- 
Takashi Yano <[email protected]>

-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.