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

Support for Swift Packages #624

Merged
merged 16 commits into from
Sep 27, 2019
Merged

Support for Swift Packages #624

merged 16 commits into from
Sep 27, 2019

Conversation

yonaskolb
Copy link
Owner

@yonaskolb yonaskolb commented Aug 13, 2019

This adds support for defining and linking to Swift Packages

packages:
  Yams:
    url: https://github.com/jpsim/Yams
    majorVersion: 2.0.0
  SwiftPM:
    url: https://github.com/apple/swift-package-manager
    branch: swift-5.0-branch
targets:
  App:
    dependencies:
      - package: Yams 
      - package: SwiftPM
        product: SPMUtility

See the ProjectSpec diff for more documentation https://github.com/yonaskolb/XcodeGen/pull/624/files#diff-938b5cf412212f1137a53f072512963a

Please test this out and report any issues.

One thing that is broken as of Xcode 11 beta 5 is that packages don't work if you are using configurations other than the default Debug and Release. That SPM bug is tracked here https://bugs.swift.org/browse/SR-10927

Copy link
Collaborator

@toshi0383 toshi0383 left a comment

Choose a reason for hiding this comment

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

LGTM🙆‍♂️

Copy link
Collaborator

@brentleyjones brentleyjones left a comment

Choose a reason for hiding this comment

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

I'm going to pull this down and experiment with our project to see if everything is good. Looks good from review though.

## Swift Package
Swift packages are defined at a project level, and then linked to individual targets via a [Dependency](#dependency).

> Note that Swift Packages don't work in projects with configurations other than Debug and Release
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Owner Author

Choose a reason for hiding this comment

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

Done

@mmmilo
Copy link

mmmilo commented Aug 13, 2019

Is it possible to allow for adding multiple products?

One use case is that I am looking to add a target that contains mock/test data.

Edit:
For example:

project.yml:

dependencies:
- package: SomeDependency
       product: [SomeDependency, SomeDependencyTestData]

Package.swift:

let package = Package(
    name: "SomeDependencyAPI",
    products: [
        .library(name: "SomeDependencyAPI", targets: ["SomeDependencyAPI"]),
        .library(name: "SomeDependencyAPITestData", targets: ["SomeDependencyAPITestData"]),
    ],
    dependencies: [
    ],
    targets: [
        .target(
            name: "SomeDependencyAPI",
            dependencies: []),
        .target(
            name: "SomeDependencyAPITestData",
            dependencies: ["SomeDependencyAPI"]),
        .testTarget(
            name: "SomeDependencyAPITests",
            dependencies: ["SomeDependencyAPITestData", "SomeDependencyAPI"]),
    ]
)

Copy link
Collaborator

@brentleyjones brentleyjones left a comment

Choose a reason for hiding this comment

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

Because these are statically linked, we should treat them like target dependencies that are static libraries. What this means is that if I declare the following:

packages:
  Yams:
    url: https://github.com/jpsim/Yams
    majorVersion: 2.0.0
targets:
  App:
    dependencies:
      - target: StaticLibraryA
      - package: Yams
  StaticLibraryA:
    dependencies:
      - package: Yams

Then Yams should only be linked to App, not StaticLibraryA, otherwise we will get duplicated symbols. (And the same if only StaticLibraryA declared the dependency). You can see how it was done at https://github.com/yonaskolb/XcodeGen/blob/swift_packages/Sources/XcodeGenKit/PBXProjGenerator.swift#L470-L479 for target dependencies.


We also need to add the packages as Target Dependencies (especially once you make the above change, since Xcode won't know to build the SPM package before building StaticLibraryA):

image


Really nice work @yonaskolb!

@brentleyjones
Copy link
Collaborator

For example, without the above change we get the following on one of our static library targets:

image

@kdubb
Copy link

kdubb commented Aug 17, 2019

This works great for us! Thanks!

Supporting local packages would help us immensely when it comes to project maintenance. This seems like it should be fairly easy since Xcode 11 already fully supports local packages.

A little background for use case...

Our main usage of this feature is to generate xcode projects for our Swift Package Manager projects that need to be tested on multiple platforms via command line; especially those with special requirements.

For example, our security framework requires the keychain access entitlement on all platforms except macOS to run unit tests. To facilitate CI we generate a project using xcodegen that has host applications setup for each of the test targets and those host applications are granted keychain access. We then simply use xcodebuild to build and run tests for each platform.

Now that xcodegen supports package dependencies we can generate a fairly straightforward project for the framework, then we add our test & test host targets. Unfortunately this means we are duplicating package dependencies that are already defined in our Package.swift. While this is way better than previous, it requires us to keep dependency versions up to date in 2 places, Package.swift and project.yml.

Supporting local packages would allow us to generate an xcodeproj that contains only test targets & test host targets. They would reference a package dependency to the local folder (e.g. .) which defines the framework itself as a package. This would be solve maintaining dependencies in two places as well as test the framework as as Swift package which is how it will be consumed.

@mbuchetics
Copy link

With Xcode 11 Final right around the corner ... are there any plans on merging this soon into master with an official release?

@yonaskolb
Copy link
Owner Author

Ok I've:

  • rebased
  • added some more docs
  • prevented linking to static libs
  • added a commented out stub for adding package target dependencies. It requires this PR I created in XcodeProj first Add PBXTargetDependency.productReference tuist/XcodeProj#481. Interestingly Xcode doesn't do this if you add a dependency via it's UI, so I wouldn't say that should stop this PR from being merged and released.

@brentleyjones could you look this over again, and make sure it works with your static library setup


@mmmilo

Is it possible to allow for adding multiple products?

To accomplish that you can use multiple dependency declarations. This allows us to control settings for a single linkage if needed

dependencies:
  - package: SomeDependency
    product: SomeDependency # this isn't required
  - package: SomeDependency
    product: SomeDependencyTestData

@kdubb

Supporting local packages would help us immensely when it comes to project maintenance. This seems like it should be fairly easy since Xcode 11 already fully supports local packages.

Yes this will be possible. It isn't in this PR but will come in a followup one. It's just adding a path as a PBXFileReference and Xcode takes care of the rest.


@mbuchetics

With Xcode 11 Final right around the corner ... are there any plans on merging this soon into master with an official release?

Yes, I'd like to get this released as soon as possible. If you could test it on your setup that would help.

Mint makes this easy:

mint run yonaskolb/xcodegen@swift_packages xcodegen generate

@yonaskolb yonaskolb reopened this Sep 27, 2019
@yonaskolb
Copy link
Owner Author

I've added support for package target dependencies for proper build dependency resolution.
I've also added local swift package support. For the moment it doesn't support linking these unless they mirror remote packages

@mbuchetics
Copy link

I just experimented with it (see https://github.com/allaboutapps/ios-starter/tree/spm) and it works great!
However, I ran into https://bugs.swift.org/browse/SR-10927 again ... this is a huge issue for us and we won't be able to use SPM until this is fixed. Can't believe this made it into 11.1 :(

@brentleyjones
Copy link
Collaborator

@yonaskolb I'll start reviewing this shortly. I'll let you know!

Copy link
Collaborator

@brentleyjones brentleyjones left a comment

Choose a reason for hiding this comment

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

Works great!

@yonaskolb yonaskolb merged commit c780ed3 into master Sep 27, 2019
@yonaskolb yonaskolb deleted the swift_packages branch September 27, 2019 14:31
@yonaskolb
Copy link
Owner Author

Released in 2.8.0!

rcari added a commit to rcari/XcodeGen that referenced this pull request Oct 31, 2019
PR yonaskolb#624 introduced a bug with operator priorities discarding false link settings
for dependencies when the target is an executable and the dependency a static
library. This PR fixes that.
brentleyjones pushed a commit that referenced this pull request Oct 31, 2019
PR #624 introduced a bug with operator priorities discarding false link settings
for dependencies when the target is an executable and the dependency a static
library. This PR fixes that.
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.

6 participants