Repository navigation
swift build fails without Xcode: Symbols.xcassets not declared as a resource, and Bundle.module unreachable in distributed apps #22
Description
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:
- The build fails outright.
Package.swiftnever declares
Symbols.xcassetsas a resource, so SwiftPM's command-line build does not
process the asset catalog and does not synthesizeBundle.module. (Xcode
auto-detects asset catalogs, which is why this is invisible in an Xcode
build.) This is a one-line manifest fix. - Once building, a distributed
.appcrashes on first symbol access,
because the generatedBundle.moduleaccessor cannot find the resource
bundle inside a.app.
Environment
- Package:
CodeEditSymbols0.2.3. - Build:
swift buildfrom the command line. No.xcodeproj. The app is
assembled into a.appby 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
-
swift builda target that depends onCodeEditSymbols(no Xcode project). -
Build fails:
Sources/CodeEditSymbols/CodeEditSymbols.swift:47:16: error: type 'Bundle' has no member 'module'
- Expected:
swift buildsucceeds 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
- With Defect 1 fixed, assemble a
.appand copy
CodeEditSymbols_CodeEditSymbols.bundleintoContents/Resources/. - Run the
.app; access anyImage(symbol:)/.symbol(named:). - 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.
Activity