Skip to content

Commit 9003f5f

Browse files
[DependencyScan] Correct setup clang VFS for dependency scanning
Currently, dependency scanner is not reporting the redirecting files that are baked inside swift-frontend for platform support. This causes dependency scanner returns virtual path for those files, and swift-driver/build-system will not be able to correct validate the files on incremental build, causing incremental build to be almost clean builds. This behavior issue is caused by the dependency scanning file system layer inside clang dependency scanner that caches stats. If the redirecting files are created underneath the layer, the real path is lost. This fixes the issue by moving the redirecting files above the caching layer using `-ivfsoverlay` option. In addition to that, this commit also unifies how clang importer and clang dependency scanner initiate the VFS, making the logic much simpler.
1 parent edfe1a1 commit 9003f5f

File tree

9 files changed

+182
-177
lines changed

9 files changed

+182
-177
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ class ClangImporter final : public ClangModuleLoader {
167167
Implementation &Impl;
168168

169169
bool requiresBuiltinHeadersInSystemModules = false;
170+
bool needSystemVFSOverlay = false;
170171

171172
ClangImporter(ASTContext &ctx, DependencyTracker *tracker,
172173
DWARFImporterDelegate *dwarfImporterDelegate);
@@ -205,6 +206,14 @@ class ClangImporter final : public ClangModuleLoader {
205206
DWARFImporterDelegate *dwarfImporterDelegate = nullptr,
206207
bool ignoreFileMapping = false);
207208

209+
static std::string getClangSystemOverlayFile(const SearchPathOptions &Opts);
210+
211+
static llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
212+
computeClangImporterFileSystem(
213+
const ASTContext &ctx,
214+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseFS,
215+
ClangImporter *importer = nullptr, bool suppressDiagnostics = false);
216+
208217
std::vector<std::string>
209218
getClangDriverArguments(ASTContext &ctx, bool ignoreClangTarget = false);
210219

@@ -883,56 +892,6 @@ std::optional<ResultConvention>
883892
getCxxRefConventionWithAttrs(const clang::Decl *decl);
884893
} // namespace importer
885894

886-
struct ClangInvocationFileMapping {
887-
/// Mapping from a file name to an existing file path.
888-
SmallVector<std::pair<std::string, std::string>, 2> redirectedFiles;
889-
890-
/// Mapping from a file name to a string of characters that represents the
891-
/// contents of the file.
892-
SmallVector<std::pair<std::string, std::string>, 1> overridenFiles;
893-
894-
bool requiresBuiltinHeadersInSystemModules;
895-
};
896-
897-
class ClangInvocationFileMappingContext {
898-
public:
899-
const LangOptions &LangOpts;
900-
SearchPathOptions &SearchPathOpts;
901-
ClangImporterOptions &ClangImporterOpts;
902-
const CASOptions &CASOpts;
903-
DiagnosticEngine &Diags;
904-
905-
ClangInvocationFileMappingContext(
906-
const LangOptions &LangOpts, SearchPathOptions &SearchPathOpts,
907-
ClangImporterOptions &ClangImporterOpts, const CASOptions &CASOpts,
908-
DiagnosticEngine &Diags)
909-
: LangOpts(LangOpts), SearchPathOpts(SearchPathOpts),
910-
ClangImporterOpts(ClangImporterOpts), CASOpts(CASOpts),
911-
Diags(Diags) {}
912-
913-
ClangInvocationFileMappingContext(const swift::ASTContext &Ctx);
914-
};
915-
916-
/// On Linux, some platform libraries (glibc, libstdc++) are not modularized.
917-
/// We inject modulemaps for those libraries into their include directories
918-
/// to allow using them from Swift.
919-
///
920-
/// `suppressDiagnostic` prevents us from emitting warning messages when we
921-
/// are unable to find headers.
922-
ClangInvocationFileMapping getClangInvocationFileMapping(
923-
const ClangInvocationFileMappingContext &ctx,
924-
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr,
925-
bool suppressDiagnostic = false);
926-
927-
/// Apply the given file mapping to the specified 'fileSystem', used
928-
/// primarily to inject modulemaps on platforms with non-modularized
929-
/// platform libraries.
930-
ClangInvocationFileMapping applyClangInvocationMapping(
931-
const ClangInvocationFileMappingContext &ctx,
932-
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseVFS,
933-
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &fileSystem,
934-
bool suppressDiagnostics = false);
935-
936895
/// Information used to compute the access level of inherited C++ members.
937896
class ClangInheritanceInfo {
938897
/// The cumulative inheritance access specifier, that is used to compute the

lib/ClangImporter/ClangImporter.cpp

Lines changed: 100 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -828,10 +828,9 @@ getEmbedBitcodeInvocationArguments(std::vector<std::string> &invocationArgStrs,
828828
});
829829
}
830830

831-
void
832-
importer::addCommonInvocationArguments(
833-
std::vector<std::string> &invocationArgStrs,
834-
ASTContext &ctx, bool requiresBuiltinHeadersInSystemModules,
831+
void importer::addCommonInvocationArguments(
832+
std::vector<std::string> &invocationArgStrs, ASTContext &ctx,
833+
bool requiresBuiltinHeadersInSystemModules, bool needSystemVFSOverlay,
835834
bool ignoreClangTarget) {
836835
using ImporterImpl = ClangImporter::Implementation;
837836
llvm::Triple triple = ctx.LangOpts.Target;
@@ -1003,6 +1002,12 @@ importer::addCommonInvocationArguments(
10031002
invocationArgStrs.push_back("-Xclang");
10041003
invocationArgStrs.push_back("-fbuiltin-headers-in-system-modules");
10051004
}
1005+
1006+
if (needSystemVFSOverlay) {
1007+
invocationArgStrs.push_back("-ivfsoverlay");
1008+
invocationArgStrs.push_back(
1009+
ClangImporter::getClangSystemOverlayFile(ctx.SearchPathOpts));
1010+
}
10061011
}
10071012

10081013
bool ClangImporter::canReadPCH(StringRef PCHFilename) {
@@ -1151,6 +1156,85 @@ ClangImporter::getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
11511156
return PCHFilename.value();
11521157
}
11531158

1159+
std::string
1160+
ClangImporter::getClangSystemOverlayFile(const SearchPathOptions &Opts) {
1161+
llvm::SmallString<256> overlayPath(Opts.RuntimeResourcePath);
1162+
llvm::sys::path::append(overlayPath,
1163+
Implementation::clangSystemVFSOverlayName);
1164+
return overlayPath.str().str();
1165+
}
1166+
1167+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
1168+
ClangImporter::computeClangImporterFileSystem(
1169+
const ASTContext &ctx,
1170+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseFS,
1171+
ClangImporter *importer, bool suppressDiagnostics) {
1172+
// Configure ClangImporter file system. There are two situations:
1173+
// * If caching is used, thus file system is immutable, the one immutable file
1174+
// system is shared between swift frontend and ClangImporter.
1175+
// * Otherwise, ClangImporter file system is configure from scratch from
1176+
// VFS in SourceMgr using ivfsoverlay options.
1177+
if (ctx.CASOpts.HasImmutableFileSystem)
1178+
return baseFS;
1179+
1180+
ClangInvocationFileMapping fileMapping =
1181+
getClangInvocationFileMapping(ctx, baseFS, suppressDiagnostics);
1182+
1183+
auto importerOpts = ctx.ClangImporterOpts;
1184+
if (importer)
1185+
importer->requiresBuiltinHeadersInSystemModules =
1186+
fileMapping.requiresBuiltinHeadersInSystemModules;
1187+
1188+
auto fileSystem = baseFS;
1189+
if (!fileMapping.redirectedFiles.empty()) {
1190+
if (importerOpts.DumpClangDiagnostics) {
1191+
llvm::errs() << "clang importer redirected file mappings:\n";
1192+
for (const auto &mapping : fileMapping.redirectedFiles) {
1193+
llvm::errs() << " mapping real file '" << mapping.second
1194+
<< "' to virtual file '" << mapping.first << "'\n";
1195+
}
1196+
llvm::errs() << "\n";
1197+
}
1198+
// Create a vfs overlay map for all redirects.
1199+
llvm::vfs::YAMLVFSWriter vfsWriter;
1200+
vfsWriter.setUseExternalNames(true);
1201+
for (const auto &mapping : fileMapping.redirectedFiles)
1202+
vfsWriter.addFileMapping(mapping.first, mapping.second);
1203+
1204+
std::string vfsYAML;
1205+
llvm::raw_string_ostream os(vfsYAML);
1206+
vfsWriter.write(os);
1207+
1208+
fileMapping.overridenFiles.push_back(llvm::MemoryBuffer::getMemBufferCopy(
1209+
vfsYAML, getClangSystemOverlayFile(ctx.SearchPathOpts)));
1210+
1211+
if (importer)
1212+
importer->needSystemVFSOverlay = true;
1213+
}
1214+
1215+
if (!fileMapping.overridenFiles.empty()) {
1216+
auto overridenVFS =
1217+
llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
1218+
for (auto &file : fileMapping.overridenFiles) {
1219+
if (importerOpts.DumpClangDiagnostics) {
1220+
llvm::errs() << "clang importer overriding file '"
1221+
<< file->getBufferIdentifier()
1222+
<< "' with the following contents:\n";
1223+
llvm::errs() << file->getBuffer() << "\n";
1224+
}
1225+
// Note MemoryBuffer is guaranteeed to be null-terminated.
1226+
std::string filePath = file->getBufferIdentifier().str();
1227+
overridenVFS->addFile(filePath, 0, std::move(file));
1228+
}
1229+
auto overlayVFS =
1230+
llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(fileSystem);
1231+
overlayVFS->pushOverlay(std::move(overridenVFS));
1232+
fileSystem = std::move(overlayVFS);
1233+
}
1234+
1235+
return fileSystem;
1236+
}
1237+
11541238
std::vector<std::string>
11551239
ClangImporter::getClangDriverArguments(ASTContext &ctx, bool ignoreClangTarget) {
11561240
assert(!ctx.ClangImporterOpts.DirectClangCC1ModuleBuild &&
@@ -1169,7 +1253,8 @@ ClangImporter::getClangDriverArguments(ASTContext &ctx, bool ignoreClangTarget)
11691253
break;
11701254
}
11711255
addCommonInvocationArguments(invocationArgStrs, ctx,
1172-
requiresBuiltinHeadersInSystemModules, ignoreClangTarget);
1256+
requiresBuiltinHeadersInSystemModules,
1257+
needSystemVFSOverlay, ignoreClangTarget);
11731258
return invocationArgStrs;
11741259
}
11751260

@@ -1235,6 +1320,10 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
12351320
CI->getTargetOpts().DarwinTargetVariantTriple = ctx.LangOpts.TargetVariant->str();
12361321
}
12371322

1323+
if (needSystemVFSOverlay)
1324+
CI->getHeaderSearchOpts().AddVFSOverlayFile(
1325+
getClangSystemOverlayFile(ctx.SearchPathOpts));
1326+
12381327
// Forward the index store path. That information is not passed to scanner
12391328
// and it is cached invariant so we don't want to re-scan if that changed.
12401329
CI->getFrontendOpts().IndexStorePath = ctx.ClangImporterOpts.IndexStorePath;
@@ -1348,18 +1437,13 @@ std::unique_ptr<ClangImporter> ClangImporter::create(
13481437
}
13491438
}
13501439

1351-
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
1352-
ctx.SourceMgr.getFileSystem();
1353-
1354-
ClangInvocationFileMapping fileMapping =
1355-
applyClangInvocationMapping(ctx, nullptr, VFS, ignoreFileMapping);
1356-
1357-
importer->requiresBuiltinHeadersInSystemModules =
1358-
fileMapping.requiresBuiltinHeadersInSystemModules;
1440+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs =
1441+
computeClangImporterFileSystem(ctx, ctx.SourceMgr.getFileSystem(),
1442+
importer.get(), ignoreFileMapping);
13591443

13601444
// Create a new Clang compiler invocation.
13611445
{
1362-
if (auto ClangArgs = importer->getClangCC1Arguments(ctx, VFS))
1446+
if (auto ClangArgs = importer->getClangCC1Arguments(ctx, vfs))
13631447
importer->Impl.ClangArgs = *ClangArgs;
13641448
else
13651449
return nullptr;
@@ -1373,7 +1457,7 @@ std::unique_ptr<ClangImporter> ClangImporter::create(
13731457
llvm::errs() << "'\n";
13741458
}
13751459
importer->Impl.Invocation = createClangInvocation(
1376-
importer.get(), importerOpts, VFS, importer->Impl.ClangArgs);
1460+
importer.get(), importerOpts, vfs, importer->Impl.ClangArgs);
13771461
if (!importer->Impl.Invocation)
13781462
return nullptr;
13791463
}
@@ -1424,7 +1508,7 @@ std::unique_ptr<ClangImporter> ClangImporter::create(
14241508
auto actualDiagClient = std::make_unique<ClangDiagnosticConsumer>(
14251509
importer->Impl, instance.getDiagnosticOpts(),
14261510
importerOpts.DumpClangDiagnostics);
1427-
instance.createVirtualFileSystem(std::move(VFS), actualDiagClient.get());
1511+
instance.createVirtualFileSystem(std::move(vfs), actualDiagClient.get());
14281512
instance.createFileManager();
14291513
instance.createDiagnostics(actualDiagClient.release());
14301514

0 commit comments

Comments
 (0)