1use std::{
18 convert::TryFrom,
19 fmt,
20 fs,
21 fs::File,
22 io::Write,
23 path::Path,
24};
25
26use anyhow::Result;
27use clap::Args;
28use polkavm_linker::TARGET_JSON_64_BIT as POLKAVM_TARGET_JSON_64_BIT;
29use rustversion::{
30 before,
31 since,
32};
33
34use crate::CrateMetadata;
35
36const POLKAVM_TARGET_NAME: &str = "riscv64emac-unknown-none-polkavm";
38
39#[derive(Default, Clone, Copy, Debug, Args)]
40pub struct VerbosityFlags {
41 #[clap(long)]
43 quiet: bool,
44 #[clap(long)]
46 verbose: bool,
47}
48
49impl TryFrom<&VerbosityFlags> for Verbosity {
50 type Error = anyhow::Error;
51
52 fn try_from(value: &VerbosityFlags) -> Result<Self, Self::Error> {
53 match (value.quiet, value.verbose) {
54 (false, false) => Ok(Verbosity::Default),
55 (true, false) => Ok(Verbosity::Quiet),
56 (false, true) => Ok(Verbosity::Verbose),
57 (true, true) => anyhow::bail!("Cannot pass both --quiet and --verbose flags"),
58 }
59 }
60}
61
62#[derive(
64 Clone, Copy, Default, serde::Serialize, serde::Deserialize, Eq, PartialEq, Debug,
65)]
66pub enum Verbosity {
67 #[default]
69 Default,
70 Quiet,
72 Verbose,
74}
75
76impl Verbosity {
77 pub fn is_verbose(&self) -> bool {
79 match self {
80 Verbosity::Quiet => false,
81 Verbosity::Default | Verbosity::Verbose => true,
82 }
83 }
84}
85
86#[derive(Eq, PartialEq, Copy, Clone, Debug, Default, serde::Serialize)]
89pub enum Network {
90 #[default]
92 Online,
93 Offline,
95}
96
97impl Network {
98 pub fn append_to_args(&self, args: &mut Vec<String>) {
100 match self {
101 Self::Online => (),
102 Self::Offline => args.push("--offline".to_owned()),
103 }
104 }
105}
106
107#[derive(
109 Copy,
110 Clone,
111 Default,
112 Eq,
113 PartialEq,
114 Debug,
115 clap::ValueEnum,
116 serde::Serialize,
117 serde::Deserialize,
118)]
119#[clap(name = "build-artifacts")]
120pub enum BuildArtifacts {
121 #[clap(name = "all")]
124 #[default]
125 All,
126 #[clap(name = "code-only")]
129 CodeOnly,
130 #[clap(name = "check-only")]
133 CheckOnly,
134}
135
136impl BuildArtifacts {
137 pub fn steps(&self) -> usize {
140 match self {
141 BuildArtifacts::All => 5,
142 BuildArtifacts::CodeOnly => 4,
143 BuildArtifacts::CheckOnly => 1,
144 }
145 }
146}
147
148#[derive(Default, Copy, Clone)]
149pub struct Target;
150
151impl Target {
152 pub fn llvm_target(crate_metadata: &CrateMetadata) -> String {
154 #[since(1.91)]
160 fn target_spec() -> String {
161 POLKAVM_TARGET_JSON_64_BIT.to_string().replace(
162 r#"target-pointer-width": "64""#,
163 r#"target-pointer-width": 64"#,
164 )
165 }
166 #[before(1.91)]
167 fn target_spec() -> String {
168 POLKAVM_TARGET_JSON_64_BIT.to_string().replace(
169 r#"target-pointer-width": 64"#,
170 r#"target-pointer-width": "64""#,
171 )
172 }
173
174 let target_dir = crate_metadata.artifact_directory.to_string_lossy();
178 let path = format!("{target_dir}/{POLKAVM_TARGET_NAME}.json");
179 if !Path::exists(Path::new(&path)) {
180 fs::create_dir_all(&crate_metadata.artifact_directory).unwrap_or_else(|e| {
181 panic!("unable to create target dir {target_dir:?}: {e:?}")
182 });
183 let mut file = File::create(&path).unwrap();
184 file.write_all(target_spec().as_bytes()).unwrap();
185 }
186 path
187 }
188
189 pub fn llvm_target_alias() -> &'static str {
191 POLKAVM_TARGET_NAME
192 }
193
194 pub fn rustflags() -> Option<&'static str> {
196 Some("--cfg\x1fsubstrate_runtime")
199 }
200
201 pub fn source_extension() -> &'static str {
203 ""
204 }
205
206 pub fn dest_extension() -> &'static str {
208 "polkavm"
209 }
210}
211
212#[derive(
214 Eq, PartialEq, Copy, Clone, Debug, Default, serde::Serialize, serde::Deserialize,
215)]
216pub enum BuildMode {
217 #[default]
219 Debug,
220 Release,
222 Verifiable,
224}
225
226impl fmt::Display for BuildMode {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 match self {
229 Self::Debug => write!(f, "debug"),
230 Self::Release => write!(f, "release"),
231 Self::Verifiable => write!(f, "verifiable"),
232 }
233 }
234}
235
236#[derive(Clone, Debug, Default)]
238pub enum OutputType {
239 #[default]
241 HumanReadable,
242 Json,
244}
245
246#[derive(Default, Clone, Debug, Args)]
247pub struct UnstableOptions {
248 #[clap(long = "unstable-options", short = 'Z', number_of_values = 1)]
250 options: Vec<String>,
251}
252
253#[derive(Clone, Default)]
254pub struct UnstableFlags {
255 pub original_manifest: bool,
256}
257
258impl TryFrom<&UnstableOptions> for UnstableFlags {
259 type Error = anyhow::Error;
260
261 fn try_from(value: &UnstableOptions) -> Result<Self, Self::Error> {
262 let valid_flags = ["original-manifest"];
263 let invalid_flags = value
264 .options
265 .iter()
266 .filter(|o| !valid_flags.contains(&o.as_str()))
267 .collect::<Vec<_>>();
268 if !invalid_flags.is_empty() {
269 anyhow::bail!("Unknown unstable-options {invalid_flags:?}")
270 }
271 Ok(UnstableFlags {
272 original_manifest: value.options.contains(&"original-manifest".to_owned()),
273 })
274 }
275}
276
277#[derive(Default, Clone, Debug, Args)]
279pub struct Features {
280 #[clap(long, value_delimiter = ',')]
282 features: Vec<String>,
283}
284
285impl From<Vec<String>> for Features {
286 fn from(features: Vec<String>) -> Self {
287 Self { features }
288 }
289}
290
291impl Features {
292 pub fn push(&mut self, feature: String) {
294 self.features.push(feature)
295 }
296
297 pub fn append_to_args(&self, args: &mut Vec<String>) {
299 if !self.features.is_empty() {
300 args.push("--features".to_string());
301 let features = if self.features.len() == 1 {
302 self.features[0].clone()
303 } else {
304 self.features.join(",")
305 };
306 args.push(features);
307 }
308 }
309}
310
311#[derive(
313 Debug,
314 Default,
315 Clone,
316 Copy,
317 PartialEq,
318 Eq,
319 clap::ValueEnum,
320 serde::Serialize,
321 serde::Deserialize,
322)]
323#[serde(rename_all = "lowercase")]
324pub enum MetadataSpec {
325 #[clap(name = "ink")]
327 #[serde(rename = "ink!")]
328 #[default]
329 Ink,
330 #[clap(name = "solidity")]
332 Solidity,
333}
334
335impl fmt::Display for MetadataSpec {
336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337 match self {
338 Self::Ink => write!(f, "ink"),
339 Self::Solidity => write!(f, "solidity"),
340 }
341 }
342}