Draft Proposal: Package Resources

Correct.

I think this will be covered by a "deployment feature" whenever we have it but in the meantime we can expose some command-line interface to return the bundle path for an executable from the bin directory.

Maybe we can add some flag like --resources-prefix which embeds additional search paths. This would be similar to linker's rpath mechanism.

1 Like

The goal of this proposal is to allow Swift packages to declare and consume resource files that are supported in a cross-platform manner using Foundation APIs. What you're suggesting should be feasible once we have extensible build tools and APIs that allow you conditionally add files based on the platform.

There's been a lot of feedback about the name of the generated accessor SPMResource. The proposal initially explored generating an extension on Bundle with the name moduleResources. This was changed to the struct because of some caveats this brings with @testable imports:

a) There is no way to disambiguate names in an extension. For example, if there are two modules that are imported into a test module using @testable, you have no way of disambiguating the two moduleResources.
b) If your test target only imports one module that has resources, you would be able to access its resources. This will immediately break as soon you import another target with resources.
c) If your test target has resources, the moduleResources of the test target will shadow the moduleResources of all of the targets you import.

I am now thinking that maybe this is OK. We can say that a module always need to explicitly expose the accessors using some API chosen by the package author (solves a and c). SwiftPM can always generate an extension for the test targets in order to shadow the moduleResources that may come from importing any target with resources (solves b).

5 Likes

The design I’m currently considering for module-qualified names would alleviate these issues:

import UIKit
@testable import Foo

...
  let expected = UIImage(named: “bar”, in: .currentTarget)
  let actual = UIImage(named: “bar”, in: .Foo::currentTarget)
...

Granted, I need to actually implement the thing, but the plan is to do so.

2 Likes

Nice!

But I am still worried about b since it'll be unfortunate if someone has to suddenly change all of their test code just because they added a resource file in their test target. So I think SwiftPM should always generate the accessor for test targets to shadow the ones from the imported modules. This will force test targets to always access the resources of the imported modules through the disambiguation syntax.

7 Likes

Sure, that seems fair.

1 Like

I think this looks very reasonable: it seems like a good design. The Linux limitations seem totally acceptable to me for now, as there appear to be sensible future directions. Nice work!

1 Like

Since the change to use the bundle extension I really don't have much to add, but I just want to say that I can't wait to see this get added. We might finally be able to reduce the number of dependency managers our project(s) uses. Great work @Aciid!

3 Likes

In general, the cross-platform problem can only be addressed by introducing a new resource that provides enough metadata for all supported target platforms and then extending SPMResources with some new resource type(s) with appropriate process rules.

It's probably too much to request this feature to be builtin into SPM: format of resources depends entirely on the target library and application that will use them.

+1

Lacking package resource supports is a weak point for SPM. And maybe SPM could support pre-script to run a bash script to download remote resources. For example, fetch the latest dependence js file or something.

+1 on the proposal, this would be great progress. thank you @Aciid and team for the thoughtful design

+1 on the proposal. This would be a total gamechanger for the modularization of the projects using package. ATM I have found package really useless because of this, tbh

1 Like

What about the other points? Will all packages with resources need to be built through Xcode on Darwin? Why are we making Xcode control and alter how packages get built, rather than letting SPM handle it?

More generally, something I've been wondering is: how do Apple see SwiftPM and Xcode co-existing? Which software is responsible for what? It often feels like Xcode is trying to take much more responsibility than an IDE should, while SwiftPM does its own thing in parallel.

I'm very much against any proposal that makes Xcode more fundamental than SwiftPM, if you get my meaning.

As I said, requiring processing by external tools will necessarily break cross-compilation. Let's say Darwin platforms require audio files to be encoded as AAC, while some linux platform requires Ogg - SwiftPM can't ensure that you have the external tools necessary to create each file, or consider every detail beyond just format (e.g. there may be a maximum supported profile or bit-rate), and I don't expect it to.

I just think it's important for the proposal to call this out explicitly.

2 Likes

My understanding of the the draft is that resource types are opaque to SPM. But they are not necessarily opaque to the target build system. And the client of SPM is also given an opportunity to provide custom rules to process these resources conditionally.

Tangentially related question: out of curiosity, what are the next steps for this proposal? I’m not sure how to interpret the SPM roadmap at this time. Resources and Binary Frameworks seem like massive must-haves, but what’s the best way to understand the scope of work, when this (or other work) is targeted for, and what integration into Xcode looks like as a whole?

Just to be clear: not trying to be pushy, just looking to better understand how SPM evolution works today. I understand the Swift Evolution process.

Thanks in advance!

1 Like

It the same as anything else in the evolution process.

Before the draft can be submitted for review, it needs an accompanying implementation. About twelve days ago, related commits began landing in the swift-package-manager repository.

Once the implementation is complete and the proposal is submitted, it will be scheduled for review.

Gotcha. Thanks!

SwiftPM proposals currently don't require accompanying implementation. I thought this was documented somewhere but apparently not.

I've landed much of infrastructure required for implementing resource support in SwiftPM. I've also landed this proposal (which isn't a lot of work with the infrastructure in place) so we can try it out on actual packages before fully committing on the design. If you're interested, you can try out the latest snapshot on this example package. I expect to take this proposal to formal evolution review sometime next month. @NeoNacho and I discussed this and we're ready to take this proposal to review now!

18 Likes

This proposal is under review now, see the review thread.

3 Likes