I’ve been testing ⚙ D101479 [Driver] Support libc++ in MSVC before re-landing that change and I discovered a few more issues, some of which may need to be addressed first (or at least documented).
What I tried to do is building Clang toolchain that includes libc++ (stage 1), and then use it to build Clang toolchain against libc++ (stage 2), so basically a self-hosting test.
The first issue is missing std::set_new_handler
on Windows. libc++ declares this function on non-Windows platforms at llvm-project/new at a6f621b8cacca926d809010c135be038fd05652c · llvm/llvm-project · GitHub, with the definition being provided by the C++ ABI library such as llvm-project/cxa_default_handlers.cpp at a6f621b8cacca926d809010c135be038fd05652c · llvm/llvm-project · GitHub. There’s no such definition provided on Windows though so we end up with undefined symbol linker error in llvm-project/ErrorHandling.cpp at a6f621b8cacca926d809010c135be038fd05652c · llvm/llvm-project · GitHub. I believe that on Windows, we need to provide our own definition that would be implemented using _set_new_handler | Microsoft Learn, this is approach is also used by STL STL/stdhndlr.cpp at 2f8342a3a57fb157d881c6a2d42a917d20e413f8 · microsoft/STL · GitHub.
When using clang-cl
with CMake I ran into a challenge since CMake doesn’t use clang-cl
for linking, instead it invokes the linker directly through the vs_link_exe
or vs_link_dll
CMake tool. This doesn’t include the /libpath:
to libc++ installation, so we end up with link error because the linker fails to find libc++ which is referenced by the auto-linking directive in libc++ headers llvm-project/__config at bb1c8b1293b60444cab566c99463905f8ffe8c34 · llvm/llvm-project · GitHub. I worked around the issue by manually including /libpath:C:/path/to/stage1/lib/x86_64-pc-windows-msvc
in CMAKE_EXE_LINKER_FLAGS
, but that experience isn’t great. I don’t know if there’s a better solution though other than extending CMake to do this automatically.
Relatedly, when linking libc++ as a shared library, you also end up with an issue where the linked binary doesn’t know how to find c++.dll
. I ran into this during the stage 2 build where clang-tblgen.exe
would silently fail. I worked around the issue by manually copying c++.dll
to C:/path/to/stage2/bin
but this is again not particularly user friendly.
The last issue I haven’t yet found a solution for is building libc++ as a static library. This would be our preferred method of distribution since it avoids the library search order issues, but it doesn’t work at the moment. The problem is that libc++ relies on STL for its implementation of std::exception_ptr
llvm-project/exception_pointer_msvc.ipp at 3e6f7ab867ac8c36f0c8a91e7fa1608742702681 · llvm/llvm-project · GitHub. This was introduced ⚙ D32927 [libc++] Implement exception_ptr on Windows and @EricWF mentioned in that change that this shouldn’t introduce any problems because the usages of msvcprt
are kept to c++.dll
, but this does seem to be causing issues in the static case. Specifically, since libc++.lib
has undefined references to __ExceptionPtr*
symbols provided by STL, libc++.lib
users also need to manually link msvcprt.lib
, but this results in link errors:
lld-link: error: bool __cdecl std::uncaught_exception(void) was replaced
A potential solution would be avoid the use of STL and __ExceptionPtr*
symbols, and instead implement std::exception_ptr
on Windows entirely within libc++ akin to STL STL/excptptr.cpp at 2f8342a3a57fb157d881c6a2d42a917d20e413f8 · microsoft/STL · GitHub. The advantage of this approach is that libc++ would become more self-contained, avoiding the dependency on STL. However, STL’s implementation is non-trivial so this strategy is likely going to require significant effort. A simpler alternative would be to declare std::exception_ptr
as unsupported on Windows llvm-project/exception_pointer_unimplemented.ipp at 08d1c43c7023a2e955c43fbf4c3f1635f91521e0 · llvm/llvm-project · GitHub, but that might affect libc++'s usability (I don’t know how widely use std::exception_ptr
is).