diff --git a/Cargo.lock b/Cargo.lock index 7dffc9d6b..38eaeb0d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1601,6 +1601,13 @@ dependencies = [ "uniffi", ] +[[package]] +name = "uniffi-bindgen-swift-package-cli" +version = "0.1.0" +dependencies = [ + "uniffi", +] + [[package]] name = "uniffi-example-arithmetic" version = "0.22.0" diff --git a/Cargo.toml b/Cargo.toml index a6dc4a83e..e997ab9f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "weedle2", "examples/app/uniffi-bindgen-cli", + "examples/app/uniffi-bindgen-swift-package-cli", "examples/arithmetic", "examples/arithmetic-procmacro", "examples/async-api-client", diff --git a/examples/app/uniffi-bindgen-swift-package-cli/Cargo.toml b/examples/app/uniffi-bindgen-swift-package-cli/Cargo.toml new file mode 100644 index 000000000..3f6647008 --- /dev/null +++ b/examples/app/uniffi-bindgen-swift-package-cli/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "uniffi-bindgen-swift-package-cli" +version = "0.1.0" +edition = "2021" +publish = false + +[[bin]] +name = "uniffi-bindgen-swift-package" +path = "uniffi-bindgen-swift-package.rs" + +[dependencies] +uniffi = { workspace = true, features = ["cli"] } + +[features] +ffi-trace = ["uniffi/ffi-trace"] diff --git a/examples/app/uniffi-bindgen-swift-package-cli/README.md b/examples/app/uniffi-bindgen-swift-package-cli/README.md new file mode 100644 index 000000000..a2cee2507 --- /dev/null +++ b/examples/app/uniffi-bindgen-swift-package-cli/README.md @@ -0,0 +1,67 @@ +# uniffi-bindgen-swift-package-cli + +An example binary for building Swift packages based on Uniffi bindgen. + +The `--build` and its related options are provided as convenience to build all required targets. + +The resulting Swift package can be used as a local path dependnecy directly. Currently code +signing and notorization is out of scope for this application. + +``` +Usage: uniffi-bindgen-swift-package [OPTIONS] --package-name --out-dir + +Options: + -p, --package-name + Rust package to use for building the Swift package + + Cargo metadata will be searched to determine the library name. + + --library-type + Type of library to package, defaults to staticlib + + Possible values: + - staticlib: Build an embedded XCFramework with static libraries + - dylib: Build an embedded XCFrameowrk with embedded dynamic Framework libraries + + -o, --out-dir + Directory in which to generate the Swift package, i.e., Package.swift parent dir + + --swift-package-name + Swift package name + + Defaults to the package library name. + + --manifest-path + Path to manifest for Rust workspace/package + + Defaults to search from current working path + + -c, --consolidate + Consolidate crate bindings into single Swift target. + + Otherwise separate targets will be generated to help avoid name conflicts. + + -b, --build + Builds package for specified targets. + + Otherwise assumes all targets have been built in the default target dir. + + -r, --release + Build artifacts in release mode, with optimization + + Requires build flag to be set + + -F, --features + Space or comma separated list of features to activate + + Requires build flag to be set + + --target + Target for target triple to include + + -h, --help + Print help (see a summary with '-h') + + -V, --version + Print version +``` \ No newline at end of file diff --git a/examples/app/uniffi-bindgen-swift-package-cli/uniffi-bindgen-swift-package.rs b/examples/app/uniffi-bindgen-swift-package-cli/uniffi-bindgen-swift-package.rs new file mode 100644 index 000000000..526e15f87 --- /dev/null +++ b/examples/app/uniffi-bindgen-swift-package-cli/uniffi-bindgen-swift-package.rs @@ -0,0 +1,3 @@ +fn main() { + uniffi::uniffi_bindgen_swift_package() +} diff --git a/uniffi/src/cli/mod.rs b/uniffi/src/cli/mod.rs index fc2e75e4a..e57b1ce12 100644 --- a/uniffi/src/cli/mod.rs +++ b/uniffi/src/cli/mod.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ mod swift; +mod swift_package; mod uniffi_bindgen; pub fn uniffi_bindgen_main() { @@ -18,3 +19,10 @@ pub fn uniffi_bindgen_swift() { std::process::exit(1); } } + +pub fn uniffi_bindgen_swift_package() { + if let Err(e) = swift_package::run_main() { + eprintln!("{e:?}"); + std::process::exit(1); + } +} diff --git a/uniffi/src/cli/swift_package.rs b/uniffi/src/cli/swift_package.rs new file mode 100644 index 000000000..a7a856440 --- /dev/null +++ b/uniffi/src/cli/swift_package.rs @@ -0,0 +1,94 @@ +use anyhow::{bail, Result}; +use camino::Utf8PathBuf; +use clap::{command, Parser}; + +// TODO: Add all-features and no-default-features options +// TODO: Add univeral library override option(s) + +#[derive(Debug, Parser)] +#[command(version, about, long_about = None)] +struct Cli { + /// Rust package to use for building the Swift package + /// + /// Cargo metadata will be searched to determine the library name. + #[arg(short = 'p', long, value_name = "SPEC")] + package_name: String, + + /// Type of library to package, defaults to staticlib. + #[arg(long, value_name = "LIB_TYPE")] + library_type: Option, + + /// Directory in which to generate the Swift package, i.e., Package.swift parent dir + #[arg(short = 'o', long)] + out_dir: Utf8PathBuf, + + /// Swift package name + /// + /// Defaults to the package library name. + #[arg(long, value_name = "NAME")] + swift_package_name: Option, + + /// Path to manifest for Rust workspace/package + /// + /// Defaults to search from current working path + #[arg(long, value_name = "MANIFEST_PATH")] + manifest_path: Option, + + /// Consolidate crate bindings into single Swift target. + /// + /// Otherwise separate Swift targets will be generated + #[arg(short = 'c', long)] + consolidate: bool, + + /// Builds package for specified targets. + /// + /// Otherwise assumes all targets have been built in the default target dir. + #[arg(short = 'b', long)] + build: bool, + + /// Build artifacts in release mode, with optimization + /// + /// Requires build flag to be set + #[arg(short = 'r', long)] + release: bool, + + /// Space or comma separated list of features to activate + /// + /// Requires build flag to be set + #[arg(short = 'F', long)] + features: Vec, + + /// Target for target triple to include + #[arg(long)] + target: Vec, +} + +#[derive(Clone, Debug, clap::ValueEnum)] +enum LibraryType { + /// Build an embedded XCFramework with static libraries + Staticlib, + /// Build an embedded XCFrameowrk with embedded dynamic Framework libraries + Dylib, +} + +pub fn run_main() -> Result<()> { + let _ = Cli::parse(); + + // TODO: Specify targets from command line with default. + let _targets = [ + "x86_64-apple-ios", + "aarch64-apple-ios-sim", + "aarch64-apple-ios", + "x86_64-apple-darwin", + "aarch64-apple-darwin", + ]; + + // TODO: Override xcframework libraries from command line. + let _library_targets = [ + vec!["x86_64-apple-ios", "aarch64-apple-ios-sim"], // iOS simulator + vec!["aarch64-apple-ios"], // iOS + vec!["x86_64-apple-darwin", "aarch64-apple-darwin"], // macOS + ]; + + bail!("Building a Swift Package is unimplemented!"); +}