This implements support for using libc++ headers in MSVC toolchain.
We only support libc++ headers that are part of the toolchain, and
not headers installed elsewhere on the system.
This implements support for using libc++ headers in MSVC toolchain.
|60 ms||x64 debian > Clang.Driver::msvc-libcxx.cpp|
Script: -- : 'RUN: at line 1'; /mnt/disks/ssd0/agent/llvm-project/build/bin/clang --driver-mode=g++ -target x86_64-pc-windows-msvc --stdlib=libc++ -### /mnt/disks/ssd0/agent/llvm-project/clang/test/Driver/msvc-libcxx.cpp 2>&1 | /mnt/disks/ssd0/agent/llvm-project/build/bin/FileCheck /mnt/disks/ssd0/agent/llvm-project/clang/test/Driver/msvc-libcxx.cpp -check-prefix MSVC-LIBCXX
|60 ms||x64 debian > lld.wasm::globals.s|
Script: -- : 'RUN: at line 1'; /mnt/disks/ssd0/agent/llvm-project/build/bin/llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o /mnt/disks/ssd0/agent/llvm-project/build/tools/lld/test/wasm/Output/globals.s.tmp.o /mnt/disks/ssd0/agent/llvm-project/lld/test/wasm/globals.s
|120 ms||x64 windows > Clang.Driver::msvc-libcxx.cpp|
Script: -- : 'RUN: at line 1'; c:\ws\w16c2-3\llvm-project\premerge-checks\build\bin\clang.exe --driver-mode=g++ -target x86_64-pc-windows-msvc --stdlib=libc++ -### C:\ws\w16c2-3\llvm-project\premerge-checks\clang\test\Driver\msvc-libcxx.cpp 2>&1 | c:\ws\w16c2-3\llvm-project\premerge-checks\build\bin\filecheck.exe C:\ws\w16c2-3\llvm-project\premerge-checks\clang\test\Driver\msvc-libcxx.cpp -check-prefix MSVC-LIBCXX
|20 ms||x64 windows > lld.wasm::globals.s|
Script: -- : 'RUN: at line 1'; c:\ws\w16c2-3\llvm-project\premerge-checks\build\bin\llvm-mc.exe -filetype=obj -triple=wasm32-unknown-unknown -o C:\ws\w16c2-3\llvm-project\premerge-checks\build\tools\lld\test\wasm\Output\globals.s.tmp.o C:\ws\w16c2-3\llvm-project\premerge-checks\lld\test\wasm\globals.s
The test doesn't seem to pass on Jenkins. Maybe we need a REQUIRES line or a fake sysroot or something for the test.
I'm guessing this is copy-pasted code from the other toolchains, but this lambda makes less sense when its only called once. If you inline it, we don't need an extra SmallString or lambda.
How does this interact with /MT / /MD? Does this link the static or the dynamic libc++? If the former, does that do the right thing for DLLs? If the latter, are users expected to manually copy libc++.dll? (Sorry, not super up to speed on the static/shared lib status of libc++ on windows.)
Right now, libc++ headers mark everything dllimport by default, unless _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS is defined. If you build a static-only libc++, libc++'s __config_site predefines _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS.
Not sure if we want the desicion between static and shared libc++ be coupled with /MT and /MD, as one can quite plausibly want to use e.g. a static libc++ with /MD.
Right, I meant more "how do users pick if they want a statically or dynamically linked libc++". Sounds like you get a dynamic libc++ by default. Since Windows doesn't have rpaths afaik, using -stdlib=libc++ means you'll get an executable that won't start, unless you know to copy the libc++ dll next to your executable with this patch as-is, yes?
Yes, that sounds correct.
As for how people choose - I guess unless you resort to trickery - you use whichever is default in the libc++ build that is used.
However, the libc++ headers inject linker directives to pull in the right form of the lib, matching the linkage of the headers. So as long as that isn't disabled, the clang driver shouldn't need to specify any lib to link against at all.
On other platforms the decision whether to use static or shared is controlled by -static-libstdc++, does CL have a similar flag or shall we support -static-libstdc++ in MSVC driver as well?
Hmm, well contrary to how -static-libstdc++ works otherwise (you only need it while linking), you'd need to define -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS everwhere when compiling, if libc++ defaults to DLL linkage but you'd want to use a static version instead.
Repeating the question - does the driver really need to know or care? Thanks to the autolinking directive in libc++ headers, the driver shouldn't need to explicitly link against the libc++ library at all?
AFAIK yes. And it's header-based, so clang-cl does the same - if you include and use the MSVC C++ standard library headers, it'll implicitly link in that library too.
Do we still need the -libpath: for the linker to find the library?
Ah, yes, that will be needed.
Whether one wants to link against the CRT statically or dynamically, and libc++ statically or dynamically, are two entirely separate things. I would e.g. expect that Chrome is built with a statically linked libc++ but linked against the dynamic CRT.
In any case, as the libc++ headers supply autolinking directives that match the declarations (whether they're doing dllimport or not), the driver shouldn't really need to decide, but it's all up to the libc++ installation.
Ah, thanks for explaining that! In the VC++ stack, /MD and /MT make the DLL/static choice for the CRT, the C++ standard library, and the compiler runtime. It never occurred to me that someone might want to select these independently.
Yup. As those components come from a different vendor than libc++, and have different distribution strategies/policies (and since there's some amount of shared global state in the CRT, which further affect how one can/should use it) one may want to link them in different ways.
The problem is that there's no way to configure the default libc++ on a per-target basis. We want to use libc++ as a default for all targets that support it, so for example even if you're compiling on Windows but targeting Fuchsia or Linux. Unfortunately, with this change that triggers D103947 when compiling compiler-rt and I don't know how to work around it.
I'd point out that we have the same problem for other defaults, for example if you set lld as the default linker on Darwin, it causes issues because Clang tries to use lld.ld64 which is not yet usable. We still want to use lld for all other targets, but there's no way to specify that in CMake today which is something we may want to address.
Ah, I see, thanks for explaining - the link between those wasn’t obvious to me.
Yes, that’s indeed a problem with the mechanism of overriding the default choices. (FWIW, in llvm-mingw I work around this issue by having small wrapper scripts, like <triple>-clang, that set the cross target and the defaults I when invoking clang - but that’s not very elegant either.)
Clang does have the concept of a config file, named the same a the target triple plus “.cfg”, iirc, located next to the compiler binary, that might work for setting different defaults per cross target. I haven’t really used that much though.