Mercurial > crates > nonstick
diff libpam-sys/build.rs @ 108:e97534be35e3
Make some proc macros for doing cfg-like stuff for PAM impls.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sat, 28 Jun 2025 00:34:45 -0400 |
parents | 49d9e2b5c189 |
children |
line wrap: on
line diff
--- a/libpam-sys/build.rs Thu Jun 26 22:42:32 2025 -0400 +++ b/libpam-sys/build.rs Sat Jun 28 00:34:45 2025 -0400 @@ -1,143 +1,3 @@ -use bindgen::MacroTypeVariation; -use std::error::Error; -use std::fmt::{Debug, Display, Formatter}; -use std::path::PathBuf; -use std::{env, fs}; - -enum PamImpl { - Illumos, - LinuxPam, - OpenPam, -} - -#[derive(Debug)] -struct InvalidEnum(String); - -impl Display for InvalidEnum { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "invalid PAM impl {:?}", self.0) - } -} - -impl Error for InvalidEnum {} - -impl TryFrom<&str> for PamImpl { - type Error = InvalidEnum; - fn try_from(value: &str) -> Result<Self, Self::Error> { - Ok(match value { - "illumos" => Self::Illumos, - "linux-pam" => Self::LinuxPam, - "openpam" => Self::OpenPam, - other => return Err(InvalidEnum(other.to_owned())), - }) - } -} - -impl Debug for PamImpl { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - Debug::fmt( - match self { - Self::Illumos => "illumos", - Self::LinuxPam => "linux-pam", - Self::OpenPam => "openpam", - }, - f, - ) - } -} - fn main() { println!("cargo:rustc-link-lib=pam"); - let out_file = PathBuf::from(env::var("OUT_DIR").unwrap()).join("constants.rs"); - let pam_impl = do_detection(); - - if cfg!(feature = "use-system-headers") { - let builder = bindgen::Builder::default() - .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) - .blocklist_function(".*") - .blocklist_type(".*") - .allowlist_var(".*") - .default_macro_constant_type(MacroTypeVariation::Unsigned); - - let builder = match pam_impl { - PamImpl::Illumos => builder.header_contents( - "illumos.h", - "\ - #include <security/pam_appl.h> - #include <security/pam_modules.h> - ", - ), - PamImpl::LinuxPam => builder.header_contents( - "linux-pam.h", - "\ - #include <security/_pam_types.h> - #include <security/pam_appl.h> - #include <security/pam_ext.h> - #include <security/pam_modules.h> - ", - ), - PamImpl::OpenPam => builder.header_contents( - "openpam.h", - "\ - #include <security/pam_types.h> - #include <security/openpam.h> - #include <security/pam_appl.h> - #include <security/pam_constants.h> - ", - ), - }; - let bindings = builder.generate().unwrap(); - bindings.write_to_file(out_file).unwrap(); - } else { - // Just write empty data to the file to avoid conditional compilation - // shenanigans. - fs::write(out_file, "").unwrap(); - } } - -fn do_detection() -> PamImpl { - println!(r#"cargo:rustc-check-cfg=cfg(pam_impl, values("illumos", "linux-pam", "openpam"))"#); - let pam_impl = _detect_internal(); - println!("cargo:rustc-cfg=pam_impl={pam_impl:?}"); - pam_impl -} - -fn _detect_internal() -> PamImpl { - if let Some(pam_impl) = option_env!("LIBPAMSYS_PAM_IMPL") { - pam_impl.try_into().unwrap() - } else if cfg!(feature = "use-system-headers") { - // Detect which impl it is from system headers. - if header_exists("security/_pam_types.h") { - PamImpl::LinuxPam - } else if header_exists("security/openpam.h") { - PamImpl::OpenPam - } else if header_exists("security/pam_appl.h") { - PamImpl::Illumos - } else { - panic!("could not detect PAM implementation") - } - } else { - // Otherwise, guess what PAM impl we're using based on the OS. - if cfg!(target_os = "linux") { - PamImpl::LinuxPam - } else if cfg!(any( - target_os = "macos", - target_os = "freebsd", - target_os = "netbsd", - target_os = "dragonfly", - target_os = "openbsd" - )) { - PamImpl::OpenPam - } else { - PamImpl::Illumos - } - } -} - -fn header_exists(header: &str) -> bool { - bindgen::Builder::default() - .blocklist_item(".*") - .header_contents("header.h", &format!("#include <{header}>")) - .generate() - .is_ok() -}