Swift PM, Bundles and Resources

Once Swift Foundation PR #1573 and #1570 are merged we will be able to use Bundle API on Linux with Freestanding bundles. This means that with the following structure:

FooExecutable
FooExecutable.resources/Info.plist
FooExecutable.resources/FooResource.json
libBarLibrary.so
BarLibrary.resources/Info.plist
BarLibrary.resources/BarImage.png

We can access the resources with the Bundle API:

Bundle.main.path(forResource: "FooResource", withExtension: "json")
// .../FooExecutable.resources/FooResource.json

let barBundle = Bundle(for: BarLibraryClass.self)
barBundle.path(forResource: "BarImage", withExtension: "png")
// .../BarLibrary.resources/BarImage.png

This opens the way to the introduction of the Resources story of Swift PM. A first basic implementation could simply copy files found in a Resources directory of the target source folder to the respective TargetName.resources folder in the products directory.

Also, if we want to support this type of architecture we will have to start to rely in dynamic linking instead of static linking executable products (otherwise we would have to copy all the input resources to the executable resources directory, with potential collisions).

Finally, this approach would be designed for non-Darwin platforms (Darwin would have to use frameworks for libraries and app bundles? for executables as freestanding bundles are not welcome).

14 Likes

Yep, bundle support in Linux will definitely open doors for resource support in SwiftPM. A couple of SwiftPM contributors are working on a draft proposal for resources. They expect to put it out for discussion this fall (it'll take some time due to upcoming vacations).

3 Likes

That's great! Looking forward for it :slight_smile:

1 Like

This is awesome - once the package manager can support app/library bundles, it will be able to apply to so many more Swift projects.

@millenomi what did you mean by Darwin CLI tools having their own mechanism for resources? Are those resources accessible via the same CFBundle API? I don't think CLI tools are considered "bundles" on Darwin, so it would be nice if some other resource API (perhaps a SwiftPM runtime library) made that transparent to the developer.

Also: I'm very interested to see a proposal which brings resources to SwiftPM. It would be cool if we could do something like R.swift (GitHub - mac-cain13/R.swift: Strong typed, autocompleted resources like images, fonts and segues in Swift projects) and generate a file as part of the package-build process. This could maybe help abstract-away some details like asset catalogues.

1 Like

While this guarantee has been textually lost in the mist of time, and while command-line tool code isn't bundled, we consider the containing directory for a command-line tool to be its containing bundle, which is the one that'll be returned by Bundle.main. This holds true on Linux.

Well, this bundle flavour is probably the most "popular" one, as all iOS apps are of this type (simply a executable in a directory). The problem with this approach for CLI tools is that the executable is usually collocated with other executables/libraries so all of them would share the same Bundle resource path (the parent directory) and therefore collisions would be probable (for example, Info.plist).

The debate would be what's the better bundle flavour for each platform and product type:

Executable Library Application
Darwin ??? Framework App Bundle
Linux Freestanding / FHS Freestanding / FHS Freestanding / FHS
Windows Freestanding Freestanding Freestanding

You're incorrect about iOS ('flat') bundles being the same as the fallback behavior for executables; we do special processing for either.

For Darwin command-line tools, the fallback bundle is rooted in that executable's directory, except that if the Mach-O binary has a __TEXT,__info_plist section, we use the content of that section to determine the content of Bundle's .infoDictionary.

For Linux, we do not support this — freestanding bundles are provided for use instead.

Also, to be clear: whenever we say 'Linux' I actually mean 'Apple currently ships and supports Swift in Xcode and with tarballs for Linux, but this behavior isn't gated to a particular operating system'. The intent for FHS is that it apply wherever the FHS applies (Linux, FreeBSD and other 'nixes).

In what way do they behave different? In my understanding the only difference between version 3 and version 4 CFBundle is the existence of the Info.plist file.

So, for reference, the picture would look like this?

Executable Library Application
Darwin Unbundled (+ Mach-O __info_plist) Framework App Bundle
Linux et al. Freestanding / FHS Freestanding / FHS Freestanding / FHS
Windows Freestanding Freestanding Freestanding

@pvieitoci Any Idea when Swift Foundation PR #1573 and #1570 will be merged? I haven't seen activity since October.

@rnantes No idea. You should probably ask @millenomi or @Tony_Parker about that.

1 Like

@Aciid There is any update on this?

3 Likes

Can SPM gain features like this in Swift's dot releases?

I'd say the prominent question is: "Will the next Xcode finally have SPM integration?"

That can only happen if SPM gains resource support (and possibly other features).

Since Xcode is being developed internally my best guess is that this feature hasn't happened yet because SPM more or less needs to coordinate with internal efforts?

It's been half a year since we got any statement from the SPM team about that topic. Could we get an update pretty please?

Of course we can see that in the meantime the SPM team has implemented great features that are fundamental to the future of SPM and possibly to Xcode integration! It's just the seemingly intentional silence on this topic is frustrating.

/cc @Aciid

1 Like

There is a work-in-progress version of a draft proposal for SwiftPM resources, but it isn't yet ready for review. It's at https://github.com/abertelrud/swift-evolution/blob/package-manager-resources/proposals/NNNN-package-manager-resources.md if you want to take a look at the thinking around this so far.

This was written earlier in the year but had to be temporarily put on hold because of other priorities. The plan is to finish it up and send out for review, but there are some open questions in the proposal that should be addressed before asking everyone to take time to review it. We also want to make sure we have bandwidth to properly engage with the review discussion and feedback.

The silence around resources hasn't been intentional; it's been a matter of trying to split the time between that and other necessary work on SwiftPM.

9 Likes

This is a great read! Thank you for sharing!

I see that by the amount of open questions this will most likely not fit into the Swift 5 timeframe. That's fine I guess, but I think that involving the community rather earlier than later on these open questions would still have been valuable.

Also it would be great to have some sense of what the priorities of features is that the team is working on :slight_smile:

Thanks for sharing, it looks promising!

This year, as with the last few, all I want for WWDC Christmas is you, Swift Package Manager. To use you for iOS development. I'm sick of Cocoapods. It's now WWDC Advent and I'm guessing I'll be disappointed again this year.

Where's this proposal at?

I'd step up and help but I'm a clueless idiot.

For a version one, I don't care if it provides an API for type safe access to resources. I just want to be done with the invasiveness of Cocoapods and all the Ruby garbage I have to deal with.

8 Likes

One more idiot here, and I’d love to finally use SwiftPM for my AppKit projects.

2 Likes

Yes please, especially since having been bit by a nasty little surprise when 10.14.4 and Xcode 10.2 was released.

I had my frameworks integrated in to a macOS app by including the SPM project files. Suddenly though this app did crash on launch on my Mac after I upgraded. It couldn't find the Swift runtime… well, the correct one at least :wink:

Turns out that SPM hardcodes the Xcode-included Swift libraries' path into the @rpath of its frameworks, so when my app launched (it was still compiled with Xcode 10.1 and Swift 4.2 was therefore embedded) it first tried to find the one from Xcode on my system and that didn't end well for the linker :slight_smile:

So a previously working app suddenly crashed because I had the new version of Xcode installed.

Well to be honest: "I was holding it wrong"

When recompiling the app with Swift 5 the problem goes away all by itself, but just in case I added an .xcconfig file for SPM so it would add @loader_path/../Frameworks/. The praise for finding this problem on my end goes to the incredible @graskind. :bowing_man:

Reposting here just in case anyone else runs into this. After all, there's many SPM early adopters here :wink:

I wish that I wouldn't have to use unsupported hacks to use SPM. It is so well built (possibly because the team actually does prioritize the important stuff first) so I really want to SPM all the things. Kudos to @Aciid et al.! So grateful for the amazing work you do!

7 Likes