1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! metadeps lets you write `pkg-config` dependencies in `Cargo.toml` metadata,
//! rather than programmatically in `build.rs`.  This makes those dependencies
//! declarative, so other tools can read them as well.
//!
//! metadeps parses metadata like this in `Cargo.toml`:
//!
//! ```toml
//! [package.metadata.pkg-config]
//! testlib = "1.2"
//! testdata = "4.5"
//! ```

#![deny(missing_docs, warnings)]

#[macro_use]
extern crate error_chain;
extern crate pkg_config;
extern crate toml;

use std::collections::HashMap;
use std::env;
use std::fs;
use std::io::Read;
use std::path::PathBuf;
use pkg_config::{Config, Library};

error_chain! {
    foreign_links {
        PkgConfig(pkg_config::Error) #[doc="pkg-config error"];
    }
}

/// Probe all libraries configured in the Cargo.toml
/// `[package.metadata.pkg-config]` section.
pub fn probe() -> Result<HashMap<String, Library>> {
    let dir = try!(env::var_os("CARGO_MANIFEST_DIR").ok_or("$CARGO_MANIFEST_DIR not set"));
    let mut path = PathBuf::from(dir);
    path.push("Cargo.toml");
    let mut manifest = try!(fs::File::open(&path).chain_err(||
        format!("Error opening {}", path.display())
    ));
    let mut manifest_str = String::new();
    try!(manifest.read_to_string(&mut manifest_str).chain_err(||
        format!("Error reading {}", path.display())
    ));
    let toml = try!(manifest_str.parse::<toml::Value>().map_err(|e|
        format!("Error parsing TOML from {}: {:?}", path.display(), e)
    ));
    let key = "package.metadata.pkg-config";
    let meta = try!(toml.lookup(key).ok_or(
        format!("No {} in {}", key, path.display())
    ));
    let table = try!(meta.as_table().ok_or(
        format!("{} not a table in {}", key, path.display())
    ));
    let mut libraries = HashMap::new();
    for (name, version) in table {
        let version_str = try!(version.as_str().ok_or(
            format!("{}.{} not a string in {}", key, name, path.display())
        ));
        let library = try!(Config::new().atleast_version(version_str).probe(name));
        libraries.insert(name.clone(), library);
    }
    Ok(libraries)
}