diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 4dc428ca62ae1..8ed7b8c89a3eb 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -73,6 +73,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/VirtualFileSystem.h" #include #include @@ -693,14 +694,6 @@ importer::getNormalInvocationArguments( } else { // FIXME: Emit a warning of some kind. } - - if (EnableCXXInterop) { - if (auto path = - getLibStdCxxModuleMapPath(searchPathOpts, triple, buffer)) { - invocationArgStrs.push_back( - (Twine("-fmodule-map-file=") + *path).str()); - } - } } if (searchPathOpts.getSDKPath().empty()) { @@ -870,6 +863,92 @@ importer::addCommonInvocationArguments( } } +/// On Linux, some platform libraries (glibc, libstdc++) are not modularized. +/// We inject modulemaps for those libraries into their include directories +/// to allow using them from Swift. +static SmallVector> +getClangInvocationFileMapping(ASTContext &ctx) { + using Path = SmallString<128>; + + const llvm::Triple &triple = ctx.LangOpts.Target; + // We currently only need this when building for Linux. + if (!triple.isOSLinux()) + return {}; + + SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; + + Path sdkPath(searchPathOpts.getSDKPath()); + if (sdkPath.empty()) + sdkPath = "/"; + + // Currently only a modulemap for libstdc++ is injected. + if (!ctx.LangOpts.EnableCXXInterop) + return {}; + + Path actualModuleMapPath; + Path buffer; + if (auto path = getLibStdCxxModuleMapPath(searchPathOpts, triple, buffer)) + actualModuleMapPath = path.getValue(); + else + return {}; + + // Only inject the module map if it actually exists. It may not, for example + // if `swiftc -target x86_64-unknown-linux-gnu -emit-ir` is invoked using + // a Swift compiler not built for Linux targets. + if (!llvm::sys::fs::exists(actualModuleMapPath)) + // FIXME: emit a warning of some kind. + return {}; + + // TODO: remove the libstdcxx.h header and reference all libstdc++ headers + // directly from the modulemap. + Path actualHeaderPath = actualModuleMapPath; + llvm::sys::path::remove_filename(actualHeaderPath); + llvm::sys::path::append(actualHeaderPath, "libstdcxx.h"); + + Path cxxStdlibsRoot(sdkPath); + llvm::sys::path::append(cxxStdlibsRoot, "usr", "include", "c++"); + if (!llvm::sys::fs::exists(cxxStdlibsRoot)) + return {}; + + // Collect all installed versions of libstdc++. We currently have no way to + // know which libstdc++ version will be used for this Clang invocation. + // TODO: extract this information from the Clang driver. + SmallVector cxxStdlibDirs; + std::error_code errorCode; + for (llvm::vfs::directory_iterator + iter = ctx.SourceMgr.getFileSystem()->dir_begin(cxxStdlibsRoot, + errorCode), + endIter; + !errorCode && iter != endIter; iter = iter.increment(errorCode)) { + cxxStdlibDirs.push_back(Path(iter->path())); + } + + SmallVector> result; + // Inject a modulemap into the VFS for each of the libstdc++ versions. + for (const Path &cxxStdlibDir : cxxStdlibDirs) { + // Only inject the module map if the module does not already exist at + // {sysroot}/usr/include/module.{map,modulemap}. + Path injectedModuleMapLegacyPath(cxxStdlibDir); + llvm::sys::path::append(injectedModuleMapLegacyPath, "module.map"); + if (llvm::sys::fs::exists(injectedModuleMapLegacyPath)) + continue; + + Path injectedModuleMapPath = cxxStdlibDir; + llvm::sys::path::append(injectedModuleMapPath, "module.modulemap"); + if (llvm::sys::fs::exists(injectedModuleMapPath)) + continue; + + Path injectedHeaderPath = cxxStdlibDir; + llvm::sys::path::append(injectedHeaderPath, "libstdcxx.h"); + + result.push_back( + {std::string(injectedModuleMapPath), std::string(actualModuleMapPath)}); + result.push_back( + {std::string(injectedHeaderPath), std::string(actualHeaderPath)}); + } + return result; +} + bool ClangImporter::canReadPCH(StringRef PCHFilename) { if (!llvm::sys::fs::exists(PCHFilename)) return false; @@ -1122,9 +1201,10 @@ ClangImporter::create(ASTContext &ctx, } } + auto fileMapping = getClangInvocationFileMapping(ctx); // Wrap Swift's FS to allow Clang to override the working directory llvm::IntrusiveRefCntPtr VFS = - llvm::vfs::RedirectingFileSystem::create({}, true, + llvm::vfs::RedirectingFileSystem::create(fileMapping, true, *ctx.SourceMgr.getFileSystem()); // Create a new Clang compiler invocation. diff --git a/stdlib/public/Cxx/libstdcxx.h b/stdlib/public/Cxx/libstdcxx.h index 5083a9c356b32..388398095da36 100644 --- a/stdlib/public/Cxx/libstdcxx.h +++ b/stdlib/public/Cxx/libstdcxx.h @@ -1,79 +1,79 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "algorithm" +#include "bitset" +#include "complex" +#include "deque" +#include "exception" +#include "fstream" +#include "functional" +#include "iomanip" +#include "ios" +#include "iosfwd" +#include "iostream" +#include "istream" +#include "iterator" +#include "limits" +#include "list" +#include "locale" +#include "map" +#include "memory" +#include "new" +#include "numeric" +#include "ostream" +#include "queue" +#include "set" +#include "sstream" +#include "stack" +#include "stdexcept" +#include "streambuf" +#include "string" +#include "utility" +#include "typeinfo" +#include "valarray" +#include "vector" +#include "array" +#include "atomic" +#include "chrono" +#include "codecvt" +#include "condition_variable" +#include "forward_list" +#include "future" +#include "initializer_list" +#include "mutex" +#include "random" +#include "ratio" +#include "regex" +#include "scoped_allocator" +#include "system_error" +#include "thread" +#include "tuple" +#include "typeindex" +#include "type_traits" +#include "unordered_map" +#include "unordered_set" // C++17 and newer: -#if __has_include() -#include +#if __has_include("any") +#include "any" #endif -#if __has_include() -#include +#if __has_include("charconv") +#include "charconv" #endif -#if __has_include() -#include +#if __has_include("execution") +#include "execution" #endif -#if __has_include() -#include +#if __has_include("filesystem") +#include "filesystem" #endif -#if __has_include() -#include +#if __has_include("memory_resource") +#include "memory_resource" #endif -#if __has_include() -#include +#if __has_include("optional") +#include "optional" #endif -#if __has_include() -#include +#if __has_include("string_view") +#include "string_view" #endif -#if __has_include() -#include +#if __has_include("variant") +#include "variant" #endif diff --git a/stdlib/public/Cxx/libstdcxx.modulemap b/stdlib/public/Cxx/libstdcxx.modulemap index 5a2dbff03adac..d8200ec6cf2e0 100644 --- a/stdlib/public/Cxx/libstdcxx.modulemap +++ b/stdlib/public/Cxx/libstdcxx.modulemap @@ -20,4 +20,13 @@ module std { header "libstdcxx.h" requires cplusplus export * + + /// C compatibility headers. + module compat { + module cassert { + header "cassert" + requires cplusplus + export * + } + } }