Repository navigation
Close Linux build gaps and package an experimental ARM64 release - #347
Merged
Merged
Conversation
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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
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.