[cxx-interop] Allow compiling with libc++ on Linux

This makes sure that Swift respects `-Xcc -stdlib=libc++` flags.

Clang already has existing logic to discover the system-wide libc++ installation on Linux. We rely on that logic here.

Importing a Swift module that was built with a different C++ stdlib is not supported and emits an error.

The Cxx module can be imported when compiling with any C++ stdlib. The synthesized conformances, e.g. to CxxRandomAccessCollection also work. However, CxxStdlib currently cannot be imported when compiling with libc++, since on Linux it refers to symbols from libstdc++ which have different mangled names in libc++.

rdar://118357548 / https://github.com/swiftlang/swift/issues/69825
This commit is contained in:
Egor Zhdan
2024-07-30 20:01:58 +01:00
parent 536a88971f
commit 059f0f97d1
31 changed files with 348 additions and 28 deletions

View File

@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Driver/Driver.h"
#include "swift/AST/SILOptions.h"
#include "swift/Basic/DiagnosticOptions.h"
#include "swift/Frontend/Frontend.h"
@@ -335,6 +336,43 @@ setBridgingHeaderFromFrontendOptions(ClangImporterOptions &ImporterOpts,
FrontendOpts.InputsAndOutputs.getFilenameOfFirstInput();
}
void CompilerInvocation::computeCXXStdlibOptions() {
auto [clangDriver, clangDiagEngine] =
ClangImporter::createClangDriver(LangOpts, ClangImporterOpts);
auto clangDriverArgs = ClangImporter::createClangArgs(
ClangImporterOpts, SearchPathOpts, clangDriver);
auto &clangToolchain =
clangDriver.getToolChain(clangDriverArgs, LangOpts.Target);
auto cxxStdlibKind = clangToolchain.GetCXXStdlibType(clangDriverArgs);
auto cxxDefaultStdlibKind = clangToolchain.GetDefaultCXXStdlibType();
auto toCXXStdlibKind =
[](clang::driver::ToolChain::CXXStdlibType clangCXXStdlibType)
-> CXXStdlibKind {
switch (clangCXXStdlibType) {
case clang::driver::ToolChain::CST_Libcxx:
return CXXStdlibKind::Libcxx;
case clang::driver::ToolChain::CST_Libstdcxx:
return CXXStdlibKind::Libstdcxx;
}
};
// The MSVC driver in Clang is not aware of the C++ stdlib, and currently
// always assumes libstdc++, which is incorrect: the Microsoft stdlib is
// normally used.
if (LangOpts.Target.isOSWindows()) {
// In the future, we should support libc++ on Windows. That would require
// the MSVC driver to support it first
// (see https://reviews.llvm.org/D101479).
LangOpts.CXXStdlib = CXXStdlibKind::Msvcprt;
LangOpts.PlatformDefaultCXXStdlib = CXXStdlibKind::Msvcprt;
}
if (LangOpts.Target.isOSLinux() || LangOpts.Target.isOSDarwin()) {
LangOpts.CXXStdlib = toCXXStdlibKind(cxxStdlibKind);
LangOpts.PlatformDefaultCXXStdlib = toCXXStdlibKind(cxxDefaultStdlibKind);
}
}
void CompilerInvocation::setRuntimeResourcePath(StringRef Path) {
SearchPathOpts.RuntimeResourcePath = Path.str();
updateRuntimeLibraryPaths(SearchPathOpts, FrontendOpts, LangOpts);
@@ -3592,6 +3630,7 @@ bool CompilerInvocation::parseArgs(
// Now that we've parsed everything, setup some inter-option-dependent state.
setIRGenOutputOptsFromFrontendOptions(IRGenOpts, FrontendOpts);
setBridgingHeaderFromFrontendOptions(ClangImporterOpts, FrontendOpts);
computeCXXStdlibOptions();
if (LangOpts.hasFeature(Feature::Embedded)) {
IRGenOpts.InternalizeAtLink = true;
IRGenOpts.DisableLegacyTypeInfo = true;