Skip to content

Commit 13d92eb

Browse files
committed
[ClangImporter] NFC: extract Clang include path mapping logic into a separate file
This logic is going to be extended to inject the modulemap and the header of Glibc in addition to libstdc++. It doesn't depend on the rest of ClangImporter, so let's extract it to a separate file to make incremental builds and IDE features faster.
1 parent 6a24087 commit 13d92eb

File tree

4 files changed

+200
-152
lines changed

4 files changed

+200
-152
lines changed

lib/ClangImporter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_swift_host_library(swiftClangImporter STATIC
1111
ClangDiagnosticConsumer.cpp
1212
ClangImporter.cpp
1313
ClangImporterRequests.cpp
14+
ClangIncludePaths.cpp
1415
ClangModuleDependencyScanner.cpp
1516
ClangSourceBufferImporter.cpp
1617
SwiftDeclSynthesizer.cpp

lib/ClangImporter/ClangImporter.cpp

Lines changed: 1 addition & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616
#include "swift/ClangImporter/ClangImporter.h"
1717
#include "ClangDiagnosticConsumer.h"
18+
#include "ClangIncludePaths.h"
1819
#include "ImporterImpl.h"
1920
#include "swift/AST/ASTContext.h"
2021
#include "swift/AST/Builtins.h"
@@ -38,21 +39,17 @@
3839
#include "swift/Basic/Version.h"
3940
#include "swift/ClangImporter/ClangImporterRequests.h"
4041
#include "swift/ClangImporter/ClangModule.h"
41-
#include "swift/Config.h"
42-
#include "swift/Demangling/Demangle.h"
4342
#include "swift/Parse/Lexer.h"
4443
#include "swift/Parse/Parser.h"
4544
#include "swift/Strings.h"
4645
#include "swift/Subsystems.h"
4746
#include "clang/AST/ASTContext.h"
4847
#include "clang/AST/Mangle.h"
49-
#include "clang/Basic/CharInfo.h"
5048
#include "clang/Basic/IdentifierTable.h"
5149
#include "clang/Basic/Module.h"
5250
#include "clang/Basic/TargetInfo.h"
5351
#include "clang/Basic/Version.h"
5452
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
55-
#include "clang/Driver/Driver.h"
5653
#include "clang/Frontend/FrontendActions.h"
5754
#include "clang/Frontend/Utils.h"
5855
#include "clang/Index/IndexingAction.h"
@@ -74,7 +71,6 @@
7471
#include "llvm/Support/Path.h"
7572
#include "llvm/Support/VirtualFileSystem.h"
7673
#include "llvm/Support/YAMLParser.h"
77-
#include "llvm/Support/YAMLTraits.h"
7874
#include <algorithm>
7975
#include <string>
8076
#include <memory>
@@ -444,60 +440,6 @@ ClangImporter::~ClangImporter() {
444440

445441
#pragma mark Module loading
446442

447-
static Optional<StringRef> getModuleMapFilePath(StringRef name,
448-
SearchPathOptions &Opts,
449-
llvm::Triple triple,
450-
SmallVectorImpl<char> &buffer) {
451-
StringRef platform = swift::getPlatformNameForTriple(triple);
452-
StringRef arch = swift::getMajorArchitectureName(triple);
453-
454-
StringRef SDKPath = Opts.getSDKPath();
455-
if (!SDKPath.empty()) {
456-
buffer.clear();
457-
buffer.append(SDKPath.begin(), SDKPath.end());
458-
llvm::sys::path::append(buffer, "usr", "lib", "swift");
459-
llvm::sys::path::append(buffer, platform, arch, name);
460-
461-
// Only specify the module map if that file actually exists. It may not;
462-
// for example in the case that `swiftc -target x86_64-unknown-linux-gnu
463-
// -emit-ir` is invoked using a Swift compiler not built for Linux targets.
464-
if (llvm::sys::fs::exists(buffer))
465-
return StringRef(buffer.data(), buffer.size());
466-
}
467-
468-
if (!Opts.RuntimeResourcePath.empty()) {
469-
buffer.clear();
470-
buffer.append(Opts.RuntimeResourcePath.begin(),
471-
Opts.RuntimeResourcePath.end());
472-
llvm::sys::path::append(buffer, platform, arch, name);
473-
474-
// Only specify the module map if that file actually exists. It may not;
475-
// for example in the case that `swiftc -target x86_64-unknown-linux-gnu
476-
// -emit-ir` is invoked using a Swift compiler not built for Linux targets.
477-
if (llvm::sys::fs::exists(buffer))
478-
return StringRef(buffer.data(), buffer.size());
479-
}
480-
481-
return None;
482-
}
483-
484-
/// Finds the glibc.modulemap file relative to the provided resource dir.
485-
///
486-
/// Note that the module map used for Glibc depends on the target we're
487-
/// compiling for, and is not included in the resource directory with the other
488-
/// implicit module maps. It's at {freebsd|linux}/{arch}/glibc.modulemap.
489-
static Optional<StringRef>
490-
getGlibcModuleMapPath(SearchPathOptions &Opts, llvm::Triple triple,
491-
SmallVectorImpl<char> &buffer) {
492-
return getModuleMapFilePath("glibc.modulemap", Opts, triple, buffer);
493-
}
494-
495-
static Optional<StringRef>
496-
getLibStdCxxModuleMapPath(SearchPathOptions &opts, llvm::Triple triple,
497-
SmallVectorImpl<char> &buffer) {
498-
return getModuleMapFilePath("libstdcxx.modulemap", opts, triple, buffer);
499-
}
500-
501443
static bool clangSupportsPragmaAttributeWithSwiftAttr() {
502444
clang::AttributeCommonInfo swiftAttrInfo(clang::SourceRange(),
503445
clang::AttributeCommonInfo::AT_SwiftAttr,
@@ -882,99 +824,6 @@ importer::addCommonInvocationArguments(
882824
}
883825
}
884826

885-
/// On Linux, some platform libraries (glibc, libstdc++) are not modularized.
886-
/// We inject modulemaps for those libraries into their include directories
887-
/// to allow using them from Swift.
888-
static SmallVector<std::pair<std::string, std::string>, 16>
889-
getClangInvocationFileMapping(ASTContext &ctx) {
890-
using Path = SmallString<128>;
891-
892-
const llvm::Triple &triple = ctx.LangOpts.Target;
893-
// We currently only need this when building for Linux.
894-
if (!triple.isOSLinux())
895-
return {};
896-
// Android uses libc++.
897-
if (triple.isAndroid())
898-
return {};
899-
900-
// Extract the libstdc++ installation path from Clang driver.
901-
auto clangDiags = clang::CompilerInstance::createDiagnostics(
902-
new clang::DiagnosticOptions());
903-
clang::driver::Driver clangDriver(ctx.ClangImporterOpts.clangPath,
904-
triple.str(), *clangDiags);
905-
// Flags passed to Swift with `-Xcc` might affect include paths.
906-
unsigned unused1, unused2;
907-
std::vector<const char *> clangArgs;
908-
for (const auto &each : ctx.ClangImporterOpts.ExtraArgs) {
909-
clangArgs.push_back(each.c_str());
910-
}
911-
llvm::opt::InputArgList clangDriverArgs =
912-
clangDriver.getOpts().ParseArgs(clangArgs, unused1, unused2);
913-
// If an SDK path was explicitly passed to Swift, make sure to pass it to
914-
// Clang driver as well. It affects the resulting include paths.
915-
auto sdkPath = ctx.SearchPathOpts.getSDKPath();
916-
if (!sdkPath.empty()) {
917-
unsigned argIndex = clangDriverArgs.MakeIndex("--sysroot", sdkPath);
918-
clangDriverArgs.append(new llvm::opt::Arg(
919-
clangDriver.getOpts().getOption(clang::driver::options::OPT__sysroot),
920-
sdkPath, argIndex));
921-
}
922-
auto cxxStdlibDirs =
923-
clangDriver.getLibStdCxxIncludePaths(clangDriverArgs, triple);
924-
if (cxxStdlibDirs.empty()) {
925-
ctx.Diags.diagnose(SourceLoc(), diag::libstdcxx_not_found, triple.str());
926-
return {};
927-
}
928-
Path cxxStdlibDir(cxxStdlibDirs.front());
929-
// VFS does not allow mapping paths that contain `../` or `./`.
930-
llvm::sys::path::remove_dots(cxxStdlibDir, /*remove_dot_dot=*/true);
931-
932-
// Currently only a modulemap for libstdc++ is injected.
933-
if (!ctx.LangOpts.EnableCXXInterop)
934-
return {};
935-
936-
Path actualModuleMapPath;
937-
Path buffer;
938-
if (auto path = getLibStdCxxModuleMapPath(ctx.SearchPathOpts, triple, buffer))
939-
actualModuleMapPath = path.getValue();
940-
else
941-
return {};
942-
943-
// Only inject the module map if it actually exists. It may not, for example
944-
// if `swiftc -target x86_64-unknown-linux-gnu -emit-ir` is invoked using
945-
// a Swift compiler not built for Linux targets.
946-
if (!llvm::sys::fs::exists(actualModuleMapPath))
947-
// FIXME: emit a warning of some kind.
948-
return {};
949-
950-
// TODO: remove the libstdcxx.h header and reference all libstdc++ headers
951-
// directly from the modulemap.
952-
Path actualHeaderPath = actualModuleMapPath;
953-
llvm::sys::path::remove_filename(actualHeaderPath);
954-
llvm::sys::path::append(actualHeaderPath, "libstdcxx.h");
955-
956-
// Inject a modulemap into VFS for the libstdc++ directory.
957-
// Only inject the module map if the module does not already exist at
958-
// {sysroot}/usr/include/module.{map,modulemap}.
959-
Path injectedModuleMapLegacyPath(cxxStdlibDir);
960-
llvm::sys::path::append(injectedModuleMapLegacyPath, "module.map");
961-
if (llvm::sys::fs::exists(injectedModuleMapLegacyPath))
962-
return {};
963-
964-
Path injectedModuleMapPath(cxxStdlibDir);
965-
llvm::sys::path::append(injectedModuleMapPath, "module.modulemap");
966-
if (llvm::sys::fs::exists(injectedModuleMapPath))
967-
return {};
968-
969-
Path injectedHeaderPath(cxxStdlibDir);
970-
llvm::sys::path::append(injectedHeaderPath, "libstdcxx.h");
971-
972-
return {
973-
{std::string(injectedModuleMapPath), std::string(actualModuleMapPath)},
974-
{std::string(injectedHeaderPath), std::string(actualHeaderPath)},
975-
};
976-
}
977-
978827
bool ClangImporter::canReadPCH(StringRef PCHFilename) {
979828
if (!llvm::sys::fs::exists(PCHFilename))
980829
return false;
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
//===--- ClangIncludePaths.cpp --------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "ClangIncludePaths.h"
14+
#include "swift/AST/ASTContext.h"
15+
#include "swift/AST/DiagnosticEngine.h"
16+
#include "swift/AST/DiagnosticsClangImporter.h"
17+
#include "swift/Basic/Platform.h"
18+
#include "clang/Driver/Driver.h"
19+
#include "clang/Frontend/CompilerInstance.h"
20+
21+
using namespace swift;
22+
23+
static Optional<StringRef> getModuleMapFilePath(StringRef name,
24+
SearchPathOptions &Opts,
25+
llvm::Triple triple,
26+
SmallVectorImpl<char> &buffer) {
27+
StringRef platform = swift::getPlatformNameForTriple(triple);
28+
StringRef arch = swift::getMajorArchitectureName(triple);
29+
30+
StringRef SDKPath = Opts.getSDKPath();
31+
if (!SDKPath.empty()) {
32+
buffer.clear();
33+
buffer.append(SDKPath.begin(), SDKPath.end());
34+
llvm::sys::path::append(buffer, "usr", "lib", "swift");
35+
llvm::sys::path::append(buffer, platform, arch, name);
36+
37+
// Only specify the module map if that file actually exists. It may not;
38+
// for example in the case that `swiftc -target x86_64-unknown-linux-gnu
39+
// -emit-ir` is invoked using a Swift compiler not built for Linux targets.
40+
if (llvm::sys::fs::exists(buffer))
41+
return StringRef(buffer.data(), buffer.size());
42+
}
43+
44+
if (!Opts.RuntimeResourcePath.empty()) {
45+
buffer.clear();
46+
buffer.append(Opts.RuntimeResourcePath.begin(),
47+
Opts.RuntimeResourcePath.end());
48+
llvm::sys::path::append(buffer, platform, arch, name);
49+
50+
// Only specify the module map if that file actually exists. It may not;
51+
// for example in the case that `swiftc -target x86_64-unknown-linux-gnu
52+
// -emit-ir` is invoked using a Swift compiler not built for Linux targets.
53+
if (llvm::sys::fs::exists(buffer))
54+
return StringRef(buffer.data(), buffer.size());
55+
}
56+
57+
return None;
58+
}
59+
60+
static Optional<StringRef>
61+
swift::getGlibcModuleMapPath(SearchPathOptions &Opts, llvm::Triple triple,
62+
SmallVectorImpl<char> &buffer) {
63+
return getModuleMapFilePath("glibc.modulemap", Opts, triple, buffer);
64+
}
65+
66+
static Optional<StringRef>
67+
getLibStdCxxModuleMapPath(SearchPathOptions &opts, llvm::Triple triple,
68+
SmallVectorImpl<char> &buffer) {
69+
return getModuleMapFilePath("libstdcxx.modulemap", opts, triple, buffer);
70+
}
71+
72+
static SmallVector<std::pair<std::string, std::string>, 16>
73+
swift::getClangInvocationFileMapping(ASTContext &ctx) {
74+
using Path = SmallString<128>;
75+
76+
const llvm::Triple &triple = ctx.LangOpts.Target;
77+
// We currently only need this when building for Linux.
78+
if (!triple.isOSLinux())
79+
return {};
80+
// Android uses libc++.
81+
if (triple.isAndroid())
82+
return {};
83+
84+
// Extract the libstdc++ installation path from Clang driver.
85+
auto clangDiags = clang::CompilerInstance::createDiagnostics(
86+
new clang::DiagnosticOptions());
87+
clang::driver::Driver clangDriver(ctx.ClangImporterOpts.clangPath,
88+
triple.str(), *clangDiags);
89+
// Flags passed to Swift with `-Xcc` might affect include paths.
90+
unsigned unused1, unused2;
91+
std::vector<const char *> clangArgs;
92+
for (const auto &each : ctx.ClangImporterOpts.ExtraArgs) {
93+
clangArgs.push_back(each.c_str());
94+
}
95+
llvm::opt::InputArgList clangDriverArgs =
96+
clangDriver.getOpts().ParseArgs(clangArgs, unused1, unused2);
97+
// If an SDK path was explicitly passed to Swift, make sure to pass it to
98+
// Clang driver as well. It affects the resulting include paths.
99+
auto sdkPath = ctx.SearchPathOpts.getSDKPath();
100+
if (!sdkPath.empty()) {
101+
unsigned argIndex = clangDriverArgs.MakeIndex("--sysroot", sdkPath);
102+
clangDriverArgs.append(new llvm::opt::Arg(
103+
clangDriver.getOpts().getOption(clang::driver::options::OPT__sysroot),
104+
sdkPath, argIndex));
105+
}
106+
auto cxxStdlibDirs =
107+
clangDriver.getLibStdCxxIncludePaths(clangDriverArgs, triple);
108+
if (cxxStdlibDirs.empty()) {
109+
ctx.Diags.diagnose(SourceLoc(), diag::libstdcxx_not_found, triple.str());
110+
return {};
111+
}
112+
Path cxxStdlibDir(cxxStdlibDirs.front());
113+
// VFS does not allow mapping paths that contain `../` or `./`.
114+
llvm::sys::path::remove_dots(cxxStdlibDir, /*remove_dot_dot=*/true);
115+
116+
// Currently only a modulemap for libstdc++ is injected.
117+
if (!ctx.LangOpts.EnableCXXInterop)
118+
return {};
119+
120+
Path actualModuleMapPath;
121+
Path buffer;
122+
if (auto path = getLibStdCxxModuleMapPath(ctx.SearchPathOpts, triple, buffer))
123+
actualModuleMapPath = path.getValue();
124+
else
125+
return {};
126+
127+
// Only inject the module map if it actually exists. It may not, for example
128+
// if `swiftc -target x86_64-unknown-linux-gnu -emit-ir` is invoked using
129+
// a Swift compiler not built for Linux targets.
130+
if (!llvm::sys::fs::exists(actualModuleMapPath))
131+
// FIXME: emit a warning of some kind.
132+
return {};
133+
134+
// TODO: remove the libstdcxx.h header and reference all libstdc++ headers
135+
// directly from the modulemap.
136+
Path actualHeaderPath = actualModuleMapPath;
137+
llvm::sys::path::remove_filename(actualHeaderPath);
138+
llvm::sys::path::append(actualHeaderPath, "libstdcxx.h");
139+
140+
// Inject a modulemap into VFS for the libstdc++ directory.
141+
// Only inject the module map if the module does not already exist at
142+
// {sysroot}/usr/include/module.{map,modulemap}.
143+
Path injectedModuleMapLegacyPath(cxxStdlibDir);
144+
llvm::sys::path::append(injectedModuleMapLegacyPath, "module.map");
145+
if (llvm::sys::fs::exists(injectedModuleMapLegacyPath))
146+
return {};
147+
148+
Path injectedModuleMapPath(cxxStdlibDir);
149+
llvm::sys::path::append(injectedModuleMapPath, "module.modulemap");
150+
if (llvm::sys::fs::exists(injectedModuleMapPath))
151+
return {};
152+
153+
Path injectedHeaderPath(cxxStdlibDir);
154+
llvm::sys::path::append(injectedHeaderPath, "libstdcxx.h");
155+
156+
return {
157+
{std::string(injectedModuleMapPath), std::string(actualModuleMapPath)},
158+
{std::string(injectedHeaderPath), std::string(actualHeaderPath)},
159+
};
160+
}

0 commit comments

Comments
 (0)