use std::env;
use std::path::PathBuf;
#[cfg(feature = "bundled")]
use std::path::Path;
#[cfg(feature = "bundled")]
use std::{fs, io};
#[cfg(feature = "bundled")]
fn vsomeip_includes() -> PathBuf {
let crate_root =
env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR environment variable is not set");
PathBuf::from(&crate_root).join("vsomeip").join("interface")
}
#[cfg(not(feature = "bundled"))]
fn vsomeip_includes() -> PathBuf {
let vsomeip_install_path = env::var("VSOMEIP_INSTALL_PATH")
.expect("You must supply the path to a vsomeip library install, e.g. /usr/local");
PathBuf::from(&vsomeip_install_path).join("include")
}
#[cfg(feature = "bundled")]
fn vsomeip_install_path() -> String {
let out_dir = env::var_os("OUT_DIR").unwrap();
let vsomeip_install_path_default = format!(
"{}",
PathBuf::from(out_dir)
.join("vsomeip")
.join("vsomeip-install")
.display()
);
env::var("VSOMEIP_INSTALL_PATH").unwrap_or(vsomeip_install_path_default)
}
#[cfg(feature = "bundled")]
fn vsomeip_lib_path() -> String {
let vsomeip_install_path = vsomeip_install_path();
let vsomeip_lib_path = PathBuf::from(&vsomeip_install_path).join("lib");
format!("{}", vsomeip_lib_path.display())
}
#[cfg(not(feature = "bundled"))]
fn vsomeip_lib_path() -> String {
let vsomeip_install_path = env::var("VSOMEIP_INSTALL_PATH")
.expect("You must supply the path to a vsomeip library install, e.g. /usr/local");
let vsomeip_lib_path = PathBuf::from(&vsomeip_install_path).join("lib");
format!("{}", vsomeip_lib_path.display())
}
fn main() -> miette::Result<()> {
#[cfg(feature = "bundled")]
build::build();
let vsomeip_interface_path = vsomeip_includes();
let out_dir = env::var_os("OUT_DIR").unwrap();
let generic_cpp_stdlib = env::var("GENERIC_CPP_STDLIB_PATH")
.expect("You must supply the path to generic C++ stdlib, e.g. /usr/include/c++/11");
let arch_specific_cpp_stdlib = env::var("ARCH_SPECIFIC_CPP_STDLIB_PATH").expect("You must supply the path to architecture-specific C++ stdlib, e.g. /usr/include/x86_64-linux-gnu/c++/11");
let project_root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let runtime_wrapper_dir = project_root.join("src/glue/include");
println!(
"debug: vsomeip_interface_path : {}",
vsomeip_interface_path.display()
);
println!("debug: generic_cpp_stdlib : {}", generic_cpp_stdlib);
println!(
"debug: arch_specific_cpp_stdlib : {}",
arch_specific_cpp_stdlib
);
bindings::generate_bindings(
&out_dir,
&vsomeip_interface_path,
&generic_cpp_stdlib,
&arch_specific_cpp_stdlib,
project_root,
&runtime_wrapper_dir,
)?;
Ok(())
}
#[cfg(feature = "bundled")]
mod build {
use cmake::Config;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use crate::copy_dir_all;
pub fn build() {
let crate_root = env::var("CARGO_MANIFEST_DIR")
.expect("CARGO_MANIFEST_DIR environment variable is not set");
let patch_folder = PathBuf::from(&crate_root).join("patches");
println!("debug: patch_folder: {}", patch_folder.display());
let submodule_folder = "vsomeip";
let submodule_git = PathBuf::from(&crate_root)
.join(submodule_folder)
.join(".git");
println!("debug: submodule_git: {:?}", submodule_git);
if !Path::new(&submodule_git).exists() {
let submodule_checkout = Command::new("git")
.arg("-C")
.arg(submodule_folder)
.arg("submodule")
.arg("update")
.arg("--init")
.status();
println!("debug: submodule_checkout: {:?}", submodule_checkout);
}
let out_dir = env::var_os("OUT_DIR").unwrap();
let submodule_to_patch = PathBuf::from(&crate_root).join(submodule_folder);
let vsomeip_build_dir = PathBuf::from(out_dir).join("vsomeip").join("vsomeip_build");
let copy_res = copy_dir_all(&submodule_to_patch, &vsomeip_build_dir);
println!(
"debug: copying vsomeip to output directory to build: {:?}",
copy_res
);
println!(
"debug: trying to apply patch to: {}",
vsomeip_build_dir.display()
);
let disable_test_patch = patch_folder.join("disable_tests.patch");
let disable_test_patch_str = format!("{}", disable_test_patch.display());
println!("disable_test_patch_str: {}", disable_test_patch_str);
let output = Command::new("patch")
.arg("-d")
.arg(&vsomeip_build_dir)
.arg("-p1")
.arg("-i")
.arg(disable_test_patch_str)
.output()
.expect("Failed to apply patch");
println!("debug: after trying to apply patch: {:?}", output);
let out_dir = env::var_os("OUT_DIR").unwrap();
let vsomeip_install_path_default = format!(
"{}",
PathBuf::from(out_dir)
.join("vsomeip")
.join("vsomeip-install")
.display()
);
let vsomeip_install_path =
env::var("VSOMEIP_INSTALL_PATH").unwrap_or(vsomeip_install_path_default);
println!("debug: vsomeip_project_root set");
println!(
"debug: vsomeip_project_root: {}",
vsomeip_build_dir.display()
);
println!("debug: vsomeip_install_path: {}", vsomeip_install_path);
let vsomeip_cmake_build = Config::new(vsomeip_build_dir)
.define("CMAKE_INSTALL_PREFIX", vsomeip_install_path.clone())
.define("ENABLE_SIGNAL_HANDLING", "1")
.build_target("install")
.build();
println!(
"debug: vsomeip_cmake_build: {}",
vsomeip_cmake_build.display()
);
}
}
mod bindings {
use std::ffi::OsString;
use std::fs::File;
use std::io::{BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};
use crate::vsomeip_lib_path;
use miette::IntoDiagnostic;
pub fn generate_bindings(
out_dir: &OsString,
vsomeip_interface_path: &PathBuf,
generic_cpp_stdlib: &String,
arch_specific_cpp_stdlib: &String,
project_root: PathBuf,
runtime_wrapper_dir: &PathBuf,
) -> miette::Result<()> {
let mut b = autocxx_build::Builder::new(
"src/lib.rs",
[&vsomeip_interface_path, &runtime_wrapper_dir],
)
.extra_clang_args(&[
format!("-I{}", generic_cpp_stdlib).as_str(),
format!("-I{}", arch_specific_cpp_stdlib).as_str(),
format!("-I{}", vsomeip_interface_path.display()).as_str(),
])
.build()?;
b.flag_if_supported("-std=c++17")
.flag_if_supported("-Wno-deprecated-declarations") .flag_if_supported("-Wno-unused-function") .compile("autocxx-portion");
println!("cargo:rerun-if-changed=src/lib.rs");
println!("cargo:rustc-link-lib=vsomeip3");
let vsomeip_lib_path = vsomeip_lib_path();
println!("cargo:rustc-link-search=native={}", vsomeip_lib_path);
let include_dir = project_root.join("src/glue");
cxx_build::bridge("src/cxx_bridge.rs")
.file("src/glue/application_registrations.cpp")
.file("src/glue/src/application_wrapper.cpp")
.include(&include_dir)
.include(vsomeip_interface_path)
.include(runtime_wrapper_dir)
.flag_if_supported("-Wno-deprecated-declarations") .flag_if_supported("-Wno-unused-function") .flag_if_supported("-std=c++17")
.extra_warnings(true)
.compile("cxx-portion");
println!("cargo:rerun-if-changed=src/cxx_bridge.rs");
let file_path = Path::new(&out_dir)
.join("autocxx-build-dir")
.join("rs")
.join("autocxx-ffi-default-gen.rs");
println!("debug: file_path : {}", file_path.display());
let input_file = File::open(&file_path).into_diagnostic()?;
let mut reader = BufReader::new(input_file);
let temp_file_path = file_path.with_extension("tmp");
let temp_file = File::create(&temp_file_path).into_diagnostic()?;
let mut writer = BufWriter::new(temp_file);
write!(writer, "# [allow (clippy::missing_safety_doc)] ").into_diagnostic()?;
write!(writer, "# [allow (rustdoc::broken_intra_doc_links)] ").into_diagnostic()?;
std::io::copy(&mut reader, &mut writer).into_diagnostic()?;
writer.flush().into_diagnostic()?;
std::fs::rename(temp_file_path, file_path).into_diagnostic()?;
println!("debug: rewrote the autocxx file");
Ok(())
}
}
#[cfg(feature = "bundled")]
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
fs::create_dir_all(&dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
} else {
fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
}
}
Ok(())
}