How to add local Swift Package as dependency?

Well, Xcode 11 beta 2 suggests only remote URLs, right?
Can I add local Swift Package as dependency to test it?

4 Likes

You can drag the package into a workspace/project to add it as a local package.

4 Likes

No luck.
It adds only Package.swift.
Compiler error: No such module 'PackageDescription'.

https://github.com/apple/swift-package-manager/blob/master/Documentation/Usage.md

Clibgit$ git init
Clibgit$ git add .
Clibgit$ git commit -m "Initial Commit"
Clibgit$ git tag 1.0.0

// other package
import PackageDescription

let package = Package(
    name: "example",
    dependencies: [
        .package(url: "../Clibgit", from: "1.0.0")
        //.package(path: "../Clibgit") // is also fine
    ]
)

And if you want to add to your app target.
File -> Swift Packages -> Add Package Dependency...
Enter package repository URL -> file:///Users/.../Clibgit -> Next.
Note: you need to commit to git here. If your package dose not commit to git, Xcode can't find it.

5 Likes

Those are very different.

The URL one requires it to be pointing at a git repository and treats that repository the same as it would a remote one, cloning it and checking out particular versions or revisions. The source you see in Xcode is managed by SwiftPM and will be “locked” and uneditable.

The path one just directly uses whatever is currently in the file system at that location. I think you can even use it that way without either package having a Git repository at all. You will be able to edit the source you see in Xcode directly.

(Caveat: I’m speaking in terms of Xcode 10.2, but the related documentation of SwiftPM looks like it’s still the same.)

5 Likes

Just drag and drop the folder where Package.swift is located too Xcode and then you can link this package to targets. I used this approach many times already without any issues.

4 Likes

I admit some detailed how-to would be appreciated. I've been fiddling with Xcode, drag&dropping all that I could reasonably think of, added my local package to the "Link Binary with Libraries" build phase, etc, without any success so far.

My setup:

  • xCodeProject.xcodeproj
  • xCodeProject
    • AppDelegate.swift
    • ...
  • Package
    • Package.swift
    • Sources
      • Product
        • ...

The goal: be able to import Product from AppDelegate.swift without "No such module 'Product'" error.

Why? I'm trying to reduce a bug in Xcode 11.2 beta 2, and I'm testing the hypothesis that the bug only happens when some code is imported from a swift package.

Thanks

Edit: see solution in the next message.

1 Like

I eventually managed to do it.

  1. Drag the package folder which contains the Package.swift into your Xcode project

  2. Click the Plus button in the "Link Binary with Libraries" section, locate the package in the modal dialog, select the gray library icon inside the package, and add this one.

  3. Build your Xcode project and move on to your next interesting task

Trouble is that Xcode lets you drag the brown package icon to the "Link Binary with Libraries" section of the "Build Phases" tab of your Xcode target. Don't do that: this has no (useful) effect.

25 Likes

What confused me was that nothing useful happens if you drag the manifest into Xcode. You do double click the manifest in order to open a package in Xcode, but you have to drag its parent directory into Xcode to add a package to a pre‐existing project. I expended about half an hour trying to figure it out when I first got Xcode 11. But in the end everything worked and the problem really was just me.

1 Like

When this happens, the problem is never you. That's why we tell those stories.

4 Likes

Granted. It was unintuitive and confusing and that could use improvement. All I meant was that I was relieved to be able to simply rethink my assumptions, and that I didn’t have to wait months for a bug fix or wrangle some awkward workaround.

The proper way to add a local Swift Package is via menu in Xcode:
Swift Packages -> Add Package Dependency...
And type the full URL pointing to your package folder, starting from file:// prefix (it is a local URL after all).

Take note, only the committed changes in the package propagate to the project builds. I.e. it behaves like a fully remote package, despite the fact that you can still edit its sources from the same Xcode project.

2 Likes

Didn't think about this one. Thanks!

We'll eventually gather enough information here in order to workaround the UI oddities of Xcode. Maybe some Apple engineer will read this thread and make the necessary changes to Xcode so that we developers don't lose hours of clueless guesses :-)

I repeat from my earlier comment that using a URL and using a path have vastly different semantics. In addition, relative URLs do not work, so you run into trouble if you are part of a team or use CI: clone the project to another device and nothing will work. There is a time and place for local URLs, but they are not a replacement for relative paths.

If we are looking for what is “proper”, the very first answer upthread came from a rather authoritative source:

2 Likes

Well, I came forward with that answer because it seemed to me some people had issues with dragging and dropping packages. And since the package integration system in Xcode is built around URLs I called the way when you in add a local package by typing in its URL "proper". I apologise if there is any confusion :blush:

2 Likes

Drag&Drop is not the same. It should be possible to add packages through SPM with relative paths as it works with Package.swift, but for Xcode's File -> Swift Packages -> Add Package Dependency... menu.

5 Likes

Your answer was super helpful and got me unblocked for local development. I still need to be able to write a CI test to make sure that the proper symbols are exposed etc... it's simply not enough to have a test that the package target itself will build. Are you aware of any ongoing work on adding proper pathing to Xcode so that we can have proper integration tests? Have you personally found a workaround for this?

Sorry, I don't think I understand your question. How to test that the package correctly exposes its symbols , like everything that has to be marked public is marked as such? Well, unit tests being compiled in separate module cannot access anything which is not exposed through public or not marked as @testable. Is that what you asking?

1 Like

I guess I mean as an integration test. Outside the context of a swift package. After I’ve created the package I want to run a smoke test with a separate project to make sure it can be consumed by that project as expected. This just means importing the libraries, making sure they compile in the context of an external app, and referencing some symbols as a sanity check.

The project I’m working with is sort of complex so it’s not a given that a consuming project will build the same way as the package on its own. I need to know that both are correct. :slightly_smiling_face:

Hmm I don't think I have ever though about implementing buildability test as something separate. technically one could create a separate test project which would be using all API types and calls that should be exposed by the package in question. And if this project builds the test passes. However, using CI implies that your package should already be deployed somewhere to be accessible via its URL by the build machine. So, it won't be local.