-
Notifications
You must be signed in to change notification settings - Fork 655
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
Library Evolution support #1257
Comments
@AMatecki are you exporting SwiftNIO types or functions as public API in your framework? I would assume no and if that's the case, can you try We will still have a look into why it fails to compile. |
Thanks for your suggestion, I'm new to working with Swift libraries, didn't knew about |
@AMatecki Right. So right now, SwiftNIO's primary and only distribution mechanism is as a SwiftPM package and SwiftPM right now only supports source distribution. SwiftNIO also doesn't guarantee an ABI because in a source-only world, having an ABI guarantee doesn't mean much because everybody will recompile every time. Are you making an |
My library was created before Xcode's SPM support, so I'm creating .xcodeproj from command line. I could include SwiftNIO package to my testing target, but it would complicate my project's build pipeline, so I prefer to attach it as a framework. Would including it using Xcode change anything? |
@AMatecki just to be clear: What you're doing is unsupported but given that you're using it in tests that may be fine. It's unsupported because you're relying on a stable binary interface (ABI) for a source-only package that is only guaranteeing stable APIs. This will only work if you're recompiling everything whenever you update SwiftNIO. So updates of the SwiftNIO containing framework without recompiling the binaries that use it may break. But in order for you to make progress on this issue, here are a few options that you may want to do. OptionsThere are three categories of options and you only need to pick one options out of one category. Each of the options should be able to resolve your immediate issue. Not recommended: Relying on stable ABI (which isn't guaranteed)
Note that relying on a SwiftNIO having a stable ABI (which it doesn't) means that you cannot just update SwiftNIO without recompiling the clients (the binaries that use your framework) too. If you always recompile the clients after every update of the SwiftNIO framework, it will work just fine because you don't need or use the ABI. If you were to pick the second option you might actually find that you can update the SwiftNIO containing framework even without recompiling the clients. That is because by removing all the Pretty Recommended: Relying on stable ABI of a wrapper frameworkIf you were to create your own wrapper framework that does not export any SwiftNIO types but wraps everything necessary, then you could Note that you still need to give your wrapper framework a stable ABI which isn't trivial or obvious. If you don't want to give your wrapper framework a stable ABI, then it's not worth it and you can just pick one of the two options in the 'not recommended' section. Actually Recommended: Use source distributionThe really recommended way is to depend on SwiftNIO using Xcode's package support only. That way you can't distribute frameworks but there's no real need for frameworks because SwiftNIO will be automatically embedded into the binary you're shipping (if you're even shipping a binary). Which option to pickI realise this is a lot of information and not everything might be 100% clear. Please feel free to ask further questions. If you would like some support on which option to pick, you'd need to tell us the answers to the following questions and we can help you:
|
Thanks for a very detailed answer. My usage of SwiftNIO is pretty limited and controlled mainly by myself, so I'll try going with Not Recommended point 2. In case of any issues I can always try going with Pretty Recommended. Actually Recommended is also doable, but I don't want to change our build pipeline just for minor convenience related to UI tests |
@AMatecki sounds great! Just to be sure: If you were to use Xcode's package support you shouldn't need to change anything in your build pipeline. |
We're using a fork this tool for generating |
@AMatecki got it, thank you! |
@weissi After removing |
@AMatecki thanks for reporting back! Glad you got it fixed, we'll try to make an effort to support this better (without making stuff |
Motivation: In SelectableEventloop, Heap, PriorityQueue, etc there were quite a few phantom publics left which cause issues with apple#1257 and are confusing. Modifications: - remove the phantom publics - move SelectableEventLoop to its own file Result: - clearer what's going on (public means public)
Motivation: In SelectableEventloop, Heap, PriorityQueue, etc there were quite a few phantom publics left which cause issues with apple#1257 and are confusing. Modifications: - remove the phantom publics - move SelectableEventLoop to its own file Result: - clearer what's going on (public means public)
Motivation: In SelectableEventloop, Heap, PriorityQueue, etc there were quite a few phantom publics left which cause issues with apple#1257 and are confusing. Modifications: - remove the phantom publics - move SelectableEventLoop to its own file Result: - clearer what's going on (public means public)
Motivation: In SelectableEventloop, Heap, PriorityQueue, etc there were quite a few phantom publics left which cause issues with #1257 and are confusing. Modifications: - remove the phantom publics - move SelectableEventLoop to its own file Result: - clearer what's going on (public means public)
Could somebody provide an example how to use this import? My dependencies added over cocoapods but I did not call any import of NIO (actually I have GRPC-swift dependency which relies on NIO) I have the same error on compilation time |
@6epreu You should be able to get this to work if you do So in short:
|
@weissi thanks for explanation I have added this to Podfile of my Framework and also @_implementationOnly import should be used where necessary
|
@6epreu very cool! Thanks for reporting back! |
Hi, I'm in the same boat. Using Vapor (that uses NIO) via. Tuist. My generated project have Creating NIOConcurrencyHelpers.xcframework...
No 'swiftinterface' files found within ..Path_To_Project/MyProject/TuistWorkspace/Projects/GamingXamarin/Build/archives/ios_simulators.xcarchive/Products/Library/Frameworks/NIOConcurrencyHelpers.framework/Modules/NIOConcurrencyHelpers.swiftmodule'. Any idea how can this be solved? |
You appear to be building an xcframework for NIOConcurrencyHelpers. That's unlikely to be the right thing to do: you should statically link that into Vapor. How are you running the build? |
@Lukasa Sorry for long read below but it will give you a better picture: We have Xamarin app that uses some native code via. XCFrameworks. Until now, we had been embedding all of our swift dependencies as XCFrameworks as well ( Here is our current script (before we added Vapor): # Archive for iOS Devices
xcodebuild archive \
-workspace $WORKSPACE \
-scheme "$SCHEME \
-showBuildTimingSummary \
-derivedDataPath $DERIVED_DATA \
CODE_SIGN_IDENTITY= \
CODE_SIGNING_REQUIRED=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
SKIP_INSTALL=NO" \
-sdk iphoneos \
-destination "generic/platform=iOS" \
-archivePath "Build/archives/ios_devices.xcarchive"
# Archive for iOS Simulators
xcodebuild archive \
-workspace $WORKSPACE \
-scheme "$SCHEME \
-showBuildTimingSummary \
-derivedDataPath $DERIVED_DATA \
CODE_SIGN_IDENTITY= \
CODE_SIGNING_REQUIRED=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
SKIP_INSTALL=NO" \
-sdk iphonesimulator \
-destination "generic/platform=iOS Simulator" \
-archivePath "Build/archives/ios_simulators.xcarchive"
# Create XCFrameworks
find $BuildDir/archives/ios_devices.xcarchive/Products/Library/Frameworks -name '*.framework' >
while read p; do
BaseFrameworkName=$(basename $p .framework)
FrameworkName=$BaseFrameworkName.framework
XCFrameworkName=$BaseFrameworkName.xcframework
DeviceArchive=$BuildDir/archives/ios_devices.xcarchive
SimulatorArchive=$BuildDir/archives/ios_simulators.xcarchive
DeviceSymbols=$DeviceArchive/dSYMS/$FrameworkName.dSYM
DeviceSymbolsSwitch=""
SimulatorSymbols=$SimulatorArchive/dSYMS/$FrameworkName.dSYM
SimulatorSymbolsSwitch=""
if [ -d "$DeviceSymbols" ]; then
DeviceSymbolsSwitch="-debug-symbols $DeviceSymbols"
fi
if [ -d "$SimulatorSymbols" ]; then
SimulatorSymbolsSwitch="-debug-symbols $SimulatorSymbols"
fi
echo
echo Creating $XCFrameworkName...
xcodebuild -create-xcframework \
-framework $DeviceArchive/Products/Library/Frameworks/$FrameworkName \
$DeviceSymbolsSwitch \
-framework $SimulatorArchive/Products/Library/Frameworks/$FrameworkName \
$SimulatorSymbolsSwitch \
-output $BuildDir/xcframeworks/$(basename $XCFrameworkName)
done Now, we need to depend on Vapor/SwiftNIO and only way to use that code in our Xamarin app is via. binary dependency. So for now, in order to build the xcframeworks I have disabled library evolution (by removing BUILD_LIBRARY_FOR_DISTRIBUTION=YES from above script) for all frameworks (internal & external) but So, i'm trying to find a better solution... Now, I really don't care about library evolution part as we can always rebuild our XCFrameworks and Xamarin code for each release of our app. But the problem is that Another thing i'm trying to do, in parallel, to solve this problem is basically try to create one XCFramework with a static library that embeds/copies all code from it's dependencies so that XCFramework won't even care about interface files from dependencies but no luck so far. I don't know if its even possible. I appreciate any feedback/help in this situation. Sorry for long comment again! |
So the core of your problem here is that you're trying to reconcile two impossible tasks. Xamarin wants you to use Xcframeworks, which require library evolution to be enabled (because you need The best solution is to build a framework that hides those dependencies statically within it, and does not expose any of their types in the interface. That framework can be built with library evolution mode, and it keeps your Swift packages as an implementation detail. |
Before I talk about suggested approach, I have few questions (unrelated to NIO but maybe you know the answers or if you can direct me where to ask that would be great):
On your suggested approach: My wrapper framework DomainKit Build Settings:
Vapor and other implicit dependencies:
So far generated |
For these questions I'd recommend asking on the Apple Developer forums, where you'll be able to get more-expert eyes.
It doesn't much matter, both will work. |
Sure, will do that..
I have successfully created a static xcframework via. cocoapods in a test project. I think I will have a working solution in my real project soon. Thank you for all the guidance and help on this forum. |
After update to xcode15, looks like this workaround not work anymore? |
In what way does the workaround not work? |
Hi, I'm using SwiftNIO 2.10.1 as a library attached to tvOS app's UI test to provide mocked backend. Since I'm distributing it as a framework I would really like not to have it rebuild with every new Swift version. To have it working SwiftNIO would have to support Library Evolution. I tried turning it on, but had a lot of errors like this:
'let' property '_storage' may not be initialized directly; use "self.init(...)" or "self = ..." instead
in multiple files. I'm not sure how to fix it by myself. Is there a plan to have Library Evolution implemented in SwiftNIO?
The text was updated successfully, but these errors were encountered: