Go + Swift in AT-IRC
PoC, 2026-10-30.
Result
Possible. gomobile bind (golang.org/x/mobile) emits a static AtircGo.xcframework linked into the app. No dynamic library, no embedding; App Store-safe.
Setup
- Install both tools:
go install golang.org/x/mobile/cmd/{gomobile,gobind}@latest.bindshells out togobind; installing onlygomobilefails with "gobind was not found". GoLib/go.mod:module atirc/golib; requiresgolang.org/x/mobile/bind.GoLib/golib.go: exportedVersion,Echo,SHA256Hex,ParseCommand,Counter.- Build:
gomobile bind -target=ios,iossimulator -o GoLib/AtircGo.xcframework atirc/golib.
Bridging
string<->NSString;[]byte<->NSData(byte slices are mutable, passed by reference).- Exported struct -> ObjC class (
GolibCounter), methods/properties bound. (T, error)->NSError**; Swift sees an explicitNSErrorPointer, notthrows. Max two results; second must beerror.- Calls are synchronous; goroutines work.
Type limits (gobind docs)
- Supported: signed ints, floats,
string,bool,[]byte, functions, interfaces, structs with supported exported fields/methods. - Unsupported: other slices, maps, channels, generics; docs list signed ints only.
- A panic crossing the boundary exits the process.
- Proxy reference cycles leak.
- Go can also call ObjC directly via reverse bindings (
import "ObjC/Foundation/NSDate").
Xcode
- Per-SDK
FRAMEWORK_SEARCH_PATHSmust point at the slice, not the xcframework parent:.../AtircGo.xcframework/ios-arm64(device) and.../ios-arm64_x86_64-simulator(sim). OTHER_LDFLAGS = $(inherited) -framework AtircGo. Static framework: nothing to embed.UpdateTargetBuildSettingrejects[sdk=...]keys; set them inproject.xcprojJSON.
Validated (iPhone, iOS 27.2)
- Tests pass: strings,
[]byte<->Data, struct + methods,(T, error)->NSError, goroutines, Go -> Swift callbacks. - Interface collides with generated class, so Swift sees
GolibCallbackProtocol. - Callbacks arrive on a Go thread; hop to
MainActorbefore touching UI.
Size (Release, arm64)
- Wrapper unreferenced: 0 delta (dead-stripped).
- Wrapper referenced (force-loaded): 1.1 MB -> 3.1 MB binary (+2.0 MB); Go
__text+768 KB.
Rebuild
GoLib/build.sh;GoLib/AtircGo.xcframeworkis gitignored.
Caveats
- iOS sandbox: no
os/exec/fork; networking OK. - Device slice ~5.2 MB unstripped; app stripping applies.
- Regenerate after Go changes (candidate Run Script phase; script sandboxing is ON).