Skip to content

Commit

Permalink
fix: add gentoo support for glibc (#779)
Browse files Browse the repository at this point in the history
Add support for gentoo glibc.
  • Loading branch information
baszalmstra authored Jul 16, 2024
1 parent 11121a4 commit 5a5a416
Showing 1 changed file with 49 additions and 20 deletions.
69 changes: 49 additions & 20 deletions crates/rattler_virtual_packages/src/libc.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! Low-level functions to detect the `LibC` family and version. See [`libc_family_and_version`].
//! Low-level functions to detect the `LibC` family and version. See
//! [`libc_family_and_version`].
use once_cell::sync::OnceCell;
use rattler_conda_types::{ParseVersionError, Version};

/// Returns the `LibC` version and family of the current platform.
///
/// Returns an error if determining the `LibC` family and version resulted in an error. Returns
/// `None` if the current platform does not provide a version of `LibC`.
/// Returns an error if determining the `LibC` family and version resulted in an
/// error. Returns `None` if the current platform does not provide a version of
/// `LibC`.
pub fn libc_family_and_version() -> Result<Option<(String, Version)>, DetectLibCError> {
static DETECTED_LIBC_VERSION: OnceCell<Option<(String, Version)>> = OnceCell::new();
DETECTED_LIBC_VERSION
Expand All @@ -22,24 +24,21 @@ pub enum DetectLibCError {
ParseLibCVersion(#[from] ParseVersionError),
}

/// Tries to detected the libc family and version that is available on the system.
/// Tries to detected the libc family and version that is available on the
/// system.
///
/// Note that this may differ from the libc version against which this binary was build. For
/// instance when compiling against musl libc the resulting binary can still run on a glibc based
/// system. For environments we are interested in the libc family that is available on the *system*.
/// Note that this may differ from the libc version against which this binary
/// was build. For instance when compiling against musl libc the resulting
/// binary can still run on a glibc based system. For environments we are
/// interested in the libc family that is available on the *system*.
///
/// Currently this code is only able to detect glibc properly. We can add more detection methods in
/// the future.
/// Currently this code is only able to detect glibc properly. We can add more
/// detection methods in the future.
#[cfg(unix)]
fn try_detect_libc_version() -> Result<Option<(String, Version)>, DetectLibCError> {
// GNU libc writes to stdout
static GNU_LIBC_RE: once_cell::sync::Lazy<regex::Regex> = once_cell::sync::Lazy::new(|| {
regex::Regex::new("(?mi)(?:glibc|gnu libc).*?([0-9]+(:?.[0-9]+)*)$").unwrap()
});

// Run `ldd --version` to detect the libc version and family on the system. `ldd` is shipped
// with libc so if an error occured during its execution we can assume no libc is available on
// the system.
// Run `ldd --version` to detect the libc version and family on the system.
// `ldd` is shipped with libc so if an error occured during its execution we
// can assume no libc is available on the system.
let output = match std::process::Command::new("ldd").arg("--version").output() {
Err(e) => {
tracing::info!(
Expand All @@ -50,15 +49,25 @@ fn try_detect_libc_version() -> Result<Option<(String, Version)>, DetectLibCErro
Ok(output) => output,
};

let stdout = String::from_utf8_lossy(&output.stdout);
Ok(
parse_glibc_ldd_version(&String::from_utf8_lossy(&output.stdout))?
.map(|version| (String::from("glibc"), version)),
)
}

#[cfg(any(test, unix))]
fn parse_glibc_ldd_version(input: &str) -> Result<Option<Version>, DetectLibCError> {
static GNU_LIBC_RE: once_cell::sync::Lazy<regex::Regex> = once_cell::sync::Lazy::new(|| {
regex::Regex::new("(?mi)(?:glibc|gentoo|gnu libc).*?([0-9]+(:?.[0-9]+)*)$").unwrap()
});

if let Some(version_match) = GNU_LIBC_RE
.captures(&stdout)
.captures(input)
.and_then(|captures| captures.get(1))
.map(|version_match| version_match.as_str())
{
let version = std::str::FromStr::from_str(version_match)?;
return Ok(Some((String::from("glibc"), version)));
return Ok(Some(version));
}

Ok(None)
Expand All @@ -71,10 +80,30 @@ const fn try_detect_libc_version() -> Result<Option<(String, Version)>, DetectLi

#[cfg(test)]
mod test {
use std::str::FromStr;

use super::*;

#[test]
#[cfg(unix)]
pub fn doesnt_crash() {
let version = super::try_detect_libc_version().unwrap();
println!("LibC {version:?}");
}

#[test]
pub fn test_parse_glibc_ldd_version() {
assert_eq!(
parse_glibc_ldd_version("ldd (Ubuntu GLIBC 2.35-0ubuntu3.1) 2.35").unwrap(),
Some(Version::from_str("2.35").unwrap())
);
assert_eq!(
parse_glibc_ldd_version("ldd (Gentoo 2.39-r9 (patchset 9)) 2.39").unwrap(),
Some(Version::from_str("2.39").unwrap())
);
assert_eq!(
parse_glibc_ldd_version("ldd (GNU libc) 2.31").unwrap(),
Some(Version::from_str("2.31").unwrap())
);
}
}

0 comments on commit 5a5a416

Please sign in to comment.