pcap_config/
lib.rs

1//! A build dependency for Cargo projects to find the location and compiler flags for linking
2//! against `libpcap` using the `pcap-config` utility.
3//!
4//! This library uses the `pcap-config` utility, which is installed with libpcap, to find the
5//! location and compiler flags required by cargo for linking to libpcap. A `Config` structure
6//! provides a way to customize the options set for running `pcap-config`.
7//!
8//! If `pcap-config` runs successfully, the Cargo metadata is printed to stdout.
9//!
10//! # Examples
11//!
12//! Using `pcap-config` with the default options:
13//!
14//! ```no_run
15//! extern crate pcap_config;
16//!
17//! fn main() {
18//!     pcap_config::find_library().unwrap();
19//! }
20//! ```
21//!
22//! Customizing how `pcap-config` reports the metadata:
23//!
24//! ```no_run
25//! extern crate pcap_config;
26//!
27//! fn main() {
28//!     pcap_config::Config::new().statik(true).find().unwrap();
29//! }
30//! ```
31
32#![deny(missing_docs)]
33
34use std::process::Command;
35
36/// Run `pcap-config` with default options.
37pub fn find_library() -> Result<(), String> {
38    Config::new().find()
39}
40
41/// A container for `pcap-config` configuration options.
42pub struct Config {
43    statik: Option<bool>,
44}
45
46impl Config {
47    /// Creates a new configuration for running `pcap-config` with the default options.
48    pub fn new() -> Config {
49        Config { statik: None }
50    }
51
52    /// Indicate whether the `--static` flag should be passed to `pcap-config`.
53    pub fn statik(&mut self, statik: bool) -> &mut Config {
54        self.statik = Some(statik);
55        self
56    }
57
58    /// Run `pcap-config` to look up compiler flags for libpcap.
59    pub fn find(&self) -> Result<(), String> {
60        let output = try!(self.command(&["--libs", "--cflags"])
61                              .output()
62                              .map_err(|e| format!("failed to run `pcap-config`: {}", e)));
63
64        let stdout = try!(String::from_utf8(output.stdout).map_err(|e| {
65            format!("unable to convert `pcap-config` output: {}", e)
66        }));
67
68        let tokens = stdout.split(' ')
69                           .filter(|l| l.len() > 2)
70                           .map(|t| (&t[0..2], &t[2..]))
71                           .collect::<Vec<_>>();
72        for &(flag, value) in tokens.iter() {
73            match flag {
74                "-L" => println!("cargo:rustc-link-search=native={}", value),
75                "-l" => {
76                    if self.is_static() {
77                        println!("cargo:rustc-link-lib=static={}", value);
78                    } else {
79                        println!("cargo:rustc-link-lib={}", value);
80                    }
81                }
82                _ => {}
83            }
84        }
85
86        Ok(())
87    }
88
89    fn is_static(&self) -> bool {
90        self.statik.unwrap_or_else(|| false)
91    }
92
93    fn command(&self, args: &[&str]) -> Command {
94        let mut cmd = Command::new("pcap-config");
95
96        if self.is_static() {
97            cmd.arg("--static");
98        }
99        cmd.args(args);
100
101        cmd
102    }
103}