Skip to content

Instantly share code, notes, and snippets.

@heeh
Created December 5, 2025 15:25
Show Gist options
  • Select an option

  • Save heeh/8eaf59c1936bda0f15bdd30cf37c0d63 to your computer and use it in GitHub Desktop.

Select an option

Save heeh/8eaf59c1936bda0f15bdd30cf37c0d63 to your computer and use it in GitHub Desktop.
[rust] ios build with cbindgen

Here’s a minimal, App Store–ready Rust → iOS dynamic framework setup, including the folder structure, header generation, shell build script, and framework layout. This is exactly how an industry team would structure a small Rust library for iOS.


1. Folder Structure

my_rust_lib/
├── Cargo.toml
├── cbindgen.toml
├── include/
│   └── my_rust_lib.h          # generated automatically by cbindgen
├── src/
│   ├── lib.rs                 # entry point
│   ├── core/                  # cross-platform logic
│   │   ├── mod.rs
│   │   ├── crypto.rs
│   │   └── utils.rs
│   └── ios/
│       └── ffi.rs             # #[no_mangle] extern "C" functions
└── ios_build/
    ├── build.sh               # shell script to build framework
    └── Info.plist             # minimal plist for framework

2. ffi.rs Example

// src/ios/ffi.rs
#[cfg(target_os = "ios")]
#[no_mangle]
pub extern "C" fn encrypt_ios(data: *const u8, len: usize, out_len: *mut usize) -> *mut u8 {
    let slice = unsafe { std::slice::from_raw_parts(data, len) };
    let encrypted = crate::core::encrypt(slice);
    let ptr = encrypted.as_ptr();
    *out_len = encrypted.len();
    std::mem::forget(encrypted); // transfer ownership to caller
    ptr as *mut u8
}

3. cbindgen.toml Example

language = "C"
include_version = false
autogen_tag = "Automatically generated, do not edit."
output = "include/my_rust_lib.h"

4. Minimal Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleIdentifier</key>
    <string>org.example.MyRustLib</string>
    <key>CFBundleName</key>
    <string>MyRustLib</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
</dict>
</plist>

5. Minimal Shell Script: ios_build/build.sh

#!/usr/bin/env bash
set -e

# 1. Generate C header
cbindgen --config ../cbindgen.toml --crate my_rust_lib --output ../include/my_rust_lib.h
echo "Header generated at include/my_rust_lib.h"

# 2. Build Rust dynamic library for iOS device
cargo build --release --target aarch64-apple-ios

# 3. Prepare framework
rm -rf MyRustLib.framework
mkdir -p MyRustLib.framework/Headers

# 4. Copy Rust library and rename (remove .dylib)
cp target/aarch64-apple-ios/release/libmy_rust_lib.dylib MyRustLib.framework/MyRustLib

# 5. Copy header and Info.plist
cp ../include/my_rust_lib.h MyRustLib.framework/Headers/
cp Info.plist MyRustLib.framework/

echo "Framework ready: MyRustLib.framework"

6. Resulting Framework Layout

MyRustLib.framework/
├── MyRustLib                # Rust dynamic library (no extension)
├── Headers/
│   └── my_rust_lib.h        # generated header
└── Info.plist               # required for framework
  • Xcode can now import the framework, call the Rust functions via the header, and App Store submission is allowed.
  • Only the device architecture (ios-arm64) is included; simulator support can be added later if needed.

This setup is minimal, clean, and App Store–ready. It also keeps the core Rust logic isolated and header generation fully automated via shell script.

If you want, I can also show a complete lib.rs + core module minimal example so you could drop this into a new project and build the XCFramework immediately. Do you want me to do that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment