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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions