cps_deps/
lib_search.rs

1use anyhow::{anyhow, Result};
2use std::collections::HashMap;
3use std::path::PathBuf;
4use std::process::Command;
5use std::sync::OnceLock;
6
7use crate::pkg_config::PkgConfigFile;
8
9fn get_multiarch_lib_path_iter() -> &'static [PathBuf] {
10    static MULTIARCH_PATH: OnceLock<Vec<PathBuf>> = OnceLock::new();
11    MULTIARCH_PATH.get_or_init(|| {
12        Command::new("gcc")
13            .arg("-dumpmachine")
14            .output()
15            .map(|o| String::from_utf8(o.stdout).unwrap_or_default())
16            .map_or(vec![], |arch| {
17                vec![PathBuf::from(format!("/usr/lib/{}", arch.trim()))]
18            })
19    })
20}
21
22pub fn find_library(library: &str, extension: &str, search_paths: &[PathBuf]) -> Result<String> {
23    let filepaths: Vec<_> = search_paths
24        .iter()
25        .chain(get_multiarch_lib_path_iter())
26        .map(|base| base.join(format!("lib{}.{}", library, extension)))
27        .collect();
28
29    let error = anyhow!(
30        "Could not find required library `{}` at paths: `{:?}`",
31        library,
32        &filepaths
33    );
34    Ok(filepaths
35        .into_iter()
36        .find(|path| path.exists())
37        .ok_or(error)?
38        .into_os_string()
39        .into_string()
40        .unwrap())
41}
42
43#[derive(Debug)]
44pub enum LibraryLocation {
45    Archive(String),
46    Dylib(String),
47    Both { archive: String, dylib: String },
48}
49
50impl LibraryLocation {
51    pub fn find(library: &str, search_paths: &[PathBuf]) -> Result<Self> {
52        let dylib = find_library(library, "so", search_paths);
53        let archive = find_library(library, "a", search_paths);
54
55        match (dylib, archive) {
56            (Ok(dylib), Err(_)) => Ok(Self::Dylib(dylib)),
57            (Err(_), Ok(archive)) => Ok(Self::Archive(archive)),
58            (Ok(dylib), Ok(archive)) => Ok(Self::Both { archive, dylib }),
59            (Err(dylib_error), Err(archive_error)) => {
60                Err(anyhow!("{}\n{}", dylib_error, archive_error))
61            }
62        }
63    }
64}
65
66pub fn find_locations(pkg_config: &PkgConfigFile) -> Result<HashMap<String, LibraryLocation>> {
67    let search_paths = pkg_config
68        .link_locations
69        .iter()
70        .map(PathBuf::from)
71        .collect::<Vec<_>>();
72
73    Ok(pkg_config
74        .link_libraries
75        .iter()
76        .map(|name| -> Result<(String, LibraryLocation)> {
77            let location = LibraryLocation::find(name, &search_paths)?;
78            Ok((name.clone(), location))
79        })
80        .collect::<Result<Vec<_>>>()?
81        .into_iter()
82        .collect())
83}