Skip to content
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

Introduce a backward-deployment library for SR-10600. #25030

Merged
merged 2 commits into from
May 29, 2019

Conversation

jckarter
Copy link
Contributor

@jckarter jckarter commented May 23, 2019

Build a static archive that can be linked into executables and take advantage of the Swift runtime's
hooking mechanism to work around the issue Doug fixed in #24759.
The Swift 5.0 version of swift_conformsToProtocol would return a false negative in some cases where
a subclass conforms using an inherited conformance, so work around this by successively retrying
the original implementation up the superclass chain to try to find a match.

rdar://problem/50057445

set(swift_runtime_compile_flags ${SWIFT_RUNTIME_CORE_CXX_FLAGS})
set(swift_runtime_linker_flags ${SWIFT_RUNTIME_CORE_LINK_FLAGS})

if(SWIFT_BUILD_SDK_OVERLAY)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gottesmm What's the best way to set up the CMake file so this only builds for Darwin targets?

Copy link
Contributor

Choose a reason for hiding this comment

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

Provide an explicit list of target SDKs, like the Platform overlay does.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

I would just do:

add_swift_target_library(swiftCompatibility50 TARGET_LIBRARY STATIC
  ProtocolConformance.cpp
  Overrides.cpp
  TARGET_SDKS ${SWIFT_APPLE_PLATFORMS}
  C_COMPILE_FLAGS ${swift_runtime_library_compile_flags}
  LINK_FLAGS ${swift_runtime_linker_flags}
  INSTALL_IN_COMPONENT stdlib)

Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

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

The change looks great, but can we make sure to test backward deployment?


if (llvm::sys::fs::exists(BackDeployLib)) {
Arguments.push_back("-force_load");
Arguments.push_back(context.Args.MakeArgString(BackDeployLib));
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this only happen in executable targets, or everywhere? What happens when there's a zillion copies of this section in the final app?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It only takes effect in the executable. I should change it so we only link it (by default) into executables.

const WitnessTable *(const Metadata *, const ProtocolDescriptor *);

const WitnessTable *
swiftoverride_conformsToProtocol(const Metadata * const type,
Copy link
Contributor

Choose a reason for hiding this comment

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

You probably shouldn't give this an exported symbol at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It should be hidden visibility by default. We build with -fvisibility=hidden.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, but since it's a static library…it can be even better. Even if you're supposed to only get one copy of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I suppose I could lump the whole thing into one .o file, but that wouldn’t scale very well if we add more back deployment stuff. What did you have in mind?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm. I had been thinking that you'd have a different override section for each entry point, and then none of them need to be exposed, but maybe that wouldn't work, or maybe it'd be a clunky solution anyway. I guess it's fine this way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would be a good idea to more strongly namespace these as swift50override_, in case a future 5.1 compatibility library wants to provide a different hook for the same entry point.

set(swift_runtime_compile_flags ${SWIFT_RUNTIME_CORE_CXX_FLAGS})
set(swift_runtime_linker_flags ${SWIFT_RUNTIME_CORE_LINK_FLAGS})

if(SWIFT_BUILD_SDK_OVERLAY)
Copy link
Contributor

Choose a reason for hiding this comment

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

Provide an explicit list of target SDKs, like the Platform overlay does.

} else {
backDeployToSwift50 = false;
}
if (backDeployToSwift50) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: can you provide a flag to explicitly turn this on or off, with the default of the deployment target check? We've found that useful for other support libraries.

Triple.getMacOSXVersion(Major, Minor, Micro);
backDeployToSwift50 = Minor <= 14;
} else if (Triple.isiOS()) {
Triple.getiOSVersion(Major, Minor, Micro);
Copy link
Contributor

Choose a reason for hiding this comment

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

tvos?

Copy link
Contributor

Choose a reason for hiding this comment

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

tvOS is a kind of iOS according to llvm::Triple. :-(

Copy link
Contributor

Choose a reason for hiding this comment

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

That should be a comment.

set(swift_runtime_compile_flags ${SWIFT_RUNTIME_CORE_CXX_FLAGS})
set(swift_runtime_linker_flags ${SWIFT_RUNTIME_CORE_LINK_FLAGS})

if(SWIFT_BUILD_SDK_OVERLAY)
Copy link
Contributor

Choose a reason for hiding this comment

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

@omochi
Copy link
Contributor

omochi commented May 24, 2019

Is this first opportunity to use __swift_hook, __swift51_hook which prepared before?

@jckarter
Copy link
Contributor Author

Yeah, this is the first time we're exercising the hooks.

@jrose-apple
Copy link
Contributor

Thought: the library should be called Compatibility51 (or actually "5.1"), not 50, because it brings older runtimes up to 5.1. Unless you're planning to make slices based on deployment target?

Is there a test that the hooks are not used on a newer runtime?

@jckarter
Copy link
Contributor Author

I think it's better to name these libraries based on the runtime version they target. The hooks vector is versioned in the section name—Swift 5.1 looks for "__swift51_hooks" instead of "__swift_hooks". For Swift 5.2 or 6.0 or future versions, we might want to link in a 5.0 and 5.1 compatibility library if we're deploying back to Swift 5.0 runtimes.

@jrose-apple
Copy link
Contributor

Got it. I'm a little concerned about the number of these hook sections increasing without bound for someone with a broad backwards-deployment story, but compared to the overall size of an app it's almost certainly not a big deal.

Build a static archive that can be linked into executables and take advantage of the Swift runtime's
hooking mechanism to work around the issue Doug fixed in swiftlang#24759.
The Swift 5.0 version of swift_conformsToProtocol would return a false negative in some cases where
a subclass conforms using an inherited conformance, so work around this by successively retrying
the original implementation up the superclass chain to try to find a match.
@jckarter jckarter force-pushed the SR-10600-back-deploy branch from 9dd1881 to 66ca52c Compare May 24, 2019 16:29
@jckarter
Copy link
Contributor Author

@swift-ci Please test

@jckarter
Copy link
Contributor Author

@jrose-apple @gottesmm @compnerd How's this look now?

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 9dd1881696865b8d0b835f654dad8200eaeb82da

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 9dd1881696865b8d0b835f654dad8200eaeb82da

@jckarter jckarter force-pushed the SR-10600-back-deploy branch from 66ca52c to 4cd4fe1 Compare May 24, 2019 17:25
@jckarter
Copy link
Contributor Author

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 66ca52c73fdeaf1b6fcb96f7e4e6fced69c90710

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 66ca52c73fdeaf1b6fcb96f7e4e6fced69c90710

@jckarter jckarter force-pushed the SR-10600-back-deploy branch from 4cd4fe1 to 2a2d40d Compare May 24, 2019 19:44
@jckarter
Copy link
Contributor Author

@swift-ci Please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 4cd4fe1002c92f784253059a9cd8c8fee93625bf

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 4cd4fe1002c92f784253059a9cd8c8fee93625bf

Copy link
Contributor

@jrose-apple jrose-apple left a comment

Choose a reason for hiding this comment

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

Driver stuff looks okay. I have a few minor comments but they don't need to block the change.

@@ -221,9 +221,46 @@ static bool wantsObjCRuntime(const llvm::Triple &triple) {
llvm_unreachable("unknown Darwin OS");
}

/// Return the earliest backward deployment compatibility version we need to
/// link in for the given target triple, if any.
static Optional<std::pair<unsigned, unsigned>>
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: can you use llvm::VersionTuple for this? Bigger, sure, but also obviously a version. (And has an "empty" representation, though the Optional is fine too.)

} else if (value.equals("none")) {
runtimeCompatibilityVersion = None;
} else {
// TODO: diagnose unknown runtime compatibility version?
Copy link
Contributor

Choose a reason for hiding this comment

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

:-( Yeah, this would have to be somewhere earlier; we currently don't diagnose from command generation.

@jckarter
Copy link
Contributor Author

jckarter commented May 24, 2019

@jrose-apple @aciidb0mb3r Hm, it looks like a couple of swiftpm tests seem to link pure C/ObjC targets using swiftc in a way that doesn't link against libswiftCore.dylib, e.g.:

14:52:21 Test Case '-[FunctionalTests.CFamilyTargetTestCase testObjectiveCPackageWithTestTarget]' started.
14:52:21 
/Users/buildnode/jenkins/workspace/swift-PR-osx/branch-master/swiftpm/Tests/FunctionalTests/CFamilyTargetTests.swift:84: error: -[FunctionalTests.CFamilyTargetTestCase testObjectiveCPackageWithTestTarget] : failed - `swift test' failed:
14:52:21 
14:52:21 executionFailure(error: terminated(1): /Users/buildnode/jenkins/workspace/swift-PR-osx/branch-master/buildbot_incremental/swiftpm-macosx-x86_64/x86_64-apple-macosx/release/swift-test --package-path /var/folders/_8/79jmzf2142z2xydc_01btlx00000gn/T/CFamilyTargets_ObjCmacOSPackage.WymNVg/CFamilyTargets_ObjCmacOSPackage output:
14:52:21     [1/2] Compiling ObjCmacOSPackageTests HelloWorldTest.m
14:52:21     Undefined symbols for architecture x86_64:
14:52:21       "_swift_getObjCClassMetadata", referenced from:
14:52:21           __ZN5swift34swift50override_conformsToProtocolEPKNS_14TargetMetadataINS_9InProcessEEEPKNS_24TargetProtocolDescriptorIS1_EEPFPKNS_18TargetWitnessTableIS1_EES4_S8_E in libswiftCompatibility50.a(ProtocolConformance.cpp.o)
14:52:21     ld: symbol(s) not found for architecture x86_64
14:52:21     <unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
14:52:21     [1/2] Linking ObjCmacOSPackagePackageTests
14:52:21     , output: "[1/2] Compiling ObjCmacOSPackageTests HelloWorldTest.m\nUndefined symbols for architecture x86_64:\n  \"_swift_getObjCClassMetadata\", referenced from:\n      __ZN5swift34swift50override_conformsToProtocolEPKNS_14TargetMetadataINS_9InProcessEEEPKNS_24TargetProtocolDescriptorIS1_EEPFPKNS_18TargetWitnessTableIS1_EES4_S8_E in libswiftCompatibility50.a(ProtocolConformance.cpp.o)\nld: symbol(s) not found for architecture x86_64\n<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)\n[1/2] Linking ObjCmacOSPackagePackageTests\n", stderr: "")
14:52:21 
14:52:21 Test Case '-[FunctionalTests.CFamilyTargetTestCase testObjectiveCPackageWithTestTarget]' failed (2.562 seconds).

Does the swift driver detect that there are no Swift source inputs and leave swiftCore out of the link, or is swiftpm doing that? I could make it so that we don't link the compatibility hooks if we don't link the runtime.

@aciidgh
Copy link
Contributor

aciidgh commented May 24, 2019

It must be the driver since we don’t pass anything to indicate the language when linking. /cc @jrose

@jckarter
Copy link
Contributor Author

Thanks @aciidb0mb3r. Jordan noted that we just rely on autolinking to get the runtime link flag. Does swiftpm know when a target is pure C? Would it be able to pass a flag to disable linking against the runtime compatibility library when building a pure C target?

@aciidgh
Copy link
Contributor

aciidgh commented May 25, 2019

Yep, that should be easily doable.

@jckarter
Copy link
Contributor Author

Great, I'll look into that.

if (Major == 10) {
if (Minor <= 14) {
return std::make_pair(5u, 0u);
} else {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you eliminate these else returns? They don't add anything. You can remove the else.

Copy link
Contributor

@gottesmm gottesmm May 26, 2019

Choose a reason for hiding this comment

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

For bonus points: invert if statements to reduce indentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would become unmanageable if we add branches for more OS versions in the future.

@jckarter
Copy link
Contributor Author

Please test with following pull request:
swiftlang/swift-package-manager#2134

@swift-ci Please test

jckarter added a commit to jckarter/swift-package-manager that referenced this pull request May 29, 2019
swiftlang/swift#25030 introduces a compatibility library that can be statically linked into binaries
in order to back-deploy runtime fixes and new features to OSes that shipped with older Swift
runtimes. This library depends on the Swift runtime being linked into the executable, so it will
cause link errors for pure Clang products (and even if it didn't, it would be a waste of code
size). When building a product without any Swift in it, ask Swift to drive the linker without
introducing any runtime compatibility libraries (and shake out a few other unnecessary linker
flags while we're here).

rdar://problem/50057445
@jckarter jckarter merged commit 2a28948 into swiftlang:master May 29, 2019
jckarter added a commit to jckarter/swift that referenced this pull request May 29, 2019
Stage in part of swiftlang#25030 so that build systems can start using it.
jckarter added a commit to jckarter/swift-package-manager that referenced this pull request Jun 10, 2019
swiftlang/swift#25030 introduces a compatibility library that can be statically linked into binaries
in order to back-deploy runtime fixes and new features to OSes that shipped with older Swift
runtimes. This library depends on the Swift runtime being linked into the executable, so it will
cause link errors for pure Clang products (and even if it didn't, it would be a waste of code
size). When building a product without any Swift in it, ask Swift to drive the linker without
introducing any runtime compatibility libraries (and shake out a few other unnecessary linker
flags while we're here).

rdar://problem/50057445
jckarter added a commit to jckarter/swift-package-manager that referenced this pull request Jun 14, 2019
swiftlang/swift#25030 introduces a compatibility library that can be statically linked into binaries
in order to back-deploy runtime fixes and new features to OSes that shipped with older Swift
runtimes. This library depends on the Swift runtime being linked into the executable, so it will
cause link errors for pure Clang products (and even if it didn't, it would be a waste of code
size). When building a product without any Swift in it, ask Swift to drive the linker without
introducing any runtime compatibility libraries (and shake out a few other unnecessary linker
flags while we're here).

rdar://problem/50057445
aemino pushed a commit to aemino/swift-package-manager that referenced this pull request Sep 14, 2019
swiftlang/swift#25030 introduces a compatibility library that can be statically linked into binaries
in order to back-deploy runtime fixes and new features to OSes that shipped with older Swift
runtimes. This library depends on the Swift runtime being linked into the executable, so it will
cause link errors for pure Clang products (and even if it didn't, it would be a waste of code
size). When building a product without any Swift in it, ask Swift to drive the linker without
introducing any runtime compatibility libraries (and shake out a few other unnecessary linker
flags while we're here).

rdar://problem/50057445
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.

8 participants