#![allow(dead_code)]
#![allow(unused)]
use cmake::Config;
use std::process::Command;
use std::{
env,
path::{Path, PathBuf},
};
const PD_EXTRA: &str = "true";
const PD_LOCALE: &str = "false";
const PD_UTILS: &str = "true";
const PD_FLOATSIZE: &str = "64";
fn main() {
let project_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let libpd_dir = project_dir.join("libpd");
let libpd_wrapper_dir = libpd_dir.join("libpd_wrapper");
transform_pd_headers(&libpd_wrapper_dir);
let pd_multi = "false";
let pd_multi_flag = false;
let target_info = get_target_info();
#[cfg(target_os = "windows")]
{
let pthread_root = project_dir.join("pthreads");
let (pthread_lib_root, pthread_lib_path, pthread_lib_name, pthread_include): (
PathBuf,
PathBuf,
&str,
PathBuf,
) = match &*target_info.arch {
"x86_64" => match &*(target_info.compiler.unwrap()) {
"msvc" => {
let lib_root = pthread_root
.join("msvc")
.join("pthreads_x64-windows-static")
.join("lib");
(
lib_root.clone(),
lib_root.join("pthreadVC3.lib"),
"pthreadVC3",
pthread_root
.join("msvc")
.join("pthreads_x64-windows-static")
.join("include"),
)
}
"gnu" => {
let lib_root = pthread_root.join("gnu/x64/lib");
(
lib_root.clone(),
lib_root.join("libpthreadGC2.a"),
"pthreadGC2",
pthread_root.join("gnu").join("include"),
)
}
_ => panic!("Unsupported compiler"),
},
"aarch64" => match &*(target_info.compiler.unwrap()) {
"msvc" => {
let lib_root = pthread_root
.join("msvc")
.join("pthreads_arm64-windows-static")
.join("lib");
(
lib_root.clone(),
lib_root.join("pthreadVC3.lib"),
"pthreadVC3",
pthread_root
.join("msvc")
.join("pthreads_arm64-windows-static")
.join("include"),
)
}
"gnu" => {
let lib_root = pthread_root.join("gnu/aarch64/lib");
(
lib_root.clone(),
lib_root.join("libpthreadGC2.a"),
"pthreadGC2",
pthread_root.join("gnu").join("include"),
)
}
_ => panic!("Unsupported compiler"),
},
_ => panic!("Unsupported architecture: {}", target_info.arch),
};
let lib_destination = Config::new("libpd")
.define("PD_EXTRA", PD_EXTRA)
.define("PD_LOCALE", PD_LOCALE)
.define("PD_MULTI", pd_multi)
.define("PD_UTILS", PD_UTILS)
.cflag(format!("-DPD_FLOATSIZE={PD_FLOATSIZE}"))
.define("CMAKE_THREAD_LIBS_INIT", pthread_lib_path.to_str().unwrap())
.define("PTHREADS_INCLUDE_DIR", pthread_include.to_str().unwrap())
.no_build_target(true)
.always_configure(true)
.very_verbose(true)
.build();
let library_root = lib_destination.join("build/libs");
println!(
"cargo:rustc-link-search={}",
pthread_lib_root.to_string_lossy()
);
println!("cargo:rustc-link-search={}", library_root.to_string_lossy());
println!("cargo:rustc-link-lib=static={}", pthread_lib_name);
if !pd_multi_flag {
println!("cargo:rustc-link-lib=static=libpd-static");
} else {
println!("cargo:rustc-link-lib=static=libpd-multi-static");
}
}
#[cfg(target_os = "linux")]
{
let lib_destination = Config::new("libpd")
.define("PD_EXTRA", PD_EXTRA)
.define("PD_LOCALE", PD_LOCALE)
.define("PD_MULTI", pd_multi)
.define("PD_UTILS", PD_UTILS)
.cflag(format!("-DPD_FLOATSIZE={PD_FLOATSIZE}"))
.no_build_target(true)
.always_configure(true)
.very_verbose(true)
.build();
let library_root = lib_destination.join("build/libs");
println!("cargo:rustc-link-search={}", library_root.to_string_lossy());
if !pd_multi_flag {
println!("cargo:rustc-link-lib=static=pd");
} else {
println!("cargo:rustc-link-lib=static=pd-multi");
}
}
#[cfg(target_os = "macos")]
{
let lib_destination = Config::new("libpd")
.define("PD_EXTRA", PD_EXTRA)
.define("PD_LOCALE", PD_LOCALE)
.define("PD_MULTI", pd_multi)
.define("PD_UTILS", PD_UTILS)
.cflag(format!("-DPD_FLOATSIZE={PD_FLOATSIZE}"))
.define("CMAKE_OSX_ARCHITECTURES", "x86_64;arm64")
.no_build_target(true)
.always_configure(true)
.very_verbose(true)
.build();
let library_root = lib_destination.join("build/libs");
println!("cargo:rustc-link-search={}", library_root.to_string_lossy());
if !pd_multi_flag {
thin_fat_lib(&library_root, false);
match &*target_info.arch {
"x86_64" => println!("cargo:rustc-link-lib=static=pd-x86_64"),
"aarch64" => println!("cargo:rustc-link-lib=static=pd-aarch64"),
_ => panic!("Unsupported architecture"),
}
} else {
thin_fat_lib(&library_root, true);
match &*target_info.arch {
"x86_64" => println!("cargo:rustc-link-lib=static=pd-multi-x86_64"),
"aarch64" => println!("cargo:rustc-link-lib=static=pd-multi-aarch64"),
_ => panic!("Unsupported architecture"),
}
}
}
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.rustfmt_bindings(true)
.clang_arg(format!("-DPD_FLOATSIZE={PD_FLOATSIZE}"))
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
#[allow(dead_code)]
#[derive(Debug)]
struct TargetInfo {
arch: String,
vendor: String,
os: String,
compiler: Option<String>,
}
impl From<Vec<&str>> for TargetInfo {
fn from(info: Vec<&str>) -> Self {
TargetInfo {
arch: info[0].to_string(),
vendor: info[1].to_string(),
os: info[2].to_string(),
compiler: info
.get(3)
.map_or_else(|| None, |value| Some(value.to_owned().to_owned())),
}
}
}
fn get_target_info() -> TargetInfo {
let info = std::env::var("TARGET").unwrap();
let info: Vec<&str> = info.split('-').collect();
TargetInfo::from(info)
}
fn thin_fat_lib<T: AsRef<Path>>(library_root: T, pd_multi: bool) {
let mut name = String::from("libpd");
if pd_multi {
name = format!("{}-multi", name);
}
let root: &str = library_root.as_ref().to_str().unwrap();
Command::new("lipo")
.arg(format!("{root}/{name}.a"))
.arg("-thin")
.arg("arm64")
.arg("-output")
.arg(format!("{root}/{name}-aarch64.a"))
.spawn()
.expect("lipo command failed to start");
Command::new("lipo")
.arg(format!("{root}/{name}.a"))
.arg("-thin")
.arg("x86_64")
.arg("-output")
.arg(format!("{root}/{name}-x86_64.a"))
.spawn()
.expect("lipo command failed to start");
}
fn transform_pd_headers(base: &Path) {
let libpd_wrapper_util_dir = base.join("util");
let z_print_util_h = libpd_wrapper_util_dir.join("z_print_util.h");
let z_queued_h = libpd_wrapper_util_dir.join("z_queued.h");
let x_libpdreceive_h = base.join("x_libpdreceive.h");
let z_libpd_h = base.join("z_libpd.h");
let data = std::fs::read_to_string(&z_libpd_h).expect("Unable to read file");
let data = data.replace(
"#include \"m_pd.h\"",
"#include \"../pure-data/src/m_pd.h\"",
);
std::fs::write(&z_libpd_h, data).expect("Unable to write file");
let data = std::fs::read_to_string(&x_libpdreceive_h).expect("Unable to read file");
let data = data.replace(
"#include \"m_pd.h\"",
"#include \"../pure-data/src/m_pd.h\"",
);
std::fs::write(&x_libpdreceive_h, data).expect("Unable to write file");
let data = std::fs::read_to_string(&z_queued_h).expect("Unable to read file");
let data = data.replace("#include \"z_libpd.h\"", "#include \"../z_libpd.h\"");
std::fs::write(&z_queued_h, data).expect("Unable to write file");
let data = std::fs::read_to_string(&z_print_util_h).expect("Unable to read file");
let data = data.replace("#include \"z_libpd.h\"", "#include \"../z_libpd.h\"");
std::fs::write(&z_print_util_h, data).expect("Unable to write file");
}