Fix direct clang cc1 emit-pcm commands with vfs overlay on Windows (#85325)

Explicit module builds currently fail on Windows because
direct-clang-cc1-module-build emit-pcm commands take overlaid system
module map files as inputs but miss the clang VFS overlay. This change
adds the overlay and fixes explicit module builds on Windows.
This commit is contained in:
Hiroshi Yamauchi
2025-11-12 21:03:15 -08:00
committed by GitHub
parent 2db0e8aea8
commit a96b57de17
6 changed files with 87 additions and 16 deletions

View File

@@ -75,6 +75,7 @@ namespace dependencies {
namespace swift { namespace swift {
enum class ResultConvention : uint8_t; enum class ResultConvention : uint8_t;
class ASTContext; class ASTContext;
class CASOptions;
class CompilerInvocation; class CompilerInvocation;
class ClangImporterOptions; class ClangImporterOptions;
class ClangInheritanceInfo; class ClangInheritanceInfo;
@@ -83,6 +84,7 @@ class ClangNode;
class ConcreteDeclRef; class ConcreteDeclRef;
class Decl; class Decl;
class DeclContext; class DeclContext;
class DiagnosticEngine;
class EffectiveClangContext; class EffectiveClangContext;
class EnumDecl; class EnumDecl;
class FuncDecl; class FuncDecl;
@@ -878,6 +880,25 @@ struct ClangInvocationFileMapping {
bool requiresBuiltinHeadersInSystemModules; bool requiresBuiltinHeadersInSystemModules;
}; };
class ClangInvocationFileMappingContext {
public:
const LangOptions &LangOpts;
SearchPathOptions &SearchPathOpts;
ClangImporterOptions &ClangImporterOpts;
const CASOptions &CASOpts;
DiagnosticEngine &Diags;
ClangInvocationFileMappingContext(
const LangOptions &LangOpts, SearchPathOptions &SearchPathOpts,
ClangImporterOptions &ClangImporterOpts, const CASOptions &CASOpts,
DiagnosticEngine &Diags)
: LangOpts(LangOpts), SearchPathOpts(SearchPathOpts),
ClangImporterOpts(ClangImporterOpts), CASOpts(CASOpts),
Diags(Diags) {}
ClangInvocationFileMappingContext(const swift::ASTContext &Ctx);
};
/// On Linux, some platform libraries (glibc, libstdc++) are not modularized. /// On Linux, some platform libraries (glibc, libstdc++) are not modularized.
/// We inject modulemaps for those libraries into their include directories /// We inject modulemaps for those libraries into their include directories
/// to allow using them from Swift. /// to allow using them from Swift.
@@ -885,7 +906,7 @@ struct ClangInvocationFileMapping {
/// `suppressDiagnostic` prevents us from emitting warning messages when we /// `suppressDiagnostic` prevents us from emitting warning messages when we
/// are unable to find headers. /// are unable to find headers.
ClangInvocationFileMapping getClangInvocationFileMapping( ClangInvocationFileMapping getClangInvocationFileMapping(
const ASTContext &ctx, const ClangInvocationFileMappingContext &ctx,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = nullptr,
bool suppressDiagnostic = false); bool suppressDiagnostic = false);
@@ -893,7 +914,7 @@ ClangInvocationFileMapping getClangInvocationFileMapping(
/// primarily to inject modulemaps on platforms with non-modularized /// primarily to inject modulemaps on platforms with non-modularized
/// platform libraries. /// platform libraries.
ClangInvocationFileMapping applyClangInvocationMapping( ClangInvocationFileMapping applyClangInvocationMapping(
const ASTContext &ctx, const ClangInvocationFileMappingContext &ctx,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseVFS, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseVFS,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &fileSystem, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &fileSystem,
bool suppressDiagnostics = false); bool suppressDiagnostics = false);

View File

@@ -202,7 +202,8 @@ ClangImporter::createClangArgs(const ClangImporterOptions &ClangImporterOpts,
} }
static SmallVector<std::pair<std::string, std::string>, 2> static SmallVector<std::pair<std::string, std::string>, 2>
getLibcFileMapping(const ASTContext &ctx, StringRef modulemapFileName, getLibcFileMapping(const ClangInvocationFileMappingContext &ctx,
StringRef modulemapFileName,
std::optional<ArrayRef<StringRef>> maybeHeaderFileNames, std::optional<ArrayRef<StringRef>> maybeHeaderFileNames,
const llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &vfs, const llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &vfs,
bool suppressDiagnostic) { bool suppressDiagnostic) {
@@ -269,7 +270,8 @@ getLibcFileMapping(const ASTContext &ctx, StringRef modulemapFileName,
} }
static void getLibStdCxxFileMapping( static void getLibStdCxxFileMapping(
ClangInvocationFileMapping &fileMapping, const ASTContext &ctx, ClangInvocationFileMapping &fileMapping,
const ClangInvocationFileMappingContext &ctx,
const llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &vfs, const llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &vfs,
bool suppressDiagnostic) { bool suppressDiagnostic) {
assert(ctx.LangOpts.EnableCXXInterop && assert(ctx.LangOpts.EnableCXXInterop &&
@@ -475,7 +477,8 @@ GetPlatformAuxiliaryFile(StringRef Platform, StringRef File,
} }
void GetWindowsFileMappings( void GetWindowsFileMappings(
ClangInvocationFileMapping &fileMapping, const ASTContext &Context, ClangInvocationFileMapping &fileMapping,
const ClangInvocationFileMappingContext &Context,
const llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &driverVFS, const llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &driverVFS,
bool &requiresBuiltinHeadersInSystemModules) { bool &requiresBuiltinHeadersInSystemModules) {
const llvm::Triple &Triple = Context.LangOpts.Target; const llvm::Triple &Triple = Context.LangOpts.Target;
@@ -615,8 +618,14 @@ void GetWindowsFileMappings(
} }
} // namespace } // namespace
ClangInvocationFileMappingContext::ClangInvocationFileMappingContext(
const swift::ASTContext &Ctx)
: ClangInvocationFileMappingContext(Ctx.LangOpts, Ctx.SearchPathOpts,
Ctx.ClangImporterOpts, Ctx.CASOpts, Ctx.Diags) {}
ClangInvocationFileMapping swift::getClangInvocationFileMapping( ClangInvocationFileMapping swift::getClangInvocationFileMapping(
const ASTContext &ctx, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs, const ClangInvocationFileMappingContext &ctx,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
bool suppressDiagnostic) { bool suppressDiagnostic) {
ClangInvocationFileMapping result; ClangInvocationFileMapping result;
if (!vfs) if (!vfs)
@@ -687,7 +696,8 @@ ClangInvocationFileMapping swift::getClangInvocationFileMapping(
return result; return result;
} }
ClangInvocationFileMapping swift::applyClangInvocationMapping(const ASTContext &ctx, ClangInvocationFileMapping swift::applyClangInvocationMapping(
const ClangInvocationFileMappingContext &ctx,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseVFS, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> baseVFS,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &fileSystem, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> &fileSystem,
bool suppressDiagnostics) { bool suppressDiagnostics) {
@@ -719,13 +729,9 @@ ClangInvocationFileMapping swift::applyClangInvocationMapping(const ASTContext &
<< "' with the following contents:\n"; << "' with the following contents:\n";
llvm::errs() << file.second << "\n"; llvm::errs() << file.second << "\n";
} }
auto contents = ctx.Allocate<char>(file.second.size() + 1); // Note MemoryBuffer is guaranteeed to be null-terminated.
std::copy(file.second.begin(), file.second.end(), contents.begin());
// null terminate the buffer.
contents[contents.size() - 1] = '\0';
overridenVFS->addFile(file.first, 0, overridenVFS->addFile(file.first, 0,
llvm::MemoryBuffer::getMemBuffer(StringRef( llvm::MemoryBuffer::getMemBufferCopy(file.second));
contents.begin(), contents.size() - 1)));
} }
llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> overlayVFS = llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> overlayVFS =
new llvm::vfs::OverlayFileSystem(fileSystem); new llvm::vfs::OverlayFileSystem(fileSystem);

View File

@@ -1992,6 +1992,14 @@ ModuleDependencyInfo ModuleDependencyScanner::bridgeClangModuleDependency(
} }
} }
// Pass the -sdk flag to make the system header VFS overlay finable
// for the -direct-clang-cc1-module-build emit-pcm command on Windows.
StringRef SDKPath = ScanASTContext.SearchPathOpts.getSDKPath();
if (!SDKPath.empty()) {
swiftArgs.push_back("-sdk");
swiftArgs.push_back(SDKPath.str());
}
// Add args reported by the scanner. // Add args reported by the scanner.
auto clangArgs = invocation.getCC1CommandLine(); auto clangArgs = invocation.getCC1CommandLine();
llvm::for_each(clangArgs, addClangArg); llvm::for_each(clangArgs, addClangArg);

View File

@@ -711,6 +711,25 @@ bool CompilerInstance::setUpVirtualFileSystemOverlays() {
new llvm::vfs::OverlayFileSystem(MemFS); new llvm::vfs::OverlayFileSystem(MemFS);
OverlayVFS->pushOverlay(SourceMgr.getFileSystem()); OverlayVFS->pushOverlay(SourceMgr.getFileSystem());
SourceMgr.setFileSystem(std::move(OverlayVFS)); SourceMgr.setFileSystem(std::move(OverlayVFS));
} else {
// For non-caching -direct-clang-cc1-module-build emit-pcm build,
// setup the clang VFS so it can find system modulemap files
// (like vcruntime.modulemap) as an input file.
if (Invocation.getClangImporterOptions().DirectClangCC1ModuleBuild &&
Invocation.getFrontendOptions().RequestedAction ==
FrontendOptions::ActionType::EmitPCM) {
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
SourceMgr.getFileSystem();
ClangInvocationFileMappingContext Context(
Invocation.getLangOptions(), Invocation.getSearchPathOptions(),
Invocation.getClangImporterOptions(), Invocation.getCASOptions(),
Diagnostics);
ClangInvocationFileMapping FileMapping = applyClangInvocationMapping(
Context, nullptr, VFS, /*suppressDiagnostic=*/false);
if (!FileMapping.redirectedFiles.empty()) {
SourceMgr.setFileSystem(std::move(VFS));
}
}
} }
auto ExpectedOverlay = auto ExpectedOverlay =

View File

@@ -0,0 +1,4 @@
module SAL [system] {
header "sal.h"
export *
}

View File

@@ -0,0 +1,13 @@
// REQUIRES: OS=windows-msvc
// Test that the -direct-clang-cc1-module-build is able to create a module from the VC runtime with an overlaid modulemap file
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// RUN: %swift_frontend_plain -target %target-triple -module-cache-path %t/clang-module-cache -scan-dependencies -module-name Test -sdk %S/Inputs/WinSDK %t/Test.swift -o %t/deps.json
// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps.json clang:SAL > %t/SAL.cmd
// RUN: %swift_frontend_plain @%t/SAL.cmd
//--- Test.swift
import SAL