cbindgen/bindgen/cargo/
cargo.rs1use std::path::{Path, PathBuf};
6
7use crate::bindgen::cargo::cargo_expand;
8use crate::bindgen::cargo::cargo_lock::{self, Lock};
9pub(crate) use crate::bindgen::cargo::cargo_metadata::PackageRef;
10use crate::bindgen::cargo::cargo_metadata::{self, Metadata};
11use crate::bindgen::cargo::cargo_toml;
12use crate::bindgen::config::Profile;
13use crate::bindgen::error::Error;
14use crate::bindgen::ir::Cfg;
15
16fn parse_dep_string(dep_string: &str) -> (&str, Option<&str>) {
18 let split: Vec<&str> = dep_string.split_whitespace().collect();
19
20 (split[0], split.get(1).cloned())
21}
22
23#[derive(Clone, Debug)]
25pub(crate) struct Cargo {
26 manifest_path: PathBuf,
27 binding_crate_name: String,
28 lock: Option<Lock>,
29 metadata: Metadata,
30 clean: bool,
31}
32
33impl Cargo {
34 pub(crate) fn load(
38 crate_dir: &Path,
39 lock_file: Option<&Path>,
40 binding_crate_name: Option<&str>,
41 use_cargo_lock: bool,
42 clean: bool,
43 only_target_dependencies: bool,
44 existing_metadata_file: Option<&Path>,
45 ) -> Result<Cargo, Error> {
46 let toml_path = crate_dir.join("Cargo.toml");
47 let metadata =
48 cargo_metadata::metadata(&toml_path, existing_metadata_file, only_target_dependencies)
49 .map_err(|x| Error::CargoMetadata(toml_path.to_str().unwrap().to_owned(), x))?;
50 let lock_path = lock_file
51 .map(PathBuf::from)
52 .unwrap_or_else(|| Path::new(&metadata.workspace_root).join("Cargo.lock"));
53
54 let lock = if use_cargo_lock {
55 match cargo_lock::lock(&lock_path) {
56 Ok(lock) => Some(lock),
57 Err(x) => {
58 warn!("Couldn't load lock file {lock_path:?}: {x:?}");
59 None
60 }
61 }
62 } else {
63 None
64 };
65
66 let binding_crate_name = match binding_crate_name {
68 Some(s) => s.to_owned(),
69 None => {
70 let manifest = cargo_toml::manifest(&toml_path)
71 .map_err(|x| Error::CargoToml(toml_path.to_str().unwrap().to_owned(), x))?;
72 manifest.package.name
73 }
74 };
75
76 Ok(Cargo {
77 manifest_path: toml_path,
78 binding_crate_name,
79 lock,
80 metadata,
81 clean,
82 })
83 }
84
85 pub(crate) fn binding_crate_name(&self) -> &str {
86 &self.binding_crate_name
87 }
88
89 pub(crate) fn binding_crate_ref(&self) -> PackageRef {
90 match self.find_pkg_to_generate_bindings_ref(&self.binding_crate_name) {
91 Some(pkg_ref) => pkg_ref,
92 None => panic!(
93 "Unable to find {} for {:?}",
94 self.binding_crate_name, self.manifest_path
95 ),
96 }
97 }
98
99 pub(crate) fn dependencies(&self, package: &PackageRef) -> Vec<(PackageRef, Option<Cfg>)> {
100 let lock = match self.lock {
101 Some(ref lock) => lock,
102 None => return vec![],
103 };
104
105 let mut dependencies = None;
106
107 if let Some(ref root) = lock.root {
109 if root.name == package.name
112 && package
113 .version
114 .as_ref()
115 .map_or(true, |v| *v == root.version)
116 {
117 dependencies = root.dependencies.as_ref();
118 }
119 }
120 if dependencies.is_none() {
121 if let Some(ref lock_packages) = lock.package {
122 for lock_package in lock_packages {
123 if lock_package.name == package.name
124 && package
125 .version
126 .as_ref()
127 .map_or(true, |v| *v == lock_package.version)
128 {
129 dependencies = lock_package.dependencies.as_ref();
130 break;
131 }
132 }
133 }
134 }
135 if dependencies.is_none() {
136 return vec![];
137 }
138
139 dependencies
140 .unwrap()
141 .iter()
142 .map(|dep| {
143 let (dep_name, dep_version) = parse_dep_string(dep);
144
145 let dep_version = dep_version.or_else(|| {
147 let mut versions = self.metadata.packages.iter().filter_map(|package| {
148 if package.name_and_version.name != dep_name {
149 return None;
150 }
151 package.name_and_version.version.as_deref()
152 });
153
154 let version = versions.next();
157 if versions.next().is_none() {
158 version
159 } else {
160 warn!("when looking for a version for package {dep_name}, multiple versions where found");
161 None
162 }
163 });
164
165 let cfg = self
167 .metadata
168 .packages
169 .get(package)
170 .and_then(|meta_package| meta_package.dependencies.get(dep_name))
171 .and_then(Cfg::load_metadata);
172
173 let package_ref = PackageRef {
174 name: dep_name.to_owned(),
175 version: dep_version.map(|v| v.to_owned()),
176 };
177
178 (package_ref, cfg)
179 })
180 .collect()
181 }
182
183 fn find_pkg_to_generate_bindings_ref(&self, package_name: &str) -> Option<PackageRef> {
187 let mut candidates = vec![];
190 for package in &self.metadata.packages {
191 if package.name_and_version.name == package_name {
192 if Path::new(package.manifest_path.as_str()) == self.manifest_path {
194 return Some(package.name_and_version.clone());
195 }
196 candidates.push(package.name_and_version.clone());
198 }
199 }
200
201 candidates.into_iter().next()
205 }
206
207 #[allow(unused)]
209 pub(crate) fn find_crate_dir(&self, package: &PackageRef) -> Option<PathBuf> {
210 self.metadata
211 .packages
212 .get(package)
213 .and_then(|meta_package| {
214 Path::new(&meta_package.manifest_path)
215 .parent()
216 .map(|x| x.to_owned())
217 })
218 }
219
220 pub(crate) fn find_crate_src(&self, package: &PackageRef) -> Option<PathBuf> {
222 let kind_lib = String::from("lib");
223 let kind_staticlib = String::from("staticlib");
224 let kind_rlib = String::from("rlib");
225 let kind_cdylib = String::from("cdylib");
226 let kind_dylib = String::from("dylib");
227
228 self.metadata
229 .packages
230 .get(package)
231 .and_then(|meta_package| {
232 for target in &meta_package.targets {
233 if target.kind.contains(&kind_lib)
234 || target.kind.contains(&kind_staticlib)
235 || target.kind.contains(&kind_rlib)
236 || target.kind.contains(&kind_cdylib)
237 || target.kind.contains(&kind_dylib)
238 {
239 return Some(PathBuf::from(&target.src_path));
240 }
241 }
242 None
243 })
244 }
245
246 pub(crate) fn expand_crate(
247 &self,
248 package: &PackageRef,
249 expand_all_features: bool,
250 expand_default_features: bool,
251 expand_features: &Option<Vec<String>>,
252 profile: Profile,
253 ) -> Result<String, cargo_expand::Error> {
254 cargo_expand::expand(
255 &self.manifest_path,
256 &package.name,
257 package.version.as_deref(),
258 self.clean,
259 expand_all_features,
260 expand_default_features,
261 expand_features,
262 profile,
263 )
264 }
265}