use bindgen::callbacks::TypeKind;
use bindgen::callbacks::{ParseCallbacks, DeriveInfo};
use std::path::PathBuf;
use std::env;
use std::fs;
#[derive(Debug)]
struct CloneCallback;
impl ParseCallbacks for CloneCallback {
fn add_derives(&self, info: &DeriveInfo) -> Vec<String> {
let mut data = vec!["Clone".into()];
if info.name.starts_with("mjui") || info.name == "mjrRect_" {
data.push("Copy".into());
}
if info.kind == TypeKind::Enum {
data.push("TryFromPrimitive".into());
}
data
}
}
fn main() {
const MUJOCO_STATIC_LIB_PATH_VAR: &str = "MUJOCO_STATIC_LINK_LIB";
const MUJOCO_DYN_LIB_PATH_VAR: &str = "MUJOCO_DYNAMIC_LINK_LIB";
const GENERATE_FFI: &str = "GENERATE_FFI";
println!("cargo:rerun-if-env-changed={MUJOCO_STATIC_LIB_PATH_VAR}");
println!("cargo:rerun-if-env-changed={MUJOCO_DYN_LIB_PATH_VAR}");
println!("cargo:rerun-if-env-changed={GENERATE_FFI}");
let mujoco_lib_path= env::var(MUJOCO_STATIC_LIB_PATH_VAR);
if let Ok(path) = mujoco_lib_path {
let mj_lib_pathbuf = PathBuf::from(path);
let mj_lib_simulate_path = mj_lib_pathbuf.join("libsimulate.a");
println!("cargo::rerun-if-changed={}", mj_lib_simulate_path.canonicalize().unwrap().display());
println!("cargo:rustc-link-search={}", mj_lib_pathbuf.canonicalize().unwrap().display());
#[cfg(feature = "cpp-viewer")]
println!("cargo:rustc-link-lib=simulate");
println!("cargo:rustc-link-lib=mujoco");
println!("cargo:rustc-link-lib=lodepng");
println!("cargo:rustc-link-lib=tinyxml2");
println!("cargo:rustc-link-lib=qhullstatic_r");
println!("cargo:rustc-link-lib=ccd");
if cfg!(unix) {
println!("cargo:rustc-link-lib=stdc++");
}
}
else {
let mujoco_dylib_path = PathBuf::from(env::var(MUJOCO_DYN_LIB_PATH_VAR)
.unwrap_or_else(|_| panic!("nor the static library path ({MUJOCO_STATIC_LIB_PATH_VAR}),\
nor the dynamic library path ({MUJOCO_DYN_LIB_PATH_VAR}) was given.")));
println!("cargo:rustc-link-search={}", mujoco_dylib_path.canonicalize().unwrap().display());
println!("cargo:rustc-link-lib=mujoco");
}
if let Ok(value) = env::var(GENERATE_FFI) {
if value == "y" || value == "1" {
let output_path = PathBuf::from("./src/");
let current_dir = env::current_dir().unwrap();
let include_dir_mujoco = current_dir.join("src/cpp/include/mujoco");
let include_dir_simulate = include_dir_mujoco.join("viewer");
let bindings_mujoco = bindgen::Builder::default()
.header(include_dir_mujoco.join("mujoco.h").to_str().unwrap())
.header(include_dir_simulate.join("simulate.hpp").to_str().unwrap())
.header(include_dir_simulate.join("glfw_dispatch.hpp").to_str().unwrap())
.clang_arg("-std=c++20")
.clang_arg("-stdlib=libc++")
.clang_arg(format!("-I{}", current_dir.join("mujoco/build/_deps/glfw3-src/include/").display()))
.blocklist_item("std::tuple.*")
.allowlist_item("mj.*")
.allowlist_item("mujoco::.*")
.allowlist_item("new_simulate")
.allowlist_item("free_simulate")
.layout_tests(false)
.derive_default(false)
.opaque_type("std::.*")
.derive_copy(false)
.rustified_enum(".*")
.parse_callbacks(Box::new(CloneCallback))
.generate()
.expect("unable to generate MuJoCo bindings");
let outputfile_dir = output_path.join("mujoco_c.rs");
let mut fdata = bindings_mujoco
.to_string();
fdata = fdata.replace("pub __lx: std_basic_string_value_type<_CharT>,", "pub __lx: std::mem::ManuallyDrop<std_basic_string_value_type<_CharT>>,");
let re = regex::Regex::new(r"#\[derive\((.*?Clone.*?), Clone, (.*?)\)\]").unwrap();
fdata = re.replace_all(&fdata, "#[derive($1, $2)]").to_string();
fdata = "use num_enum::TryFromPrimitive;\n\n".to_string() + &fdata;
fs::write(outputfile_dir, fdata).unwrap();
}
}
}