use std::{ path::{Path, PathBuf}, process::Command, env, ffi::{OsString, OsStr}, }; use build_helper::rustc::{link_search, link_lib}; fn get_vcvars_path_and_platform() -> (OsString, &'static str) { let vswhere_output = Command::new(r"build_tools\vswhere.exe") .args(&[ "-latest", "-legacy", "-property", "installationPath"]) .output() .expect("failed to execute vswhere.exe"); if !vswhere_output.status.success() { fail("vswhere failed to locate Microsoft Visual Studio"); } let visual_studio_path = { let vswhere_stdout = String::from_utf8(vswhere_output.stdout) .expect("vswhere output is not valid UTF-8"); String::from(vswhere_stdout.trim()) }; match build_helper::target::triple().arch() { "i686" => { let old_style_path = [&visual_studio_path, "VC", "bin", "vcvars32.bat"].iter().collect::(); if old_style_path.is_file() { return (old_style_path.into_os_string(), "Win32"); } let new_style_path = [&visual_studio_path, "VC", "Auxiliary", "Build", "vcvars32.bat"].iter().collect::(); if new_style_path.is_file() { return (new_style_path.into_os_string(), "Win32"); } panic!("failed to locate 'vcvars32.bat'"); }, "x86_64" => { let old_style_path = [&visual_studio_path, "VC", "bin", "x86_amd64", "vcvarsx86_amd64.bat"].iter().collect::(); if old_style_path.is_file() { return (old_style_path.into_os_string(), "x64"); } let new_style_path = [&visual_studio_path, "VC", "Auxiliary", "Build", "vcvarsx86_amd64.bat"].iter().collect::(); if new_style_path.is_file() { return (new_style_path.into_os_string(), "x64"); } panic!("failed to locate 'vcvarsx86_amd64.bat'"); }, arch => panic!("'{}' is not a valid architecture for MSVC builds", arch) } } fn main() { println!("cargo:rerun-if-changed=unicorn"); if !build_helper::windows() { if Command::new("pkg-config").output().is_ok() && pkg_config::Config::new().atleast_version("1.0.0").probe("unicorn").is_ok() { return; } } if !Path::new("unicorn/.git").exists() { let _ = Command::new("git") .args(&["submodule", "update", "--init", "--depth", "5"]) .status(); } let out_dir = env::var("OUT_DIR").unwrap(); let make_args = match os_type::current_platform().os_type { os_type::OSType::OSX => ["macos-universal-no"], _ => [""], }; if build_helper::target::triple().env().unwrap_or("").contains("msvc") { let build_cmd_path: PathBuf = [ env::current_dir().expect("failed to retrieve current directory").as_path(), Path::new("build_tools"), Path::new("msvc_build.bat")].iter().collect(); let platform_toolset = match env::var("PLATFORMTOOLSET") { Ok(x) => x, Err(_) => "".to_owned(), }; let (vcvars_path, platform) = get_vcvars_path_and_platform(); let status = match Command::new(build_cmd_path) .args(&[&vcvars_path, OsStr::new(&out_dir), OsStr::new(&platform_toolset), OsStr::new(platform)]) .current_dir("unicorn") .status() { Ok(status) => status, Err(e) => fail(&format!("failed to execute command: {}", e)), }; if !status.success() { fail(&format!("command did not execute successfully, got {}", status)); } link_search(Some(build_helper::SearchKind::Native), build_helper::out_dir()); link_lib(Some(build_helper::LibKind::Static), "unicorn_static"); } else { // TODO(sduquette): the package build should fail if this command fails. let _ = Command::new("./make.sh").args(&make_args).current_dir("unicorn").status(); let unicorn = "libunicorn.a"; let _ = Command::new("cp").current_dir("unicorn").arg(&unicorn).arg(&out_dir).status(); link_search(Some(build_helper::SearchKind::Native), build_helper::out_dir()); link_lib(Some(build_helper::LibKind::Static), "unicorn"); } } fn fail(s: &str) -> ! { panic!("\n{}\n\nbuild script failed, must exit now", s) }