DMARC-Filter: OpenDMARC Filter v1.4.2 delorie.com 60PC57E1504975 Authentication-Results: delorie.com; dmarc=pass (p=none dis=none) header.from=cygwin.com Authentication-Results: delorie.com; spf=pass smtp.mailfrom=cygwin.com DKIM-Filter: OpenDKIM Filter v2.11.0 delorie.com 60PC57E1504975 Authentication-Results: delorie.com; dkim=pass (1024-bit key, unprotected) header.d=cygwin.com header.i=@cygwin.com header.a=rsa-sha256 header.s=default header.b=q9qXD4Bv X-Recipient: archive-cygwin AT delorie DOT com DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7A7854BA9034 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cygwin.com; s=default; t=1769342706; bh=yodlLoN4gCLlWb4UdcmdHZIn9sbP6GujI/MIP6dk9IU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=q9qXD4BvL+CHZgn6TmT/2/gUt8t3XaKY+CQihN+IpWDRlptrK8QAwjCU2xebIPsPW M2NgegpTJRcKkTj+6o0hqfXRwSjvvAWDXGXf4izY1ZwYRmzx8BS8wQMlelkNii6u0C 1m/b1kHpDVw9cZhLJhpv964XcWcqfDGfH3mX19ug= X-Original-To: cygwin AT cygwin DOT com Delivered-To: cygwin AT cygwin DOT com DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 212884BA9023 ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 212884BA9023 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1769342683; cv=none; b=ZVfXkr1PYKojNra515QFguEhNR1CMMLqmSdrbpIO32CS3ZGzAdnqJJ8e0h7JLmVuXV9wYCt6bRgyddts7o7t8dHPrOsKDokchyIRCmMne0HVg/mjbG8H2TBdH3+uM0/lSR179GczI4tVtfSaqMfOAozCcMt8Wactk94uzRYF5p8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1769342683; c=relaxed/simple; bh=tXuTn8BXDbItFrIJvchqFgyflTQPKFtBZFCO+I+gpo0=; h=DKIM-Signature:Message-Id:From:To:Subject:Date:MIME-Version; b=NMn0vbT0Zy/wFMmQFgGglpDaHyk/zAcJtFO6s5b2GzWqbB9UtpWQ6LP+I29NuaLaywUGq/9WoykmJqg854I6Y5zaXvCuZ9FqOojA+TC2dysP7fMzGleLsBsPOQo15BqIwc3HfrvEdDKf6LSr/Aja9PZSdSNtx5rCd1Wiw1F1NFo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 212884BA9023 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769342682; x=1769947482; h=mime-version:content-transfer-encoding:user-agent:references :in-reply-to:date:subject:to:from:message-id:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=RXC4WCpvmDZdIg5SuFAZtVvTcg9Nb4V+xTAqCdTaAQc=; b=UFHMmJU73lUTvPu/3DhP2gS0PatgxxEisA181M8KXYDrxZdi4/GcNlmwvxsOOBN+mJ iqNz0ft5j+U55fuaEFEOwTPvz3lMWenNHv2Bf8so5kUj7G/3NBg6tV+UcF3ZQZblgStx BE0lZ3plez0kmi0QJHe9bQ33ODDko/yg8t4RpBmnpO3Txa2MeY5c3l6es/3uww1uZIn8 QMai0JBE+ieSyCUYnZSwGbXiwEjEz+xdp0YDbEM4CnXQKHsF/DKfWr5r1RDlHUUEwq1a WVDFbWbqQGjc6Jcme3JKkcAShOq0Zrl+yHkcUD1uz3i3SDvPYaKPUZp8Kgdi0RMituAn uOdg== X-Gm-Message-State: AOJu0YznILX83gZavMieGO1DF2yIC1qkRFMgWBDqfLVuVmS6S6zGbocr NsiEGxh4NYFBQRNRDZgzH5TWky+cq2V2DbumTo4WqbqTeYwYzIzEbCAFLW6Rhg== X-Gm-Gg: AZuq6aIsgy8c/Haeb3KWAr3Ys30tdgPxy3Bit1LTEubimncW1Mr6UyokELHDf5tuIgM Y0QfcQduA6VyJtcZALziLZrSQFiPdl2pifdmJ+nY8LJtUxoEvsiWteSSR2L2DiT9dGi1womklVL QiGBX39XjpNFz/j0PCOU7Twqk2eu2jRDtln3WhQOHtzKQvBpVZW62C42muUUxbKtcmL/FyRNFMI +XgEIokh2UaYRm8g2w0jnUbKjAFTg38Pxz7ZgJJxJN1o8R1yIMSTbBZAGJF9m1QHOTFuMol3LxU hqCEzp0ykGSWFv+lRJ2K30QAraSt4q9I8U0K4dyje8WSEu9PJWFitTg3+iqeodCEAIHID1Cn7A3 pcdimHl1gnG12FWONjsb+X7h351sw8BuoRJK2LOGVum4xIYNYtMlWCUUJFH+8oEqwKnHX1uFKXT VLvv45OZHqjiACOVPUbqwBYXKO X-Received: by 2002:a17:90b:510b:b0:340:d578:f2a2 with SMTP id 98e67ed59e1d1-353c40b3869mr1354639a91.6.1769342681888; Sun, 25 Jan 2026 04:04:41 -0800 (PST) Message-Id: <1769247254202.3033329163.3934744690@gmail.com> To: Takashi Yano via Cygwin Subject: Re: Request to update libc++ related packages for current Clang/LLVM toolchain Date: Sun, 25 Jan 2026 12:04:39 +0000 In-Reply-To: <20260124182952.57fe14cbe385c0d33ac74613@nifty.ne.jp> References: <20260124182952 DOT 57fe14cbe385c0d33ac74613 AT nifty DOT ne DOT jp> X-Mailer: Vivaldi Mail User-Agent: Vivaldi Mail/7.7.3851.67 MIME-Version: 1.0 X-BeenThere: cygwin AT cygwin DOT com X-Mailman-Version: 2.1.30 Precedence: list List-Id: General Cygwin discussions and problem reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: kikairoya via Cygwin Reply-To: kikairoya Content-Type: text/plain; charset="utf-8" Errors-To: cygwin-bounces~archive-cygwin=delorie DOT com AT cygwin DOT com Sender: "Cygwin" Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from base64 to 8bit by delorie.com id 60PC57E1504975 Hello Takashi, To be clear, I'm not asking you to fix the TLS functionality of compiler-rt; I'm just asking you to not package a DLL built with -rtlib=compiler-rt (and also -stdlib=libc++). Such a library implicitly enforces the use of specific compiler options, making it incompatible with other libraries, even if compiler-rt is provided as a shared library. 2026年1月24日 18:29:52 (+09:00) で、Takashi Yano via Cygwin さんが書きました: > > > > I’m 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. > That doesn't explain the benefit of using compiler-rt instead of libgcc. The availability itself of the option to select a runtime (i.e., the existence of the compiler-rt package -- thanks for your effort!) is indeed a benefit for programmers, but not for other packages or users, including programmers who want to use the other package as a library. Regarding building a package with -rtlib=compiler-rt, either verification that the problem does not affect programmers in practice or a clear justification is needed, since there is at least one downside. To verify that a package built with -rtlib=compiler-rt doesn't cause a problem with the TLS, it would be enough to check that if no module (not only DLLs; EXEs also can export symbols) in the package exports a symbol beginning with __emutls_. However, I believe this kind of check should be automated for *all* packages by default, regardless of who maintains it or whether the package uses compiler-rt; otherwise, the check will easily be overlooked. Of course, the checker must always pass for a module which is linked to libgcc_s. > > 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 > As you confirmed below, importing a TLS variable from a DLL that built with -rtlib=compiler-rt requires end-programmers to also use the same flag for it to work correctly. Therefore, a DLL built with comipler-rt can't work with another DLL that exports a TLS variable. > > - 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. > Yes, I explained that building compiler-rt as a shared library doesn't solve the problem. > > 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. > I don't understand how the split runtime solves the problem. > > 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. > It seems you're saying "No" to something what I didn't claim. I'm worried that you might build the next version of the llvm package (or other library packages you maintain) with -stdlib=libc++ and -rtlib=compiler-rt. That's all I'm asking with "Please don't do that." Consider to the case of someone is developing an LLVM plugin helped with Boost. Both of the LLVM headers and the Boost headers include standard C++ libraries. If the llvm package were built with libc++, how would they specify the -stdlib flag to compile a .cpp file that includes both of LLVM and Boost headers? > 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 > This is the problem I mentioned as "no way to know that the linking needs compiler-rt except inspecting the DLL with ldd or objdump". > Furthermore, the following test case also works. > > $ cat hello.cc > #include > #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) > This is not a case of "A DLL that exports C++ interfaces", even though the exported symbol is C++-mangled. hello.exe references std::cout independently of hello.dll, meaning they pull references from different instances. $ cat ios.cc #include void s(); #ifdef DLL void s() { std::cout << 42 << std::endl; } #endif #ifdef EXE int main() { std::cout << std::hex << 42 << std::endl; s(); std::cout << 42 << std::endl; } #endif $ clang++ -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL ios.cc -shared -o ios.dll && clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DEXE ios.cc ios.dll -o ios.exe && ./ios.exe 2a 42 2a There are examples of how fail with "A DLL that exports C++ interfaces" below. A case that fails to link: $ cat vec.cc #include void f(std::vector *x); #ifdef DLL void f(std::vector *x) {}; #endif #ifdef EXE int main() { f(nullptr); } #endif $ clang++ -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL vec.cc -shared -o vec.dll && clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DEXE vec.cc vec.dll -o vec.exe && ./vec.exe /usr/bin/ld: /tmp/vec-c89382.o:vec.cc:(.text+0x14): undefined reference to `f(std::vector >*)' clang++: error: linker command failed with exit code 1 (use -v to see invocation) A case that causes a runtime error or broken silently: #include std::string g(); #ifdef DLL std::string g() { return "abc"; } #endif #ifdef EXE #include int main() { printf("%zu\n", g().length()); } #endif $ clang++ -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL str.cc -shared -o str.dll && clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DEXE str.cc str.dll -o str.exe && ./str.exe Segmentation fault $ clang++ -stdlib=libstdc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL str.cc -shared -o str.dll && clang++ -stdlib=libc++ -rtlib=libgcc -unwindlib=libgcc -DEXE str.cc str.dll -o str.exe && ./str.exe 92 In this case, changing "abc" to "abcdefghijkl" gives: $ clang++ -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL str.cc -shared -o str.dll && clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DEXE str.cc str.dll -o str.exe && ./str.exe (succeeded with no output) However, gdb says that it aborts with SIGSEGV: $ gdb ./str.exe -q --batch -ex r -ex q [New Thread 85460.0xb39c] [New Thread 85460.0xee68] [New Thread 85460.0x11f24] [New Thread 85460.0xc7d0] Thread 1 "str" received signal SIGSEGV, Segmentation fault. 0x00000003f7c20af3 in std::basic_string, std::allocator >::length (this=0x7ffffcc08) at /usr/src/debug/gcc-13.4.0-1/libstdc++-v3/include/bits/cow_string.h:929 929 { return size(); } A debugging session is active. Inferior 1 [process 85460] will be killed. Quit anyway? (y or n) [answered Y; input not from terminal] Another case that is silently broken: $ cat exc.cc void e(); #ifdef DLL void e() { throw 3; } #endif #ifdef EXE #include int main() { try { puts("try"); e(); } catch (int a) { printf("catch %d\n", a); } catch (...) { puts("catch other"); } puts("finish"); } #endif $ clang++ -stdlib=libstdc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL exc.cc -shared -o exc.dll && clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DEXE exc.cc exc.dll -o exc.exe && ./exc.exe try catch 3 finish $ clang++ -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL exc.cc -shared -o exc.dll && clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DEXE exc.cc exc.dll -o exc.exe && ./exc.exe try catch other finish A case that looks slightly more practical: $ cat deq.cc #include class some_state { std::deque state; public: void modify_state(int x); bool verify_state() const; }; #ifdef DLL void some_state::modify_state(int x) { state.push_back(x); } bool some_state::verify_state() const { int x = 0; for (auto i: state) x += i; return x > 0; } #endif #ifdef EXE #include int main() { some_state s; s.modify_state(3); printf("%d\n", s.verify_state()); } #endif $ clang++ -stdlib=libc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL deq.cc -shared -o deq.dll && clang++ -stdlib=libstdc++ -rtlib=libgcc -unwindlib=libgcc -DEXE deq.cc deq.dll -o deq.exe && ./deq.exe Segmentation fault $ clang++ -stdlib=libstdc++ -rtlib=compiler-rt -unwindlib=libunwind -DDLL deq.cc -shared -o deq.dll && clang++ -stdlib=libc++ -rtlib=libgcc -unwindlib=libgcc -DEXE deq.cc deq.dll -o deq.exe && ./deq.exe (succeeded with no output, the same as the str.cpp case. I'm not sure whether cygwin1.dll or libc++ needs to be fixed.) Therefore, providing a libc++-ed DLL that exports C++ interfaces is quite dangerous. Please don't do that. To be fair, a DLL that only exports pure C interfaces doesn't force programmers to specify a particular -stdlib flag, even if the DLL is linked with libc++. Therefore, what I'm worried about doesn't matter in that case. Checking that no exported symbols begin with _Z may be sufficient to verify the exports (again, this check should be automated, I think.) -- Tomohiro Kashiwada (@kikairoya) -- 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