7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 1 | use std::{ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 2 | collections::HashMap, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 3 | fs::{copy, create_dir_all, remove_dir_all, remove_file, rename}, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 4 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 5 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 6 | use camino::{Utf8Path, Utf8PathBuf}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 7 | use clap::{Args, Subcommand}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 8 | use uniffi_bindgen::bindings::{GenerateOptions, TargetLanguage, generate}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 9 | use xshell::cmd; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 10 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 11 | use crate::{Result, sh, workspace}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 12 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 13 | /// Builds the SDK for Swift as a Static Library or XCFramework. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 14 | #[derive(Args)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 15 | pub struct SwiftArgs { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 16 | #[clap(subcommand)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 17 | cmd: SwiftCommand, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 18 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 19 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 20 | #[derive(Subcommand)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 21 | enum SwiftCommand { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 22 | /// Builds the SDK for Swift as a static lib. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 23 | BuildLibrary, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 24 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 25 | /// Builds the SDK for Swift as an XCFramework. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 26 | BuildFramework { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 27 | /// Build with the release profile |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 28 | #[clap(long)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 29 | release: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 30 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 31 | /// Build with a custom profile, takes precedence over `--release` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 32 | #[clap(long)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 33 | profile: Option<String>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 34 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 35 | /// Build the given target. This option can be specified multiple times |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 36 | /// to build more than one. Omitting this option will build all |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 37 | /// supported targets. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 38 | #[clap(long)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 39 | target: Option<Vec<String>>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 40 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 41 | /// Includes the Tier 3 targets (such as watchOS) when building all |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 42 | /// supported targets. Requires a nightly toolchain with the `rust-src` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 43 | /// component installed. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 44 | #[clap(long)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 45 | tier3_targets: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 46 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 47 | /// Move the generated xcframework and swift sources into the given |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 48 | /// components-folder |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 49 | #[clap(long)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 50 | components_path: Option<Utf8PathBuf>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 51 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 52 | /// The iOS deployment target to use when building the framework. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 53 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 54 | /// Defaults to not being set, which implies that the build will use the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 55 | /// default values provided by the Rust and Xcode toolchains. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 56 | #[clap(long)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 57 | ios_deployment_target: Option<String>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 58 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 59 | /// The wachOS deployment target to use when building the framework. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 60 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 61 | /// Defaults to not being set, which implies that the build will use the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 62 | /// default values provided by the Rust and Xcode toolchains. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 63 | #[clap(long)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 64 | watchos_deployment_target: Option<String>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 65 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 66 | /// Build the targets one by one instead of passing all of them |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 67 | /// to cargo in one go, which makes it hang on lesser devices like plain |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 68 | /// Apple Silicon M1s |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 69 | #[clap(long)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 70 | sequentially: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 71 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 72 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 73 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 74 | impl SwiftArgs { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 75 | pub fn run(self) -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 76 | let sh = sh(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 77 | let _p = sh.push_dir(workspace::root_path()?); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 78 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 79 | match self.cmd { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 80 | SwiftCommand::BuildLibrary => build_library(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 81 | SwiftCommand::BuildFramework { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 82 | release, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 83 | profile, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 84 | target: targets, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 85 | tier3_targets, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 86 | components_path, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 87 | ios_deployment_target, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 88 | watchos_deployment_target, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 89 | sequentially, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 90 | } => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 91 | // The dev profile seems to cause crashes on some platforms so we default to |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 92 | // reldbg (https://github.com/matrix-org/matrix-rust-sdk/issues/4009) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 93 | let profile = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 94 | profile.as_deref().unwrap_or(if release { "release" } else { "reldbg" }); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 95 | build_xcframework( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 96 | profile, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 97 | targets, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 98 | tier3_targets, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 99 | components_path, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 100 | sequentially, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 101 | ios_deployment_target.as_deref(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 102 | watchos_deployment_target.as_deref(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 103 | ) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 104 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 105 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 106 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 107 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 108 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 109 | /// A specific build target supported by the SDK. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 110 | struct Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 111 | triple: &'static str, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 112 | platform: Platform, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 113 | status: TargetStatus, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 114 | description: &'static str, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 115 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 116 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 117 | #[derive(Hash, PartialEq, Eq, Clone)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 118 | enum TargetStatus { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 119 | /// A tier 1 or 2 target that can be built with stable Rust. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 120 | TopTier, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 121 | /// A tier 3 target that requires nightly Rust and `-Zbuild-std`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 122 | Tier3, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 123 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 124 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 125 | /// The platform for which a particular target can run on. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 126 | #[derive(Hash, PartialEq, Eq, Clone)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 127 | enum Platform { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 128 | Macos, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 129 | Ios, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 130 | IosSimulator, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 131 | Watchos, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 132 | WatchosSimulator, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 133 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 134 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 135 | impl Platform { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 136 | /// The human-readable name of the platform. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 137 | fn as_str(&self) -> &str { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 138 | match self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 139 | Platform::Macos => "macOS", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 140 | Platform::Ios => "iOS", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 141 | Platform::IosSimulator => "iOS Simulator", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 142 | Platform::Watchos => "watchOS", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 143 | Platform::WatchosSimulator => "watchOS Simulator", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 144 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 145 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 146 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 147 | /// The name of the subfolder in which to place the library for the platform |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 148 | /// once all architectures are lipo'd together. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 149 | fn lib_folder_name(&self) -> &str { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 150 | match self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 151 | Platform::Macos => "macos", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 152 | Platform::Ios => "ios", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 153 | Platform::IosSimulator => "ios-simulator", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 154 | Platform::Watchos => "watchos", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 155 | Platform::WatchosSimulator => "watchos-simulator", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 156 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 157 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 158 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 159 | /// The base name of the FFI library. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 160 | const FFI_LIBRARY_NAME: &str = "libmatrix_sdk_ffi.a"; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 161 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 162 | /// The features enabled for the FFI library. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 163 | const FFI_FEATURES: &str = "sentry"; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 164 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 165 | /// The list of targets supported by the SDK. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 166 | const TARGETS: &[Target] = &[ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 167 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 168 | triple: "aarch64-apple-ios", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 169 | platform: Platform::Ios, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 170 | status: TargetStatus::TopTier, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 171 | description: "iOS", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 172 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 173 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 174 | triple: "aarch64-apple-darwin", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 175 | platform: Platform::Macos, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 176 | status: TargetStatus::TopTier, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 177 | description: "macOS (Apple Silicon)", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 178 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 179 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 180 | triple: "x86_64-apple-darwin", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 181 | platform: Platform::Macos, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 182 | status: TargetStatus::TopTier, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 183 | description: "macOS (Intel)", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 184 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 185 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 186 | triple: "aarch64-apple-ios-sim", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 187 | platform: Platform::IosSimulator, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 188 | status: TargetStatus::TopTier, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 189 | description: "iOS Simulator (Apple Silicon)", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 190 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 191 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 192 | triple: "x86_64-apple-ios", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 193 | platform: Platform::IosSimulator, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 194 | status: TargetStatus::TopTier, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 195 | description: "iOS Simulator (Intel) ", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 196 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 197 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 198 | triple: "aarch64-apple-watchos", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 199 | platform: Platform::Watchos, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 200 | status: TargetStatus::Tier3, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 201 | description: "watchOS (ARM64)", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 202 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 203 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 204 | triple: "arm64_32-apple-watchos", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 205 | platform: Platform::Watchos, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 206 | status: TargetStatus::Tier3, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 207 | description: "watchOS (ARM64_32)", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 208 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 209 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 210 | triple: "aarch64-apple-watchos-sim", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 211 | platform: Platform::WatchosSimulator, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 212 | status: TargetStatus::Tier3, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 213 | description: "watchOS Simulator (ARM64)", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 214 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 215 | Target { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 216 | triple: "x86_64-apple-watchos-sim", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 217 | platform: Platform::WatchosSimulator, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 218 | status: TargetStatus::Tier3, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 219 | description: "watchOS Simulator (Intel)", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 220 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 221 | ]; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 222 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 223 | fn build_library() -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 224 | println!("Running debug library build."); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 225 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 226 | let root_directory = workspace::root_path()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 227 | let target_directory = workspace::target_path()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 228 | let ffi_directory = root_directory.join("bindings/apple/generated/matrix_sdk_ffi"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 229 | let lib_output_dir = target_directory.join("debug"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 230 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 231 | create_dir_all(ffi_directory.as_path())?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 232 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 233 | let sh = sh(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 234 | cmd!(sh, "rustup run stable cargo build -p matrix-sdk-ffi --features {FFI_FEATURES}").run()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 235 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 236 | rename(lib_output_dir.join(FFI_LIBRARY_NAME), ffi_directory.join(FFI_LIBRARY_NAME))?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 237 | let swift_directory = root_directory.join("bindings/apple/generated/swift"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 238 | create_dir_all(swift_directory.as_path())?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 239 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 240 | generate_uniffi(&ffi_directory.join(FFI_LIBRARY_NAME), &ffi_directory)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 241 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 242 | let module_map_file = ffi_directory.join("module.modulemap"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 243 | if module_map_file.exists() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 244 | remove_file(module_map_file.as_path())?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 245 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 246 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 247 | consolidate_modulemap_files(&ffi_directory, &ffi_directory)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 248 | move_files("swift", &ffi_directory, &swift_directory)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 249 | update_swift_module_imports(&swift_directory)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 250 | Ok(()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 251 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 252 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 253 | fn generate_uniffi(library_path: &Utf8Path, ffi_directory: &Utf8Path) -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 254 | generate(GenerateOptions { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 255 | languages: vec![TargetLanguage::Swift], |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 256 | source: library_path.to_path_buf(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 257 | out_dir: ffi_directory.to_path_buf(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 258 | ..GenerateOptions::default() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 259 | })?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 260 | Ok(()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 261 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 262 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 263 | fn build_xcframework( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 264 | profile: &str, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 265 | targets: Option<Vec<String>>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 266 | tier3_targets: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 267 | components_path: Option<Utf8PathBuf>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 268 | sequentially: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 269 | ios_deployment_target: Option<&str>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 270 | watchos_deployment_target: Option<&str>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 271 | ) -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 272 | let root_dir = workspace::root_path()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 273 | let apple_dir = root_dir.join("bindings/apple"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 274 | let generated_dir = apple_dir.join("generated"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 275 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 276 | // Cleanup destination folder |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 277 | let _ = remove_dir_all(&generated_dir); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 278 | create_dir_all(&generated_dir)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 279 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 280 | let headers_dir = generated_dir.join("headers"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 281 | // Use a subdirectory to fix conflicts with other UniFFI libraries. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 282 | let headers_module_dir = headers_dir.join("MatrixSDKFFI"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 283 | let swift_dir = generated_dir.join("swift"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 284 | create_dir_all(headers_module_dir.clone())?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 285 | create_dir_all(swift_dir.clone())?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 286 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 287 | let targets = if let Some(triples) = targets { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 288 | triples |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 289 | .iter() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 290 | .map(|t| { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 291 | TARGETS.iter().find(|target| target.triple == *t).expect("Invalid target specified") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 292 | }) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 293 | .collect() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 294 | } else if tier3_targets { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 295 | TARGETS.iter().collect() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 296 | } else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 297 | TARGETS.iter().filter(|target| target.status == TargetStatus::TopTier).collect() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 298 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 299 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 300 | let platform_build_paths = build_targets( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 301 | targets, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 302 | profile, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 303 | sequentially, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 304 | ios_deployment_target, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 305 | watchos_deployment_target, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 306 | )?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 307 | let libs = lipo_platform_libraries(&platform_build_paths, &generated_dir)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 308 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 309 | println!("-- Generating uniffi files"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 310 | let uniffi_lib_path = platform_build_paths.values().next().unwrap().first().unwrap().clone(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 311 | generate_uniffi(&uniffi_lib_path, &generated_dir)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 312 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 313 | move_files("h", &generated_dir, &headers_module_dir)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 314 | consolidate_modulemap_files(&generated_dir, &headers_module_dir)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 315 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 316 | move_files("swift", &generated_dir, &swift_dir)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 317 | update_swift_module_imports(&swift_dir)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 318 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 319 | println!("-- Generating MatrixSDKFFI.xcframework framework"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 320 | let xcframework_path = generated_dir.join("MatrixSDKFFI.xcframework"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 321 | if xcframework_path.exists() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 322 | remove_dir_all(&xcframework_path)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 323 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 324 | let sh = sh(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 325 | let mut cmd = cmd!(sh, "xcodebuild -create-xcframework"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 326 | for p in libs { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 327 | cmd = cmd.arg("-library").arg(p).arg("-headers").arg(&headers_dir) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 328 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 329 | cmd.arg("-output").arg(&xcframework_path).run()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 330 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 331 | // Copy the Swift package manifest to the SDK root for local development. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 332 | copy(apple_dir.join("Debug-Package.swift"), root_dir.join("Package.swift"))?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 333 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 334 | // Copy an empty package to folders we want ignored |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 335 | let ignored_package_folders = ["target"]; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 336 | for path in ignored_package_folders { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 337 | copy( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 338 | apple_dir.join("Debug-Empty-Package.swift"), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 339 | root_dir.join(path).join("Package.swift"), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 340 | )?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 341 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 342 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 343 | // cleaning up the intermediate data |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 344 | remove_dir_all(headers_dir.as_path())?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 345 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 346 | if let Some(path) = components_path { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 347 | println!("-- Copying MatrixSDKFFI.xcframework to {path}"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 348 | let framework_target = path.join("MatrixSDKFFI.xcframework"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 349 | let swift_target = path.join("Sources/MatrixRustSDK"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 350 | if framework_target.exists() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 351 | remove_dir_all(&framework_target)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 352 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 353 | if swift_target.exists() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 354 | remove_dir_all(&swift_target)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 355 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 356 | create_dir_all(&framework_target)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 357 | create_dir_all(&swift_target)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 358 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 359 | let copy_options = fs_extra::dir::CopyOptions { content_only: true, ..Default::default() }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 360 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 361 | fs_extra::dir::copy(&xcframework_path, &framework_target, ©_options)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 362 | fs_extra::dir::copy(&swift_dir, &swift_target, ©_options)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 363 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 364 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 365 | println!("-- All done and hunky dory. Enjoy!"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 366 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 367 | Ok(()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 368 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 369 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 370 | /// Builds the SDK for the specified targets and profile. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 371 | fn build_targets( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 372 | targets: Vec<&Target>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 373 | profile: &str, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 374 | sequentially: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 375 | ios_deployment_target: Option<&str>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 376 | watchos_deployment_target: Option<&str>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 377 | ) -> Result<HashMap<Platform, Vec<Utf8PathBuf>>> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 378 | let sh = sh(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 379 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 380 | // Note: `push_env` stores environment variables and returns a RAII guard that |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 381 | // will restore the environment variable to its previous value when dropped. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 382 | let _env_guard1 = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 383 | sh.push_env("CARGO_TARGET_AARCH64_APPLE_IOS_RUSTFLAGS", "-Clinker=/usr/bin/clang"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 384 | let _env_guard2 = sh.push_env("AARCH64_APPLE_IOS_CC", "/usr/bin/clang"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 385 | let _env_guard3 = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 386 | ios_deployment_target.map(|target| sh.push_env("IPHONEOS_DEPLOYMENT_TARGET", target)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 387 | let _env_guard4 = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 388 | watchos_deployment_target.map(|target| sh.push_env("WATCHOS_DEPLOYMENT_TARGET", target)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 389 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 390 | if sequentially { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 391 | for target in &targets { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 392 | let triple = target.triple; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 393 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 394 | println!("-- Building for {}", target.description); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 395 | if target.status == TargetStatus::TopTier { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 396 | cmd!(sh, "rustup run stable cargo build -p matrix-sdk-ffi --target {triple} --profile {profile} --features {FFI_FEATURES}") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 397 | .run()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 398 | } else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 399 | cmd!(sh, "rustup run nightly cargo build -p matrix-sdk-ffi -Zbuild-std --target {triple} --profile {profile} --features {FFI_FEATURES}") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 400 | .run()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 401 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 402 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 403 | } else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 404 | let (stable_targets, tier3_targets): (Vec<&Target>, Vec<&Target>) = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 405 | targets.iter().partition(|t| t.status == TargetStatus::TopTier); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 406 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 407 | if !stable_targets.is_empty() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 408 | let triples = stable_targets.iter().map(|target| target.triple).collect::<Vec<_>>(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 409 | let mut cmd = cmd!(sh, "rustup run stable cargo build -p matrix-sdk-ffi"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 410 | for triple in &triples { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 411 | cmd = cmd.arg("--target").arg(triple); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 412 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 413 | cmd = cmd.arg("--profile").arg(profile).arg("--features").arg(FFI_FEATURES); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 414 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 415 | println!("-- Building for {} targets", triples.len()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 416 | cmd.run()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 417 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 418 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 419 | if !tier3_targets.is_empty() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 420 | let triples = tier3_targets.iter().map(|target| target.triple).collect::<Vec<_>>(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 421 | let mut cmd = cmd!(sh, "rustup run nightly cargo build -p matrix-sdk-ffi -Zbuild-std"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 422 | for triple in &triples { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 423 | cmd = cmd.arg("--target").arg(triple); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 424 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 425 | cmd = cmd.arg("--profile").arg(profile).arg("--features").arg(FFI_FEATURES); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 426 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 427 | println!("-- Building for {} targets with nightly -Zbuild-std", triples.len()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 428 | cmd.run()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 429 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 430 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 431 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 432 | // a hashmap of platform to array, where each array contains all the paths for |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 433 | // that platform. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 434 | let mut platform_build_paths = HashMap::new(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 435 | for target in targets { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 436 | let path = build_path_for_target(target, profile)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 437 | let paths = platform_build_paths.entry(target.platform.clone()).or_insert_with(Vec::new); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 438 | paths.push(path); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 439 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 440 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 441 | Ok(platform_build_paths) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 442 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 443 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 444 | /// The path of the built library for a specific target and profile. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 445 | fn build_path_for_target(target: &Target, profile: &str) -> Result<Utf8PathBuf> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 446 | // The builtin dev profile has its files stored under target/debug, all |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 447 | // other targets have matching directory names |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 448 | let profile_dir_name = if profile == "dev" { "debug" } else { profile }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 449 | Ok(workspace::target_path()?.join(target.triple).join(profile_dir_name).join(FFI_LIBRARY_NAME)) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 450 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 451 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 452 | /// Lipo's together the libraries for each platform into a single library. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 453 | fn lipo_platform_libraries( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 454 | platform_build_paths: &HashMap<Platform, Vec<Utf8PathBuf>>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 455 | generated_dir: &Utf8Path, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 456 | ) -> Result<Vec<Utf8PathBuf>> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 457 | let mut libs = Vec::new(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 458 | let sh = sh(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 459 | for platform in platform_build_paths.keys() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 460 | let paths = platform_build_paths.get(platform).unwrap(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 461 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 462 | if paths.len() == 1 { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 463 | libs.push(paths[0].clone()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 464 | continue; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 465 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 466 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 467 | let output_folder = generated_dir.join("lipo").join(platform.lib_folder_name()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 468 | create_dir_all(&output_folder)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 469 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 470 | let output_path = output_folder.join(FFI_LIBRARY_NAME); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 471 | let mut cmd = cmd!(sh, "lipo -create"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 472 | for path in paths { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 473 | cmd = cmd.arg(path); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 474 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 475 | cmd = cmd.arg("-output").arg(&output_path); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 476 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 477 | println!("-- Running Lipo for {}", platform.as_str()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 478 | cmd.run()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 479 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 480 | libs.push(output_path); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 481 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 482 | Ok(libs) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 483 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 484 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 485 | /// Moves all files of the specified file extension from one directory into |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 486 | /// another. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 487 | fn move_files(extension: &str, source: &Utf8Path, destination: &Utf8Path) -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 488 | for entry in source.read_dir_utf8()? { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 489 | let entry = entry?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 490 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 491 | if entry.file_type()?.is_file() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 492 | let path = entry.path(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 493 | if path.extension() == Some(extension) { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 494 | let file_name = path.file_name().expect("Failed to get file name"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 495 | rename(path, destination.join(file_name)).expect("Failed to move swift file"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 496 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 497 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 498 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 499 | Ok(()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 500 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 501 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 502 | /// Updates all the swift files in the given directory to import the same module |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 503 | /// that gets defined by the `consolidate_modulemap_files` function. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 504 | fn update_swift_module_imports(directory: &Utf8Path) -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 505 | let regex = regex::Regex::new(r"#if canImport\(\w+FFI\)\nimport \w+FFI\n#endif")?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 506 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 507 | for entry in directory.read_dir_utf8()? { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 508 | let entry = entry?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 509 | if entry.file_type()?.is_file() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 510 | let path = entry.path(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 511 | if path.extension() == Some("swift") { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 512 | let contents = std::fs::read_to_string(path)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 513 | let new_contents = regex.replace_all( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 514 | &contents, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 515 | "#if canImport(MatrixSDKFFI)\nimport MatrixSDKFFI\n#endif", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 516 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 517 | if new_contents != contents { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 518 | std::fs::write(path, new_contents.as_ref())?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 519 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 520 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 521 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 522 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 523 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 524 | Ok(()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 525 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 526 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 527 | /// Consolidates the modulemap files found in the source directory into a single |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 528 | /// `module.modulemap` file in the destination directory. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 529 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 530 | /// The first modulemap file found is used as the base and all `header` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 531 | /// directives from the remaining modulemap files are spliced in after the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 532 | /// base's own header line. All other content in the base (e.g. `export *`, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 533 | /// `use` directives, and any future additions) is preserved verbatim. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 534 | fn consolidate_modulemap_files(source: &Utf8Path, destination: &Utf8Path) -> Result<()> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 535 | let mut base_contents: Option<String> = None; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 536 | let mut extra_headers: Vec<String> = Vec::new(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 537 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 538 | for entry in source.read_dir_utf8()? { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 539 | let entry = entry?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 540 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 541 | if entry.file_type()?.is_file() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 542 | let path = entry.path(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 543 | if path.extension() == Some("modulemap") { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 544 | let contents = std::fs::read_to_string(path)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 545 | if base_contents.is_none() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 546 | base_contents = Some(contents); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 547 | } else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 548 | for line in contents.lines() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 549 | if line.trim().starts_with("header ") |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 550 | && !extra_headers.contains(&line.to_string()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 551 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 552 | extra_headers.push(line.to_string()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 553 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 554 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 555 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 556 | remove_file(path)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 557 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 558 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 559 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 560 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 561 | let base = base_contents.expect("No modulemap files found"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 562 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 563 | // Rebuild the base line-by-line, renaming the module to MatrixSDKFFI and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 564 | // inserting the extra headers immediately after the base's own header line. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 565 | let mut lines: Vec<String> = Vec::new(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 566 | let mut last_header_position: Option<usize> = None; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 567 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 568 | for line in base.lines() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 569 | if line.starts_with("module ") { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 570 | lines.push("module MatrixSDKFFI {".to_string()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 571 | } else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 572 | if line.trim().starts_with("header ") { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 573 | last_header_position = Some(lines.len()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 574 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 575 | lines.push(line.to_string()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 576 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 577 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 578 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 579 | if let Some(last_header_position) = last_header_position { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 580 | lines.splice(last_header_position + 1..last_header_position + 1, extra_headers); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 581 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 582 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 583 | let modulemap = lines.join("\n") + "\n"; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 584 | std::fs::write(destination.join("module.modulemap"), modulemap)?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 585 | Ok(()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 586 | } |