mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	Now that WGPU has upgraded its dependency on `libloading`, we can finally remove our fake `libloading` 0.7 crate! 🙌 I found this audit and review easiest to do by generating a diff. that ignores whitespace-only differences. In my case, I did the following: ``` git diff --ignore-space-at-eol --ignore-space-change --ignore-all-space --ignore-blank-lines ``` Differential Revision: https://phabricator.services.mozilla.com/D209290
		
			
				
	
	
		
			281 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
#![allow(dead_code)]
 | 
						|
 | 
						|
extern crate glob;
 | 
						|
extern crate serial_test;
 | 
						|
extern crate tempfile;
 | 
						|
 | 
						|
use std::collections::HashMap;
 | 
						|
use std::env;
 | 
						|
use std::fs;
 | 
						|
use std::path::PathBuf;
 | 
						|
use std::sync::Arc;
 | 
						|
use std::sync::Mutex;
 | 
						|
 | 
						|
use serial_test::serial;
 | 
						|
use tempfile::TempDir;
 | 
						|
 | 
						|
#[macro_use]
 | 
						|
#[path = "../build/macros.rs"]
 | 
						|
mod macros;
 | 
						|
 | 
						|
#[path = "../build/common.rs"]
 | 
						|
mod common;
 | 
						|
#[path = "../build/dynamic.rs"]
 | 
						|
mod dynamic;
 | 
						|
#[path = "../build/static.rs"]
 | 
						|
mod r#static;
 | 
						|
 | 
						|
#[derive(Debug, Default)]
 | 
						|
struct RunCommandMock {
 | 
						|
    invocations: Vec<(String, String, Vec<String>)>,
 | 
						|
    responses: HashMap<Vec<String>, String>,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Debug)]
 | 
						|
struct Env {
 | 
						|
    os: String,
 | 
						|
    pointer_width: String,
 | 
						|
    env: Option<String>,
 | 
						|
    vars: HashMap<String, (Option<String>, Option<String>)>,
 | 
						|
    cwd: PathBuf,
 | 
						|
    tmp: TempDir,
 | 
						|
    files: Vec<String>,
 | 
						|
    commands: Arc<Mutex<RunCommandMock>>,
 | 
						|
}
 | 
						|
 | 
						|
impl Env {
 | 
						|
    fn new(os: &str, pointer_width: &str) -> Self {
 | 
						|
        Env {
 | 
						|
            os: os.into(),
 | 
						|
            pointer_width: pointer_width.into(),
 | 
						|
            env: None,
 | 
						|
            vars: HashMap::new(),
 | 
						|
            cwd: env::current_dir().unwrap(),
 | 
						|
            tmp: tempfile::Builder::new().prefix("clang_sys_test").tempdir().unwrap(),
 | 
						|
            files: vec![],
 | 
						|
            commands: Default::default(),
 | 
						|
        }
 | 
						|
        .var("CLANG_PATH", None)
 | 
						|
        .var("LD_LIBRARY_PATH", None)
 | 
						|
        .var("LIBCLANG_PATH", None)
 | 
						|
        .var("LIBCLANG_STATIC_PATH", None)
 | 
						|
        .var("LLVM_CONFIG_PATH", None)
 | 
						|
        .var("PATH", None)
 | 
						|
    }
 | 
						|
 | 
						|
    fn env(mut self, env: &str) -> Self {
 | 
						|
        self.env = Some(env.into());
 | 
						|
        self
 | 
						|
    }
 | 
						|
 | 
						|
    fn var(mut self, name: &str, value: Option<&str>) -> Self {
 | 
						|
        let previous = env::var(name).ok();
 | 
						|
        self.vars.insert(name.into(), (value.map(|v| v.into()), previous));
 | 
						|
        self
 | 
						|
    }
 | 
						|
 | 
						|
    fn dir(mut self, path: &str) -> Self {
 | 
						|
        self.files.push(path.into());
 | 
						|
        let path = self.tmp.path().join(path);
 | 
						|
        fs::create_dir_all(path).unwrap();
 | 
						|
        self
 | 
						|
    }
 | 
						|
 | 
						|
    fn file(mut self, path: &str, contents: &[u8]) -> Self {
 | 
						|
        self.files.push(path.into());
 | 
						|
        let path = self.tmp.path().join(path);
 | 
						|
        fs::create_dir_all(path.parent().unwrap()).unwrap();
 | 
						|
        fs::write(self.tmp.path().join(path), contents).unwrap();
 | 
						|
        self
 | 
						|
    }
 | 
						|
 | 
						|
    fn dll(self, path: &str, pointer_width: &str) -> Self {
 | 
						|
        // PE header.
 | 
						|
        let mut contents = [0; 64];
 | 
						|
        contents[0x3C..0x3C + 4].copy_from_slice(&i32::to_le_bytes(10));
 | 
						|
        contents[10..14].copy_from_slice(&[b'P', b'E', 0, 0]);
 | 
						|
        let magic = if pointer_width == "64" { 523 } else { 267 };
 | 
						|
        contents[34..36].copy_from_slice(&u16::to_le_bytes(magic));
 | 
						|
 | 
						|
        self.file(path, &contents)
 | 
						|
    }
 | 
						|
 | 
						|
    fn so(self, path: &str, pointer_width: &str) -> Self {
 | 
						|
        // ELF header.
 | 
						|
        let class = if pointer_width == "64" { 2 } else { 1 };
 | 
						|
        let contents = [127, 69, 76, 70, class];
 | 
						|
 | 
						|
        self.file(path, &contents)
 | 
						|
    }
 | 
						|
 | 
						|
    fn command(self, command: &str, args: &[&str], response: &str) -> Self {
 | 
						|
        let command = command.to_string();
 | 
						|
        let args = args.iter().map(|a| a.to_string()).collect::<Vec<_>>();
 | 
						|
 | 
						|
        let mut key = vec![command];
 | 
						|
        key.extend(args);
 | 
						|
        self.commands.lock().unwrap().responses.insert(key, response.into());
 | 
						|
 | 
						|
        self
 | 
						|
    }
 | 
						|
 | 
						|
    fn enable(self) -> Self {
 | 
						|
        env::set_var("_CLANG_SYS_TEST", "yep");
 | 
						|
        env::set_var("_CLANG_SYS_TEST_OS", &self.os);
 | 
						|
        env::set_var("_CLANG_SYS_TEST_POINTER_WIDTH", &self.pointer_width);
 | 
						|
        if let Some(env) = &self.env {
 | 
						|
            env::set_var("_CLANG_SYS_TEST_ENV", env);
 | 
						|
        }
 | 
						|
 | 
						|
        for (name, (value, _)) in &self.vars {
 | 
						|
            if let Some(value) = value {
 | 
						|
                env::set_var(name, value);
 | 
						|
            } else {
 | 
						|
                env::remove_var(name);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        env::set_current_dir(&self.tmp).unwrap();
 | 
						|
 | 
						|
        let commands = self.commands.clone();
 | 
						|
        let mock = &mut *common::RUN_COMMAND_MOCK.lock().unwrap();
 | 
						|
        *mock = Some(Box::new(move |command, path, args| {
 | 
						|
            let command = command.to_string();
 | 
						|
            let path = path.to_string();
 | 
						|
            let args = args.iter().map(|a| a.to_string()).collect::<Vec<_>>();
 | 
						|
 | 
						|
            let mut commands = commands.lock().unwrap();
 | 
						|
            commands.invocations.push((command.clone(), path, args.clone()));
 | 
						|
 | 
						|
            let mut key = vec![command];
 | 
						|
            key.extend(args);
 | 
						|
            commands.responses.get(&key).cloned()
 | 
						|
        }));
 | 
						|
 | 
						|
        self
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl Drop for Env {
 | 
						|
    fn drop(&mut self) {
 | 
						|
        env::remove_var("_CLANG_SYS_TEST");
 | 
						|
        env::remove_var("_CLANG_SYS_TEST_OS");
 | 
						|
        env::remove_var("_CLANG_SYS_TEST_POINTER_WIDTH");
 | 
						|
        env::remove_var("_CLANG_SYS_TEST_ENV");
 | 
						|
 | 
						|
        for (name, (_, previous)) in &self.vars {
 | 
						|
            if let Some(previous) = previous {
 | 
						|
                env::set_var(name, previous);
 | 
						|
            } else {
 | 
						|
                env::remove_var(name);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if let Err(error) = env::set_current_dir(&self.cwd) {
 | 
						|
            println!("Failed to reset working directory: {:?}", error);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
//================================================
 | 
						|
// Dynamic
 | 
						|
//================================================
 | 
						|
 | 
						|
// Linux -----------------------------------------
 | 
						|
 | 
						|
#[test]
 | 
						|
#[serial]
 | 
						|
fn test_linux_directory_preference() {
 | 
						|
    let _env = Env::new("linux", "64")
 | 
						|
        .so("usr/lib/libclang.so.1", "64")
 | 
						|
        .so("usr/local/lib/libclang.so.1", "64")
 | 
						|
        .enable();
 | 
						|
 | 
						|
    assert_eq!(
 | 
						|
        dynamic::find(true),
 | 
						|
        Ok(("usr/local/lib".into(), "libclang.so.1".into())),
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
#[test]
 | 
						|
#[serial]
 | 
						|
fn test_linux_version_preference() {
 | 
						|
    let _env = Env::new("linux", "64")
 | 
						|
        .so("usr/lib/libclang-3.so", "64")
 | 
						|
        .so("usr/lib/libclang-3.5.so", "64")
 | 
						|
        .so("usr/lib/libclang-3.5.0.so", "64")
 | 
						|
        .enable();
 | 
						|
 | 
						|
    assert_eq!(
 | 
						|
        dynamic::find(true),
 | 
						|
        Ok(("usr/lib".into(), "libclang-3.5.0.so".into())),
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
#[test]
 | 
						|
#[serial]
 | 
						|
fn test_linux_directory_and_version_preference() {
 | 
						|
    let _env = Env::new("linux", "64")
 | 
						|
        .so("usr/local/llvm/lib/libclang-3.so", "64")
 | 
						|
        .so("usr/local/lib/libclang-3.5.so", "64")
 | 
						|
        .so("usr/lib/libclang-3.5.0.so", "64")
 | 
						|
        .enable();
 | 
						|
 | 
						|
    assert_eq!(
 | 
						|
        dynamic::find(true),
 | 
						|
        Ok(("usr/lib".into(), "libclang-3.5.0.so".into())),
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
// Windows ---------------------------------------
 | 
						|
 | 
						|
#[cfg(target_os = "windows")]
 | 
						|
#[test]
 | 
						|
#[serial]
 | 
						|
fn test_windows_bin_sibling() {
 | 
						|
    let _env = Env::new("windows", "64")
 | 
						|
        .dir("Program Files\\LLVM\\lib")
 | 
						|
        .dll("Program Files\\LLVM\\bin\\libclang.dll", "64")
 | 
						|
        .enable();
 | 
						|
 | 
						|
    assert_eq!(
 | 
						|
        dynamic::find(true),
 | 
						|
        Ok(("Program Files\\LLVM\\bin".into(), "libclang.dll".into())),
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
#[cfg(target_os = "windows")]
 | 
						|
#[test]
 | 
						|
#[serial]
 | 
						|
fn test_windows_mingw_gnu() {
 | 
						|
    let _env = Env::new("windows", "64")
 | 
						|
        .env("gnu")
 | 
						|
        .dir("MSYS\\MinGW\\lib")
 | 
						|
        .dll("MSYS\\MinGW\\bin\\clang.dll", "64")
 | 
						|
        .dir("Program Files\\LLVM\\lib")
 | 
						|
        .dll("Program Files\\LLVM\\bin\\libclang.dll", "64")
 | 
						|
        .enable();
 | 
						|
 | 
						|
    assert_eq!(
 | 
						|
        dynamic::find(true),
 | 
						|
        Ok(("MSYS\\MinGW\\bin".into(), "clang.dll".into())),
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
#[cfg(target_os = "windows")]
 | 
						|
#[test]
 | 
						|
#[serial]
 | 
						|
fn test_windows_mingw_msvc() {
 | 
						|
    let _env = Env::new("windows", "64")
 | 
						|
        .env("msvc")
 | 
						|
        .dir("MSYS\\MinGW\\lib")
 | 
						|
        .dll("MSYS\\MinGW\\bin\\clang.dll", "64")
 | 
						|
        .dir("Program Files\\LLVM\\lib")
 | 
						|
        .dll("Program Files\\LLVM\\bin\\libclang.dll", "64")
 | 
						|
        .enable();
 | 
						|
 | 
						|
    assert_eq!(
 | 
						|
        dynamic::find(true),
 | 
						|
        Ok(("Program Files\\LLVM\\bin".into(), "libclang.dll".into())),
 | 
						|
    );
 | 
						|
}
 |