Skip to content

swift build fails without Xcode: Symbols.xcassets not declared as a resource, and Bundle.module unreachable in distributed apps #22

Description

@sohei56

Summary

CodeEditSymbols builds cleanly under Xcode but has two problems for consumers
who build with swift build on the command line and package their own .app:

  1. The build fails outright. Package.swift never declares
    Symbols.xcassets as a resource, so SwiftPM's command-line build does not
    process the asset catalog and does not synthesize Bundle.module. (Xcode
    auto-detects asset catalogs, which is why this is invisible in an Xcode
    build.) This is a one-line manifest fix.
  2. Once building, a distributed .app crashes on first symbol access,
    because the generated Bundle.module accessor cannot find the resource
    bundle inside a .app.

Environment

  • Package: CodeEditSymbols 0.2.3.
  • Build: swift build from the command line. No .xcodeproj. The app is
    assembled into a .app by a custom script that copies the SwiftPM resource
    bundle (CodeEditSymbols_CodeEditSymbols.bundle) into
    MyApp.app/Contents/Resources/.
  • macOS, Apple Silicon, current Swift toolchain.

Defect 1 — swift build fails: asset catalog not declared as a resource

Root cause

Package.swift declares the target with no resources: rule:

.target(
    name: "CodeEditSymbols",
    dependencies: []
),

Sources/CodeEditSymbols/Symbols.xcassets is therefore not treated as a
package resource by the SwiftPM command-line build, Bundle.module is not
generated, and CodeEditSymbols.swift (which references Bundle.module)
fails to compile / the resource is never processed. Xcode papers over this by
auto-detecting .xcassets; swift build does not.

Repro

  1. swift build a target that depends on CodeEditSymbols (no Xcode project).

  2. Build fails:

    Sources/CodeEditSymbols/CodeEditSymbols.swift:47:16: error: type 'Bundle' has no member 'module'
    
  • Expected: swift build succeeds and bundles the symbol assets.
  • Actual: build failure.

Fix

Declare the asset catalog as a processed resource. .process has been
available since swift-tools-version 5.3, so no tools-version bump is needed
(the manifest stays at 5.5):

.target(
    name: "CodeEditSymbols",
    dependencies: [],
    resources: [
        .process("Symbols.xcassets")
    ]
),

Defect 2 — Bundle.module fatalErrors in a distributed .app

Root cause

Same shape as the companion CodeEditLanguages issue. The SwiftPM-generated
accessor probes only Bundle.main.bundleURL/<name>.bundle (the .app wrapper
root) and a hardcoded absolute build-machine path, then fatalErrors.
Contents/Resources/<name>.bundle — where a CLI-assembled app copies the
resource bundle — is not among the probed locations.

Bundle.module is used in CodeEditSymbols.swift:

init(symbol: String) {
    self.init(symbol, bundle: Bundle.module)   // Image
}
static func symbol(named: String) -> NSImage? {
    Bundle.module.image(forResource: named)    // NSImage
}

Repro

  1. With Defect 1 fixed, assemble a .app and copy
    CodeEditSymbols_CodeEditSymbols.bundle into Contents/Resources/.
  2. Run the .app; access any Image(symbol:) / .symbol(named:).
  3. Crash at the accessor's fatalError.
  • Expected: the symbol renders; no crash.
  • Actual: fatalError("could not load resource bundle …").

Fix

Resolve the bundle from Bundle.main.resourceURL (i.e. Contents/Resources)
first, then fall back to Bundle.module (which still serves swift build /
swift test on the build machine). This changes nothing for Xcode consumers:

let symbolsBundle: Bundle = {
    if let bundled = Bundle.main.resourceURL?
        .appendingPathComponent("CodeEditSymbols_CodeEditSymbols.bundle"),
       let bundle = Bundle(url: bundled) {
        return bundle
    }
    return Bundle.module
}()

…and route the two Bundle.module references through symbolsBundle.

Offer to contribute

We're already running both changes as a local patch against 0.2.3 with no
observed regression. Per the CodeEdit contribution convention (open an issue
first, ask to be assigned), we'd be happy to submit the PR — could you assign
this to us? The patch passes SwiftLint. Glad to adjust if you'd prefer a
different approach.

Thanks for maintaining CodeEditSymbols.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions