diff options
| author | Daniel Mueller <deso@posteo.net> | 2018-12-10 20:51:50 -0800 | 
|---|---|---|
| committer | Daniel Mueller <deso@posteo.net> | 2018-12-10 20:51:50 -0800 | 
| commit | 5875df6c958743cf86c75b2cb5fc2efe5ca0de43 (patch) | |
| tree | 5c2275396ba921da440dc54dd76c0e5be1d3c60e /pkg-config | |
| parent | df88d39cd9c7b254057ee80dad5367313f2bb87f (diff) | |
| download | nitrocli-5875df6c958743cf86c75b2cb5fc2efe5ca0de43.tar.gz nitrocli-5875df6c958743cf86c75b2cb5fc2efe5ca0de43.tar.bz2 | |
Update pkg-config crate to 0.3.14
This change updates the pkg-config crate to version 0.3.14.
Import subrepo pkg-config/:pkg-config at f867f8be1babca4d6d9cddc92a817519ae845193
Diffstat (limited to 'pkg-config')
| -rw-r--r-- | pkg-config/.gitignore | 2 | ||||
| -rw-r--r-- | pkg-config/CHANGELOG.md | 19 | ||||
| -rw-r--r-- | pkg-config/Cargo.toml | 9 | ||||
| -rw-r--r-- | pkg-config/README.md | 39 | ||||
| -rw-r--r-- | pkg-config/src/lib.rs | 250 | ||||
| -rw-r--r-- | pkg-config/tests/escape.pc | 5 | ||||
| -rw-r--r-- | pkg-config/tests/framework.pc | 2 | ||||
| -rw-r--r-- | pkg-config/tests/test.rs | 19 | 
8 files changed, 271 insertions, 74 deletions
| diff --git a/pkg-config/.gitignore b/pkg-config/.gitignore index 4fffb2f..d6904d2 100644 --- a/pkg-config/.gitignore +++ b/pkg-config/.gitignore @@ -1,2 +1,4 @@  /target  /Cargo.lock +.idea +*.iml diff --git a/pkg-config/CHANGELOG.md b/pkg-config/CHANGELOG.md new file mode 100644 index 0000000..3f56db1 --- /dev/null +++ b/pkg-config/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [0.3.10] - 2018-04-23 + +### Added +- Allow static linking of /usr/ on macOS (#42) +- Add support for parsing `-Wl,` style framework flags (#48) +- Parse defines in `pkg-config` output (#49) +- Rerun on `PKG_CONFIG_PATH` changes (#50) +- Introduce target-scoped variables (#58) +- Respect pkg-config escaping rules used with --cflags and --libs (#61) + +### Changed +- Use `?` instead of `try!()` in the codebase (#63) diff --git a/pkg-config/Cargo.toml b/pkg-config/Cargo.toml index 7393b5b..6f06af5 100644 --- a/pkg-config/Cargo.toml +++ b/pkg-config/Cargo.toml @@ -1,16 +1,19 @@  [package]  name = "pkg-config" -version = "0.3.9" +version = "0.3.14"  authors = ["Alex Crichton <alex@alexcrichton.com>"]  license = "MIT/Apache-2.0"  repository = "https://github.com/alexcrichton/pkg-config-rs" -documentation = "http://alexcrichton.com/pkg-config-rs" +documentation = "https://docs.rs/pkg-config"  description = """  A library to run the pkg-config system tool at build time in order to be used in  Cargo build scripts.  """  keywords = ["build-dependencies"] +[badges] +travis-ci = { repository = "alexcrichton/pkg-config-rs" } +  [dev-dependencies] -lazy_static = "0.2" +lazy_static = "1" diff --git a/pkg-config/README.md b/pkg-config/README.md index 80e372a..cb9ebd5 100644 --- a/pkg-config/README.md +++ b/pkg-config/README.md @@ -1,8 +1,9 @@  # pkg-config-rs  [](https://travis-ci.org/alexcrichton/pkg-config-rs) +[](https://github.com/alexcrichton/pkg-config-rs/) -[Documentation](http://alexcrichton.com/pkg-config-rs) +[Documentation](https://docs.rs/pkg-config)  A simple library meant to be used as a build dependency with Cargo packages in  order to use the system `pkg-config` tool (if available) to determine where a @@ -12,6 +13,8 @@ You can use this crate directly to probe for specific libraries, or use  [metadeps](https://github.com/joshtriplett/metadeps) to declare all your  `pkg-config` dependencies in `Cargo.toml`. +This library requires Rust 1.13+. +  # Example  Find the system library named `foo`, with minimum version 1.2.3: @@ -35,10 +38,36 @@ fn main() {  }  ``` +# External configuration via target-scoped environment variables + +In cross-compilation context, it is useful to manage separately PKG_CONFIG_PATH +and a few other variables for the `host` and the `target` platform. + +The supported variables are: `PKG_CONFIG_PATH`, `PKG_CONFIG_LIBDIR`, and +`PKG_CONFIG_SYSROOT_DIR`. + +Each of these variables can also be supplied with certain prefixes and suffixes, in the following prioritized order: + +1. `<var>_<target>` - for example, `PKG_CONFIG_PATH_x86_64-unknown-linux-gnu` +2. `<var>_<target_with_underscores>` - for example, `PKG_CONFIG_PATH_x86_64_unknown_linux_gnu` +3. `<build-kind>_<var>` - for example, `HOST_PKG_CONFIG_PATH` or `TARGET_PKG_CONFIG_PATH` +4. `<var>` - a plain `PKG_CONFIG_PATH` + +Also note that `PKG_CONFIG_ALLOW_CROSS` must always be set in cross-compilation context. +  # License -`pkg-config-rs` is primarily distributed under the terms of both the MIT -license and the Apache License (Version 2.0), with portions covered by various -BSD-like licenses. +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or +   http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or +   http://opensource.org/licenses/MIT) + +at your option. + +### Contribution -See LICENSE-APACHE, and LICENSE-MIT for details. +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/pkg-config/src/lib.rs b/pkg-config/src/lib.rs index c88bd34..88dd310 100644 --- a/pkg-config/src/lib.rs +++ b/pkg-config/src/lib.rs @@ -61,38 +61,36 @@  //! }  //! ``` -#![doc(html_root_url = "http://alexcrichton.com/pkg-config-rs")] -#![cfg_attr(test, deny(warnings))] +#![doc(html_root_url = "https://docs.rs/pkg-config/0.3")] +#[allow(unused_imports)] // Required for Rust <1.23  use std::ascii::AsciiExt; +use std::collections::HashMap;  use std::env;  use std::error;  use std::ffi::{OsStr, OsString};  use std::fmt; -use std::fs;  use std::io;  use std::path::{PathBuf, Path};  use std::process::{Command, Output};  use std::str;  pub fn target_supported() -> bool { -    let target = env::var("TARGET").unwrap_or(String::new()); -    let host = env::var("HOST").unwrap_or(String::new()); +    let target = env::var("TARGET").unwrap_or_else(|_| String::new()); +    let host = env::var("HOST").unwrap_or_else(|_| String::new());      // Only use pkg-config in host == target situations by default (allowing an -    // override) and then also don't use pkg-config on MSVC as it's really not -    // meant to work there but when building MSVC code in a MSYS shell we may be -    // able to run pkg-config anyway. -    (host == target || env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some()) && -    !target.contains("msvc") +    // override). +    (host == target || env::var_os("PKG_CONFIG_ALLOW_CROSS").is_some())  } -#[derive(Clone)] +#[derive(Clone, Default)]  pub struct Config {      statik: Option<bool>,      atleast_version: Option<String>,      extra_args: Vec<OsString>,      cargo_metadata: bool, +    env_metadata: bool,      print_system_libs: bool,  } @@ -103,6 +101,7 @@ pub struct Library {      pub frameworks: Vec<String>,      pub framework_paths: Vec<PathBuf>,      pub include_paths: Vec<PathBuf>, +    pub defines: HashMap<String, Option<String>>,      pub version: String,      _priv: (),  } @@ -119,9 +118,6 @@ pub enum Error {      /// Override with `PKG_CONFIG_ALLOW_CROSS=1`.      CrossCompilation, -    /// Attempted to compile using the MSVC ABI build -    MSVC, -      /// Failed to run `pkg-config`.      ///      /// Contains the command and the cause. @@ -145,7 +141,6 @@ impl error::Error for Error {                  "pkg-config doesn't handle cross compilation. \                   Use PKG_CONFIG_ALLOW_CROSS=1 to override"              } -            Error::MSVC => "pkg-config is incompatible with the MSVC ABI build.",              Error::Command { .. } => "failed to run pkg-config",              Error::Failure { .. } => "pkg-config did not exit sucessfully",              Error::__Nonexhaustive => panic!(), @@ -196,7 +191,6 @@ impl fmt::Debug for Error {                   .finish()              }              Error::CrossCompilation => write!(f, "CrossCompilation"), -            Error::MSVC => write!(f, "MSVC"),              Error::Command { ref command, ref cause } => {                  f.debug_struct("Command")                   .field("command", command) @@ -224,22 +218,18 @@ impl fmt::Display for Error {                  write!(f, "Cross compilation detected. \                         Use PKG_CONFIG_ALLOW_CROSS=1 to override")              } -            Error::MSVC => { -                write!(f, "MSVC target detected. If you are using the MSVC ABI \ -                       rust build, please use the GNU ABI build instead.") -            }              Error::Command { ref command, ref cause } => {                  write!(f, "Failed to run `{}`: {}", command, cause)              }              Error::Failure { ref command, ref output } => {                  let stdout = str::from_utf8(&output.stdout).unwrap();                  let stderr = str::from_utf8(&output.stderr).unwrap(); -                try!(write!(f, "`{}` did not exit successfully: {}", command, output.status)); +                write!(f, "`{}` did not exit successfully: {}", command, output.status)?;                  if !stdout.is_empty() { -                    try!(write!(f, "\n--- stdout\n{}", stdout)); +                    write!(f, "\n--- stdout\n{}", stdout)?;                  }                  if !stderr.is_empty() { -                    try!(write!(f, "\n--- stderr\n{}", stderr)); +                    write!(f, "\n--- stderr\n{}", stderr)?;                  }                  Ok(())              } @@ -264,7 +254,8 @@ pub fn probe_library(name: &str) -> Result<Library, Error> {  pub fn get_variable(package: &str, variable: &str) -> Result<String, Error> {      let arg = format!("--variable={}", variable);      let cfg = Config::new(); -    Ok(try!(run(cfg.command(package, &[&arg]))).trim_right().to_owned()) +    let out = run(cfg.command(package, &[&arg]))?; +    Ok(str::from_utf8(&out).unwrap().trim_right().to_owned())  }  impl Config { @@ -277,6 +268,7 @@ impl Config {              extra_args: vec![],              print_system_libs: true,              cargo_metadata: true, +            env_metadata: false,          }      } @@ -310,6 +302,14 @@ impl Config {          self      } +    /// Define whether metadata should be emitted for cargo allowing to +    /// automatically rebuild when environment variables change. Defaults to +    /// `false`. +    pub fn env_metadata(&mut self, env_metadata: bool) -> &mut Config { +        self.env_metadata = env_metadata; +        self +    } +      /// Enable or disable the `PKG_CONFIG_ALLOW_SYSTEM_LIBS` environment      /// variable.      /// @@ -331,24 +331,19 @@ impl Config {      /// `pkg-config` is run.      pub fn probe(&self, name: &str) -> Result<Library, Error> {          let abort_var_name = format!("{}_NO_PKG_CONFIG", envify(name)); -        if env::var_os(&abort_var_name).is_some() { +        if self.env_var_os(&abort_var_name).is_some() {              return Err(Error::EnvNoPkgConfig(abort_var_name))          } else if !target_supported() { -            if env::var("TARGET").unwrap_or(String::new()).contains("msvc") { -                return Err(Error::MSVC); -            } -            else { -                return Err(Error::CrossCompilation); -            } +            return Err(Error::CrossCompilation);          }          let mut library = Library::new(); -        let output = try!(run(self.command(name, &["--libs", "--cflags"]))); +        let output = run(self.command(name, &["--libs", "--cflags"]))?;          library.parse_libs_cflags(name, &output, self); -        let output = try!(run(self.command(name, &["--modversion"]))); -        library.parse_modversion(&output); +        let output = run(self.command(name, &["--modversion"]))?; +        library.parse_modversion(str::from_utf8(&output).unwrap());          Ok(library)      } @@ -359,12 +354,41 @@ impl Config {          get_variable(package, variable).map_err(|e| e.to_string())      } +    fn targetted_env_var(&self, var_base: &str) -> Result<String, env::VarError> { +        if let Ok(target) = env::var("TARGET") { +            let host = env::var("HOST")?; +            let kind = if host == target { "HOST" } else { "TARGET" }; +            let target_u = target.replace("-", "_"); + +            self.env_var(&format!("{}_{}", var_base, target)) +                .or_else(|_| self.env_var(&format!("{}_{}", var_base, target_u))) +                .or_else(|_| self.env_var(&format!("{}_{}", kind, var_base))) +                .or_else(|_| self.env_var(var_base)) +        } else { +            self.env_var(var_base) +        } +    } + +    fn env_var(&self, name: &str) -> Result<String, env::VarError> { +        if self.env_metadata { +            println!("cargo:rerun-if-env-changed={}", name); +        } +        env::var(name) +    } + +    fn env_var_os(&self, name: &str) -> Option<OsString> { +        if self.env_metadata { +            println!("cargo:rerun-if-env-changed={}", name); +        } +        env::var_os(name) +    } +      fn is_static(&self, name: &str) -> bool { -        self.statik.unwrap_or_else(|| infer_static(name)) +        self.statik.unwrap_or_else(|| self.infer_static(name))      }      fn command(&self, name: &str, args: &[&str]) -> Command { -        let exe = env::var("PKG_CONFIG").unwrap_or(String::from("pkg-config")); +        let exe = self.env_var("PKG_CONFIG").unwrap_or_else(|_| String::from("pkg-config"));          let mut cmd = Command::new(exe);          if self.is_static(name) {              cmd.arg("--static"); @@ -372,6 +396,15 @@ impl Config {          cmd.args(args)             .args(&self.extra_args); +        if let Ok(value) = self.targetted_env_var("PKG_CONFIG_PATH") { +            cmd.env("PKG_CONFIG_PATH", value); +        } +        if let Ok(value) = self.targetted_env_var("PKG_CONFIG_LIBDIR") { +            cmd.env("PKG_CONFIG_LIBDIR", value); +        } +        if let Ok(value) = self.targetted_env_var("PKG_CONFIG_SYSROOT_DIR") { +            cmd.env("PKG_CONFIG_SYSROOT_DIR", value); +        }          if self.print_system_libs {              cmd.env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");          } @@ -388,6 +421,21 @@ impl Config {              println!("cargo:{}", s);          }      } + +    fn infer_static(&self, name: &str) -> bool { +        let name = envify(name); +        if self.env_var_os(&format!("{}_STATIC", name)).is_some() { +            true +        } else if self.env_var_os(&format!("{}_DYNAMIC", name)).is_some() { +            false +        } else if self.env_var_os("PKG_CONFIG_ALL_STATIC").is_some() { +            true +        } else if self.env_var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() { +            false +        } else { +            false +        } +    }  }  impl Library { @@ -398,21 +446,29 @@ impl Library {              include_paths: Vec::new(),              frameworks: Vec::new(),              framework_paths: Vec::new(), +            defines: HashMap::new(),              version: String::new(),              _priv: (),          }      } -    fn parse_libs_cflags(&mut self, name: &str, output: &str, config: &Config) { -        let parts = output.trim_right() -                          .split(' ') +    fn parse_libs_cflags(&mut self, name: &str, output: &[u8], config: &Config) { +        let mut is_msvc = false; +        if let Ok(target) = env::var("TARGET") { +            if target.contains("msvc") { +                is_msvc = true; +            } +        } + +        let words = split_flags(output); +        let parts = words.iter()                            .filter(|l| l.len() > 2)                            .map(|arg| (&arg[0..2], &arg[2..]))                            .collect::<Vec<_>>();          let mut dirs = Vec::new();          let statik = config.is_static(name); -        for &(flag, val) in parts.iter() { +        for &(flag, val) in &parts {              match flag {                  "-L" => {                      let meta = format!("rustc-link-search=native={}", val); @@ -429,20 +485,35 @@ impl Library {                      self.include_paths.push(PathBuf::from(val));                  }                  "-l" => { -                    self.libs.push(val.to_string()); -                    if statik && !is_system(val, &dirs) { +                    // These are provided by the CRT with MSVC +                    if is_msvc && ["m", "c", "pthread"].contains(&val) { +                        continue; +                    } + +                    if statik && is_static_available(val, &dirs) {                          let meta = format!("rustc-link-lib=static={}", val);                          config.print_metadata(&meta);                      } else {                          let meta = format!("rustc-link-lib={}", val);                          config.print_metadata(&meta);                      } + +                    self.libs.push(val.to_string()); +                } +                "-D" => { +                    let mut iter = val.split("="); +                    self.defines.insert(iter.next().unwrap().to_owned(), iter.next().map(|s| s.to_owned()));                  }                  _ => {}              }          } -        let mut iter = output.trim_right().split(' '); +        let mut iter = words.iter() +                            .flat_map(|arg| if arg.starts_with("-Wl,") { +                                 arg[4..].split(',').collect() +                             } else { +                                 vec![arg.as_ref()] +                             });          while let Some(part) = iter.next() {              if part != "-framework" {                  continue @@ -460,41 +531,32 @@ impl Library {      }  } -fn infer_static(name: &str) -> bool { -    let name = envify(name); -    if env::var_os(&format!("{}_STATIC", name)).is_some() { -        true -    } else if env::var_os(&format!("{}_DYNAMIC", name)).is_some() { -        false -    } else if env::var_os("PKG_CONFIG_ALL_STATIC").is_some() { -        true -    } else if env::var_os("PKG_CONFIG_ALL_DYNAMIC").is_some() { -        false -    } else { -        false -    } -} -  fn envify(name: &str) -> String {      name.chars().map(|c| c.to_ascii_uppercase()).map(|c| {          if c == '-' {'_'} else {c}      }).collect()  } -fn is_system(name: &str, dirs: &[PathBuf]) -> bool { +/// System libraries should only be linked dynamically +fn is_static_available(name: &str, dirs: &[PathBuf]) -> bool {      let libname = format!("lib{}.a", name); -    let root = Path::new("/usr"); -    !dirs.iter().any(|d| { -        !d.starts_with(root) && fs::metadata(&d.join(&libname)).is_ok() +    let system_roots = if cfg!(target_os = "macos") { +        vec![Path::new("/Library"), Path::new("/System")] +    } else { +        vec![Path::new("/usr")] +    }; + +    dirs.iter().any(|dir| { +        !system_roots.iter().any(|sys| dir.starts_with(sys)) && +        dir.join(&libname).exists()      })  } -fn run(mut cmd: Command) -> Result<String, Error> { +fn run(mut cmd: Command) -> Result<Vec<u8>, Error> {      match cmd.output() {          Ok(output) => {              if output.status.success() { -                let stdout = String::from_utf8(output.stdout).unwrap(); -                Ok(stdout) +                Ok(output.stdout)              } else {                  Err(Error::Failure {                      command: format!("{:?}", cmd), @@ -508,3 +570,61 @@ fn run(mut cmd: Command) -> Result<String, Error> {          }),      }  } + +/// Split output produced by pkg-config --cflags and / or --libs into separate flags. +/// +/// Backslash in output is used to preserve literal meaning of following byte.  Different words are +/// separated by unescaped space. Other whitespace characters generally should not occur unescaped +/// at all, apart from the newline at the end of output. For compatibility with what others +/// consumers of pkg-config output would do in this scenario, they are used here for splitting as +/// well. +fn split_flags(output: &[u8]) -> Vec<String> { +    let mut word = Vec::new(); +    let mut words = Vec::new(); +    let mut escaped = false; + +    for &b in output { +        match b { +            _ if escaped => { +                escaped = false; +                word.push(b); +            } +            b'\\' => { +                escaped = true +            } +            b'\t' | b'\n' | b'\r' | b' ' => { +                if !word.is_empty() { +                    words.push(String::from_utf8(word).unwrap()); +                    word = Vec::new(); +                } +            } +            _ => word.push(b), +        } +    } + +    if !word.is_empty() { +        words.push(String::from_utf8(word).unwrap()); +    } + +    words +} + +#[test] +#[cfg(target_os = "macos")] +fn system_library_mac_test() { +    assert!(!is_static_available("PluginManager", &[PathBuf::from("/Library/Frameworks")])); +    assert!(!is_static_available("python2.7", &[PathBuf::from("/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config")])); +    assert!(!is_static_available("ffi_convenience", &[PathBuf::from("/Library/Ruby/Gems/2.0.0/gems/ffi-1.9.10/ext/ffi_c/libffi-x86_64/.libs")])); + +    // Homebrew is in /usr/local, and it's not a part of the OS +    if Path::new("/usr/local/lib/libpng16.a").exists() { +        assert!(is_static_available("png16", &[PathBuf::from("/usr/local/lib")])); +    } +} + +#[test] +#[cfg(target_os = "linux")] +fn system_library_linux_test() { +    assert!(!is_static_available("util", &[PathBuf::from("/usr/lib/x86_64-linux-gnu")])); +    assert!(!is_static_available("dialog", &[PathBuf::from("/usr/lib")])); +} diff --git a/pkg-config/tests/escape.pc b/pkg-config/tests/escape.pc new file mode 100644 index 0000000..701c4bf --- /dev/null +++ b/pkg-config/tests/escape.pc @@ -0,0 +1,5 @@ +Name: Escape +Version: 4.2.0 +Description: Escape utility library +Libs: -Llink\ path\ with\ spaces +Cflags: -Iinclude\ path\ with\ spaces -DA=\"escaped\ string\'\ literal\" -DB=ESCAPED\ IDENTIFIER -DFOX=🦊 diff --git a/pkg-config/tests/framework.pc b/pkg-config/tests/framework.pc index 57c0447..fec17f4 100644 --- a/pkg-config/tests/framework.pc +++ b/pkg-config/tests/framework.pc @@ -11,6 +11,6 @@ Name: Valgrind  Description: A dynamic binary instrumentation framework  Version: 3.10.0.SVN  Requires: -Libs: -F${libdir} -framework foo +Libs: -F${libdir} -framework foo -Wl,-framework,bar -Wl,-framework -Wl,baz -Wl,-framework,foobar,-framework,foobaz  Cflags: -I${includedir} diff --git a/pkg-config/tests/test.rs b/pkg-config/tests/test.rs index ee8613c..fad0fcf 100644 --- a/pkg-config/tests/test.rs +++ b/pkg-config/tests/test.rs @@ -75,11 +75,30 @@ fn output_ok() {  }  #[test] +fn escapes() { +    let _g = LOCK.lock(); +    reset(); +    let lib = find("escape").unwrap(); +    assert!(lib.include_paths.contains(&PathBuf::from("include path with spaces"))); +    assert!(lib.link_paths.contains(&PathBuf::from("link path with spaces"))); +    assert_eq!(lib.defines.get("A"), +               Some(&Some("\"escaped string' literal\"".to_owned()))); +    assert_eq!(lib.defines.get("B"), +               Some(&Some("ESCAPED IDENTIFIER".to_owned()))); +    assert_eq!(lib.defines.get("FOX"), +               Some(&Some("🦊".to_owned()))); +} + +#[test]  fn framework() {      let _g = LOCK.lock();      reset();      let lib = find("framework").unwrap();      assert!(lib.frameworks.contains(&"foo".to_string())); +    assert!(lib.frameworks.contains(&"bar".to_string())); +    assert!(lib.frameworks.contains(&"baz".to_string())); +    assert!(lib.frameworks.contains(&"foobar".to_string())); +    assert!(lib.frameworks.contains(&"foobaz".to_string()));      assert!(lib.framework_paths.contains(&PathBuf::from("/usr/lib")));  } | 
