diff libpam-sys/libpam-sys-helpers/src/pam_impl.rs @ 136:efbc235f01d3

Separate libpam-sys-helpers from libpam-sys. This separates the parts of libpam-sys that don't need linking against libpam from the parts that do need to link against libpam.
author Paul Fisher <paul@pfish.zone>
date Thu, 03 Jul 2025 14:28:04 -0400
parents libpam-sys/src/pam_impl.rs@6c1e1bdb4164
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpam-sys/libpam-sys-helpers/src/pam_impl.rs	Thu Jul 03 14:28:04 2025 -0400
@@ -0,0 +1,113 @@
+// 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<Self> {
+                vec![$(Self::$item),*]
+            }
+
+            /// Attempts to parse the enum from the string. For internal use.
+            fn try_from(value: &str) -> Result<Self, String> {
+                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
+/// use libpam_sys_helpers::pam_impl;
+/// fn main() {
+///     pam_impl::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(",")
+    )
+}