Skip to content

Close Linux build gaps and package an experimental ARM64 release - #347

Merged
hyzyla merged 63 commits into
mainfrom
codex/linux-build-followups
Nov 8, 2026
Merged

hyzyla merged 63 commits into
mainfrom
codex/linux-build-followups

Conversation

@hyzyla

@hyzyla hyzyla commented Nov 8, 2026 •

Copy link
Copy Markdown
Collaborator

Linux builds need a release artifact that users can install without compiling Sweetpad, plus regression coverage for the gaps found in real apps and on an iPhone.

  • Close corpus, resource, macro, linker, MMKV, debug-symbol, and automatic test-manifest gaps. The patched corpus builds 127 of 128 current schemes; the deliberate missing-package fixture remains a negative test.
  • Add authenticated direct Linux iPhone USB and Wi-Fi transport, isolated network pairing, and automatic multicast/DNS-SD discovery.
  • Package an experimental Ubuntu 24.04 ARM64 CLI with an installer, DAP alias, checksums, licenses, a sample app, and public setup sources. Apple SDKs and signing material stay private. Fix macro runtime lookup exposed by the isolated installation check.
  • Add hosted ARM64 packaging and clean-container checks, plus a manually selected private-SDK integration job. Tag publication waits for verified macOS and Linux packages; manual Linux-only runs publish nothing.

Validation: optimized ARM64 release build; installation in a clean Ubuntu 24.04 ARM64 container; installed sample compiled into an ARM64 Mach-O app with an empty home, fresh DerivedData, no network, and explicit read-only toolchain/SDK prerequisites; 28 Python checks on macOS and ARM64 Linux; actionlint; formatting; documentation production build. Earlier follow-up reports cover native bundle controls, incremental/prebuilt test execution, unshimmed MMKV storage, Flutter AOT, React Native/Hermes, and physical iPhone USB/Wi-Fi operations. The ARM64 release dry run passes clean installation, the isolated SDK build, all four fresh hybrid Release builds, automatic manifests, and package-linking controls. The final PR artifact also passes a separate isolated app build with its installed binary hash unchanged. All final PR checks pass.

The macOS signing regression compares executable-path and bundle-path signing byte for byte, then uses Apple’s strict verifier and native resource seals. The PIF probe reconstructs its recorded empty directory in an isolated copy, with its comparison baseline unchanged.

The release remains experimental. Simulator operation and Apple test execution require macOS. Distribution IPA export and Linux device debugging/readiness remain unsupported. Optional .omo work and dependency-size cleanup stay deferred.

hyzyla added 30 commits October 10, 2026 23:47
Add a hidden 'sweetpad pbxproj pif' that translates a project.pbxproj into the PIF Swift Build takes as input, which the engine needs to build an Xcode project on Linux. For a new fixture app the output matches 'xcodebuild -dumpPIF' except for the project GUID and the signatures, and a test checks that.
Gate the macOS-only FFI behind target_os = "macos": window capture and Accessibility in 'app', CommonCrypto SHA-256 and sysctl in 'feedback', and the suspended posix_spawn the debugger uses. Off macOS they get stand-ins that return nothing or fail with an error saying macOS is needed, and SHA-256 comes from libcrypto, so sweetpad compiles and runs on Linux. macOS builds are unchanged.
ci/linux-setup.sh provisions an OrbStack machine or a Linux host with Swift, xtool's Darwin SDK from the local Xcode.app, swbuild and Rust; ci/linux-build.sh then emits the project's PIF with sweetpad and builds it with swbuild, checking the result is a Mach-O for the target arch. They replace the xtool-backend script and fixture, which call a 'build generate --backend xtool' command that main doesn't have.
pbxproj pif now takes a workspace as well as a project, follows project references, and derives every GUID the way xcodebuild -dumpPIF does, so cross-project dependencies, synchronized folders and their exception sets, build rules, platform filters and xcconfig anchors come out as Xcode writes them. Tests compare the output against Xcode 27 dumps of a probe fixture and, where corpus/ is checked out, 21 corpus projects.
sweetpad build gains a Swift Build engine, the default where there is no Xcode and '--engine swift-build' elsewhere: it writes the workspace's PIF and build parameters beside the build's intermediates, runs swbuild, and turns its messages into the same events, diagnostics record and productPath an xcodebuild build gives. Off macOS the SDKs and linker come from a Darwin Swift SDK bundle, and ci/linux-build.sh now builds through it.
Six CLI tests need codesign, PlistBuddy or the macOS version, so off macOS they're ignored with the reason. Two path tests took an existing /private/tmp to mean macOS, which OrbStack's mount of the Mac's /private also satisfies, so they now check that /tmp resolves to /private/tmp.
Swift Build makes diagnostics only of 'ld:' and 'clang:' lines, so lld's warnings reached sweetpad as task output, which it dropped when the task succeeded. A successful link's lld warnings now show once each, and lld's notice that it doesn't support the platform, repeated for every input, is left out.
Swift Build runs Xcode's actool for asset catalogs, and Linux has none. Run under that name, the sweetpad binary now writes asset symbols exactly as actool does, so code using Color(.brand) compiles, and links each catalog without an Assets.car, with a warning naming the colors, images and icon the app goes without. Xcode's app template now builds and runs from Linux.
Without an Assets.car, the actool stand-in now writes an iOS app icon at the two sizes actool does, scaled from the 1024-point original when the set has no exact size, along with actool's CFBundleIcons keys, and copies raster images out as the files UIImage looks up by name. The icon shows on the home screen and UIKit finds the images; SwiftUI's Image and named colors still need an Assets.car, which the warning now says.
A build writes a root manifest that depends on the workspace's packages, with its Package.resolved beside it, and adds the package projects SwiftPM's dump-pif emits for it to the PIF. It is the builder Xcode embeds, so the GUIDs match what the projects' targets refer to.
Run as xcstringstool, the binary compiles a catalog into each language's strings and stringsdict tables and generates its string symbols, matching Xcode's output on golden probes and on every corpus catalog. The Swift Build engine links it in beside actool, puts it on swbuild's PATH, and reads strings files that name no encoding as UTF-8, since Swift Build only detects one on macOS.
Xcode's compiler loads cross-import overlays like StoreKit's for SwiftUI by default and the open-source one doesn't, so the engine adds a toolset that passes -enable-cross-import-overlays. The Linux fixture uses PhotosPicker so its build checks this.
The actool stand-in compiles a target's colors, system color references and PNG images into an Assets.car, with their appearances, idioms and scales, so lookups by name work in UIKit and SwiftUI the way they do in an Xcode build. Images are stored gzip-compressed; vector images are still left out with a warning.
The actool stand-in draws a catalog's PDFs (with hayro) and SVGs (with resvg) at each scale the platform has, sized as Xcode sizes them, and keeps the original for sets that preserve vector data. Symbol templates become the per-weight glyphs CoreUI draws and interpolates, with their metrics and the BITMAPKEYS index CoreUI needs to find them. The checker app built on Linux matches Xcode's build on every lookup, and 89 of 93 corpus catalogs list the same assets as Xcode's.
hyzyla added 29 commits November 3, 2026 20:42
Swift Build's console only signs ad hoc, and xtool's SDK leaves signing to xtool. sweetpad stands in for codesign and derq and answers the provisioning requests the Swift Build patch sends it, so a device build signs the way Xcode's automatic signing would. The signatures match Apple's codesign on the same files, apart from the CMS signing time.
…name

sweetpad passed swbuild each scheme target by name as well as by GUID in the build request, and swbuild resolves the names first, failing when a package's product and module share one. The request alone names the targets now.
Swift Build reads Mach-O files and looks up text encodings only through the Darwin SDK, so on Linux it couldn't embed a package's binary framework or Sparkle, or write a Mac app's UTF-16 .strings files. The patch defines the Mach-O structures in a new SWBUtil/MachOStructures.swift and names the encodings Foundation converts on every platform.
Main added its own sweetpad-lib pif module for bsp serve, so the branch's PIF emitter moves to workspace_pif.
Add audited Linux dependency preparation and regression workflows. Preserve XCTest selection, environment, and quoted argument rows in generated manifests.

Retire the MMKV fixture header shim with a narrow Linux header-merge correction, guard llbuild directory scans, select system SQLite for Apple package builds, and inspect linker response files.
@hyzyla
hyzyla merged commit e56e699 into main Nov 8, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant