How to add local Swift Package as dependency?

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.

19 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.

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

3 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.

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.

So the whole idea is that I could test it before it's deployed somewhere by using the local branch. I think this is still possible, just need to tool around with it a bit more.

I'm working on my libs by using them in my projects so I expect that my libs are connected locally so I can change their code on-the-fly. With Cocoapods I can do easily cause they put local pods to the specific folder named Development Pods and this is extremely useful.

I came here while trying to find out why dragging my Swift package into an Xcode project was not working. The package would show up in the project pane, but without the disclosure triangle, and the library it contained wouldn't show up when I tried to choose it with "Link Binary with Libraries".

The solution I found was to close the Xcode project after dropping the Swift package. On reopening the project, the disclosure triangle appeared, and everything else worked.

This is in Xcode 11.3 on MacOS 10.15.1. Hope this helps someone else.

3 Likes

If you're looking for a "development pods" type of experience, where you've got a local copy of the package source and you want to edit that source from inside the host project without having to commit and push your changes there's not currently a way to do that. However... I have found a hack that gets you halfway there. I'm using this approach in a sample project I include in one of my package's repositories.

Before proceeding, the following assumptions are made:

• you have your package repo cloned to your machine
• create a sample Xcode project in your Package repo

The root directory of your package repo should look like this, more or less:

Package.swift
Sources/
Tests/
SampleProject/

Then perform the following steps:

  1. Use the Xcode GUI to add your package to the sample project. You'll need to use the actual HTTPS URL to the repo origin. Specify a branch name to a branch you're comfortable working from regularly, e.g. a "develop" branch or something.

  2. Open the sample project's project.pbxproj file in a text editor.

  3. Find the XCRemoteSwiftPackageReference section.

  4. Edit the repositoryURL value so the line reads: repositoryURL = "../";

Now you should be able to build your sample project and run it normally.

The big caveat here is that it won't see any changes you haven't committed to the specified branch on your local clone. The good news is you don't have to push those changes to remote. Xcode resolves the ../ path to a local file URL and clones your local clone, not the remote branch.

4 Likes

This is the answer I was looking for, thank you. One small note is that latest committed changes are not made available immediately to the project, for that you need to select File > Swift Packages > Update

@Aciid As drag-n-drop approach does not seem to work for the case when application that uses the package is in the same folder with the package itself, can you consider it as a bug worth fixing? It seems to be a common scenario for libraries to provide a sample app along with the library itself.

Terms of Service

Privacy Policy

Cookie Policy