rules_swift_package_manager icon indicating copy to clipboard operation
rules_swift_package_manager copied to clipboard

Packages with xcassets that use generated ColorResource and ImageResource extensions fail to build

Open daltonclaybrook opened this issue 11 months ago • 1 comments

If a Swift package contains an asset catalog, in iOS 17+/macOS 14+, Xcode will generate Swift extensions for ColorResource and ImageResource for each color and image asset in the catalog. For example, if a color is named "primaryBackground" in the catalog, Xcode will generate a file with these contents:

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension DeveloperToolsSupport.ColorResource {

    /// The "primaryBackground" asset catalog color resource.
    static let primaryBackground = DeveloperToolsSupport.ColorResource(name: "primaryBackground", bundle: resourceBundle)
}

The color can then be instantiated with Color(.primaryBackground).

When using rules_swift_package_manager, if you depend on a package that uses these accessors, the build fails with the following error:

external/rules_swift_package_manager++swift_deps+swiftpkg_dependency/Sources/Dependency/Dependency.swift:7:50: error: reference to member 'primaryBackground' cannot be resolved without a contextual type
 5 |     public static let primaryAccent = Color(.primaryAccent)
 6 |     public static let secondaryAccent = Color(.secondaryAccent)
 7 |     public static let primaryBackground = Color(.primaryBackground)
   |                                                  `- error: reference to member 'primaryBackground' cannot be resolved without a contextual type

I've created a sample project to demonstrate this issue. Clone the repo, then run:

bazel build //Example

Of course, this problem is not specific to Swift packages, so I'd imagine we could benefit from a new rule in rules_apple like "apple_xcassets_accessors" or something. Because of this, let me know if you think this issue is misplaced here.

daltonclaybrook avatar May 26 '25 17:05 daltonclaybrook

@daltonclaybrook Do you manage this package yourself?

I find R.swift generated accessors for resources great, as it stays a bit outside the Apple ecosystem and allows you to better use resources in a static libs — keeping resources separate. You are able to make a genrule for this that uses the binary built from rules_swift_package_manger via $(location @swiftpkg_r.swift//:rswift). Good luck!

def rswift_resource_module(name, resources, access_level = "public"):
    native.genrule(
        name = name + "_generate_r",
        srcs = [ resources ],
        outs = [ "Resources/" + name + "_R.generated.swift" ],
        tools = [
          "@swiftpkg_r.swift//:rswift",
        ],
        cmd = """
          set -e

          "$(location @swiftpkg_r.swift//:rswift)" generate \
            --access-level {access} \
            --input-files $(locations {res}) \
            --input-type input-files \
            $(OUTS)
        """.format(name = name, access = access_level, res = resources),
        visibility = ["//visibility:public"],
    )

    swift_library(
        name = name,
        srcs = [ "Resources/" + name + "_R.generated.swift" ],
        module_name = name,
        deps = [
          "@swiftpkg_r.swift//:RswiftLibrary",
        ],
        visibility = ["//visibility:public"],
    )

jeffhodsdon avatar Jun 09 '25 08:06 jeffhodsdon