|
73 | 73 | #include "llvm/Support/Path.h"
|
74 | 74 | #include "llvm/Support/YAMLParser.h"
|
75 | 75 | #include "llvm/Support/YAMLTraits.h"
|
| 76 | +#include "llvm/Support/VirtualFileSystem.h" |
76 | 77 | #include <algorithm>
|
77 | 78 | #include <memory>
|
78 | 79 |
|
@@ -693,14 +694,6 @@ importer::getNormalInvocationArguments(
|
693 | 694 | } else {
|
694 | 695 | // FIXME: Emit a warning of some kind.
|
695 | 696 | }
|
696 |
| - |
697 |
| - if (EnableCXXInterop) { |
698 |
| - if (auto path = |
699 |
| - getLibStdCxxModuleMapPath(searchPathOpts, triple, buffer)) { |
700 |
| - invocationArgStrs.push_back( |
701 |
| - (Twine("-fmodule-map-file=") + *path).str()); |
702 |
| - } |
703 |
| - } |
704 | 697 | }
|
705 | 698 |
|
706 | 699 | if (searchPathOpts.getSDKPath().empty()) {
|
@@ -870,6 +863,92 @@ importer::addCommonInvocationArguments(
|
870 | 863 | }
|
871 | 864 | }
|
872 | 865 |
|
| 866 | +/// On Linux, some platform libraries (glibc, libstdc++) are not modularized. |
| 867 | +/// We inject modulemaps for those libraries into their include directories |
| 868 | +/// to allow using them from Swift. |
| 869 | +static SmallVector<std::pair<std::string, std::string>> |
| 870 | +getClangInvocationFileMapping(ASTContext &ctx) { |
| 871 | + using Path = SmallString<128>; |
| 872 | + |
| 873 | + const llvm::Triple &triple = ctx.LangOpts.Target; |
| 874 | + // We currently only need this when building for Linux. |
| 875 | + if (!triple.isOSLinux()) |
| 876 | + return {}; |
| 877 | + |
| 878 | + SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; |
| 879 | + |
| 880 | + Path SDKPath(searchPathOpts.getSDKPath()); |
| 881 | + if (SDKPath.empty()) |
| 882 | + SDKPath = "/"; |
| 883 | + |
| 884 | + // Currently only a modulemap for libstdc++ is injected. |
| 885 | + if (!ctx.LangOpts.EnableCXXInterop) |
| 886 | + return {}; |
| 887 | + |
| 888 | + Path actualModuleMapPath; |
| 889 | + Path buffer; |
| 890 | + if (auto path = getLibStdCxxModuleMapPath(searchPathOpts, triple, buffer)) { |
| 891 | + actualModuleMapPath = path.getValue(); |
| 892 | + } else |
| 893 | + return {}; |
| 894 | + |
| 895 | + // Only inject the module map if it actually exists. It may not, for example |
| 896 | + // if `swiftc -target x86_64-unknown-linux-gnu -emit-ir` is invoked using |
| 897 | + // a Swift compiler not built for Linux targets. |
| 898 | + if (!llvm::sys::fs::exists(actualModuleMapPath)) |
| 899 | + // FIXME: emit a warning of some kind. |
| 900 | + return {}; |
| 901 | + |
| 902 | + // TODO: remove the libstdcxx.h header and reference all libstdc++ headers |
| 903 | + // directly from the modulemap. |
| 904 | + Path actualHeaderPath = actualModuleMapPath; |
| 905 | + llvm::sys::path::remove_filename(actualHeaderPath); |
| 906 | + llvm::sys::path::append(actualHeaderPath, "libstdcxx.h"); |
| 907 | + |
| 908 | + Path cxxStdlibsRoot(SDKPath); |
| 909 | + llvm::sys::path::append(cxxStdlibsRoot, "usr", "include", "c++"); |
| 910 | + if (!llvm::sys::fs::exists(cxxStdlibsRoot)) |
| 911 | + return {}; |
| 912 | + |
| 913 | + // Collect all installed versions of libstdc++. We currently have no way to |
| 914 | + // know which libstdc++ version will be used for this Clang invocation. |
| 915 | + // TODO: extract this information from the Clang driver. |
| 916 | + SmallVector<Path, 1> cxxStdlibDirs; |
| 917 | + std::error_code errorCode; |
| 918 | + for (llvm::vfs::directory_iterator |
| 919 | + iter = ctx.SourceMgr.getFileSystem()->dir_begin(cxxStdlibsRoot, |
| 920 | + errorCode), |
| 921 | + endIter; |
| 922 | + !errorCode && iter != endIter; iter = iter.increment(errorCode)) { |
| 923 | + cxxStdlibDirs.push_back(SmallString<128>(iter->path())); |
| 924 | + } |
| 925 | + |
| 926 | + SmallVector<std::pair<std::string, std::string>> result; |
| 927 | + // Inject a modulemap into the VFS for each of the libstdc++ versions. |
| 928 | + for (const auto &cxxStdlibDir : cxxStdlibDirs) { |
| 929 | + // Only inject the module map if the module does not already exist at |
| 930 | + // {sysroot}/usr/include/module.{map,modulemap}. |
| 931 | + Path injectedModuleMapLegacyPath(cxxStdlibDir); |
| 932 | + llvm::sys::path::append(injectedModuleMapLegacyPath, "module.map"); |
| 933 | + if (llvm::sys::fs::exists(injectedModuleMapLegacyPath)) |
| 934 | + continue; |
| 935 | + |
| 936 | + Path injectedModuleMapPath = cxxStdlibDir; |
| 937 | + llvm::sys::path::append(injectedModuleMapPath, "module.modulemap"); |
| 938 | + if (llvm::sys::fs::exists(injectedModuleMapPath)) |
| 939 | + continue; |
| 940 | + |
| 941 | + Path injectedHeaderPath = cxxStdlibDir; |
| 942 | + llvm::sys::path::append(injectedHeaderPath, "libstdcxx.h"); |
| 943 | + |
| 944 | + result.push_back( |
| 945 | + {std::string(injectedModuleMapPath), std::string(actualModuleMapPath)}); |
| 946 | + result.push_back( |
| 947 | + {std::string(injectedHeaderPath), std::string(actualHeaderPath)}); |
| 948 | + } |
| 949 | + return result; |
| 950 | +} |
| 951 | + |
873 | 952 | bool ClangImporter::canReadPCH(StringRef PCHFilename) {
|
874 | 953 | if (!llvm::sys::fs::exists(PCHFilename))
|
875 | 954 | return false;
|
@@ -1122,9 +1201,10 @@ ClangImporter::create(ASTContext &ctx,
|
1122 | 1201 | }
|
1123 | 1202 | }
|
1124 | 1203 |
|
| 1204 | + auto fileMapping = getClangInvocationFileMapping(ctx); |
1125 | 1205 | // Wrap Swift's FS to allow Clang to override the working directory
|
1126 | 1206 | llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
|
1127 |
| - llvm::vfs::RedirectingFileSystem::create({}, true, |
| 1207 | + llvm::vfs::RedirectingFileSystem::create(fileMapping, true, |
1128 | 1208 | *ctx.SourceMgr.getFileSystem());
|
1129 | 1209 |
|
1130 | 1210 | // Create a new Clang compiler invocation.
|
|
0 commit comments