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

Add dynamic library product to Package.swift #1483

Merged
merged 1 commit into from
Oct 30, 2020

Conversation

pwc3
Copy link
Contributor

@pwc3 pwc3 commented Oct 28, 2020

We have two products that depend upon Apollo for iOS:

  • Our core iOS app
  • A first-party framework we use in other iOS apps

We recently migrated to use Swift Package Manager in both the core app and in the framework and are in the process of integrating the framework into the core app. This causes an error to occur:

Swift package product 'Apollo' is linked as a static library by '<core app>' and '<framework>'. This will result in duplication of library code.

This is a known issue when integrating Swift packages in Xcode. The Swift Package Manager documentation states that:

A library's product can either be statically or dynamically linked. If possible, don't declare the type of library explicitly to let the Swift Package Manager choose between static or dynamic linking based on the preference of the package's consumer.

However, Xcode links Swift packages as static libraries unless they are specified as dynamic libraries in their respective Package.swift files. (Reference 1, Reference 2, Reference 3.)

This PR proposes a way to work around this issue: It provides an additional Apollo-Dynamic product that is simply the Apollo library with the .dynamic type specifier. This is similar approach to Paper/PaperStatic/PaperDynamic sample code provided in the Swift Package Manager documentation.

This PR allows our core app and framework (and any others encountering this issue) to include the Apollo-Dynamic library and resolve the compiler/linker error. The Apollo product continues to act as a statically linked library.

@apollo-cla
Copy link

@pwc3: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Apollo Contributor License Agreement here: https://contribute.apollographql.com/

@designatednerd
Copy link
Contributor

Interesting! Thanks for the very thorough write-up.

I'm curious: Why not have an intermediate framework that both app and first-party-framework depend on, and have that be where you put Apollo into the mix? That's definitely been a workaround to this issue I've seen repeatedly.

This seems fairly reasonable, though I'm curious what would happen if you tried to add both Apollo and Apollo-Dynamic. Also, are you able to make this work with ApolloCore not being dynamic? There are bits of Apollo which depend on it.

@pwc3
Copy link
Contributor Author

pwc3 commented Oct 30, 2020

I didn't want to go down the intermediate framework path for a couple of reasons. First, the core app and framework live in two different repositories. This would add a third repo into the mix. That's a solvable problem, though. I was more concerned about maintainability. Integrating with Apollo directly via SPM (or previously via CocoaPods), it's relatively simple to stay up to date with the latest releases. Having an intermediate framework in a separate repo would make staying up to date a bit more complicated.

This approach works without making ApolloCore dynamic. As I understand it, ApolloCore is statically linked to Apollo or Apollo-Dynamic. Having the core app and the framework depend on Apollo-Dynamic ultimately results in only a single copy of Apollo-Dynamic in the bundle.

I did an experiment to see what happens if I try to add both Apollo and Apollo-Dynamic to an app. This resulted in two immediate build errors:

  • Swift package target 'ApolloCore' is linked as a static library by '' and 'Apollo-Dynamic'. This will result in duplication of library code.
  • Swift package target 'Apollo' is linked as a static library by '<AppName' and 'Apollo-Dynamic'. This will result in duplication of library code.

I considered proposing the following products:

.library(name: "Apollo", targets: ["Apollo"]),
.library(name: "Apollo-Static", type: .static, targets: ["Apollo"]),
.library(name: "Apollo-Dynamic", type: .dynamic, targets: ["Apollo"]),

This approach, similar to an example in Apple's documentation, would leave Apollo without a specified linkage, allowing SPM to choose the linking. Then the other two products are explicitly statically or dynamically linked. I don't know if that makes things any clearer.

@designatednerd
Copy link
Contributor

Cool, thank you for clarifying, particularly about what happens with Apollo-Core. And it seems like the error is clear enough if you try to add Apollo-Dynamic and Apollo at the same time.

I don't think at this point we need to have the static specifier as a separate target. Hopefully at some point the Xcode SPM integration will let you select whether you want something statically or dynamically linked.

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