Skip to content

Commit 78f46ae

Browse files
thunderseethecopybara-github
authored andcommitted
Construct a crate to produce the staticlib in the subcommand.
This solves the issue of how does generated Rust code for bindings depend on `bridge.rs`. We create a Cargo.toml package for the generated rust code and use that to produce a staticlib. The Cargo.toml can then depend on `bridge.rs`. We're okay with this dependency being implicit like this because we want the subcommand to control which version of bridge.rs is used (and we only want to change versions when subcommand versions are changed). PiperOrigin-RevId: 901485778
1 parent 2b6e50b commit 78f46ae

File tree

1 file changed

+76
-14
lines changed

1 file changed

+76
-14
lines changed

cc_bindings_from_rs/cargo-cpp_api_from_rust.rs

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ fn main() -> Result<()> {
193193
pkg_to_header.insert(pkg_id.repr, intermediate_h.to_string());
194194
lib_rs_content
195195
.push_str(&format!("#[path = {:?}]\nmod r#{};\n", intermediate_rs, rs_crate_name));
196-
// Final outputs: copy/rename from deps/ to their final locations.
197196
if !final_h.exists() {
198197
fs::copy(&intermediate_h, &final_h)?;
199198
}
@@ -254,21 +253,84 @@ fn main() -> Result<()> {
254253
fs::write(&lib_rs_path, lib_rs_content)?;
255254

256255
let static_lib_path = target_dir.join(&profile_dir).join(format!("lib{}.a", root_name));
257-
let mut final_rustc_args = vec![
258-
"rustc".to_string(),
259-
lib_rs_path.to_string(),
260-
format!("--edition={}", edition),
261-
format!("--crate-name={}_cc_api", root_name),
262-
"--crate-type=staticlib".to_string(),
263-
format!("-Ldependency={}", deps_dir.as_str()),
264-
"-o".to_string(),
265-
static_lib_path.to_string(),
266-
];
267-
for (_, artifact_info) in pkg_to_artifact.iter() {
268-
final_rustc_args.push(format!("--extern={}={}", artifact_info.name, artifact_info.path));
256+
let mut cargo_toml_content = format!(
257+
r#"[package]
258+
name = "{root_name}-cc-api"
259+
version = "0.1.0"
260+
edition = "{edition}"
261+
262+
[lib]
263+
path = "{lib_rs_filename}"
264+
crate-type = ["staticlib"]
265+
266+
[dependencies]
267+
crubit_bridge_rust = "0.0.1"
268+
"#,
269+
root_name = root_name,
270+
edition = edition,
271+
lib_rs_filename = lib_rs_path.file_name().unwrap(),
272+
);
273+
274+
let pkg_id_to_package: HashMap<_, _> =
275+
metadata.packages.iter().map(|p| (p.id.clone(), p)).collect();
276+
let root_node = resolve
277+
.nodes
278+
.iter()
279+
.find(|n| n.id == root.id)
280+
.expect("Root package must be in resolve graph");
281+
282+
for dep in &root_node.dependencies {
283+
let pkg = pkg_id_to_package.get(dep).expect("Dependency must be in package list");
284+
if let Some(source) = &pkg.source {
285+
if source.is_crates_io() {
286+
cargo_toml_content.push_str(&format!("{} = \"{}\"\n", pkg.name, pkg.version));
287+
} else {
288+
// If it's not crates.io, we may need a more complex way to resolve it.
289+
// For now, we'll try to use the path if it's available.
290+
cargo_toml_content.push_str(&format!(
291+
"{} = {{ path = {:?} }}\n",
292+
pkg.name,
293+
pkg.manifest_path.parent().unwrap()
294+
));
295+
}
296+
} else {
297+
// No source means it's a local/path dependency.
298+
// We need to find the relative path from deps_dir to the package's directory.
299+
let pkg_dir = pkg.manifest_path.parent().unwrap();
300+
cargo_toml_content.push_str(&format!("{} = {{ path = {:?} }}\n", pkg.name, pkg_dir));
301+
}
269302
}
270303

271-
cpp_api_from_rust_lib::run_rustc(&final_rustc_args);
304+
let cargo_toml_path = deps_dir.join("Cargo.toml");
305+
fs::write(&cargo_toml_path, cargo_toml_content)?;
306+
307+
let mut cargo_build = Command::new(cargo_bin());
308+
cargo_build.args([
309+
"build",
310+
"--manifest-path",
311+
cargo_toml_path.as_str(),
312+
format!("--target-dir={}", target_dir).as_str(),
313+
]);
314+
315+
let profile = if profile_dir.as_str() == "release" { "--release" } else { "--debug" };
316+
if profile == "--release" {
317+
cargo_build.arg("--release");
318+
}
319+
320+
let status =
321+
cargo_build.status().map_err(|err| anyhow!("Failed to run cargo build: {}", err))?;
322+
if !status.success() {
323+
bail!("Cargo build of bindings failed");
324+
}
325+
326+
// Cargo will output to target_dir/profile/staticlibname.a
327+
// The previous implementation expected it at lib{root_name}.a directly under the profile dir.
328+
let cargo_static_lib_path =
329+
target_dir.join(&profile_dir).join(format!("lib{}_cc_api.a", root_name.replace('-', "_")));
330+
331+
if cargo_static_lib_path.exists() {
332+
fs::copy(&cargo_static_lib_path, &static_lib_path)?;
333+
}
272334

273335
Ok(())
274336
}

0 commit comments

Comments
 (0)