diff --git a/Cargo.toml b/Cargo.toml index 2b5c4ab..10998c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,9 @@ [package] name = "rustc-llvm-proxy" -version = "0.1.11" +version = "0.2.0" authors = ["Denys Zariaiev "] license = "MIT" +edition = "2018" readme = "README.md" description = "Dynamically proxy LLVM calls into Rust own shared library" diff --git a/README.md b/README.md index 66cefe0..63c94df 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Then all you need to do is to include the crate into your project: ``` toml [dependencies] -rustc-llvm-proxy = "0.1" +rustc-llvm-proxy = "0.2" ``` ``` rust diff --git a/appveyor.yml b/appveyor.yml index c9fdc89..701fe59 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,6 +4,8 @@ environment: matrix: - TARGET: x86_64-pc-windows-gnu - TARGET: i686-pc-windows-gnu + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc install: - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe diff --git a/src/path.rs b/src/path.rs index 1ce352d..34f660a 100644 --- a/src/path.rs +++ b/src/path.rs @@ -1,33 +1,26 @@ use std::env; +use std::fs::read_dir; use std::path::{Path, PathBuf}; use std::process::Command; use failure::Error; pub fn find_lib_path() -> Result { - let paths = collect_possible_paths()?; + let directories = collect_possible_directories(); - if paths.is_empty() { + if directories.is_empty() { bail!("Unable to find possible LLVM shared lib locations."); } - for path in &paths { - if path.join("librustc_codegen_llvm-llvm.so").exists() { - return Ok(path.join("librustc_codegen_llvm-llvm.so")); - } - - if path.join("librustc_codegen_llvm-llvm.dylib").exists() { - return Ok(path.join("librustc_codegen_llvm-llvm.dylib")); - } - - if path.join("rustc_codegen_llvm-llvm.dll").exists() { - return Ok(path.join("rustc_codegen_llvm-llvm.dll")); + for directory in &directories { + if let Some(library) = find_library_in_directory(&directory) { + return Ok(library); } } bail!( "Unable to find LLVM shared lib in possible locations:\n- {}", - paths + directories .into_iter() .map(|item| item.to_str().unwrap().to_owned()) .collect::>() @@ -35,148 +28,42 @@ pub fn find_lib_path() -> Result { ); } -fn collect_possible_paths() -> Result, Error> { +fn collect_possible_directories() -> Vec { let mut paths = vec![]; - - // Special case: find the location for Rust built from sources. - if let Ok(env_path) = env::var("PATH") { - for item in env_path.split(':') { - let mut rustc_path = PathBuf::from(item); - - rustc_path.pop(); - paths.push(rustc_path.join("codegen-backends")); - } - } - - if let Ok(rustup_home) = env::var("RUSTUP_HOME") { - let rustup_home = PathBuf::from(rustup_home); - let rustup_toolchain = env::var("RUSTUP_TOOLCHAIN")?; - let rustup_arch = extract_arch(&rustup_toolchain); - - paths.push( - rustup_home - .join("toolchains") - .join(&rustup_toolchain) - .join("lib") - .join("rustlib") - .join(rustup_arch) - .join("codegen-backends"), - ); - } + let separator = if cfg!(windows) { ';' } else { ':' }; if let Ok(lib_paths) = env::var("LD_LIBRARY_PATH") { - for item in lib_paths.split(':') { - let mut possible_path = PathBuf::from(item); - possible_path.pop(); - - if let Some(possible_toolchain) = possible_path.file_name() { - let possible_arch = extract_arch(possible_toolchain.to_str().unwrap()); - - paths.push( - possible_path - .join("lib") - .join("rustlib") - .join(possible_arch) - .join("codegen-backends"), - ); - } + for item in lib_paths.split(separator) { + paths.push(PathBuf::from(item)); } } - if let Ok(cargo) = env::var("CARGO") { - let mut cargo_path = PathBuf::from(cargo); - cargo_path.pop(); - cargo_path.pop(); - - if let Some(toolchain) = cargo_path.file_name() { - let arch = - env::var("HOST").unwrap_or_else(|_| extract_arch(toolchain.to_str().unwrap())); - - paths.push( - cargo_path - .join("lib") - .join("rustlib") - .join(arch) - .join("codegen-backends"), - ); + if let Ok(lib_paths) = env::var("DYLD_FALLBACK_LIBRARY_PATH") { + for item in lib_paths.split(separator) { + paths.push(PathBuf::from(item)); } } - if let Some(rustc) = find_rustc() { - if let Ok(output) = Command::new(&rustc).args(&["--print", "sysroot"]).output() { - let sysroot = PathBuf::from(String::from_utf8_lossy(&output.stdout).trim()); - if let Some(arch) = find_arch(&rustc, &sysroot) { - paths.push( - sysroot - .join("lib") - .join("rustlib") - .join(arch) - .join("codegen-backends"), - ); - } - } - } - - if let Ok(output) = Command::new("rustup").args(&["which", "rustc"]).output() { - let mut rustc_path = PathBuf::from(String::from_utf8_lossy(&output.stdout).trim()); - rustc_path.pop(); - rustc_path.pop(); - - if let Some(toolchain) = rustc_path.file_name() { - let arch = extract_arch(toolchain.to_str().unwrap()); + if let Ok(bin_paths) = env::var("PATH") { + for item in bin_paths.split(separator) { + let mut possible_path = PathBuf::from(item); - paths.push( - rustc_path - .join("lib") - .join("rustlib") - .join(arch) - .join("codegen-backends"), - ); + possible_path.pop(); + possible_path.push("lib"); + paths.push(possible_path); } } - Ok(paths) + paths } -// Fails if using nightly build from a specific date -// e.g. nightly-2018-11-30-x86_64-unknown-linux-gnu -fn extract_arch(toolchain: &str) -> String { - toolchain - .split('-') - // Skip `nightly` rust version prefix. - .skip(1) - // Also skip rust version specification if exists. - .skip_while(|item| match item.chars().next() { - None | Some('0'..='9') => true, - _ => false, - }) - .collect::>() - .join("-") -} +fn find_library_in_directory(directory: &Path) -> Option { + match read_dir(directory) { + Ok(files) => files + .filter_map(Result::ok) + .find(|file| file.file_name().to_string_lossy().starts_with("libLLVM")) + .map(|file| file.path()), -fn find_rustc() -> Option { - if let Some(path) = env::var_os("RUSTC") { - Some(path.into()) - } else if let Ok(output) = Command::new("rustup").args(&["which", "rustc"]).output() { - Some(String::from_utf8_lossy(&output.stdout).trim().into()) - } else { - None - } -} - -fn find_arch(rustc: &Path, sysroot: &Path) -> Option { - if let Ok(path) = env::var("HOST") { - Some(path) - } else if let Ok(output) = Command::new(&rustc).args(&["-vV"]).output() { - for line in String::from_utf8_lossy(&output.stdout).lines() { - if line.starts_with("host") { - return Some(line.trim_start_matches("host:").trim().to_string()); - } - } - None - } else if let Some(toolchain) = sysroot.file_name() { - Some(extract_arch(toolchain.to_str().unwrap())) - } else { - None + Err(_) => None, } }