Skip to content

Commit 1ef02ef

Browse files
authored
Merge pull request #58843 from apple/egorzhdan/libstdcxx-vfs
[cxx-interop] Use VFS to inject modulemap into libstdc++ installation
2 parents 04256dc + 20650ea commit 1ef02ef

File tree

3 files changed

+166
-77
lines changed

3 files changed

+166
-77
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#include "llvm/Support/Path.h"
7474
#include "llvm/Support/YAMLParser.h"
7575
#include "llvm/Support/YAMLTraits.h"
76+
#include "llvm/Support/VirtualFileSystem.h"
7677
#include <algorithm>
7778
#include <memory>
7879

@@ -693,14 +694,6 @@ importer::getNormalInvocationArguments(
693694
} else {
694695
// FIXME: Emit a warning of some kind.
695696
}
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-
}
704697
}
705698

706699
if (searchPathOpts.getSDKPath().empty()) {
@@ -870,6 +863,92 @@ importer::addCommonInvocationArguments(
870863
}
871864
}
872865

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(Path(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 Path &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+
873952
bool ClangImporter::canReadPCH(StringRef PCHFilename) {
874953
if (!llvm::sys::fs::exists(PCHFilename))
875954
return false;
@@ -1122,9 +1201,10 @@ ClangImporter::create(ASTContext &ctx,
11221201
}
11231202
}
11241203

1204+
auto fileMapping = getClangInvocationFileMapping(ctx);
11251205
// Wrap Swift's FS to allow Clang to override the working directory
11261206
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
1127-
llvm::vfs::RedirectingFileSystem::create({}, true,
1207+
llvm::vfs::RedirectingFileSystem::create(fileMapping, true,
11281208
*ctx.SourceMgr.getFileSystem());
11291209

11301210
// Create a new Clang compiler invocation.

stdlib/public/Cxx/libstdcxx.h

Lines changed: 68 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,79 @@
1-
#include <algorithm>
2-
#include <bitset>
3-
#include <complex>
4-
#include <deque>
5-
#include <exception>
6-
#include <fstream>
7-
#include <functional>
8-
#include <iomanip>
9-
#include <ios>
10-
#include <iosfwd>
11-
#include <iostream>
12-
#include <istream>
13-
#include <iterator>
14-
#include <limits>
15-
#include <list>
16-
#include <locale>
17-
#include <map>
18-
#include <memory>
19-
#include <new>
20-
#include <numeric>
21-
#include <ostream>
22-
#include <queue>
23-
#include <set>
24-
#include <sstream>
25-
#include <stack>
26-
#include <stdexcept>
27-
#include <streambuf>
28-
#include <string>
29-
#include <utility>
30-
#include <typeinfo>
31-
#include <valarray>
32-
#include <vector>
33-
#include <array>
34-
#include <atomic>
35-
#include <chrono>
36-
#include <codecvt>
37-
#include <condition_variable>
38-
#include <forward_list>
39-
#include <future>
40-
#include <initializer_list>
41-
#include <mutex>
42-
#include <random>
43-
#include <ratio>
44-
#include <regex>
45-
#include <scoped_allocator>
46-
#include <system_error>
47-
#include <thread>
48-
#include <tuple>
49-
#include <typeindex>
50-
#include <type_traits>
51-
#include <unordered_map>
52-
#include <unordered_set>
1+
#include "algorithm"
2+
#include "bitset"
3+
#include "complex"
4+
#include "deque"
5+
#include "exception"
6+
#include "fstream"
7+
#include "functional"
8+
#include "iomanip"
9+
#include "ios"
10+
#include "iosfwd"
11+
#include "iostream"
12+
#include "istream"
13+
#include "iterator"
14+
#include "limits"
15+
#include "list"
16+
#include "locale"
17+
#include "map"
18+
#include "memory"
19+
#include "new"
20+
#include "numeric"
21+
#include "ostream"
22+
#include "queue"
23+
#include "set"
24+
#include "sstream"
25+
#include "stack"
26+
#include "stdexcept"
27+
#include "streambuf"
28+
#include "string"
29+
#include "utility"
30+
#include "typeinfo"
31+
#include "valarray"
32+
#include "vector"
33+
#include "array"
34+
#include "atomic"
35+
#include "chrono"
36+
#include "codecvt"
37+
#include "condition_variable"
38+
#include "forward_list"
39+
#include "future"
40+
#include "initializer_list"
41+
#include "mutex"
42+
#include "random"
43+
#include "ratio"
44+
#include "regex"
45+
#include "scoped_allocator"
46+
#include "system_error"
47+
#include "thread"
48+
#include "tuple"
49+
#include "typeindex"
50+
#include "type_traits"
51+
#include "unordered_map"
52+
#include "unordered_set"
5353

5454
// C++17 and newer:
5555

56-
#if __has_include(<any>)
57-
#include <any>
56+
#if __has_include("any")
57+
#include "any"
5858
#endif
59-
#if __has_include(<charconv>)
60-
#include <charconv>
59+
#if __has_include("charconv")
60+
#include "charconv"
6161
#endif
62-
#if __has_include(<execution>)
63-
#include <execution>
62+
#if __has_include("execution")
63+
#include "execution"
6464
#endif
65-
#if __has_include(<filesystem>)
66-
#include <filesystem>
65+
#if __has_include("filesystem")
66+
#include "filesystem"
6767
#endif
68-
#if __has_include(<memory_resource>)
69-
#include <memory_resource>
68+
#if __has_include("memory_resource")
69+
#include "memory_resource"
7070
#endif
71-
#if __has_include(<optional>)
72-
#include <optional>
71+
#if __has_include("optional")
72+
#include "optional"
7373
#endif
74-
#if __has_include(<string_view>)
75-
#include <string_view>
74+
#if __has_include("string_view")
75+
#include "string_view"
7676
#endif
77-
#if __has_include(<variant>)
78-
#include <variant>
77+
#if __has_include("variant")
78+
#include "variant"
7979
#endif

stdlib/public/Cxx/libstdcxx.modulemap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,13 @@ module std {
2020
header "libstdcxx.h"
2121
requires cplusplus
2222
export *
23+
24+
/// C compatibility headers.
25+
module compat {
26+
module cassert {
27+
header "cassert"
28+
requires cplusplus
29+
export *
30+
}
31+
}
2332
}

0 commit comments

Comments
 (0)