rust-pcap / pcap

Rust language pcap library
Apache License 2.0
595 stars 138 forks source link

pkg-config support #276

Closed Fuuzetsu closed 1 year ago

Fuuzetsu commented 1 year ago

It would very nice if pkg-config crate could be used to probe for location and version of libpcap. This can work a lot better than specifying LIBPCAP_LIBDIR and LIBPCAP_VERSION manually in a lot of scenarioes.

I can send a PR if desired, even with a feature gate.

Fuuzetsu commented 1 year ago

Something like this seems to work well for us: on top of 0.9.1 as it's just what version we happened to have at the moment. pkg-config can probably be an optional feature or something.

diff --git a/Cargo.toml b/Cargo.toml
index d5d11a2..75453ff 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,6 +31,7 @@ tempdir = "0.3"
 [build-dependencies]
 libloading = "0.6"
 regex = "1"
+pkg-config = "0.3"

 [features]
 # This feature enables access to the function Capture::stream.
diff --git a/build.rs b/build.rs
index b8a0a9d..6cae3ff 100644
--- a/build.rs
+++ b/build.rs
@@ -3,6 +3,8 @@ use std::ffi::CStr;
 use std::os::raw::c_char;
 use std::path::PathBuf;

+extern crate pkg_config;
+
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
 struct Version {
     major: usize,
@@ -131,12 +133,16 @@ fn main() {
     println!("cargo:rerun-if-env-changed=LIBPCAP_LIBDIR");
     println!("cargo:rerun-if-env-changed=LIBPCAP_VER");

-    let mut libdirpath: Option<PathBuf> = None;
-    if let Ok(libdir) = env::var("LIBPCAP_LIBDIR") {
-        println!("cargo:rustc-link-search=native={}", libdir);
-        libdirpath = Some(PathBuf::from(&libdir));
-    }
+    let version = if let Ok(library) = pkg_config::probe_library("libpcap") {
+        Version::parse(&library.version).unwrap()
+    } else {
+        let mut libdirpath: Option<PathBuf> = None;
+        if let Ok(libdir) = env::var("LIBPCAP_LIBDIR") {
+            println!("cargo:rustc-link-search=native={}", libdir);
+            libdirpath = Some(PathBuf::from(&libdir));
+        }
+        get_pcap_lib_version(libdirpath).unwrap()
+    };

-    let version = get_pcap_lib_version(libdirpath).unwrap();
     emit_cfg_flags(version);
 }
Wojtek242 commented 1 year ago

Hi, looks great! A PR would be welcome!

Rather than feature gating, would it be possible to make build.rs try to detect if pkg-config is installed? If it's not installed then just fall back to the old method.

Also, the PR would need to make sure it runs on all three OSes: Windows, mac, and linux. For those OSes on which it can't work it should just use the old LIBPCAP_LIBDIR method.

The old method should also always be available as the last fallback in case pkg-config is not found.

If that's doable a PR is welcome :-)

Fuuzetsu commented 1 year ago

Rather than feature gating, would it be possible to make build.rs try to detect if pkg-config is installed? If it's not installed then just fall back to the old method.

I think the diff I posted already does this out of the box. If pkg-config is not present, probe_library returns this info inside Error: https://docs.rs/pkg-config/latest/pkg_config/enum.Error.html#variant.Command

The feature gate is only useful if for some reason one wants to not compile the pkg-config rust crate for some reason... if that's not a requirement then no feature gate is needed. I'll send a pull request momentarily.

Stargateur commented 1 year ago

There is not need for extern crate pkg_config; since Rust Edition 2018.

I would also like any help that give user friendly installation of libpcap, the diff proposed look simple enough. If I understand correctly pkg-config crate is not os dep, it's only try to call pkg-config executable and error if not present.