Skip to content

[stdlib] Add a version number for the stdlib itself; use it in unit tests #24254

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

Closed
wants to merge 8 commits into from

Conversation

lorentey
Copy link
Member

@lorentey lorentey commented Apr 24, 2019

The usual OS-based availability checks aren't always appropriate -- the stdlib we're actually using may not correspond to the version that shipped with the OS we're running on. This makes it tricky to decide whether a particular fix is supposed to be present in the current stdlib, which is a problem for unit tests that are supposed to test these changes.

Add an (arbitrary) version number for the stdlib itself, and use it to skip certain tests that are checking for behavioral changes introduced in 5.1.

rdar://problem/50150948

This is primarily useful to check for the presence/absence of specific modifications while testing the Standard Library itself.

There are two version numbers — _stdlibStaticVersion is the version number the code was compiled with, while _stdlibDynamicVersion is the version that’s currently running.
@lorentey lorentey force-pushed the stdlib-version-checks branch 2 times, most recently from fa14e3b to 3adb5a0 Compare April 24, 2019 21:17
@lorentey lorentey force-pushed the stdlib-version-checks branch from 3adb5a0 to 309e564 Compare April 24, 2019 21:29
@lorentey
Copy link
Member Author

@swift-ci please test

@lorentey lorentey marked this pull request as ready for review April 25, 2019 01:20
@lorentey
Copy link
Member Author

lorentey commented Apr 25, 2019

These version numbers would form a progression like this:

                master:  (1024, 0) → (1025, 0) → (1026, 0) → (1027, 0) → ...
swift-<version>-branch:              (1025, 0) → (1025, 1) → (1025, 2) → ...

We would need to bump the version whenever we introduce a behavioral change that we want to be able to reliably test.

In this setup, versions corresponding to actual toolchain releases would be whatever the version was on the tag the toolchain was built from: say, (1025, 24) or (1329, 128).

These values would explicitly not correspond to major/minor/patch version numbers in some semantic versioning scheme.

Points to ponder:

  • Instead of such versioning, would it be enough to know if the current stdlib was loaded from /usr/lib/swift or a custom toolchain build?

    • I suspect it would, but it could be challenging to ensure we get the logic right every time.
  • How often will this cause merge conflicts?

    • Cherry picking to release branches will be more annoying, and PRs will conflict more often.

    • We should make sure routine version bumps never lead to automerger failures -- the version must be kept in sync between branches that use change propagation.

  • Do we keep tests indefinitely gated at random .custom(2312, 13) version numbers, or do we go back and update them to the released version once that's done?

    • How do we maintain the mapping between official releases and these versions?
  • Should we rather implement a proper semantic versioning scheme?

  • Is there a way to tie the availability of stdlib's own features to these finer-grained versions, rather than magical 9999 OS versions?

@lorentey
Copy link
Member Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 71f57d3

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 71f57d3

Copy link
Member

@milseman milseman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't see why we need to back-deploy or bake any implementation details into our ABI.

/// The two integer components are not intended to correspond to major or minor
/// versions in a semantic versioning scheme. Neither do they correlate with
/// toolchain or OS version numbers.
@_alwaysEmitIntoClient // Introduced in 5.1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we want back-deployment?

Copy link
Member Author

@lorentey lorentey Apr 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we shouldn't? I expect to always be able to retrieve a version number; tying it to an explicit availability check would reduce its usefulness.

}

@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
@usableFromInline
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed if not back deploying

/// The two integer components are not intended to correspond to major or minor
/// versions in a semantic versioning scheme. Neither do they correlate with
/// toolchain or OS version numbers.
public var _stdlibStaticVersion: (Int, Int) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still a little confused. Why is this public?

Copy link
Member Author

@lorentey lorentey Apr 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It allows tests to easily determine if they are back/forward deployed. Binaries that are intimately tied to a particular revision of the stdlib and should not be separately back/forward deployed (e.g. libswiftFoundation) could use it for sanity checks.

if _stdlibDynamicVersion < _stdlibStaticVersion {
  print("I'm back-deployed")
}

This is not strictly necessary, but it seems like a cheap addition. If it's available, the "current" version need not be duplicated (and updated) in more than one place.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, dyld provides two similar version numbers through NSVersionOfRunTimeLibrary and NSVersionOfLinkTimeLibrary.

(The link-time version queries the linkage of the main executable, not the current object, so it's different(ly useful) than the static version number implemented here.)

@milseman
Copy link
Member

@lorentey and I discussed this. If this is just used for our own testing, we can keep it internal so long as StdlibUnittest is built with disable access control.

Karoy, what do you think about making this proper API at some point?

@lorentey
Copy link
Member Author

lorentey commented May 6, 2019

Closing; adding 9999 availability guards to such behavioral tests already covers the most important deployment scenarios. (#24496) A version number like this would be helpful, but its maintenance cost would exceed its usefulness in its current form. (E.g., this variant does not plug into @available syntax.)

@lorentey lorentey closed this May 6, 2019
@lorentey
Copy link
Member Author

lorentey commented May 6, 2019

@milseman I think all resilient Swift modules should have their own separate version number, and there should be a standard way to access it (both at compile-time and at runtime). The version number should be usable in compile-time @available declarations and runtime #available checks. Also, the version number should match the one used by SPM, which implies a semantic versioning scheme.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants