This project demos how to integate a Rust static library to a SwiftUI macOS app. The app provides a text editor for entering a string of Typst markups, a button to compile it to a PDF, and a save dialog to export the PDF.
SwiftUI App (iOS/macOS) Rust Static Library System Storage
│ │ │
│ 1. Call PDF generation func │ │
│───────────────────────────────>│ │
│ │ │
│ │ 2. Generate PDF │
│ │ ┌─────────────────────┐ │
│ │ │ PDF Creation │ │
│ │ └─────────────────────┘ │
│ │ │
│ 3. Return PDF data (byte[]) │ │
│<───────────────────────────────│ │
│ │ │
│ 4. Save PDF to documents │ │
│────────────────────────────────────────────────────────────>│
│ │ │
- Xcode: Version 16.4 or later.
- Rust Library: The
typst-ffistatic library (libtypst_ffi.a) and header file (typst_ffi.h), built as described in thetypst-ffiproject’sREADME.md. - macOS: Developed for Apple Silicon (arm64).
The typst-ffi Rust library provides two functions to be called by Swift code for actually generating a PDF. Below are the steps that created this project.
Notice, to build and run this project you only need step 2.
But the following lists all the steps involved in creating this project from scratch.
-
Create the Xcode Project:
- In Xcode, create a new macOS App project with SwiftUI interface (e.g.,
TypstFFIApp). - Save it to a directory (e.g.,
~/TypstFFIApp).
- In Xcode, create a new macOS App project with SwiftUI interface (e.g.,
-
Add the Rust Library:
- Copy
libtypst_ffi.aandtypst_ffi.hfrom thetypst-ffiproject to the Xcode project directory:cp ~/typst-ffi/target/release/libtypst_ffi.a ~/TypstFFIApp/ cp ~/typst-ffi/typst_ffi.h ~/TypstFFIApp/
- In Xcode, go to File > Add Files to "TypstFFIApp" and add
typst_ffi.h. (N.B. if you also addlibtypst_ffi.a, you will likely get a duplicate linker flag warning from build) - Ensure
libtypst_ffi.aandtypst_ffi.hare included in the Target Membership for the app target.
- Copy
-
Create a Bridging Header:
- Create a file named
TypstFFIApp-Bridging-Header.hin the project directory:#ifndef TypstFFIApp_Bridging_Header_h #define TypstFFIApp_Bridging_Header_h #include "typst_ffi.h" #endif
- In Xcode, go to Build Settings, search for Objective-C Bridging Header, and set it to:
$(SRCROOT)/TypstFFIApp-Bridging-Header.h
- Create a file named
-
Configure Build Settings:
- In Build Settings:
- Library Search Paths: Add
$(SRCROOT)to locatelibtypst_ffi.a. - Other Linker Flags: Add:
-ltypst_ffi -lc++ -lm -ldl -lpthread -framework CoreFoundation -framework Security - Architectures: Set to
arm64for Apple Silicon (or$(ARCHS_STANDARD)for universal binaries). - Excluded Architectures: Add
x86_64for archiving if targeting only arm64.
- Library Search Paths: Add
- In Build Phases > Link Binary With Libraries, ensure
libtypst_ffi.ais listed.
- In Build Settings:
-
SwiftUI Implementation:
- The
ContentView.swiftfile implements a SwiftUI interface with:- A
TextEditorfor Typst input. - A button to call
compile_typst, which converts the input to a PDF. - An
NSSavePanelto save the PDF output. - A status message to show success or errors.
- A
- The Rust library’s
compile_typstfunction is called via FFI, with memory management handled byfree_typst_buffer.
- The
-
Build the App:
- Open
TypstFFIApp.xcodeprojin Xcode. - Select the app target and a macOS destination (e.g., My Mac (Apple Silicon)).
- Press Cmd + B to build or Cmd + R to run.
- Open
-
Test the App:
- Enter Typst code (e.g.,
#set page(width: 200pt, height: 200pt)\nHello, *Typst* world!). - Click Compile to PDF.
- Save the PDF via the save dialog and verify its contents.
- Enter Typst code (e.g.,
-
Archive for Distribution:
- Go to Product > Archive.
- In Window > Organizer, select the archive and click Distribute App > Export.
- Choose Custom then Copy App for local share.
- Save the exported
TypstFFIApp.appand share it (e.g., as a.zip).
- Linker Errors:
- Ensure
libtypst_ffi.ais in the project directory. - Verify Library Search Paths and Other Linker Flags are correct.
- Ensure
- Architecture Issues:
- For arm64-only builds, exclude
x86_64in Excluded Architectures during archiving.
- For arm64-only builds, exclude
- PDF Issues:
- If PDFs are corrupted, verify the
NotoSans-Regular.ttffont is embedded in the Rust library. - Add debug logging in
typst-ffi’slib.rsto trace errors.
- If PDFs are corrupted, verify the
