1use std::path::PathBuf;
2
3use anyhow::{Result, anyhow};
4use std::process::{Command, Stdio};
5
6#[derive(Default)]
7pub struct Builder {
8 pub name: String,
9 pub force_rebuild: bool,
10 pub env: Vec<(String, String)>,
11 pub features: Vec<String>,
12 pub target: Option<String>,
13 pub output_dir: Option<PathBuf>,
14 pub cargo_args: Vec<String>,
15 pub manifest_path: Option<PathBuf>,
16 pub user_crate_name: Option<String>,
18}
19impl Builder {
20 pub fn new(name: &str) -> Self {
21 Self {
22 name: name.to_string(),
23 ..Default::default()
24 }
25 }
26
27 pub fn env(mut self, key: &str, value: &str) -> Self {
28 self.env.push((key.to_string(), value.to_string()));
29 self
30 }
31
32 pub fn feature(mut self, feature: &str) -> Self {
33 self.features.push(feature.to_string());
34 self
35 }
36
37 pub fn cargo_args<T: AsRef<str>>(mut self, args: &[T]) -> Self {
38 self.cargo_args
39 .extend(args.iter().map(|s| s.as_ref().to_string()));
40 self
41 }
42
43 pub fn cargo_arg<T: AsRef<str>>(mut self, arg: T) -> Self {
44 self.cargo_args.push(arg.as_ref().to_string());
45 self
46 }
47
48 pub fn target(mut self, target: &str) -> Self {
49 self.target = Some(target.to_string());
50 self
51 }
52
53 pub fn build(self) -> Result<Output> {
54 let output_dir = self
55 .output_dir
56 .unwrap_or_else(|| PathBuf::from(std::env::var("OUT_DIR").unwrap()));
57
58 let target = self.target.unwrap_or_else(|| {
59 std::env::var("TARGET").expect("TARGET environment variable is not set")
60 });
61
62 BinCrate {
63 name: self.name,
64 force_rebuild: self.force_rebuild,
65 envs: self.env,
66 features: self.features,
67 target,
68 output_dir,
69 cargo_args: self.cargo_args,
70 manifest_path: self.manifest_path,
71 }
72 .run()
73 }
74}
75
76#[derive(Default)]
77pub struct BinCrate {
78 pub name: String,
79 pub force_rebuild: bool,
80 pub envs: Vec<(String, String)>,
81 pub features: Vec<String>,
82 pub target: String,
83 pub output_dir: PathBuf,
84 cargo_args: Vec<String>,
85 manifest_path: Option<PathBuf>,
86}
87
88impl BinCrate {
89 pub fn run(&mut self) -> Result<Output> {
90 let manifest_path = self
91 .manifest_path
92 .clone()
93 .unwrap_or_else(|| std::env::var("CARGO_MANIFEST_PATH").unwrap().into());
94
95 let mut cargo_metadata = cargo_metadata::MetadataCommand::new();
96
97 let metadata = cargo_metadata.manifest_path(&manifest_path).exec()?;
98
99 let package = metadata
100 .packages
101 .iter()
102 .find(|p| p.name.eq_ignore_ascii_case(&self.name))
103 .ok_or_else(|| anyhow!("Cannot find package {}, is it has lib.rs?", &self.name))?;
104
105 println!("mf: {}", package.manifest_path);
106 let mf_path = package.manifest_path.as_str();
107 if mf_path.contains(".cargo/registry") || mf_path.contains(".cargo\\registry") {
108 println!("is online");
109 } else {
110 println!("is local");
111 println!(
112 "cargo:rerun-if-changed={}",
113 package.manifest_path.parent().unwrap()
114 );
115 }
116
117 self.manifest_path = Some(package.manifest_path.as_os_str().into());
118
119 self.build_crate()?;
120 let out_dir = self.output_dir.join("bin");
121 Ok(Output {
122 dir: out_dir.clone(),
123 elf: out_dir.join(&self.name),
124 })
125 }
126
127 fn build_crate(&self) -> Result<()> {
129 let manifest = self.manifest_path.as_ref().unwrap().clone();
130 println!("开始编译...");
131
132 let mut cargo = Command::new("cargo");
133
134 cargo
135 .arg("install")
136 .arg(&self.name)
137 .args(["--locked", "-Z", "unstable-options", "--target"])
138 .arg(&self.target)
139 .arg("--root")
140 .arg(&self.output_dir)
141 .arg("--path")
142 .arg(manifest.parent().unwrap())
143 .env_remove("RUSTFLAGS")
144 .env_remove("CARGO_ENCODED_RUSTFLAGS")
145 .env_remove("RUSTC_WORKSPACE_WRAPPER") .stdout(Stdio::inherit()) .stderr(Stdio::inherit()); for (key, value) in self.envs.iter() {
150 cargo.env(key, value);
151 }
152 for f in self.features.iter() {
153 cargo.arg("--features").arg(f);
154 }
155
156 for a in self.cargo_args.iter() {
157 cargo.arg(a);
158 }
159
160 println!("cmd: {cargo:?}");
161
162 let status = cargo.status()?;
164
165 if !status.success() {
166 anyhow::bail!("编译失败: {}", status);
167 }
168
169 Ok(())
170 }
171}
172
173#[derive(Debug, Clone)]
174pub struct Output {
175 pub dir: PathBuf,
176 pub elf: PathBuf,
177}