Repository navigation
Widget app extension: .appex binary is empty (dead-stripped) and the extension crashes in ExtensionFoundation on launch #313
Description
Description
Building a WidgetKit app extension with xtool produces an .appex whose binary
is empty (no __text). Once the entry point is corrected so the widget code
is retained, the extension launches but crashes inside Apple's
ExtensionFoundation before any widget is registered.
Both are reproducible with the repo's own example at Examples/DemoExtensions.
- Empty
.appexbinary.Packeremits-e _NSExtensionMainfor every app
extension._NSExtensionMaincomes fromFoundation, so the linker resolves
the entry point outside the binary and drops all objects from the widget's
.libraryproduct. The appex has no__text, onlyU _NSExtensionMain.
A WidgetKit extension should use the defaultmainfrom@main/WidgetBundle. - Crash in
ExtensionFoundation. Without-e _NSExtensionMainthe widget
code is retained and the appex launches, but the process dies with
EXC_BREAKPOINT (SIGTRAP)while initializing_EXRunningExtension._shared.
Environment
Host OS / version: WSL2; Windows 11 25H2 (10.0.26200), Ubuntu 26.04.1 LTS
iOS device: 27.0.1 (24A446), iPhone 15 Pro Max
Swift: 6.4 (swift-6.4-RELEASE), x86_64-unknown-linux-gnu · SDK: iphoneos27.0
xtool: 1.21.0
Steps to reproduce
- Run
xtool dev buildon a project with a WidgetKit extension (e.g.Examples/DemoExtensions). - Inspect the appex binary → no
__text, onlyU _NSExtensionMain(issue 1). - In
xtool/.xtool-tmp/Package.swift, drop"-Xlinker", "-e", "-Xlinker", "_NSExtensionMain", rebuild the extension product, copy it into the appex. xtool install <app>.
Expected
The extension launches and its widgets appear in the home-screen widget gallery.
Actual
The extension launches, WidgetKit resolves the bundle host, then the process traps:
exception.type = EXC_BREAKPOINT,signal = SIGTRAP,termination.code = 5exception.codes = [1, 0x19e541268]— the same fixed address on every crash- faulting thread:
com.apple.main-thread
closure #1 in closure #1 in ... static _EXRunningExtension._shared + 116
specialized static MainActor.assumeIsolated<A>(_:file:line:) + 140
closure #1 in closure #1 in ... static _EXRunningExtension._shared + 228
one-time initialization function for _shared + 16
_dispatch_client_callout + 16
_dispatch_once_callout + 32
static _EXRunningExtension.sharedInstance() + 112
static _EXExtension.bootstrap(with:) + 40
StudoWidgets.$main() + 40
main + 12
start + 6616
The crash is silent: a __attribute__((constructor)) that redirects
stderr/stdout into os_log arms (STUDO-STDERR armed) but captures no
message before the trap — consistent with a compiler-emitted brk #1, not a
fatalError (no _assertionFailure frames).
Evidence
- Default appex from
Examples/DemoExtensions: 49408 bytes, no__text, onlyU _NSExtensionMain. - After the entry fix: ~900 KB (debug) / ~487 KB (release),
_main+__swift5_entrypresent. chronodlogs:main [WidgetBundle]→WidgetHost - Optional(ResolvedWidgetBundleHost)→ crash.- Ruled out:
Info.plist(identical to Xcode's Widget Extension template),CFBundleSupportedPlatforms/UIDeviceFamily, missing__info_plist,-all_load, debug vs release, Mach-O load commands.
Cause (issue 1)
Sources/PackLib/Packer.swift, case .appExtension:
unsafeFlags([
// Set the entry point to Foundation`_NSExtensionMain
"-Xlinker", "-e", "-Xlinker", "_NSExtensionMain",
...
]),For SwiftUI/WidgetKit extensions the entry point must be the main generated by @main; omitting this flag keeps the widget code.
Notes
SignerImpl.signforwards only the root app's entitlements to nested bundles (// TODO: #131).- Related: Support for App Extensions (e.g. Widgets) #45 (app extension support), Allow one app group on free teams #284 (app groups on free teams).
Activity
ウィジェット拡張を一時的に無効化