Skip to content

[6.0 🍒][Dependency Scanning] Resolve cross-import overlays relative to defining interface for prebuilt binary Swift dependencies #74949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions include/swift/AST/ModuleDependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,13 +367,15 @@ class SwiftBinaryModuleDependencyStorage
const std::string &sourceInfoPath,
const std::vector<ScannerImportStatementInfo> &moduleImports,
const std::vector<ScannerImportStatementInfo> &optionalModuleImports,
const std::string &headerImport, const bool isFramework,
const std::string &headerImport,
const std::string &definingModuleInterface, const bool isFramework,
const std::string &moduleCacheKey)
: ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary,
moduleImports, optionalModuleImports,
moduleCacheKey),
compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath),
sourceInfoPath(sourceInfoPath), headerImport(headerImport),
definingModuleInterfacePath(definingModuleInterface),
isFramework(isFramework) {}

ModuleDependencyInfoStorageBase *clone() const override {
Expand All @@ -392,6 +394,10 @@ class SwiftBinaryModuleDependencyStorage
/// The path of the .h dependency of this module.
const std::string headerImport;

/// The path of the defining .swiftinterface that this
/// binary .swiftmodule was built from, if one exists.
const std::string definingModuleInterfacePath;

/// Source files on which the header inputs depend.
std::vector<std::string> headerSourceFiles;

Expand All @@ -401,6 +407,15 @@ class SwiftBinaryModuleDependencyStorage
/// A flag that indicates this dependency is a framework
const bool isFramework;

/// Return the path to the defining .swiftinterface of this module
/// of one was determined. Otherwise, return the .swiftmodule path
/// itself.
std::string getDefiningModulePath() const {
if (definingModuleInterfacePath.empty())
return compiledModulePath;
return definingModuleInterfacePath;
}

static bool classof(const ModuleDependencyInfoStorageBase *base) {
return base->dependencyKind == ModuleDependencyKind::SwiftBinary;
}
Expand Down Expand Up @@ -560,12 +575,13 @@ class ModuleDependencyInfo {
const std::vector<ScannerImportStatementInfo> &moduleImports,
const std::vector<ScannerImportStatementInfo> &optionalModuleImports,
const std::string &headerImport,
const std::string &definingModuleInterface,
bool isFramework, const std::string &moduleCacheKey) {
return ModuleDependencyInfo(
std::make_unique<SwiftBinaryModuleDependencyStorage>(
compiledModulePath, moduleDocPath, sourceInfoPath,
moduleImports, optionalModuleImports,
headerImport, isFramework, moduleCacheKey));
moduleImports, optionalModuleImports, headerImport,
definingModuleInterface, isFramework, moduleCacheKey));
}

/// Describe the main Swift module.
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/ModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ ModuleDependencyInfo::collectCrossImportOverlayNames(
}
case swift::ModuleDependencyKind::SwiftBinary: {
auto *swiftBinaryDep = getAsSwiftBinaryModule();
modulePath = swiftBinaryDep->compiledModulePath;
modulePath = swiftBinaryDep->getDefiningModulePath();
assert(modulePath.has_value());
StringRef parentDir = llvm::sys::path::parent_path(*modulePath);
if (llvm::sys::path::extension(parentDir) == ".swiftmodule") {
Expand Down
3 changes: 2 additions & 1 deletion lib/DependencyScan/ModuleDependencyCacheSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,11 +508,12 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
if (!headerImport)
llvm::report_fatal_error("Bad binary direct dependencies: no header import");

// TODO: DefiningModulePath
// Form the dependencies storage object
auto moduleDep = ModuleDependencyInfo::forSwiftBinaryModule(
*compiledModulePath, *moduleDocPath, *moduleSourceInfoPath,
currentModuleImports, currentOptionalModuleImports,
*headerImport, isFramework, *moduleCacheKey);
*headerImport, "", isFramework, *moduleCacheKey);

auto headerModuleDependencies = getStringArray(headerModuleDependenciesArrayID);
if (!headerModuleDependencies)
Expand Down
16 changes: 2 additions & 14 deletions lib/Serialization/ModuleFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,6 @@ static bool isTargetTooNew(const llvm::Triple &moduleTarget,
return ctxTarget.isOSVersionLT(moduleTarget);
}

std::string ModuleFile::resolveModuleDefiningFilename(const ASTContext &ctx) {
if (!Core->ModuleInterfacePath.empty()) {
std::string interfacePath = Core->ModuleInterfacePath.str();
if (llvm::sys::path::is_relative(interfacePath)) {
SmallString<128> absoluteInterfacePath(ctx.SearchPathOpts.getSDKPath());
llvm::sys::path::append(absoluteInterfacePath, interfacePath);
return absoluteInterfacePath.str().str();
} else
return interfacePath;
} else
return getModuleLoadedFilename().str();
}

namespace swift {
namespace serialization {
bool areCompatible(const llvm::Triple &moduleTarget,
Expand Down Expand Up @@ -271,7 +258,8 @@ Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc,

ASTContext &ctx = getContext();
// Resolve potentially-SDK-relative module-defining .swiftinterface path
ResolvedModuleDefiningFilename = resolveModuleDefiningFilename(ctx);
ResolvedModuleDefiningFilename =
Core->resolveModuleDefiningFilePath(ctx.SearchPathOpts.getSDKPath());

llvm::Triple moduleTarget(llvm::Triple::normalize(Core->TargetTriple));
if (!areCompatible(moduleTarget, ctx.LangOpts.Target)) {
Expand Down
4 changes: 0 additions & 4 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,6 @@ class ModuleFile
ArrayRef<ProtocolConformanceID>
claimLazyConformanceLoaderToken(uint64_t token);

/// If the module-defining `.swiftinterface` file is an SDK-relative path,
/// resolve it to be absolute to the context's SDK.
std::string resolveModuleDefiningFilename(const ASTContext &ctx);

/// Represents an identifier that may or may not have been deserialized yet.
///
/// If \c Ident is empty, the identifier has not been loaded yet.
Expand Down
13 changes: 13 additions & 0 deletions lib/Serialization/ModuleFileSharedCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1773,6 +1773,19 @@ bool ModuleFileSharedCore::hasSourceInfo() const {
return !!DeclUSRsTable;
}

std::string ModuleFileSharedCore::resolveModuleDefiningFilePath(const StringRef SDKPath) const {
if (!ModuleInterfacePath.empty()) {
std::string interfacePath = ModuleInterfacePath.str();
if (llvm::sys::path::is_relative(interfacePath)) {
SmallString<128> absoluteInterfacePath(SDKPath);
llvm::sys::path::append(absoluteInterfacePath, interfacePath);
return absoluteInterfacePath.str().str();
} else
return interfacePath;
} else
return ModuleInputBuffer->getBufferIdentifier().str();
}

ModuleLoadingBehavior
ModuleFileSharedCore::getTransitiveLoadingBehavior(
const Dependency &dependency,
Expand Down
4 changes: 4 additions & 0 deletions lib/Serialization/ModuleFileSharedCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,10 @@ class ModuleFileSharedCore {
return Dependencies;
}

/// If the module-defining `.swiftinterface` file is an SDK-relative path,
/// resolve it to be absolute to the specified SDK.
std::string resolveModuleDefiningFilePath(const StringRef SDKPath) const;

/// Returns \c true if this module file contains a section with incremental
/// information.
bool hasIncrementalInfo() const { return HasIncrementalInfo; }
Expand Down
8 changes: 6 additions & 2 deletions lib/Serialization/SerializedModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -494,11 +494,15 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework,
optionalModuleImports.push_back(
ScannerImportStatementInfo(optionalImportedModule.str()));

// Attempt to resolve the module's defining .swiftinterface path
std::string definingModulePath =
loadedModuleFile->resolveModuleDefiningFilePath(Ctx.SearchPathOpts.getSDKPath());

// Map the set of dependencies over to the "module dependencies".
auto dependencies = ModuleDependencyInfo::forSwiftBinaryModule(
modulePath.str(), moduleDocPath, sourceInfoPath, moduleImports,
optionalModuleImports, importedHeader, isFramework,
/*module-cache-key*/ "");
optionalModuleImports, importedHeader, definingModulePath,
isFramework, /*module-cache-key*/ "");

return std::move(dependencies);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// REQUIRES: objc_interop
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/module-cache)
// RUN: %empty-directory(%t/inputs)
// RUN: %empty-directory(%t/binaryInputs)
// RUN: %empty-directory(%t/separateModules)
// RUN: %empty-directory(%t/inputs/Foo.swiftcrossimport)
// RUN: split-file %s %t

// - Fixup the input module file map
// RUN: sed -e "s|INPUTSDIR|%/t/inputs|g" %t/map.json.template > %t/map.json.template1
// RUN: sed -e "s|STDLIBMOD|%/stdlib_module|g" %t/map.json.template1 > %t/map.json.template2
// RUN: sed -e "s|ONONEMOD|%/ononesupport_module|g" %t/map.json.template2 > %t/map.json.template3
// RUN: sed -e "s|SWIFTLIBDIR|%swift-lib-dir|g" %t/map.json.template3 > %t/map.json

// - Pre-compile explicit module dependency inputs
// RUN: %target-swift-emit-pcm -module-name SwiftShims %swift-lib-dir/swift/shims/module.modulemap -o %t/inputs/SwiftShims.pcm

// - Pre-compile the Foo module into a separately-stored binary module
// RUN: %target-swift-frontend -compile-module-from-interface %t/separateModules/Foo.swiftinterface -o %t/binaryInputs/Foo.swiftmodule -module-name Foo -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -disable-implicit-swift-modules -Xcc -fno-implicit-modules -Xcc -fno-implicit-module-maps -explicit-swift-module-map-file %t/map.json

// - Run a dependency scan on test.swift which will pick-up the ready-made binary dependency on Foo.swiftmodule
// and use the binary module's serialized originating defining .swiftinterface path to be able to
// discover the cross-import overlay _Foo_Bar.
// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/module-cache %t/test.swift -o %t/deps.json -I %t/inputs -I %t/binaryInputs -module-name test -enable-cross-import-overlays -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import

// CHECK: "mainModuleName": "test"
// CHECK: "swift": "test"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "modulePath": "test.swiftmodule"
// CHECK-NEXT: "sourceFiles": [
// CHECK-NEXT: "{{.*}}{{/|\\}}module_deps_cross_import_of_binary_module.swift.tmp{{/|\\}}test.swift"
// CHECK-NEXT: ]
// CHECK-NEXT: "directDependencies": [
// CHECK-DAG: "swiftPrebuiltExternal": "Swift"
// CHECK-DAG: "swiftPrebuiltExternal": "SwiftOnoneSupport"
// CHECK-DAG: "swiftPrebuiltExternal": "Foo"
// CHECK-DAG: "swift": "Bar"
// CHECK-DAG: "swift": "_Foo_Bar"

//--- map.json.template
[
{
"moduleName": "Swift",
"modulePath": "STDLIBMOD",
"isFramework": false
},
{
"moduleName": "SwiftOnoneSupport",
"modulePath": "ONONEMOD",
"isFramework": false
},
{
"moduleName": "SwiftShims",
"isFramework": false,
"clangModuleMapPath": "SWIFTLIBDIR/swift/shims/module.modulemap",
"clangModulePath": "INPUTSDIR/SwiftShims.pcm"
}]

//--- test.swift
import Foo
import Bar

//--- separateModules/Foo.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name Foo
public func foo() {}

//--- inputs/Bar.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name Bar
public func bar() {}

//--- inputs/_Foo_Bar.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name _Foo_Bar
public func foobar() {}

//--- separateModules/Foo.swiftcrossimport/Bar.swiftoverlay
%YAML 1.2
---
version: 1
modules:
- name: _Foo_Bar