use std::path::{Path, PathBuf}; use std::{fs, io}; #[cfg(any(feature = "static_gperftools", feature = "static_unwind"))] use std::process::Command; #[cfg(any(feature = "static_gperftools", feature = "static_unwind"))] fn is_directory_empty>(p: P) -> std::io::Result { let mut entries = fs::read_dir(p)?; Ok(entries.next().is_none()) } #[cfg(any(feature = "static_gperftools", feature = "static_unwind"))] fn check() { let libs = vec!["third_party/gperftools", "third_party/libunwind-0.99"]; for lib in libs { if is_directory_empty(lib).unwrap_or(true) { panic!( "Can't find library {}. You need to run `git submodule \ update --init --recursive` and `./download.sh` first to build the project.", lib ); } } } #[cfg(feature = "static_gperftools")] fn build_gperftools( source_root: &PathBuf, libunwind_path: Option, ) -> std::io::Result { check(); let target_gperftool_source_dir = { let mut source_root = source_root.clone(); source_root.push("gperftools"); source_root }; let mut autogen = Command::new("./autogen.sh") .current_dir(&target_gperftool_source_dir) .spawn()?; autogen.wait()?; let mut configure_args = vec![ "--disable-heap-profiler", "--disable-heap-checker", "--disable-debugalloc", "--disable-shared", "CFLAGS=-fPIC", "CXXFLAGS=-fPIC", ]; let link_args; let include_args; if cfg!(feature = "static_unwind") { let libunwind_path = libunwind_path.unwrap(); link_args = format!("LDFLAGS=-L{}/src/.libs", libunwind_path.display()); include_args = format!("CPPFLAGS=-I{}/include", libunwind_path.display()); configure_args.push(&link_args); configure_args.push(&include_args); } let mut configure = Command::new("./configure") .args(&configure_args) .current_dir(&target_gperftool_source_dir) .spawn()?; configure.wait()?; let cpu_num = num_cpus::get(); let mut make = Command::new("make") .args(&[format!("-j{}", cpu_num), "--keep-going".to_owned()]) .current_dir(&target_gperftool_source_dir) .spawn()?; make.wait()?; Ok(target_gperftool_source_dir) } #[cfg(not(feature = "static_gperftools"))] fn build_gperftools(_: &PathBuf, _: Option) -> std::io::Result { unreachable!(); } #[cfg(feature = "static_unwind")] fn build_unwind(source_root: &PathBuf) -> std::io::Result { check(); let target_unwind_source_dir = { let mut source_root = source_root.clone(); source_root.push("libunwind-0.99"); source_root }; let mut configure = Command::new("./configure") .args(&[ "--disable-shared", "--disable-minidebuginfo", "--disable-zlibdebuginfo", "CFLAGS=-fPIC", "CXXFLAGS=-fPIC", ]) .current_dir(&target_unwind_source_dir) .spawn()?; configure.wait()?; let cpu_num = num_cpus::get(); let mut make = Command::new("make") .args(&[ &format!("-j{}", cpu_num), "--keep-going", "CFLAGS=-U_FORTIFY_SOURCE", ]) .current_dir(&target_unwind_source_dir) .spawn()?; make.wait()?; Ok(target_unwind_source_dir) } #[cfg(not(feature = "static_unwind"))] fn build_unwind(_: &PathBuf) -> std::io::Result { unreachable!(); } fn copy_source_files() -> std::io::Result { let mut copy_options = fs_extra::dir::CopyOptions::new(); copy_options.overwrite = true; copy_options.copy_inside = true; let third_party_source_dir = { let mut current = std::env::current_dir()?; current.push("third_party"); current }; let target_third_party_source_dir: PathBuf = { let out_dir: String = std::env::var("OUT_DIR").unwrap(); PathBuf::from(out_dir) }; match fs_extra::dir::copy( &third_party_source_dir, &target_third_party_source_dir, ©_options, ) { Ok(_) => { let mut target = target_third_party_source_dir.clone(); target.push("third_party"); Ok(target) } Err(err) => Err(io::Error::new(io::ErrorKind::Other, err)), } } fn main() -> std::io::Result<()> { let source_root = copy_source_files()?; let unwind = if cfg!(feature = "static_unwind") { let unwind = build_unwind(&source_root)?; println!("cargo:rustc-link-lib=static=unwind"); println!( "cargo:rustc-link-search=native={}/src/.libs", unwind.display() ); Some(unwind) } else { None }; if cfg!(feature = "static_gperftools") { let gperftools = build_gperftools(&source_root, unwind)?; println!("cargo:rustc-link-lib=dylib=stdc++"); println!("cargo:rustc-link-lib=static=profiler"); println!( "cargo:rustc-link-search=native={}/.libs", gperftools.display() ); } Ok(()) }