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

Why is AnyPromise not available with SPM? #1192

Closed
DG0BAB opened this issue Mar 16, 2021 · 25 comments
Closed

Why is AnyPromise not available with SPM? #1192

DG0BAB opened this issue Mar 16, 2021 · 25 comments

Comments

@DG0BAB
Copy link

DG0BAB commented Mar 16, 2021

  • Please specify the PromiseKit major version you are using
    6

  • Please specify how you installed PromiseKit, ie. Carthage, CocoaPods, SwiftPM or other. If other provide DETAILED information about how you are integrating PromiseKit.
    CocoaPods and indirectly with SPM (see text)

AnyPromise is not available when using Swift PackageManager. But why?
I read in another issue that this is documented but I can't find anything regarding this fact.

My Problem:

I'm using PromiseKit in a mixed Swift/ObjC project. I'm including PromiseKit using CocoaPods but trying to successively switch to SPM. Since I need AnyPromise, I wasn't able to move PromiseKit from CocoaPods to SPM so far.

But now I ran into another Problem: I'm using a SwiftPackage, which itself has a dependency to PromiseKit. Now my main project is complaining that AnyPromise isn't available, because the SPM (internal) dependency to PromiseKit is "overriding" the CocoaPods dependency. As far as I know, there is no way, to create something like a "private" dependency within a Swift Package. All dependencies are automatically "re-exported" and visible to the main project.

I was searching through the Swift Forums already but there currently seems to be no way to avoid re-exporting SPM package dependencies. Maybe if I understand why AnyPromise isn't available when using SPM I might be able to find a workaround.

@mxcl
Copy link
Owner

mxcl commented Mar 16, 2021

AnyPromise is Objective C, initially you couldn't build any objc with SwiftPM and I believe it is still problematic.

I imagine you can copy the sources for AnyPromise into your project.

@DG0BAB
Copy link
Author

DG0BAB commented Mar 16, 2021

Copying the sources seems reasonable. Thanks for that tip.

But on the other hand, are you sure about that Objc thing? I'm using two form libraries in my project: XLForm for Objective-C and Eureka for Swift. I migrated both from CocoaPods to SPM. The XLForm is 100% Objective-C and it works flawlessly with SPM. Both are from xmartlabs.

@mxcl
Copy link
Owner

mxcl commented Mar 17, 2021

I’m not sure no. A PR that added AnyPromise would be welcome. I fear however it is as I fear here, we do some serious shit in some of those sources.

@DG0BAB
Copy link
Author

DG0BAB commented Mar 17, 2021

I already got it working! SPM and AnyPromise in both worlds Swift and ObjC.

Just forked the Repo. I'm currently busy to integrate my changes into it. If all is well I'll create a PR soon.

It's not as shitty as you fear :-)

@mxcl
Copy link
Owner

mxcl commented Mar 17, 2021

Be sure to add all the AnyPromise tests to the package.

I expect the tests to fail on Linux, as well as the build.

@DG0BAB
Copy link
Author

DG0BAB commented Mar 17, 2021

I wasn't able to add the AnyPromise tests to the package. SPM needs a strict separation of swift and Objective-C files within a target. Which means a target can only consist of Swift-Files or ObjC-Files but not both.

I tried to create separate ObjC and Swift Test-Targets, but since they are depending on each other, I couldn't get it to work. I believe the only way to solve this, is adding the Test-Targets to the Product-Package but then they would be visible to the client.

But, I was able to change PromiseKit.xcodeproject in a way that all tests are running on cmd+U. And guess what? All the Bridging and AnyPromise tests succeeded!

I'm going to create a PR now. Please let me know the results of your review.

@DG0BAB
Copy link
Author

DG0BAB commented Mar 17, 2021

Your expectations about failing on Linux were correct!

@DG0BAB
Copy link
Author

DG0BAB commented Mar 19, 2021

The command swift test --generate-linuxmain -Xswiftc -target -Xswiftc x86_64-apple-macosx10.12 is failing. If I run the same command locally on my machine in the project dir, it completes without errors. I don't know the reason why it's failing on Travis. I noticed that the toolchain on Travis is rather old. Xcode 10.3 and iOS SDK 12.4. Maybe the order of how specific artefacts are build is different. It's failing at @import PromiseKit;.

@DG0BAB
Copy link
Author

DG0BAB commented Mar 22, 2021

Just tested it on my machine with Xcode 10.3 and it's failing as well. I currently have no idea how to work around this problem. It works flawlessly with Xcode 12 and it solves my problem. I can use AnyPromise with SPM, Swift and Objective-C. Maybe someone else can come up with a solution? Would be nice if the solution in my Fork could be merged into the main repo. Sadly I currently don't have the time, to further investigate this issue. @mxcl would be nice, if you could link this Issue to my PR. Thank you.

@mxcl
Copy link
Owner

mxcl commented May 24, 2021

Closing in lieu of #1193

@mxcl mxcl closed this as completed May 24, 2021
@nfrydenholm
Copy link

Is there a status on how this issue (and the PR) is coming along?
I bumped into the issue with the missing AnyPromise, while migrating from CocoaPod to SPM.

I've tried to just copy the ObjC files into my project, while using the SPM. But eventually that end up failing with duplicate symbol '_OBJC_CLASS_$_PMKArray' in: (it complains about 5 duplicate symbols - all pointing to the PMKArray, and it seems to be the PMKCallVariadicBlock and the AnyPromise that is causing the duplication).
But I cannot really see anything obvious that is causing the duplicate symbols 🤷

Next attempt was to try the fork @DG0BAB is working on. I can get the SPM just fine (just pointing to master for now), but I don't have any PromiseKitObjc to import in places where I need the AnyPromise 🤔

Any ideas/suggestions would be greatly appreciated.

@DG0BAB
Copy link
Author

DG0BAB commented Jul 13, 2021

Hey Niels,

normally you can just use my fork at https://github.com/DG0BAB/PromiseKit, pointing to master as you did. Then just use #import "PromiseKit.h" in ObjectiveC to get access to AnyPromise. At least that's how it worked for me.

If problems remain, I'm glad to help!

@nfrydenholm
Copy link

nfrydenholm commented Jul 13, 2021

Thanks @DG0BAB - I did try to point to master of your fork. So far only from my own SPM module (where there is no ObjC), so I haven't tried to #import "PromiseKit.h" , but I was under the impression that I should be able e.g. do an import PromiseKitObjC in my own SPM, but there is not such a thing.

Making my own SPM is new to me, so I'm not expert in defining the Packages, but I'm wondering if this one https://github.com/DG0BAB/PromiseKit/blob/master/Package%40swift-5.3.swift. should be similar to https://github.com/DG0BAB/PromiseKit/blob/master/Package%40swift-5.0.swift and have multiple targets, and if that could be the reason I don't see the PromiseKitObjC target available for import?

@DG0BAB
Copy link
Author

DG0BAB commented Jul 13, 2021

In Swift as well in ObjectiveC you just have to import PromiseKit to get both - Promise and AnyPromise. You should never have to import PromiseKitObjC. PromiseKitObjC is just an implementation detail since SPM is not able to deal with mixed source code targets. In one target you can either have pure ObjectiveC or pure Swift source code. So I moved all ObjectiveC code to the PromiseKitObjC target and made that depend upon PromiseKit. The PromiseKit Package consists of one product PromiseKit and this depends on two targets PromiseKit and PromiseKitObjC. Sadly it's not possible to create some kind of private target in SPM which would not be visible to the client but only internal to the package. If there were such a thing, I would have made the PromiseKitObjC target private.

If you just use Xcode to point to my fork's master, you should not have the Package@swift-5.3.swift at all but only the Package@swift-5.0.swift besides the Package@swift-4.2.swift.

I have the same setup as you. In my main Project, which is mixed ObjectiveC and Swift, I'm using, besides others, my Backchat Swift framework. Which in turn has a dependency to PromiseKit. In the Swift code of my main Project I can just use import PromiseKit to get access to AnyPromise. In the ObjectiveC parts I'm using #import "PromiseKit.h".

So, just forget about PromiseKitObjC. You don't need to import it.

@nfrydenholm
Copy link

I have now changed my SPM to use your fork, and it's the correct one now also being resolved in my app (that depends on my SPM)

I have imported PromiseKit in a Swift class, where I'm returning AnyPromise as it's a function used from ObjC.
But I get the "Cannot find AnyPromise in scope".

image

When I expand the PromiseKit package, I do see the Package@swift-5.3.swift - not sure that is the problem, but it's my best guess for now 😄
image

@DG0BAB
Copy link
Author

DG0BAB commented Jul 13, 2021

Sorry, I had a cached version lying around. After updating I can see Package@swift-5.3.swift, and I believe it has to be adjusted to have the same content as Package@swift-5.0.swift. Just as you recommended. I did a small and fast fix on the develop branch in my repository, Could you please point to develop instead of master, try again and tell me if it works? If so, I will merge the fix over to master.

@nfrydenholm
Copy link

I have now tested it with the develop branch, and it works much better now 👍
I can now use AnyPromise from Swift and return it to an ObjC class to continue with some then operation.

I do have one problem in an ObjC file, where I'm creating a Promise like this

    AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve){
       // do some more stuff
        resolve(nil);
    }];
    return promise;

When I have that code enabled I get a

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_AnyPromise", referenced from:

I'm not really sure what could be causing that issue 🤔

But as far as the changes in the Package@swift-5.3.swift on the developbranch, it's working fine 👌
Thanks for your quick change/test on that branch.

@nfrydenholm
Copy link

@DG0BAB it appears the Undefined symbols happens if I try to make an AnyPromise in ObjC using any of the [AnyPromise promiseWith....] - however, it works fine using an AnyPromise in ObjC, if it's being created/returned from a Swift function.

Will you merge the develop branch to master, for the Package@swift-5.3.swift changes?

@DG0BAB
Copy link
Author

DG0BAB commented Jul 15, 2021

Hey! I never had to create the AnyPromise in ObjectiveC. I always create them in Swift to hand them over to ObjectiveC so I never hit that error. If I find the time I might do some investigation on that.

I'm going to merge develop into master now.

@nfrydenholm
Copy link

I also worked around the problem with ObjC for now - it was only in one place, which I could easy extract into a Swift extension to create the AnyPromise.

I'll switch back to the master branch from your fork 😄

@nfrydenholm
Copy link

@DG0BAB would it be possible to tag the current state on master of your fork, so I can reference a specific version rather han a branch (or a revision for a specific commit, which I'm currently using)?

I bump into some SPM issues, where my own modules cannot be referenced with a specific version, because it depends on an "unstable version" of Promisekit. And I would prefer using versions for my internal modules rather than different branches. 😄

Dependencies could not be resolved because package 'ios-core-library' is required using a stable-version but 'ios-core-library' depends on an unstable-version package 'promisekit'

@nfrydenholm
Copy link

@DG0BAB Would the idea above ☝️ be possible, so I can avoid doing a fork of a fork? 😄

@DG0BAB
Copy link
Author

DG0BAB commented Aug 11, 2021

Sorry for the delay...

I'll create a version as soon as I find the time. Most possibly by the end of this week. I'll let you know. So stay tuned 😉

@nfrydenholm
Copy link

@DG0BAB any update on creating a version? 🙂

@nfrydenholm
Copy link

@DG0BAB just a friendly request/reminder about the tagging with a version, so I can avoid making a fork of a fork 😄

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

No branches or pull requests

3 participants