1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 use camino::Utf8PathBuf;
6 use clap::{Parser, Subcommand};
7 use uniffi_bindgen::bindings::TargetLanguage;
8 use uniffi_bindgen::BindingGeneratorDefault;
9 
10 // Structs to help our cmdline parsing. Note that docstrings below form part
11 // of the "help" output.
12 
13 /// Scaffolding and bindings generator for Rust
14 #[derive(Parser)]
15 #[clap(name = "uniffi-bindgen")]
16 #[clap(version = clap::crate_version!())]
17 #[clap(propagate_version = true)]
18 struct Cli {
19     #[clap(subcommand)]
20     command: Commands,
21 }
22 
23 #[derive(Subcommand)]
24 enum Commands {
25     /// Generate foreign language bindings
26     Generate {
27         /// Foreign language(s) for which to build bindings.
28         #[clap(long, short, value_enum)]
29         language: Vec<TargetLanguage>,
30 
31         /// Directory in which to write generated files. Default is same folder as .udl file.
32         #[clap(long, short)]
33         out_dir: Option<Utf8PathBuf>,
34 
35         /// Do not try to format the generated bindings.
36         #[clap(long, short)]
37         no_format: bool,
38 
39         /// Path to optional uniffi config file. This config is merged with the `uniffi.toml` config present in each crate, with its values taking precedence.
40         #[clap(long, short)]
41         config: Option<Utf8PathBuf>,
42 
43         /// Extract proc-macro metadata from a native lib (cdylib or staticlib) for this crate.
44         #[clap(long)]
45         lib_file: Option<Utf8PathBuf>,
46 
47         /// Pass in a cdylib path rather than a UDL file
48         #[clap(long = "library")]
49         library_mode: bool,
50 
51         /// When `--library` is passed, only generate bindings for one crate.
52         /// When `--library` is not passed, use this as the crate name instead of attempting to
53         /// locate and parse Cargo.toml.
54         #[clap(long = "crate")]
55         crate_name: Option<String>,
56 
57         /// Path to the UDL file, or cdylib if `library-mode` is specified
58         source: Utf8PathBuf,
59     },
60 
61     /// Generate Rust scaffolding code
62     Scaffolding {
63         /// Directory in which to write generated files. Default is same folder as .udl file.
64         #[clap(long, short)]
65         out_dir: Option<Utf8PathBuf>,
66 
67         /// Do not try to format the generated bindings.
68         #[clap(long, short)]
69         no_format: bool,
70 
71         /// Path to the UDL file.
72         udl_file: Utf8PathBuf,
73     },
74 
75     /// Print a debug representation of the interface from a dynamic library
76     PrintRepr {
77         /// Path to the library file (.so, .dll, .dylib, or .a)
78         path: Utf8PathBuf,
79     },
80 }
81 
run_main() -> anyhow::Result<()>82 pub fn run_main() -> anyhow::Result<()> {
83     let cli = Cli::parse();
84     match cli.command {
85         Commands::Generate {
86             language,
87             out_dir,
88             no_format,
89             config,
90             lib_file,
91             source,
92             crate_name,
93             library_mode,
94         } => {
95             if library_mode {
96                 if lib_file.is_some() {
97                     panic!("--lib-file is not compatible with --library.")
98                 }
99                 let out_dir = out_dir.expect("--out-dir is required when using --library");
100                 if language.is_empty() {
101                     panic!("please specify at least one language with --language")
102                 }
103                 uniffi_bindgen::library_mode::generate_bindings(
104                     &source,
105                     crate_name,
106                     &BindingGeneratorDefault {
107                         target_languages: language,
108                         try_format_code: !no_format,
109                     },
110                     config.as_deref(),
111                     &out_dir,
112                     !no_format,
113                 )?;
114             } else {
115                 uniffi_bindgen::generate_bindings(
116                     &source,
117                     config.as_deref(),
118                     BindingGeneratorDefault {
119                         target_languages: language,
120                         try_format_code: !no_format,
121                     },
122                     out_dir.as_deref(),
123                     lib_file.as_deref(),
124                     crate_name.as_deref(),
125                     !no_format,
126                 )?;
127             }
128         }
129         Commands::Scaffolding {
130             out_dir,
131             no_format,
132             udl_file,
133         } => {
134             uniffi_bindgen::generate_component_scaffolding(
135                 &udl_file,
136                 out_dir.as_deref(),
137                 !no_format,
138             )?;
139         }
140         Commands::PrintRepr { path } => {
141             uniffi_bindgen::print_repr(&path)?;
142         }
143     };
144     Ok(())
145 }
146