-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
Conversation
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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)
There was a problem hiding this 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?
lib/Driver/DarwinToolChains.cpp
Outdated
|
||
if (llvm::sys::fs::exists(BackDeployLib)) { | ||
Arguments.push_back("-force_load"); | ||
Arguments.push_back(context.Args.MakeArgString(BackDeployLib)); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
lib/Driver/DarwinToolChains.cpp
Outdated
} else { | ||
backDeployToSwift50 = false; | ||
} | ||
if (backDeployToSwift50) { |
There was a problem hiding this comment.
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.
lib/Driver/DarwinToolChains.cpp
Outdated
Triple.getMacOSXVersion(Major, Minor, Micro); | ||
backDeployToSwift50 = Minor <= 14; | ||
} else if (Triple.isiOS()) { | ||
Triple.getiOSVersion(Major, Minor, Micro); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tvos?
There was a problem hiding this comment.
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. :-(
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this first opportunity to use |
Yeah, this is the first time we're exercising the hooks. |
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? |
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. |
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.
9dd1881
to
66ca52c
Compare
@swift-ci Please test |
@jrose-apple @gottesmm @compnerd How's this look now? |
Build failed |
Build failed |
66ca52c
to
4cd4fe1
Compare
@swift-ci Please test |
Build failed |
Build failed |
4cd4fe1
to
2a2d40d
Compare
@swift-ci Please test |
Build failed |
Build failed |
There was a problem hiding this 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>> |
There was a problem hiding this comment.
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? |
There was a problem hiding this comment.
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.
@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
Does the swift driver detect that there are no Swift source inputs and leave |
It must be the driver since we don’t pass anything to indicate the language when linking. /cc @jrose |
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? |
Yep, that should be easily doable. |
Great, I'll look into that. |
if (Major == 10) { | ||
if (Minor <= 14) { | ||
return std::make_pair(5u, 0u); | ||
} else { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Please test with following pull request: @swift-ci Please test |
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
Stage in part of swiftlang#25030 so that build systems can start using it.
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
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
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
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