Skip to main content

ipeddle

Build iOS apps on Linux. No Mac, no Xcode. · Português

ipeddle is to iOS what Gradle is to Android: one command line tool that takes your app's source and gives you an installable package. You write a SwiftPM app, run ipeddle build, and get an unsigned .ipa that you can sign and install on your iPhone with Sideloadly or AltStore and a free Apple ID.

$ pipx install ipeddle
$ ipeddle setup                 # once: Swift for Linux, an iOS linker, the iOS SDK
$ ipeddle build examples/hello
==> building Hello (release, iOS 16.0+, dev.ipeddle.example.hello)
    [5/7] Compiling Hello HelloApp.swift
    [6/7] Linking Hello
==> packaging
 ok  examples/hello/.build/Hello.ipa  (37.6 KB, unsigned) in 2.3s
$ ipeddle inspect examples/hello/.build/Hello.ipa
App:        Hello.app  (dev.ipeddle.example.hello)
Executable: Hello  [arm64]
Platform:   iOS  min 16.0  (built with SDK 18.6)
Links:      29 libraries, 146 imported symbols
Result:     OK

Status: alpha (0.1.0). Pure-SwiftPM apps (SwiftUI or UIKit, Swift and C/Objective-C targets, resources, binary xcframeworks) build. Read Limitations before relying on it.

Requirements

  • Linux x86_64 or aarch64 (Ubuntu 22.04/24.04, Debian 12/13, Fedora, RHEL-likes). On Windows use WSL2. On a Mac, just use Xcode.
  • Python 3.10+ and git.
  • About 4 GB of free disk for setup (Swift ~2.5 GB, SDK ~0.6 GB, caches).
  • The system libraries the Swift toolchain needs, see https://www.swift.org/install/linux/ (on Ubuntu: sudo apt install binutils git libc6-dev libcurl4-openssl-dev libedit2 libgcc-13-dev libstdc++-13-dev libxml2-dev libncurses-dev libz3-dev pkg-config tzdata unzip zlib1g-dev).

ipeddle doctor checks all of this and tells you what is missing.

Quick start

pipx install ipeddle            # or: pip install --user ipeddle ('ipeddle[icons]' to resize app icons)
# latest from git: pipx install git+https://github.com/Neguiolidas/ipeddle
ipeddle doctor                  # what is there, what is missing, how to fix it
ipeddle setup                   # ~5-10 min the first time, mostly downloads
git clone https://github.com/Neguiolidas/ipeddle && cd ipeddle
ipeddle build examples/hello --inspect

The .ipa is in examples/hello/.build/Hello.ipa. To put it on a phone:

  1. Install Sideloadly (Windows/macOS) or AltStore.
  2. Plug in the iPhone, drop the .ipa in, sign in with your Apple ID (a free one works; apps then expire after 7 days and you re-install).
  3. On the phone: Settings → General → VPN & Device Management → trust your Apple ID. On iOS 16+ also enable Settings → Privacy & Security → Developer Mode.

Commands

Command What it does
ipeddle init DIR Creates a minimal SwiftUI app (Package.swift, ipeddle.toml, .gitignore) to start from.
ipeddle doctor [--deep] Checks Python, OS, disk, the toolchain, the linker, the SDK; --deep also compiles and links a test program.
ipeddle setup Downloads Swift for Linux and the linker, fetches the iOS SDK, prepares it. Idempotent: re-running only does what is missing.
ipeddle build [DIR] Builds the SwiftPM app in DIR into DIR/.build/<App>.ipa (-o to choose). -c debug, --product, --clean, --inspect.
ipeddle inspect FILE Checks an .ipa or .app: architectures, minimum iOS, Info.plist, embedded frameworks, and that every imported symbol exists in the library it is bound to. --json for scripts.
ipeddle clean [DIR] Deletes temporary files, an app's .build, or with --all everything ipeddle installed.

Setup options: --swift DIR (use a toolchain you have), --linker FILE, --sdk DIR (an iPhoneOS*.sdk you have), --xip FILE (extract the SDK from an Xcode_*.xip you downloaded from Apple; only the SDK is written to disk), --sdk-version (default 18.6), --force, --no-download. ipeddle clean --cache empties the shared module cache. Everything lives in $IPEDDLE_HOME (default ~/.local/share/ipeddle).

Making an app ipeddle can build

An ipeddle app is a regular Swift package with an executable product and an iOS platform. See examples/hello:

// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "Hello",
    platforms: [.iOS(.v16)],
    products: [.executable(name: "Hello", targets: ["Hello"])],
    targets: [
        .executableTarget(name: "Hello", resources: [.process("Resources")]),
    ]
)

The @main SwiftUI App (or a UIKit UIApplicationMain) lives in the executable target. App settings go in an optional ipeddle.toml:

[app]
product = "Hello"                     # which executable product to package
bundle-id = "com.example.hello"       # default: dev.ipeddle.<product>
display-name = "Hello"
version = "1.0.0"                     # CFBundleShortVersionString
build = "1"                           # CFBundleVersion
icon = "Icon.png"                     # square PNG, 1024x1024 recommended
info-plist = "Info.plist"             # extra keys (permissions, URL types...); $(VARS) are expanded
resources = ["Extra"]                 # files/folders copied into the .app as-is
device-family = ["iphone", "ipad"]
swiftc-flags = []

How it works

Apple's toolchain is open source; what makes "iOS on Linux" hard is everything around it. ipeddle puts these pieces together on your machine:

  1. Compiler. The official Swift toolchain for Linux already contains swiftc, clang and llvm-ar with the ARM64/Darwin backends.
  2. Linker. The Linux toolchain's ld64.lld refuses iOS, so setup downloads the ld64-compatible lld that the xtool project publishes.
  3. SDK. Headers, .swiftinterface files and .tbd stubs for iOS. By default setup makes a sparse, shallow git checkout of a public mirror (only the one SDK folder, a few hundred MB). You can point it at an SDK you already have, or at an Xcode.xip (streamed: only the SDK is extracted).
  4. SDK patches, generated on your machine. Public SDK mirrors carry reconstructed .tbd stubs that describe the newest iOS layout, so a naively linked app crashes on older iOS. ipeddle copies the SDK (hard links, so it costs almost no disk) and rewrites the stubs with rules derived from the SDK itself, never from a hand-made list:
    • Swift overlays. Until iOS 17 the Swift half of a framework (Foundation's Data, URLRequest...) lived in /usr/lib/swift/libswiftFoundation.dylib; since iOS 18 it lives in the framework. Every Swift symbol whose mangled name says it belongs to module X is moved from the framework's stub to libswiftX's stub. Binding through the overlay works on both old and new systems.
    • Split frameworks. Declarations moved to a new framework keep their original mangling (@_originallyDefinedIn), e.g. SwiftUICore split out of SwiftUI in iOS 18. Such symbols are moved back into the parent that re-exports the child, so the app never links the child and still launches on iOS 15-17.
    • Missing symbols. If the link fails on Swift symbols the stubs do not list at all, ipeddle works out the owning module from the mangled name, declares them in that module's overlay, and relinks. What it learns is kept in the patched SDK for every later build.
  5. Runtime bits. Xcode ships libclang_rt.ios.a; ipeddle compiles the one routine apps need from it (__isPlatformVersionAtLeast, used by #available / @available) from its own source at setup.
  6. Build and package. swift build cross-compiles with a generated Swift SDK bundle; ipeddle then assembles Payload/<App>.app (binary, resource bundles, frameworks, Info.plist, icons) and zips a reproducible .ipa.

Caching

  • The SDK's Swift and Clang modules (Swift, Foundation, UIKit, SwiftUI...) are compiled into one module cache shared by all your apps. Setup ends with a test compile that also fills it, so even the first build of a new app is fast.
  • SwiftPM's incremental build does the rest; the .ipa step takes milliseconds.
  • When the SDK stubs change (re-setup, learned symbols), the next build relinks.

Measured on a 16-core Linux box with examples/hello:

Build Time
very first compile, empty module cache 68 s
first build of an app after ipeddle setup (cache filled by setup) 2.0 s
--clean rebuild 2.1 s
rebuild with no changes 0.7 s

Limitations

Honest list. Some are fundamental, some are just not done yet.

  • No code signing. The .ipa is unsigned. Sideloadly/AltStore sign it with your Apple ID; App Store / TestFlight distribution still needs Apple's tools and a paid developer account.
  • No asset catalogs (actool). .xcassets cannot be compiled. ipeddle falls back: the app icon is taken from icon (or the largest PNG of an AppIcon set), and image sets are bundled as loose name@2x.png files, which UIImage(named:) and Image("name") find. Color sets, data sets and symbol sets are not supported; define them in code.
  • No Interface Builder (ibtool). Storyboards and XIBs are not compiled; build UI in code (SwiftUI or UIKit). The launch screen comes from UILaunchScreen in Info.plist.
  • SwiftPM projects only. .xcodeproj / .xcworkspace projects are not read. CocoaPods are not supported; SwiftPM dependencies and binary .xcframework targets are.
  • Device builds only (arm64). There is no iOS Simulator on Linux.
  • iOS 15 or newer. Older deployment targets need back-deployment libraries that only ship with Xcode.
  • Public SDK caveats. The symbol rules are derived from the SDK and examples/hello (SwiftUI, Foundation, a C target with #available) and a UIKit + PhotosUI app built from the 18.6 SDK were launched on iOS 16.7, but the rules are heuristics over reconstructed stubs: a symbol that lived in a different library on some older iOS version than the stubs suggest will fail at launch on that version. ipeddle inspect catches symbols the SDK does not export at all, not this case. Test on the oldest iOS you support.
  • Macros. Macros that ship with the Swift toolchain (@Observable, #Predicate...) work; SwiftUI's #Preview and other Apple-only macro plugins do not (remove #Preview blocks or wrap them in #if DEBUG checks you do not build).
  • Embedded dynamic frameworks (from binary .xcframework targets) are packaged the way Xcode does it (Frameworks/, stripped of headers and modules, @executable_path/Frameworks rpath) and pass ipeddle inspect, but have not yet been launched on a real device.
  • Less-tested inputs. Development used the public mirror's 18.6 SDK. SDKs extracted from an Xcode .xip use the same code path but have had less testing; downloads are checked for completeness, not signatures.
  • No dSYMs (-debug-info-format none), so crash logs are not symbolicated.
  • SwiftPM prints a deprecation warning for the native build system that ipeddle uses; a future Swift release may require changes.

ipeddle is licensed under the Apache License 2.0 and contains no Apple software. The iOS SDK is downloaded by you, onto your machine, from a source you choose, and Apple's license terms apply to it (Apple's Xcode and SDK agreement allows use on Apple-branded computers; whether and how you may use the SDK elsewhere is between you and Apple). ipeddle does not redistribute SDK files and the patched copy never leaves your machine.

ipeddle is not affiliated with, endorsed by, or sponsored by Apple Inc. iOS, iPhone, iPad, Xcode and Swift are trademarks of Apple Inc.

Acknowledgements

  • xtool (MIT) pioneered Xcode-free iOS builds on Linux; ipeddle downloads its ld64-compatible linker.
  • The Swift project for the Linux toolchain.

Contributing

pip install -e '.[dev]'
ruff check src tests
pytest

Unit tests use synthetic .tbd, Mach-O and .xip fixtures generated in the tests themselves; no Apple files are needed or allowed in the repository.

Metadata

Release files for ipeddle 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ipeddle 0.1.0
File Size Uploaded Provenance
ipeddle-0.1.0.tar.gz 81.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ipeddle 0.1.0
File Interpreter ABI Platform
ipeddle-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 148.1 kB

Release files / ipeddle-0.1.0.tar.gz

Download URL ipeddle-0.1.0.tar.gz
Size 81.0 kB
Tags Source
SHA-256 checksum
How to use checksums
a12a34de3614de007cd66bb2811ececd4c29c5350fd7c96730960a73b44bcbf4
BLAKE2b-256 checksum
How to use checksums
804a37250f65d027cdd18e5c7df6a7948db27efadb3ac365fd6edafab913df8d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / ipeddle-0.1.0-py3-none-any.whl

Download URL ipeddle-0.1.0-py3-none-any.whl
Size 67.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e84a7bc8240579ebef495edf5be2a657a8fa5d1de44f786a887768c7d91f6082
BLAKE2b-256 checksum
How to use checksums
e8e40f7fb0e1c3645e843e29224f03822b2c6ba2b965201764bfe5c31eb486be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for ipeddle 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ipeddle-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page