use std::env;
use std::error::Error;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
fn get_bazel_library_version(library_name: &str) -> String {
let output: Output = Command::new("bazel")
.arg("mod")
.arg("explain")
.output()
.expect("Failed to execute 'bazel mod explain'");
let process_output: String = String::from_utf8_lossy(&output.stdout).to_string();
let library_token: String = library_name.to_owned() + "@";
let mut process_output_lines: std::str::Lines = process_output.lines();
let line_index: usize = process_output_lines
.position(|line| line.contains(&library_token))
.expect("Couldn't find the library");
let mut library_version: &str = process_output
.lines()
.nth(line_index)
.expect("Failed to retrieve the line from the process output.")
.split('@')
.next_back()
.expect("Failed to retrieve library version.")
.trim(); if library_version == "_" {
library_version = "override";
}
String::from(library_version)
}
fn resolve_bazel_package_path(
bazel_bin_dir: &Path,
subdir: &str,
crate_name: &str,
version: &str,
postfix_path: Option<&str>,
) -> PathBuf {
let base_path = bazel_bin_dir.join(subdir);
let try_path = |suffix: String| {
let mut path = base_path.join(suffix);
if let Some(postfix) = postfix_path {
path = path.join(postfix);
}
path
};
let plus_path = try_path(format!("{}+", crate_name));
if plus_path.exists() {
return plus_path;
}
let tilde_path = try_path(format!("{}~{}", crate_name, version));
if tilde_path.exists() {
return tilde_path;
}
let tilde_only_path = try_path(format!("{}~", crate_name));
if tilde_only_path.exists() {
return tilde_only_path;
}
panic!(
"Could not resolve Bazel path for `{}` using either '+', '~{}' or '{}~'",
crate_name, version, crate_name
);
}
fn main() -> Result<(), Box<dyn Error>> {
println!("cargo:rerun-if-changed=src/lib.rs");
println!("cargo:rerun-if-changed=.bazelrc");
println!("cargo:rerun-if-changed=BUILD.bazel");
println!("cargo:rerun-if-changed=MODULE.bazel");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let bazel_output_base_dir = out_dir.join("bazel_output_base");
fs::create_dir_all(&bazel_output_base_dir)?;
let malidrive_enabled = env::var("CARGO_FEATURE_MALIPUT_MALIDRIVE").is_ok();
let geopackage_enabled = env::var("CARGO_FEATURE_MALIPUT_GEOPACKAGE").is_ok();
let jobs = env::var("NUM_JOBS").unwrap().to_string();
let sdk_lib_name = match (malidrive_enabled, geopackage_enabled) {
(true, true) => "maliput_sdk",
(true, false) => "maliput_sdk_malidrive",
(false, true) => "maliput_sdk_geopackage",
(false, false) => {
panic!("At least one backend feature must be enabled (maliput_malidrive or maliput_geopackage)")
}
};
let sdk_target = format!("//:{}", sdk_lib_name);
let mut bazel_targets: Vec<&str> = vec![&sdk_target];
if malidrive_enabled {
bazel_targets.push("//:maliput_malidrive_dummy");
}
let mut bazel_cmd = Command::new("bazel");
bazel_cmd
.arg(format!("--output_base={}", bazel_output_base_dir.display()))
.arg("build")
.arg(format!(
"--symlink_prefix={}",
bazel_output_base_dir.join("bazel-").display()
))
.arg("--macos_minimum_os=10.15")
.arg(format!("--jobs={}", jobs));
for target in &bazel_targets {
bazel_cmd.arg(*target);
}
let code = bazel_cmd.status().expect("Failed to generate build script");
if code.code() != Some(0) {
panic!("Failed to generate build script");
}
let bazel_bin_dir = bazel_output_base_dir.join("bazel-bin");
let maliput_version = get_bazel_library_version("maliput");
println!("cargo:info=maliput version: <{}>", maliput_version);
let maliput_bin_path = resolve_bazel_package_path(&bazel_bin_dir, "external", "maliput", &maliput_version, None);
let maliput_malidrive_bin_path = if malidrive_enabled {
let maliput_malidrive_version = get_bazel_library_version("maliput_malidrive");
println!("cargo:info=maliput_malidrive version: <{}>", maliput_malidrive_version);
let path = resolve_bazel_package_path(
&bazel_bin_dir,
"external",
"maliput_malidrive",
&maliput_malidrive_version,
None,
);
println!("cargo:info=maliput_malidrive_bin_path: {:?}", path);
Some((path, maliput_malidrive_version))
} else {
None
};
let maliput_geopackage_bin_path = if geopackage_enabled {
let maliput_geopackage_version = get_bazel_library_version("maliput_geopackage");
println!(
"cargo:info=maliput_geopackage version: <{}>",
maliput_geopackage_version
);
let path = resolve_bazel_package_path(
&bazel_bin_dir,
"external",
"maliput_geopackage",
&maliput_geopackage_version,
None,
);
println!("cargo:info=maliput_geopackage_bin_path: {:?}", path);
Some(path)
} else {
None
};
let virtual_includes_path = maliput_bin_path.join("_virtual_includes");
println!("{:?}", virtual_includes_path);
let mut virtual_includes = Vec::new();
for entry in fs::read_dir(virtual_includes_path)? {
println!("{:?}", entry);
let entry = entry?;
let path = entry.path();
if path.is_dir() {
virtual_includes.push(path);
}
}
for (i, path) in virtual_includes.iter().enumerate() {
println!("cargo:CXXBRIDGE_DIR{}={}", i, path.display());
}
if let Some((ref malidrive_path, ref malidrive_version)) = maliput_malidrive_bin_path {
let lib_dir = if cfg!(target_os = "macos") {
"libmaliput_malidrive_dummy.dylib.runfiles"
} else if cfg!(target_os = "linux") {
"libmaliput_malidrive_dummy.so.runfiles"
} else {
"maliput_malidrive_dummy.dll.runfiles"
};
let maliput_malidrive_resource_path = resolve_bazel_package_path(
&bazel_bin_dir,
lib_dir,
"maliput_malidrive",
malidrive_version,
Some("resources"),
);
println!(
"cargo:rustc-env=MALIPUT_MALIDRIVE_BIN_PATH={}",
malidrive_path.display()
);
println!(
"cargo:rustc-env=MALIPUT_MALIDRIVE_PLUGIN_PATH={}",
malidrive_path.join("maliput_plugins").display()
);
println!(
"cargo:rustc-env=MALIPUT_MALIDRIVE_RESOURCE_PATH={}",
maliput_malidrive_resource_path.display()
);
println!("cargo:maliput_malidrive_bin_path={}", malidrive_path.display()); println!(
"cargo:maliput_malidrive_plugin_path={}",
malidrive_path.join("maliput_plugins").display()
); }
if let Some(ref geopackage_path) = maliput_geopackage_bin_path {
println!(
"cargo:rustc-env=MALIPUT_GEOPACKAGE_BIN_PATH={}",
geopackage_path.display()
);
println!(
"cargo:rustc-env=MALIPUT_GEOPACKAGE_PLUGIN_PATH={}",
geopackage_path.join("maliput_plugins").display()
);
println!("cargo:maliput_geopackage_bin_path={}", geopackage_path.display()); println!(
"cargo:maliput_geopackage_plugin_path={}",
geopackage_path.join("maliput_plugins").display()
); }
println!("cargo:rustc-env=MALIPUT_BIN_PATH={}", maliput_bin_path.display());
println!("cargo:root={}", out_dir.display()); println!("cargo:bin_path={}", bazel_bin_dir.display()); println!("cargo:maliput_bin_path={}", maliput_bin_path.display());
println!("cargo:sdk_lib_name={}", sdk_lib_name);
Ok(())
}