Package Manager exported dependencies

Hi, is there a way to have exported dependencies with SPM?

To provide some context, let’s say I have a simple MyLibrary, which depends on Result.
What I want to achieve is everywhere the MyLibrary is used, the Result package is available as well.
Hence the name “exported”, because Result package is exported as part of MyLibrary.

This is possible with CocoaPods.
This is also possible with Buck, they even have a special exported_dependencies option for that.

However, with SPM all dependencies that I list under dependencies: seem to be internal and describe what is required to build this package.

Is it possible to achieve with current version of SPM or is it on the roadmap?

1 Like

Yes, there is a way.

In MyLibrary, when you import Result, add the @_exported annotation to the import statement. This will export the module from the target.

@_exported import Result
1 Like

This feels like something internal that should not be used outside of the stdlib and the like (because of leading underscore). Is this safe to use going forward?

Everything I read around the web says “don’t use it, it could break any time because it’s private, etc.”. I agree that it could break any time, but that annotation is widely used in some Swift communities and I think a hue and cry would be raised should it be removed.

I found this thread that discusses this subject of the visibility of an import and is also the only place I have seen a Core Swift Team member discuss it. From what I read, I don’t think there is too much of a concern at this point of its removal, though I could be wrong on that.

I agree that there’s a need for a public version of this.

One thing to be aware of about @_exported import: it doesn’t export operator declarations, so if you export a library that defines operators, consumers will still need to explicitly import the library where those operators are declared.

One thing to be aware of about @_exported import: it doesn’t export operator declarations, so if you export a library that defines operators, consumers will still need to explicitly import the library where those operators are declared.

You could also just add the declarations to your project, because the implementations are exported.

You could also just add the declarations to your project, because the implementations are exported.

True, but that’s taking on an extra maintenance burden — what if your operator declarations get out of sync with your dependency’s? I suppose as long is a consumer isn’t importing both it’s probably fine, but it could get tricky.

I don’t believe this is correct. When I use @_exported import Foo inside of module Bar, then operators from Foo show up just fine in Bar without having to explicitly import Foo in each respective file. I mention this in my blog post here: https://davedelong.com/blog/2018/01/19/simplifying-swift-framework-development/

This is correct within Bar, but for an app Foobar which imports Bar and not Foo, they will get the Operator is not a known binary operator error unless they also import Foo to get the operator declaration(s).

Thanks all for the answers!

@_exported did the trick.
I realize that _ means it’s private, but it works for us so far, since package manager is (yet) not the main dependency management tool, so we won’t be impacted if @_exported is removed. Well, maybe we’ll be a bit upset :slight_smile:

Terms of Service

Privacy Policy

Cookie Policy