Add IsSDKRelative field to ModuleInterfaceLayout

When serializing the module interface path of an interface that
is part of the SDK, we serialize relative to the SDK path. During
deserialization we need to know if a path was serialized relative
to the SDK or not. The existing logic assumes any relative path
has been serialized relative to the SDK, which makes it impossible
to compile modules from relative swiftinterface paths that are not
part of the SDK.

Update the swiftmodule file to include an attribute to show if the
path was serialized relative to the SDK or not, which is used
during deserialization to correctly reconstruct the interface path.
This commit is contained in:
Richard Howell
2024-11-27 08:42:29 -08:00
parent 9e7fa1a023
commit a007833cc0
10 changed files with 50 additions and 11 deletions

View File

@@ -162,6 +162,7 @@ public:
bool SkipNonExportableDecls = false;
bool ExplicitModuleBuild = false;
bool EnableSerializationRemarks = false;
bool IsInterfaceSDKRelative = false;
};
} // end namespace swift

View File

@@ -291,9 +291,10 @@ std::error_code ExplicitModuleInterfaceBuilder::buildSwiftModuleFromInterface(
StringRef SDKPath = Instance.getASTContext().SearchPathOpts.getSDKPath();
auto SDKRelativePath = getRelativeDepPath(InPath, SDKPath);
if (SDKRelativePath.has_value())
if (SDKRelativePath.has_value()) {
SerializationOpts.ModuleInterface = SDKRelativePath.value();
else
SerializationOpts.IsInterfaceSDKRelative = true;
} else
SerializationOpts.ModuleInterface = InPath;
SerializationOpts.SDKName = Instance.getASTContext().LangOpts.SDKName;

View File

@@ -1615,6 +1615,8 @@ ModuleFileSharedCore::ModuleFileSharedCore(
break;
}
case input_block::MODULE_INTERFACE_PATH: {
input_block::ModuleInterfaceLayout::readRecord(
scratch, IsModuleInterfaceSDKRelative);
ModuleInterfacePath = blobData;
break;
}
@@ -1837,10 +1839,12 @@ bool ModuleFileSharedCore::hasSourceInfo() const {
std::string ModuleFileSharedCore::resolveModuleDefiningFilePath(const StringRef SDKPath) const {
if (!ModuleInterfacePath.empty()) {
std::string interfacePath = ModuleInterfacePath.str();
if (llvm::sys::path::is_relative(interfacePath) && !ModuleInterfacePath.starts_with(SDKPath)) {
SmallString<128> absoluteInterfacePath(SDKPath);
llvm::sys::path::append(absoluteInterfacePath, interfacePath);
return absoluteInterfacePath.str().str();
if (IsModuleInterfaceSDKRelative &&
!ModuleInterfacePath.starts_with(SDKPath) &&
llvm::sys::path::is_relative(interfacePath)) {
SmallString<128> resolvedPath(SDKPath);
llvm::sys::path::append(resolvedPath, interfacePath);
return resolvedPath.str().str();
} else
return interfacePath;
} else

View File

@@ -74,6 +74,9 @@ class ModuleFileSharedCore {
/// Empty if this module didn't come from an interface file.
StringRef ModuleInterfacePath;
/// true if this module interface was serialized relative to the SDK path.
bool IsModuleInterfaceSDKRelative = false;
/// The module interface path if this module is adjacent to such an interface
/// or it was itself compiled from an interface. Empty otherwise.
StringRef CorrespondingInterfacePath;

View File

@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 904; // @available renamed decl ID removed
const uint16_t SWIFTMODULE_VERSION_MINOR = 905; // IsModuleInterfaceSDKRelative
/// A standard hash seed used for all string hashes in a serialized module.
///
@@ -1158,7 +1158,8 @@ namespace input_block {
using ModuleInterfaceLayout = BCRecordLayout<
MODULE_INTERFACE_PATH,
BCBlob // file path
BCFixed<1>, // SDK-relative?
BCBlob // file path
>;
}

View File

@@ -1352,7 +1352,8 @@ void Serializer::writeInputBlock() {
}
if (!Options.ModuleInterface.empty())
ModuleInterface.emit(ScratchRecord, Options.ModuleInterface);
ModuleInterface.emit(ScratchRecord, Options.IsInterfaceSDKRelative,
Options.ModuleInterface);
SmallVector<ExternalMacroPlugin> macros;
M->getExternalMacros(macros);

View File

@@ -0,0 +1,8 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -target arm64-apple-macosx15.0 -module-name A
import B
public struct AStruct {
var y : BStruct
}

View File

@@ -0,0 +1,9 @@
// swift-interface-format-version: 1.0
// swift-module-flags: -target arm64-apple-macosx15.0 -module-name B
import Swift
public struct BStruct {
var x : Int
public init()
}

View File

@@ -0,0 +1,11 @@
// RUN: %empty-directory(%t.relative_interface_path)
// RUN: cp -R %S/Inputs/relative_path %t.relative_interface_path/
// RUN: cd %t.relative_interface_path
// RUN: mkdir out
// RUN: %target-swift-frontend -target arm64-apple-macosx15.0 -compile-module-from-interface \
// RUN: relative_path/B.swiftmodule/arm64-apple-macos.swiftinterface -o out/B.swiftmodule
// RUN: %target-swift-frontend -target arm64-apple-macosx15.0 -compile-module-from-interface \
// RUN: relative_path/A.swiftmodule/arm64-apple-macos.swiftinterface -o out/A.swiftmodule -I out
// REQUIRES: OS=macosx

View File

@@ -18,8 +18,8 @@
// RUN: llvm-bcanalyzer -dump %t/inputs/Foo.swiftmodule > %t/Foo.sdk.moduledump.txt
// RUN: cat %t/Foo.sdk.moduledump.txt | %FileCheck %s -check-prefix CHECK-SDK-FOO
// CHECK-FREESTANDING-FOO: <MODULE_INTERFACE_PATH abbrevid={{[0-9]+}}/> blob data = '{{.*}}{{/|\\}}modules{{/|\\}}Foo.swiftinterface'
// CHECK-SDK-FOO: <MODULE_INTERFACE_PATH abbrevid={{[0-9]+}}/> blob data = 'usr/lib/Foo.swiftmodule/Foo.swiftinterface'
// CHECK-FREESTANDING-FOO: <MODULE_INTERFACE_PATH abbrevid={{[0-9]+}} op0=0/> blob data = '{{.*}}{{/|\\}}modules{{/|\\}}Foo.swiftinterface'
// CHECK-SDK-FOO: <MODULE_INTERFACE_PATH abbrevid={{[0-9]+}} op0=1/> blob data = 'usr/lib/Foo.swiftmodule/Foo.swiftinterface'
//--- modules/Foo.swiftinterface
// swift-interface-format-version: 1.0