# HG changeset patch # User Paul Fisher # Date 1754174866 14400 # Node ID 995aca290452fdccd9a6963557c4491160d2338a # Parent b2456d274576a569e07a3ea150b26a7539c93850 Restructure the way libpam-sys-impls works to fix cross-compilation. The previous structure of libpam-sys-impls meant that things got confusing (including for me) between what constants were build-time and what constants were run-time. This broke cross-compilation. This simplifies the way that works so that `libpam-sys-impls` has *no* build script itself and is intended mostly as a library to be included in other libraries' build scripts (while also exporting the PamImpl enum). diff -r b2456d274576 -r 995aca290452 libpam-sys/build.rs --- a/libpam-sys/build.rs Thu Jul 31 15:42:12 2025 -0400 +++ b/libpam-sys/build.rs Sat Aug 02 18:47:46 2025 -0400 @@ -1,4 +1,26 @@ +use std::{env, fs}; + fn main() { println!("cargo:rustc-link-lib=pam"); libpam_sys_impls::enable_pam_impl_cfg(); + + let pam_impl = libpam_sys_impls::build_target_impl(); + let impl_str = pam_impl.map(|i| format!("{i:?}")).unwrap_or("[undefined]".into()); + println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}"); + let output = match pam_impl { + None => "".into(), + Some(pam_impl) => { + format!("\ + /// The implementation of PAM this library was built against. + pub const CURRENT: PamImpl = PamImpl::{pam_impl:?}; + /// The name of the PAM implementation this library was built + /// against, as a string. + #[macro_export] + macro_rules! pam_impl_name {{ () => {{ \"{pam_impl:?}\" }} }} + pub(crate) use pam_impl_name; + ") + } + }; + let outfile = format!("{out}/pam_impl_consts.rs", out = env::var("OUT_DIR").expect("missing OUT_DIR env var")); + fs::write(outfile, output).expect("couldn't write output file"); } diff -r b2456d274576 -r 995aca290452 libpam-sys/libpam-sys-impls/README.md --- a/libpam-sys/libpam-sys-impls/README.md Thu Jul 31 15:42:12 2025 -0400 +++ b/libpam-sys/libpam-sys-impls/README.md Sat Aug 02 18:47:46 2025 -0400 @@ -1,66 +1,12 @@ # `libpam-sys-impls`: LibPAM library detection This crate detects what implementation of LibPAM should be used, as part of the build script, and exports that information to downstream crates. +It can also be used at runtime, but is primarily intended for build scripts. -This is mostly a backend crate for [libpam-sys](https://crates.io/crates/libpam-sys/). +Its main use is as a backend for [libpam-sys](https://crates.io/crates/libpam-sys/). That crate re-exports pretty much everything we provide. In most cases, you can just use that instead of depending upon this directly. -## Usage - -Different PAM implementations have different constants and some different behaviors. -If you need to change your library's behavior based on PAM implementation, there are a few ways to do so. - -### Constants - -You can match on the current PAM implementation at runtime. -All known PAM implementations are in the `PamImpl` enumeration, and `PamImpl::CURRENT` is set to the current implementation. -This is present as a string literal macro in `pam_impl_name!`. - -### Conditional compilation - -This package provides custom `#[cfg]`s to compile based on the current PAM implementation. - -First, **enable custom `#[cfg]`s in your build.rs**: - -```rust -// build.rs -use libpam_sys_impls::pam_impl; - -fn main() { - pam_impl::enable_pam_impl_cfg(); - - // everything else you do at build time -} -``` - -This will then allow you to use the `pam_impl` configuration variable at compile time: - -```rust -#[cfg(pam_impl = "LinuxPam")] -fn handle_pam() { - // do things in a Linux-PAM specific way -} - -#[cfg(not(pam_impl = "LinuxPam"))] -fn handle_pam() { - // do things in another, more different way -} -``` - -## Configuration - -Known implementations of PAM are listed in the `PamImpl` enum, and your currently installed implementation is automatically detected. - -If you need to configure this, you can override it **at build time** with the `LIBPAMSYS_IMPL` environment variable: - -- Unset or empty (the default): Use the version of PAM most commonly found on the target OS. - If we don't know what kind of PAM is usually installed on this OS, we fall back to `__installed__`. -- `__installed__`: Looks at the PAM library installed on the current machine. - If none is recognized, falls back to `XSso`. -- The name of a `PamImpl` entry: The named PAM implementation. - For instance, `LIBPAMSYS_IMPL=OpenPam cargo build` will build this library for OpenPAM. - ## MSRV This library supports **Rust 1.75**, as the version currently (July 2025) available in Debian Trixie and Ubuntu 24.04 LTS. \ No newline at end of file diff -r b2456d274576 -r 995aca290452 libpam-sys/libpam-sys-impls/build.rs --- a/libpam-sys/libpam-sys-impls/build.rs Thu Jul 31 15:42:12 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -#![allow(unexpected_cfgs)] - -use std::ffi::{c_void, CString}; -use std::ptr::NonNull; -use std::{env, fs}; - -include!("src/pam_impl.rs"); - -/// The strategy to use to detect PAM. -enum Detect { - /// Use the default PAM implementation based on the OS, - /// or the currently-installed version if the OS is not recognized. - TargetDefault, - /// Detect the installed implementation. - Installed, - /// Use the named version of PAM. - Specified(PamImpl), -} - -const INSTALLED: &str = "__installed__"; - -fn main() { - let detection = match option_env!("LIBPAMSYS_IMPL") { - Some("") | None => Detect::TargetDefault, - Some(INSTALLED) => Detect::Installed, - Some(val) => Detect::Specified(PamImpl::try_from(val).unwrap_or_else(|_| { - panic!( - "unknown PAM implementation {val:?}. \ - valid LIBPAMSYS_IMPLs are {:?}, \ - {INSTALLED:?} to use the currently-installed version, \ - or unset to use the OS default", - PamImpl::items() - ) - })), - }; - let pam_impl = match detection { - Detect::TargetDefault => LibPam::target_default(), - Detect::Installed => LibPam::probe_detect(), - Detect::Specified(other) => other, - }; - let impl_str = format!("{pam_impl:?}"); - println!("{}", generate_cfg(&impl_str)); - // We set this environment variable to substitute into docstrings. - println!("cargo:rustc-env=LIBPAMSYS_IMPL={impl_str}"); - fs::write( - format!("{}/pam_impl_const.rs", env::var("OUT_DIR").unwrap()), - generate_consts(&impl_str), - ) - .unwrap(); -} - -fn generate_consts(impl_str: &str) -> String { - format!( - "\ -impl PamImpl {{ -/// The implementation of libpam this was built for (`{impl_str}`). -pub const CURRENT: Self = Self::{impl_str}; -}} - -/// String name of [`PamImpl::CURRENT`], for substituting into docs. -#[macro_export] -macro_rules! pam_impl_name {{ () => ({impl_str:?}) }} - " - ) -} - -struct LibPam(NonNull); - -impl LibPam { - /// Guess the PAM implementation based on the current OS. - fn target_default() -> PamImpl { - 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 if cfg!(any(target_os = "illumos", target_os = "solaris")) { - PamImpl::Sun - } else { - Self::probe_detect() - } - } - - /// Look at the currently-installed LibPAM. - fn probe_detect() -> PamImpl { - if let Some(lib) = Self::open() { - if lib.has("pam_syslog") { - return PamImpl::LinuxPam; - } else if lib.has("_openpam_log") { - return PamImpl::OpenPam; - } else if lib.has("__pam_get_authtok") { - return PamImpl::Sun; - } - } - // idk - PamImpl::XSso - } - - fn open() -> Option { - let dlopen = |s: &[u8]| unsafe { libc::dlopen(s.as_ptr().cast(), libc::RTLD_LAZY) }; - NonNull::new(dlopen(b"libpam.so\0")) - .or_else(|| NonNull::new(dlopen(b"libpam.dylib\0"))) - .map(Self) - } - - fn has(&self, name: &str) -> bool { - let name = CString::new(name).unwrap(); - let symbol = unsafe { libc::dlsym(self.0.as_ptr(), name.as_ptr()) }; - !symbol.is_null() - } -} - -impl Drop for LibPam { - fn drop(&mut self) { - unsafe { - libc::dlclose(self.0.as_ptr()); - } - } -} diff -r b2456d274576 -r 995aca290452 libpam-sys/libpam-sys-impls/src/lib.rs --- a/libpam-sys/libpam-sys-impls/src/lib.rs Thu Jul 31 15:42:12 2025 -0400 +++ b/libpam-sys/libpam-sys-impls/src/lib.rs Sat Aug 02 18:47:46 2025 -0400 @@ -1,53 +1,267 @@ -//! Information about the PAM implementation you're using right now. +#![allow(clippy::needless_doctest_main)] +//! An enumeration of PAM implementations and tools to detect them. //! -//! This module contains constants and values that can be used at build-script, -//! compile, and run time to determine what PAM implementation you're using. +//! # Configuration //! -//! ## Always available +//! When used at compile time, this crate uses the target OS by default, +//! but can be overridden with the `LIBPAMSYS_IMPL` environment variable. +//! See the documentation of [`build_target_impl`] for details. //! -//! [`PamImpl::CURRENT`] will tell you what version of PAM you're using. -//! It can be imported in any Rust code, from build scripts to runtime. +//! # Detecting PAM //! -//! ## Compile time +//! ## Build time //! //! Use [`enable_pam_impl_cfg`] in your `build.rs` to generate custom `#[cfg]`s //! for conditional compilation based on PAM implementation. //! -//! ``` -//! // Your package's build.rs: +//! To detect the implementation that will be used at runtime, use the +//! [`build_target_impl`] function. //! -//! fn main() { -//! // Also available at libpam_sys::pam_impl::enable_pam_impl_cfg(). -//! libpam_sys_impls::enable_pam_impl_cfg(); -//! // whatever else you do in your build script. -//! } -//! ``` -//! -//! This will set the current `pam_impl` as well as registering all known -//! PAM implementations with `rustc-check-cfg` to get cfg-checking. -//! -//! The names that appear in the `cfg` variables are the same as the values -//! in the [`PamImpl`] enum. +//! ## Run time //! -//! ```ignore -//! #[cfg(pam_impl = "OpenPam")] -//! fn openpam_specific_func(handle: *const libpam_sys::pam_handle) { -//! let environ = libpam_sys::pam_getenvlist(handle); -//! // ... -//! libpam_sys::openpam_free_envlist() -//! } -//! -//! // This will give you a warning since "UnknownImpl" is not in the cfg. -//! #[cfg(not(pam_impl = "UnknownImpl"))] -//! fn do_something() { -//! // ... -//! } -//! ``` -//! -//! The [`pam_impl_name!`] macro will expand to this same value, currently -#![doc = concat!("`", env!("LIBPAMSYS_IMPL"), "`.")] +//! The implementation of PAM installed on the machine where the code is running +//! can be detected with [`currently_installed`], or you can use +//! [`os_default`] to see what implementation is used on a given target. + +use std::env; +use std::env::VarError; +use std::ffi::c_void; +use std::ptr::NonNull; + +/// An enum that knows its own values. +macro_rules! self_aware_enum { + ( + $(#[$enumeta:meta])* + $viz:vis enum $name:ident { + $( + $(#[$itemeta:meta])* + $item:ident, + )* + } + ) => { + $(#[$enumeta])* + $viz enum $name { + $( + $(#[$itemeta])* + $item, + )* + } + + // The implementations in this block are private for now + // to avoid putting a contract into the public API. + #[allow(dead_code)] + impl $name { + /// Iterator over the items in the enum. For internal use. + pub(crate) fn items() -> Vec { + vec![$(Self::$item),*] + } + + /// Attempts to parse the enum from the string. For internal use. + pub(crate) fn try_from(value: &str) -> Result { + match value { + $(stringify!($item) => Ok(Self::$item),)* + _ => Err(value.into()), + } + } + } + }; +} + +self_aware_enum! { + /// The PAM implementations supported by `libpam-sys`. + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + #[non_exhaustive] + pub enum PamImpl { + /// [Linux-PAM] is provided by most Linux distributions. + /// + /// [Linux-PAM]: https://github.com/linux-pam/linux-pam + LinuxPam, + /// [OpenPAM] is used by most BSDs, including Mac OS X. + /// + /// [OpenPAM]: https://git.des.dev/OpenPAM/OpenPAM + OpenPam, + /// Illumos and Solaris use a derivative of [Sun's implementation][sun]. + /// + /// [sun]: https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/lib/libpam + Sun, + /// Only the functionality and constants in [the PAM spec]. + /// + /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm + XSso, + } +} + +#[allow(clippy::needless_doctest_main)] +/// Generates `cargo` directives for build scripts to enable `cfg(pam_impl)`. +/// +/// Print this in your `build.rs` script to be able to use the custom `pam_impl` +/// configuration directive. +/// +/// ``` +/// // Your package's build.rs: +/// +/// fn main() { +/// // Also available at libpam_sys::pam_impl::enable_pam_impl_cfg(). +/// libpam_sys_impls::enable_pam_impl_cfg(); +/// // whatever else you do in your build script. +/// } +/// ``` +/// +/// This will set the current `pam_impl` as well as registering all known +/// PAM implementations with `rustc-check-cfg` to get cfg-checking. +/// +/// The names that appear in the `cfg` variables are the same as the values +/// in the [`PamImpl`] enum. +/// +/// ```ignore +/// #[cfg(pam_impl = "OpenPam")] +/// fn openpam_specific_func(handle: *const libpam_sys::pam_handle) { +/// let environ = libpam_sys::pam_getenvlist(handle); +/// // ... +/// libpam_sys::openpam_free_envlist() +/// } +/// +/// // This will give you a warning since "UnknownImpl" is not a known +/// // PAM implementation. +/// #[cfg(not(pam_impl = "UnknownImpl"))] +/// fn do_something() { +/// // ... +/// } +/// ``` +pub fn enable_pam_impl_cfg() { + println!("{}", pam_impl_cfg_string()) +} + +/// [`enable_pam_impl_cfg`], but returned as a string. +pub fn pam_impl_cfg_string() -> String { + generate_cfg(build_target_impl()) +} -mod pam_impl; +fn generate_cfg(pam_impl: Option) -> String { + let impls: Vec<_> = PamImpl::items() + .into_iter() + .map(|i| format!(r#""{i:?}""#)) + .collect(); + let mut lines = vec![ + format!( + "cargo:rustc-check-cfg=cfg(pam_impl, values({impls}))", + impls = impls.join(",") + ), + "cargo:rustc-cfg=pam_impl".into(), + ]; + if let Some(pam_impl) = pam_impl { + lines.push("cargo:rustc-cfg=pam_impl".into()); + lines.push(format!("cargo:rustc-cfg=pam_impl=\"{pam_impl:?}\"")); + } + lines.join("\n") +} + +/// The strategy to use to detect PAM. +enum Detect { + /// Use the default PAM implementation based on the target OS. + TargetDefault, + /// Detect the installed implementation. + Installed, + /// Use the named version of PAM. + Specified(PamImpl), +} + +const INSTALLED: &str = "__installed__"; -#[doc(inline)] -pub use pam_impl::*; +/// For `build.rs` use: Detects the PAM implementation that should be used +/// for the target of the currently-running build script. +/// +/// # Configuration +/// +/// The PAM implementation selected depends upon the value of the +/// `LIBPAMSYS_IMPL` environment variable. +/// +/// - Empty or unset (default): Use the default PAM implementation for the +/// Cargo target OS (as specified by `CARGO_CFG_TARGET_OS`). +/// - Linux: Linux-PAM +/// - BSD (and Mac): OpenPAM +/// - Illumos/Solaris: Sun PAM +/// - `__installed__`: Use the PAM implementation installed on the host system. +/// This opens the `libpam` library and looks for specific functions. +/// - The name of a [PamImpl] member: Use that PAM implementation. +/// +/// # Panics +/// +/// If an unknown PAM implementation is provided in `LIBPAMSYS_IMPL`. +pub fn build_target_impl() -> Option { + let detection = match env::var("LIBPAMSYS_IMPL").as_deref() { + Ok("") | Err(VarError::NotPresent) => Detect::TargetDefault, + Ok(INSTALLED) => Detect::Installed, + Ok(val) => Detect::Specified(PamImpl::try_from(val).unwrap_or_else(|_| { + panic!( + "unknown PAM implementation {val:?}. \ + valid LIBPAMSYS_IMPL values are {:?}, \ + {INSTALLED:?} to use the currently-installed version, \ + or unset to use the OS default", + PamImpl::items() + ) + })), + Err(other) => panic!("Couldn't detect PAM version: {other}"), + }; + match detection { + Detect::TargetDefault => env::var("CARGO_CFG_TARGET_OS") + .ok() + .as_deref() + .and_then(os_default), + Detect::Installed => currently_installed(), + Detect::Specified(other) => Some(other), + } +} + +/// Gets the PAM version based on the target OS. +/// +/// The target OS name passed in is one of the [Cargo target OS values][os]. +/// +/// [os]: https://doc.rust-lang.org/reference/conditional-compilation.html#r-cfg.target_os.values +pub fn os_default(target_os: &str) -> Option { + match target_os { + "linux" => Some(PamImpl::LinuxPam), + "macos" | "freebsd" | "netbsd" | "dragonfly" | "openbsd" => Some(PamImpl::OpenPam), + "illumos" | "solaris" => Some(PamImpl::Sun), + _ => None, + } +} + +/// The version of LibPAM installed on this machine (as found by `dlopen`). +pub fn currently_installed() -> Option { + LibPam::open().map(|lib| { + if lib.has(b"pam_syslog\0") { + PamImpl::LinuxPam + } else if lib.has(b"_openpam_log\0") { + PamImpl::OpenPam + } else if lib.has(b"__pam_get_authtok\0") { + PamImpl::Sun + } else { + PamImpl::XSso + } + }) +} + +struct LibPam(NonNull); + +impl LibPam { + fn open() -> Option { + let dlopen = |s: &[u8]| unsafe { libc::dlopen(s.as_ptr().cast(), libc::RTLD_LAZY) }; + NonNull::new(dlopen(b"libpam.so\0")) + .or_else(|| NonNull::new(dlopen(b"libpam.dylib\0"))) + .map(Self) + } + + fn has(&self, name: &[u8]) -> bool { + let symbol = unsafe { libc::dlsym(self.0.as_ptr(), name.as_ptr().cast()) }; + !symbol.is_null() + } +} + +impl Drop for LibPam { + fn drop(&mut self) { + unsafe { + libc::dlclose(self.0.as_ptr()); + } + } +} diff -r b2456d274576 -r 995aca290452 libpam-sys/libpam-sys-impls/src/pam_impl.rs --- a/libpam-sys/libpam-sys-impls/src/pam_impl.rs Thu Jul 31 15:42:12 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -// This file is include!d directly by `../build.rs`, so its doc comment -// is found in lib.rs. - -/// An enum that knows its own values. -macro_rules! self_aware_enum { - ( - $(#[$enumeta:meta])* - $viz:vis enum $name:ident { - $( - $(#[$itemeta:meta])* - $item:ident, - )* - } - ) => { - $(#[$enumeta])* - $viz enum $name { - $( - $(#[$itemeta])* - $item, - )* - } - - // The implementations in this block are private for now - // to avoid putting a contract into the public API. - #[allow(dead_code)] - impl $name { - /// Iterator over the items in the enum. For internal use. - fn items() -> Vec { - vec![$(Self::$item),*] - } - - /// Attempts to parse the enum from the string. For internal use. - fn try_from(value: &str) -> Result { - match value { - $(stringify!($item) => Ok(Self::$item),)* - _ => Err(value.into()), - } - } - } - }; -} - -self_aware_enum! { - /// The PAM implementations supported by `libpam-sys`. - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - #[cfg_attr(pam_impl, non_exhaustive)] - pub enum PamImpl { - /// [Linux-PAM] is provided by most Linux distributions. - /// - /// [Linux-PAM]: https://github.com/linux-pam/linux-pam - LinuxPam, - /// [OpenPAM] is used by most BSDs, including Mac OS X. - /// - /// [OpenPAM]: https://git.des.dev/OpenPAM/OpenPAM - OpenPam, - /// Illumos and Solaris use a derivative of [Sun's implementation][sun]. - /// - /// [sun]: https://code.illumos.org/plugins/gitiles/illumos-gate/+/refs/heads/master/usr/src/lib/libpam - Sun, - /// Only the functionality and constants in [the PAM spec]. - /// - /// [the PAM spec]: https://pubs.opengroup.org/onlinepubs/8329799/toc.htm - XSso, - } -} - -// This generated file contains: -// - pam_impl_name! -// - PamImpl::CURRENT -#[cfg(pam_impl)] -include!(concat!(env!("OUT_DIR"), "/pam_impl_const.rs")); - -#[allow(clippy::needless_doctest_main)] -/// Generates `cargo` directives for build scripts to enable `cfg(pam_impl)`. -/// -/// Print this in your `build.rs` script to be able to use the custom `pam_impl` -/// configuration directive. -/// -/// ``` -/// // build.rs -/// fn main() { -/// libpam_sys_impls::enable_pam_impl_cfg(); -/// -/// // Whatever other stuff you do in your build.rs. -/// } -/// ``` -#[cfg(pam_impl)] -pub fn enable_pam_impl_cfg() { - println!("{}", pam_impl_cfg_string()) -} - -/// Generates the `cargo:` directives to print in build scripts. -#[cfg(pam_impl)] -pub fn pam_impl_cfg_string() -> String { - generate_cfg(pam_impl_name!()) -} - -fn generate_cfg(name: &str) -> String { - let impls: Vec<_> = PamImpl::items() - .into_iter() - .map(|i| format!(r#""{i:?}""#)) - .collect(); - format!( - "\ -cargo:rustc-check-cfg=cfg(pam_impl) -cargo:rustc-check-cfg=cfg(pam_impl, values({impls})) -cargo:rustc-cfg=pam_impl -cargo:rustc-cfg=pam_impl={name:?} - ", - impls = impls.join(",") - ) -} diff -r b2456d274576 -r 995aca290452 libpam-sys/libpam-sys-test/build.rs --- a/libpam-sys/libpam-sys-test/build.rs Thu Jul 31 15:42:12 2025 -0400 +++ b/libpam-sys/libpam-sys-test/build.rs Sat Aug 02 18:47:46 2025 -0400 @@ -1,5 +1,5 @@ use bindgen::MacroTypeVariation; -use libpam_sys_impls::pam_impl_name; +use libpam_sys::pam_impl_name; use libpam_sys_impls::PamImpl; use proc_macro2::{Group, Ident, TokenStream, TokenTree}; use quote::{format_ident, ToTokens}; @@ -13,7 +13,7 @@ fn main() { libpam_sys_impls::enable_pam_impl_cfg(); - let config = match PamImpl::CURRENT { + let config = match libpam_sys::pam_impl::CURRENT { PamImpl::LinuxPam => TestConfig { headers: vec![ "", @@ -76,8 +76,8 @@ "#[allow(deprecated, overflowing_literals)]".into(), "fn main() {".into(), format!( - "assert_eq!(libpam_sys::pam_impl::PamImpl::CURRENT, libpam_sys::pam_impl::PamImpl::{:?});", - PamImpl::CURRENT + "assert_eq!(libpam_sys::pam_impl::CURRENT, libpam_sys::pam_impl::PamImpl::{:?});", + libpam_sys::pam_impl::CURRENT ), ]; tests.extend( diff -r b2456d274576 -r 995aca290452 libpam-sys/src/constants.rs --- a/libpam-sys/src/constants.rs Thu Jul 31 15:42:12 2025 -0400 +++ b/libpam-sys/src/constants.rs Sat Aug 02 18:47:46 2025 -0400 @@ -172,6 +172,7 @@ } } + #[doc(inline)] pub use pam_modutil_redirect_fd::*; } diff -r b2456d274576 -r 995aca290452 libpam-sys/src/lib.rs --- a/libpam-sys/src/lib.rs Thu Jul 31 15:42:12 2025 -0400 +++ b/libpam-sys/src/lib.rs Sat Aug 02 18:47:46 2025 -0400 @@ -9,12 +9,12 @@ //! for callback types used in libpam, so you don't have to type //! `unsafe extern "C" fn(this is so long)` all the time. #![doc = ""] -#![doc = concat!("This documentation was built for the **", pam_impl_name!(), "** implementation.")] +#![doc = concat!("This documentation was built for the **", env!("LIBPAMSYS_IMPL"), "** implementation.")] //! //! You can override this **at build time** by setting the `LIBPAMSYS_IMPL` //! environment variable to one of the values of the [`pam_impl::PamImpl`] enum. -//! For more information about configuration, see the documentation of -//! [`libpam-sys-impls`](https://crates.io/crates/libpam-sys-impls). +//! For more information about configuration, see [the documentation of +//! libpam-sys-impls](libpam_sys_impls::build_target_impl). #![allow(non_camel_case_types)] #![allow(unused_imports)] @@ -23,7 +23,12 @@ mod ffi; #[doc(inline)] pub use crate::{constants::*, ffi::*}; -#[doc(inline)] -pub use libpam_sys_impls as pam_impl; -#[doc(inline)] -pub use libpam_sys_impls::pam_impl_name; + +/// Information about the current PAM implementation (or the implementation +/// that is being built for). +pub mod pam_impl { + #[doc(inline)] + pub use libpam_sys_impls::{PamImpl, enable_pam_impl_cfg, pam_impl_cfg_string}; + + include!(concat!(env!("OUT_DIR"), "/pam_impl_consts.rs")); +} diff -r b2456d274576 -r 995aca290452 src/lib.rs --- a/src/lib.rs Thu Jul 31 15:42:12 2025 -0400 +++ b/src/lib.rs Sat Aug 02 18:47:46 2025 -0400 @@ -257,4 +257,6 @@ handle::{ModuleClient, PamShared, Transaction}, module::PamModule, }; -use libpam_sys_impls::pam_impl_name; +#[doc(inline)] +pub use libpam_sys::pam_impl; +use libpam_sys::pam_impl_name;