Generating resource_bundle_accessor, Type 'Bundle' has no member 'module'
Asked Answered
O

10

79

Some times Xcode can not determine the module parameter in the Bundle.

Type 'Bundle' has no member 'module'

My investigations show that SPM generates an extension on the module (some times) for this property automatically in a file called resource_bundle_accessor like:

import class Foundation.Bundle

private class BundleFinder {}

extension Foundation.Bundle {
    /// Returns the resource bundle associated with the current Swift module.
    static var module: Bundle = {
        let bundleName = "ABUIKit_ABStyleKit"

        let candidates = [
            // Bundle should be present here when the package is linked into an App.
            Bundle.main.resourceURL,

            // Bundle should be present here when the package is linked into a framework.
            Bundle(for: BundleFinder.self).resourceURL,

            // For command-line tools.
            Bundle.main.bundleURL,
        ]

        for candidate in candidates {
            let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle")
            if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
                return bundle
            }
        }
        fatalError("unable to find bundle named ABUIKit_ABStyleKit")
    }()
}

But sometimes it won't. Why is that and how can I make it work automatically again (Without the need to manually implement that.)

Both situations happen on Xcode 12 beta.3

Update

Sometimes it shows:

'module' is inaccessible due to 'internal' protection level

And it's not showing the file at all.

Offprint answered 3/8, 2020 at 21:46 Comment(3)
Where is this resource_bundle_accessor file located? I tried everything suggested in the answers and it will just not work. Might as well create it myself instead then.Rappel
No you must NOT create it yourself!!! It is autogenerated and that is the main point of the question.Offprint
I actually posted a related question here this morning: #64404146 - maybe you can spot an error in my Package.swift file?Rappel
O
150

SPM generates the resource_bundle_accessor only if the corresponding target contains resources as the argument like:

    .target(
        name: "ChenzookKit",
        dependencies: ["Apollo"],
        resources: [.process("Resources")] // <- `copy` or `process` doesn't really matter 
    ),

Also, note that it should be a valid resource path.

AND❗️

The project MUST contains Resources inside the target's Directory!

Example

AND❗️❗️

The Resources MUST contain something and MUST NOT be an empty directory

AND❗️❗️❗️

Don't forget to build (cmd+b) the code to make the .module be created!

Offprint answered 4/8, 2020 at 7:49 Comment(5)
Future readers, it seems that these solutions don't work yet for Swift 5.5 and executable targets: cf. this comment on a bug report and my own experience 😉Thaliathalidomide
It worked for me, the Resources folder must be not-empty!Olpe
I found I needed to restart Xcode for it to recognise the directory was there.Keniakenilworth
Oh the Second point needs special clarification (although the pic depicts it so nicely). The Resources folder needs to be inside Sources->Package Folder Name.Carlina
This is an exceedingly frustrating problem, but I really want to thank those of you who've posted here. I finally got module to generate but it felt a lot like hocus-pocus. I'm floored at how fragile this whole eco-system feels, but thanks for helping me get through it!Delius
V
40

If you see errors like this:

Error: found 1 file(s) which are unhandled; explicitly declare them as resources or exclude from the target

Type 'Bundle' has no member 'module'

Then review the following five conditions:

1. Check that the first line of your Package.swift declares the use of swift-tools-version:5.3 or a later version.

// swift-tools-version:5.3

2. Check the Resource folder is under the target folder. For instance,

Sources/MyTarget/Resources
Tests/MyTargetTests/Resources

3. Check that you already added at least one resource. For instance,

Tests/MyTargetTests/Resources/paginatedLabels.json

4. Check that you open the package by opening the file Package.swift with Xcode.

5. Check that the Package.swift file declares a resources element, like this:

.testTarget(
    name: "MyTargetTests",
    dependencies: ["MyTarget"],
    resources: [
        .process("Resources")
    ]
),

At this point, the compiler synthesized a file resource_bundle_accessor.swift with this content:

extension Foundation.Bundle {
    static var module: Bundle = {
...

To check that the file was indeed synthesized:

# is the bundle being synthesized when you build?
find ~/Library/Developer/Xcode/DerivedData* -iname resource_bundle_accessor.swift

To load resources from the package bundle use Bundle.module, e.g.

UIImage(named: "share", in: Bundle.module, compatibleWith: nil)

To find the path to the package bundle directory:

MODULE=MyModuleName && find -E ~/Library/Developer/Xcode/DerivedData -regex ".*$MODULE_$MODULE.bundle"

To check that the package bundle contains a particular resource, e.g. an image:

# I’m building for iPhone 12 (@3x). Is [email protected] inside the bundle?
find ~/Library/Developer/Xcode/DerivedData* -iname Assets.car -exec xcrun --sdk iphoneos assetutil --info {} \; | grep -E "share.*png"

Here is an example that uses custom directories:

targets: [
    .target(
        name: "Kit",
        dependencies: [],
        path: "sources/main",
        resources: [
            .process("resources")
        ]
    ),

where directories are:

Kit/
├── sources/
│   └── main/
│       ├── SourceFile.swift
│       └── resources/
│           └── file.json
└── Package.swift

If everything fails and you suspect a bug check the bug database for SPM.

Vannie answered 14/3, 2021 at 22:3 Comment(1)
The first condition solves my problem, thank you :)Jeramie
P
7

Okay I found a solution, so Swift actually generates the Bundle.module file 🎉

The documentation explicitly states that you have to put your Resources under the folder <project_root>/Sources/<MyTarget>/ since SPM scopes resources by target. The target definition looks then like this for my repo SHSearchBar (compare file structure on Github):

// swift-tools-version:5.3
import PackageDescription


    targets: [
        .target(
            name: "SHSearchBar",
            resources: [.copy("Resources")]
        )
    ]

Target Folder: <project_root>/Sources/SHSearchBar
Resource Folder: <project_root>/Sources/SHSearchBar/Resources

By the way, to build an iOS package from command line you can use this command uses the iOS 14 SDK:

swift build -Xswiftc "-sdk" -Xswiftc "\`xcrun --sdk iphonesimulator --show-sdk-path\`" -Xswiftc "-target" -Xswiftc "x86_64-apple-ios14.0-simulator"

To make my little post here complete I also want to mention that a package using the Bundle.module approach can be integrated in apps that run on iOS <14 too since the generated extension does not contain any new API 👍

Pashm answered 1/9, 2020 at 13:4 Comment(1)
Don't make the mistake I did: be sure you have // swift-tools-version:5.3 or greater at the top of your package file, instead of, say, swift-tools-version:5.1 because it was copied from another package as a template. If not 5.3 or above, Bundle will not be generated and the error messages are not super clear.Infanta
P
3

Bundle.module will only be generated by SwiftPM if the resources in the Package.swift file is not empty and the specified resources actually exist.

So there are two possible reasons why it might not work for you:

  1. You don't have any resources specified in Package.swift. Fix like this:
.target(
    name: "MyLibrary",
    dependencies: [
        /* your dependencies */
    ],
    resources: [
        .copy("JsonData"),
        .process("Assets.xcassets"),
    ]
),
  1. The specified paths don't exist or are empty.

    Fix by checking that you've actually placed your resources inside the Sources/MyLibrary directory. A common mistake is to place them directly to Sources or to a different targets subfolder.

Phenformin answered 14/8, 2020 at 6:55 Comment(0)
A
2

You can also expose the bundle by creating a class with static let:

public class YourPackageBundle {
   public static let yourPackageBundle = Bundle.module
}

Then you can access it in your public classes and use it:

public init(backgroundImage: Image? = nil,
            logoImage: Image? = nil,
            userIconImage: Image? = nil,
            userTextFieldPlaceholder:String = NSLocalizedString("global_username", bundle: YourPackageBundle.yourPackageBundle, comment: "User placeholder text")
Alumna answered 8/6, 2021 at 13:38 Comment(0)
V
1

In my case, I've tried all the solutions and nothing helped until I've restarted Xcode.

Done on Xcode 14.0.0

Vevine answered 25/9, 2022 at 20:49 Comment(1)
@luizv it is an / the answer.Himyarite
S
1
  1. Make sure that the Resources folder exists and that it has files
  2. Bundle.module is autogenerated by XCode when the Resources folder is not empty. However it is internal
  3. Add @testable import YourPackage to make makes internal files in your package sources available to tests.
Somnambulism answered 16/2, 2023 at 18:4 Comment(0)
P
1

If you have your text.json in the Resources folder, make sure that you have .process("Resources/text.json") path in your Package.swift

Pascasia answered 23/5, 2023 at 11:27 Comment(0)
S
-1

Xcode version 15.2:

Inside the package description file, if your target describes the path, you don't need a Resources folder:

targets: [
        .target(
            name: "BackyardBirdsData",
            path: "."
        )
    ]

You just have to make sure that your package already contains at least one resource (i.e. a .json file)

Segura answered 28/1 at 17:50 Comment(0)
F
-1

The module is also created when you put a String Catalog file in your module.

Fish answered 7/6 at 7:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.