Skip to content

ModuleInterface/Serialization: allow library authors to define a custom module version number #37177

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
merged 3 commits into from
Apr 30, 2021
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
8 changes: 8 additions & 0 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,14 @@ class ModuleDecl : public DeclContext, public TypeDecl {
ModuleABIName = name;
}

/// User-defined module version number.
llvm::VersionTuple UserModuleVersion;
void setUserModuleVersion(llvm::VersionTuple UserVer) {
UserModuleVersion = UserVer;
}
llvm::VersionTuple getUserModuleVersion() const {
return UserModuleVersion;
}
private:
/// A cache of this module's underlying module and required bystander if it's
/// an underscored cross-import overlay.
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class FrontendOptions {
/// For these modules, we should prefer using Swift interface when importing them.
std::vector<std::string> PreferInterfaceForModules;

/// User-defined module version number.
llvm::VersionTuple UserModuleVersion;

/// Emit index data for imported serialized swift system modules.
bool IndexSystemModules = false;

Expand Down
5 changes: 5 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,11 @@ def working_directory : Separate<["-"], "working-directory">,
def working_directory_EQ : Joined<["-"], "working-directory=">,
Alias<working_directory>;

def user_module_version : Separate<["-"], "user-module-version">,
Flags<[FrontendOption, ModuleInterfaceOption]>,
HelpText<"Module version specified from Swift module authors">,
MetaVarName<"<vers>">;

// VFS

def vfsoverlay : JoinedOrSeparate<["-"], "vfsoverlay">,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Serialization/SerializationOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define SWIFT_SERIALIZATION_SERIALIZATIONOPTIONS_H

#include "swift/Basic/LLVM.h"
#include "llvm/Support/VersionTuple.h"

namespace swift {

Expand All @@ -32,6 +33,7 @@ namespace swift {
const char *SourceInfoOutputPath = nullptr;
std::string SymbolGraphOutputDir;
bool SkipSymbolGraphInheritedDocs = true;
llvm::VersionTuple UserModuleVersion;

StringRef GroupInfoPath;
StringRef ImportedHeader;
Expand Down
1 change: 1 addition & 0 deletions include/swift/Serialization/Validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ struct ValidationInfo {
StringRef shortVersion = {};
StringRef miscVersion = {};
version::Version compatibilityVersion = {};
llvm::VersionTuple userModuleVersion;
size_t bytes = 0;
Status status = Status::Malformed;
};
Expand Down
7 changes: 7 additions & 0 deletions lib/Frontend/ArgsToFrontendOptionsConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ bool ArgsToFrontendOptionsConverter::convert(
Opts.BadFileDescriptorRetryCount = limit;
}

if (auto A = Args.getLastArg(OPT_user_module_version)) {
if (Opts.UserModuleVersion.tryParse(StringRef(A->getValue()))) {
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
A->getAsString(Args), A->getValue());
}
}

Opts.DisableImplicitModules |= Args.hasArg(OPT_disable_implicit_swift_modules);

Opts.ImportPrescan |= Args.hasArg(OPT_import_prescan);
Expand Down
1 change: 1 addition & 0 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ SerializationOptions CompilerInvocation::computeSerializationOptions(
if (opts.SerializeBridgingHeader && !outs.ModuleOutputPath.empty())
serializationOpts.ImportedHeader = opts.ImplicitObjCHeaderPath;
serializationOpts.ModuleLinkName = opts.ModuleLinkName;
serializationOpts.UserModuleVersion = opts.UserModuleVersion;
serializationOpts.ExtraClangOptions = getClangImporterOptions().ExtraArgs;

if (opts.EmitSymbolGraph) {
Expand Down
1 change: 1 addition & 0 deletions lib/Frontend/ModuleInterfaceBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
SerializationOpts.ModuleLinkName = FEOpts.ModuleLinkName;
SerializationOpts.AutolinkForceLoad =
!subInvocation.getIRGenOptions().ForceLoadSymbolName.empty();
SerializationOpts.UserModuleVersion = FEOpts.UserModuleVersion;

// Record any non-SDK module interface files for the debug info.
StringRef SDKPath = SubInstance.getASTContext().SearchPathOpts.SDKPath;
Expand Down
4 changes: 4 additions & 0 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ class ModuleFile
return Core->ModuleABIName;
}

llvm::VersionTuple getUserModuleVersion() const {
return Core->UserModuleVersion;
}

/// The Swift compatibility version in use when this module was built.
const version::Version &getCompatibilityVersion() const {
return Core->CompatibilityVersion;
Expand Down
8 changes: 7 additions & 1 deletion lib/Serialization/ModuleFileSharedCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,12 @@ validateControlBlock(llvm::BitstreamCursor &cursor,
// These fields were added later; be resilient against their absence.
switch (scratch.size()) {
default:
// Add new cases here, in descending order.
// Add new cases here, in descending order.
case 6:
case 5: {
result.userModuleVersion = llvm::VersionTuple(scratch[4], scratch[5]);
LLVM_FALLTHROUGH;
}
case 4:
if (scratch[3] != 0) {
result.compatibilityVersion =
Expand Down Expand Up @@ -1172,6 +1177,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
Name = info.name;
TargetTriple = info.targetTriple;
CompatibilityVersion = info.compatibilityVersion;
UserModuleVersion = info.userModuleVersion;
Bits.ArePrivateImportsEnabled = extInfo.arePrivateImportsEnabled();
Bits.IsSIB = extInfo.isSIB();
Bits.IsTestable = extInfo.isTestable();
Expand Down
3 changes: 3 additions & 0 deletions lib/Serialization/ModuleFileSharedCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class ModuleFileSharedCore {
/// The Swift compatibility version in use when this module was built.
version::Version CompatibilityVersion;

/// User-defined module version number.
llvm::VersionTuple UserModuleVersion;

/// The data blob containing all of the module's identifiers.
StringRef IdentifierData;

Expand Down
4 changes: 3 additions & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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 = 611; // implicit bit for CompletionHandlerAsyncAttr
const uint16_t SWIFTMODULE_VERSION_MINOR = 612; // add user-defined module version

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down Expand Up @@ -763,6 +763,8 @@ namespace control_block {
BCFixed<16>, // Module format minor version
BCVBR<8>, // length of "short version string" in the blob
BCVBR<8>, // length of "short compatibility version string" in the blob
BCVBR<17>, // User module format major version
BCVBR<17>, // User module format minor version
BCBlob // misc. version information
>;

Expand Down
6 changes: 6 additions & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -961,10 +961,16 @@ void Serializer::writeHeader(const SerializationOptions &options) {
size_t compatibilityVersionStringLength =
versionString.tell() - shortVersionStringLength - 1;
versionString << ")/" << version::getSwiftFullVersion();
auto userModuleMajor = options.UserModuleVersion.getMajor();
auto userModuleMinor = 0;
if (auto minor = options.UserModuleVersion.getMinor()) {
userModuleMinor = *minor;
}
Metadata.emit(ScratchRecord,
SWIFTMODULE_VERSION_MAJOR, SWIFTMODULE_VERSION_MINOR,
shortVersionStringLength,
compatibilityVersionStringLength,
userModuleMajor, userModuleMinor,
versionString.str());

Target.emit(ScratchRecord, M->getASTContext().LangOpts.Target.str());
Expand Down
9 changes: 6 additions & 3 deletions lib/Serialization/SerializeDoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -489,10 +489,11 @@ void DocSerializer::writeDocHeader() {
control_block::TargetLayout Target(Out);

auto& LangOpts = M->getASTContext().LangOpts;
auto verText = version::getSwiftFullVersion(LangOpts.EffectiveLanguageVersion);
Metadata.emit(ScratchRecord, SWIFTDOC_VERSION_MAJOR, SWIFTDOC_VERSION_MINOR,
/*short version string length*/0, /*compatibility length*/0,
version::getSwiftFullVersion(
LangOpts.EffectiveLanguageVersion));
/*user module version major*/0,
/*user module version minor*/0, verText);

ModuleName.emit(ScratchRecord, M->getName().str());
Target.emit(ScratchRecord, LangOpts.Target.str());
Expand Down Expand Up @@ -872,10 +873,12 @@ class SourceInfoSerializer : public SerializerBase {
control_block::TargetLayout Target(Out);

auto& LangOpts = M->getASTContext().LangOpts;
auto verText = version::getSwiftFullVersion(LangOpts.EffectiveLanguageVersion);
Metadata.emit(ScratchRecord, SWIFTSOURCEINFO_VERSION_MAJOR,
SWIFTSOURCEINFO_VERSION_MINOR,
/*short version string length*/0, /*compatibility length*/0,
version::getSwiftFullVersion(LangOpts.EffectiveLanguageVersion));
/*user module version major*/0,
/*user module version minor*/0, verText);

ModuleName.emit(ScratchRecord, M->getName().str());
Target.emit(ScratchRecord, LangOpts.Target.str());
Expand Down
2 changes: 1 addition & 1 deletion lib/Serialization/SerializedModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,7 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
M.setHasIncrementalInfo();
if (!loadedModuleFile->getModuleABIName().empty())
M.setABIName(Ctx.getIdentifier(loadedModuleFile->getModuleABIName()));

M.setUserModuleVersion(loadedModuleFile->getUserModuleVersion());
auto diagLocOrInvalid = diagLoc.getValueOr(SourceLoc());
loadInfo.status = loadedModuleFile->associateWithFileContext(
fileUnit, diagLocOrInvalid, Ctx.LangOpts.AllowModuleWithCompilerErrors);
Expand Down
20 changes: 20 additions & 0 deletions test/ModuleInterface/user-module-version.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/textual)
// RUN: %empty-directory(%t/binary)
// RUN: %empty-directory(%t/module-cache)

// RUN: %target-swift-frontend -emit-module %s -module-name Foo -swift-version 5 -disable-implicit-concurrency-module-import -user-module-version 113.33 -emit-module-interface-path %t/textual/Foo.swiftinterface -enable-library-evolution -emit-module-path %t/binary/Foo.swiftmodule

// RUN: %FileCheck %s --check-prefix=INTERFACE-FLAG < %t/textual/Foo.swiftinterface

// RUN: %target-swift-ide-test -print-module-metadata -module-to-print Foo -I %t/textual -source-filename %s -module-cache-path %t/module-cache | %FileCheck %s --check-prefix=USER-MODULE-PRINT

// RUN: %target-swift-ide-test -print-module-metadata -module-to-print Foo -I %t/binary -source-filename %s | %FileCheck %s --check-prefix=USER-MODULE-PRINT

// RUN: rm %t/binary/Foo.swiftmodule
// RUN: %target-swift-frontend -compile-module-from-interface %t/textual/Foo.swiftinterface -o %t/binary/Foo.swiftmodule
// RUN: %target-swift-ide-test -print-module-metadata -module-to-print Foo -I %t/binary -source-filename %s | %FileCheck %s --check-prefix=USER-MODULE-PRINT

// INTERFACE-FLAG: -user-module-version 113.33

// USER-MODULE-PRINT: user module version: 113.33
1 change: 1 addition & 0 deletions tools/swift-ide-test/swift-ide-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2515,6 +2515,7 @@ static int doPrintModuleGroups(const CompilerInvocation &InitInvok,

static void printModuleMetadata(ModuleDecl *MD) {
auto &OS = llvm::outs();
OS << "user module version: " << MD->getUserModuleVersion().getAsString() << "\n";
OS << "fingerprint=" << MD->getFingerprint().getRawValue() << "\n";
MD->collectLinkLibraries([&](LinkLibrary lib) {
OS << "link library: " << lib.getName()
Expand Down