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}