uniffi_bindgen_library_mode/
main.rs1use std::{
6 env::consts::{DLL_PREFIX, DLL_SUFFIX},
7 fmt, process,
8};
9
10use anyhow::{bail, Result};
11use camino::{Utf8Path, Utf8PathBuf};
12use clap::{Args, Parser, Subcommand};
13use uniffi_bindgen::bindings::{generate_swift_bindings, SwiftBindingsOptions};
14
15#[derive(Parser)]
16#[command(version, about, long_about = None)]
17struct Cli {
18 #[command(flatten)]
19 megazord: MegazordArg,
20 #[command(subcommand)]
21 command: Command,
22}
23
24#[derive(Args)]
25#[group(required = true, multiple = false)]
26struct MegazordArg {
27 #[arg(short, long, value_parser=["megazord", "megazord_ios", "megazord_focus", "cirrus", "nimbus-experimenter"])]
29 megazord: Option<String>,
30
31 #[arg(short, long)]
33 library: Option<Utf8PathBuf>,
34}
35
36#[derive(Subcommand)]
37enum Command {
38 Kotlin {
39 out_dir: Utf8PathBuf,
40 },
41 Swift {
42 out_dir: Utf8PathBuf,
43 #[arg(long)]
45 swift_sources: bool,
46 #[arg(long)]
48 headers: bool,
49 #[arg(long)]
51 modulemap: bool,
52 #[arg(long)]
54 xcframework: bool,
55 #[arg(long)]
57 module_name: Option<String>,
58 #[arg(long)]
60 modulemap_filename: Option<String>,
61 },
62 Python {
63 out_dir: Utf8PathBuf,
64 },
65}
66
67enum Language {
68 Kotlin,
69 Swift,
70 Python,
71}
72
73fn main() {
74 if let Err(e) = run_uniffi_bindgen(Cli::parse()) {
75 eprintln!("{e}");
76 std::process::exit(1);
77 }
78}
79
80fn run_uniffi_bindgen(cli: Cli) -> Result<()> {
81 let metadata = cargo_metadata::MetadataCommand::new()
82 .exec()
83 .expect("error running cargo metadata");
84 let megazord = Megazord::new(
85 &cli.megazord,
86 cli.command.language(),
87 &metadata.workspace_root,
88 )?;
89 let config_supplier = uniffi::CargoMetadataConfigSupplier::from(metadata);
90
91 match cli.command {
92 Command::Kotlin { out_dir } => {
93 uniffi::generate_bindings_library_mode(
94 &megazord.library_path,
95 None,
96 &uniffi::KotlinBindingGenerator,
97 &config_supplier,
98 None,
99 &out_dir,
100 false,
101 )?;
102 }
103 Command::Swift {
104 out_dir,
105 mut swift_sources,
106 mut headers,
107 mut modulemap,
108 xcframework,
109 module_name,
110 modulemap_filename,
111 } => {
112 let module_name = module_name.unwrap_or_else(|| "MozillaRustComponents".to_owned());
113 if !(swift_sources || headers || modulemap) {
115 swift_sources = true;
116 headers = true;
117 modulemap = true;
118 }
119
120 generate_swift_bindings(SwiftBindingsOptions {
121 out_dir,
122 generate_swift_sources: swift_sources,
123 generate_headers: headers,
124 generate_modulemap: modulemap,
125 library_path: megazord.library_path,
126 xcframework,
127 module_name: Some(module_name),
128 modulemap_filename,
129 metadata_no_deps: false,
130 ..SwiftBindingsOptions::default()
131 })?;
132 }
133 Command::Python { out_dir } => {
134 uniffi::generate_bindings_library_mode(
135 &megazord.library_path,
136 None,
137 &uniffi::PythonBindingGenerator,
138 &config_supplier,
139 None,
140 &out_dir,
141 false,
142 )?;
143 }
144 };
145 Ok(())
146}
147
148struct Megazord {
149 library_path: Utf8PathBuf,
150}
151
152impl Megazord {
153 fn new(arg: &MegazordArg, language: Language, workspace_root: &Utf8Path) -> Result<Self> {
154 if let Some(crate_name) = &arg.megazord {
155 process::Command::new("cargo")
157 .args(["build", "--release", "-p", crate_name])
158 .spawn()?
159 .wait()?;
160
161 let filename = match language {
162 Language::Swift => format!("lib{}.a", crate_name.replace('-', "_")),
164 _ => format!(
166 "{}{}{}",
167 DLL_PREFIX,
168 crate_name.replace('-', "_"),
169 DLL_SUFFIX
170 ),
171 };
172 let library_path = workspace_root.join("target").join("release").join(filename);
173 Ok(Self { library_path })
174 } else if let Some(library_path) = &arg.library {
175 Ok(Self {
176 library_path: library_path.clone(),
177 })
178 } else {
179 bail!("Neither megazord nor library specified")
180 }
181 }
182}
183
184impl fmt::Display for Language {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 let name = match self {
187 Self::Swift => "swift",
188 Self::Kotlin => "kotlin",
189 Self::Python => "python",
190 };
191 write!(f, "{}", name)
192 }
193}
194
195impl Command {
196 fn language(&self) -> Language {
197 match self {
198 Self::Kotlin { .. } => Language::Kotlin,
199 Self::Swift { .. } => Language::Swift,
200 Self::Python { .. } => Language::Python,
201 }
202 }
203}