diff --git a/include/swift/Frontend/FrontendOptions.h b/include/swift/Frontend/FrontendOptions.h index 8b130b59f0073..6b9b422209a4e 100644 --- a/include/swift/Frontend/FrontendOptions.h +++ b/include/swift/Frontend/FrontendOptions.h @@ -14,6 +14,7 @@ #define SWIFT_FRONTEND_FRONTENDOPTIONS_H #include "swift/Basic/FileTypes.h" +#include "swift/Basic/Version.h" #include "swift/Frontend/FrontendInputsAndOutputs.h" #include "swift/Frontend/InputFile.h" #include "llvm/ADT/Hashing.h" @@ -262,6 +263,16 @@ class FrontendOptions { /// The install_name to use in the TBD file. std::string TBDInstallName; + // The current project version to use in the generated TBD file. Defaults + // to 1, which matches the default if the DYLIB_CURRENT_VERSION build setting + // is not set. + version::Version TBDCurrentVersion = {1, 0, 0}; + + // The dylib compatibility-version to use in the generated TBD file. Defaults + // to 1, which matches the default if the DYLIB_COMPATIBILITY_VERSION build + // setting is not set. + version::Version TBDCompatibilityVersion = {1, 0, 0}; + /// An enum with different modes for automatically crashing at defined times. enum class DebugCrashMode { None, ///< Don't automatically crash. diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 6bc86d88139a5..fa834f1891cbe 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -74,6 +74,20 @@ def tbd_install_name def tbd_install_name_EQ : Joined<["-"], "tbd-install_name=">, Alias; +def tbd_current_version + : Separate<["-"], "tbd-current-version">, MetaVarName<"">, + HelpText<"The current_version to use in an emitted TBD file">; + +def tbd_current_version_EQ : Joined<["-"], "tbd-current-version=">, + Alias; + +def tbd_compatibility_version + : Separate<["-"], "tbd-compatibility-version">, MetaVarName<"">, + HelpText<"The compatibility_version to use in an emitted TBD file">; + +def tbd_compatibility_version_EQ : Joined<["-"], "tbd-compatibility-version=">, + Alias; + def verify : Flag<["-"], "verify">, HelpText<"Verify diagnostics against expected-{error|warning|note} " "annotations">; diff --git a/include/swift/TBDGen/TBDGen.h b/include/swift/TBDGen/TBDGen.h index ef4190079ba5d..2f940180ccb78 100644 --- a/include/swift/TBDGen/TBDGen.h +++ b/include/swift/TBDGen/TBDGen.h @@ -14,6 +14,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "swift/Basic/Version.h" namespace llvm { class raw_ostream; @@ -35,6 +36,10 @@ struct TBDGenOptions { llvm::StringRef InstallName; /// \brief The module link name (for force loading). llvm::StringRef ModuleLinkName; + /// \brief The current project version. + version::Version CurrentVersion; + /// \brief The dylib compatibility version. + version::Version CompatibilityVersion; }; void enumeratePublicSymbols(FileUnit *module, llvm::StringSet<> &symbols, diff --git a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp index 770b1c8e1b6ca..0c05036cd0240 100644 --- a/lib/Frontend/ArgsToFrontendOptionsConverter.cpp +++ b/lib/Frontend/ArgsToFrontendOptionsConverter.cpp @@ -217,6 +217,18 @@ void ArgsToFrontendOptionsConverter::computeTBDOptions() { if (const Arg *A = Args.getLastArg(OPT_tbd_install_name)) { Opts.TBDInstallName = A->getValue(); } + if (const Arg *A = Args.getLastArg(OPT_tbd_compatibility_version)) { + if (auto vers = version::Version::parseVersionString( + A->getValue(), SourceLoc(), &Diags)) { + Opts.TBDCompatibilityVersion = *vers; + } + } + if (const Arg *A = Args.getLastArg(OPT_tbd_current_version)) { + if (auto vers = version::Version::parseVersionString( + A->getValue(), SourceLoc(), &Diags)) { + Opts.TBDCurrentVersion = *vers; + } + } } void ArgsToFrontendOptionsConverter::setUnsignedIntegerArgument( diff --git a/lib/FrontendTool/FrontendTool.cpp b/lib/FrontendTool/FrontendTool.cpp index 09bc9a2379268..ccb3d1274b1d0 100644 --- a/lib/FrontendTool/FrontendTool.cpp +++ b/lib/FrontendTool/FrontendTool.cpp @@ -801,6 +801,8 @@ static bool writeTBDIfNeeded(CompilerInvocation &Invocation, opts.InstallName = installName; opts.HasMultipleIGMs = Invocation.getSILOptions().hasMultipleIGMs(); opts.ModuleLinkName = frontendOpts.ModuleLinkName; + opts.CurrentVersion = frontendOpts.TBDCurrentVersion; + opts.CompatibilityVersion = frontendOpts.TBDCompatibilityVersion; return writeTBD(Instance.getMainModule(), TBDPath, opts); } diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index bd00a6d5913b2..1c65cbd7ce45f 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -411,6 +411,18 @@ void TBDGenVisitor::addFirstFileSymbols() { } } +/// Converts a version tuple into a packed version, ignoring components beyond +/// major, minor, and subminor. +static tapi::internal::PackedVersion +convertToPacked(version::Version &version) { + // FIXME: Warn if version is greater than 3 components? + unsigned major = 0, minor = 0, subminor = 0; + if (version.size() > 0) major = version[0]; + if (version.size() > 1) minor = version[1]; + if (version.size() > 2) subminor = version[2]; + return tapi::internal::PackedVersion(major, minor, subminor); +} + static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile, StringSet *symbols, llvm::raw_ostream *os, @@ -422,10 +434,9 @@ static void enumeratePublicSymbolsAndWrite(ModuleDecl *M, FileUnit *singleFile, tapi::internal::InterfaceFile file; file.setFileType(tapi::internal::FileType::TBD_V3); file.setInstallName(opts.InstallName); - file.setCompatibilityVersion(tapi::internal::PackedVersion(1, 0, 0)); + file.setCurrentVersion(convertToPacked(opts.CurrentVersion)); + file.setCompatibilityVersion(convertToPacked(opts.CompatibilityVersion)); file.setTwoLevelNamespace(); - // FIXME: proper version - file.setCurrentVersion(tapi::internal::PackedVersion(1, 0, 0)); file.setSwiftABIVersion(TAPI_SWIFT_ABI_VERSION); file.setPlatform(tapi::internal::mapToSinglePlatform(target)); auto arch = tapi::internal::getArchType(target.getArchName()); diff --git a/test/TBD/dylib-version.swift b/test/TBD/dylib-version.swift new file mode 100644 index 0000000000000..4df259ba9a63d --- /dev/null +++ b/test/TBD/dylib-version.swift @@ -0,0 +1,26 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend -emit-ir -o /dev/null %s -tbd-current-version 2.0.3 -tbd-compatibility-version 1.7 -emit-tbd -emit-tbd-path %t/both_provided.tbd +// RUN: %target-swift-frontend -emit-ir -o /dev/null %s -tbd-current-version 2.0 -emit-tbd -emit-tbd-path %t/only_current_provided.tbd +// RUN: %target-swift-frontend -emit-ir -o /dev/null %s -tbd-compatibility-version 2 -emit-tbd -emit-tbd-path %t/only_compat_provided.tbd +// RUN: not %target-swift-frontend -emit-ir -o /dev/null %s -tbd-compatibility-version not_a_version_string -emit-tbd -emit-tbd-path /dev/null 2>&1 | %FileCheck %s --check-prefix BOGUS + +// RUN: %FileCheck %s --check-prefix BOTH < %t/both_provided.tbd +// RUN: %FileCheck %s --check-prefix CURRENT < %t/only_current_provided.tbd +// RUN: %FileCheck %s --check-prefix COMPAT < %t/only_compat_provided.tbd + +// BOTH: current-version: 2.0.3 +// BOTH: compatibility-version: 1.7 +// CURRENT: current-version: 2 + +// Compatibility version defaults to 1 if not present in TBD file, and +// tapi does not write field if compatibility version is 1 + +// CURRENT-NOT: compatibility-version: 1 + +// COMPAT: compatibility-version: 2 + +// Same as above -- current version defaults to 1 and is not present in +// emitted TBD file if it's 1. +// COMPAT-NOT: current-version: 1 + +// BOGUS: version component contains non-numeric characters