From 7781719d2f7f9437aea12cfc0508df9fa4e063ae Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Tue, 23 Mar 2021 12:26:58 -0700 Subject: [PATCH] move glibc version detection logic into its own crate so we can write tests for it --- Cargo.lock | 8 ++++ Cargo.toml | 1 + glibc_version/Cargo.toml | 8 ++++ glibc_version/src/lib.rs | 88 ++++++++++++++++++++++++++++++++++++++++ rust/Cargo.toml | 2 +- rust/build.rs | 37 +---------------- 6 files changed, 108 insertions(+), 36 deletions(-) create mode 100644 glibc_version/Cargo.toml create mode 100644 glibc_version/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index eeb4bd0a09..efe3556bf0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -608,6 +608,7 @@ dependencies = [ "env_logger", "errno", "futures", + "glibc_version", "lazy_static", "libc", "log", @@ -1000,6 +1001,13 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +[[package]] +name = "glibc_version" +version = "0.1.0" +dependencies = [ + "regex", +] + [[package]] name = "h2" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index d13711e34d..f20530f236 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,5 @@ members = [ "ruby", "rust", "python", + "glibc_version", ] diff --git a/glibc_version/Cargo.toml b/glibc_version/Cargo.toml new file mode 100644 index 0000000000..68e0828fc8 --- /dev/null +++ b/glibc_version/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "glibc_version" +version = "0.1.0" +authors = ["Qingping Hou "] +edition = "2018" + +[dependencies] +regex = "1" diff --git a/glibc_version/src/lib.rs b/glibc_version/src/lib.rs new file mode 100644 index 0000000000..ac0e5d0886 --- /dev/null +++ b/glibc_version/src/lib.rs @@ -0,0 +1,88 @@ +pub struct Version { + pub major: usize, + pub minor: usize, +} + +#[cfg(all(target_os = "linux", target_env = "gnu"))] +mod imp { + use super::Version; + use std::process::Command; + + use regex::Regex; + + // glibc version is taken from std/sys/unix/os.rs + pub fn get_version() -> Result { + let output = Command::new("ldd") + .args(&["--version"]) + .output() + .expect("failed to execute ldd"); + let output_str = std::str::from_utf8(&output.stdout).unwrap(); + let version_str = ldd_output_to_version_str(output_str)?; + + parse_glibc_version(version_str) + .ok_or_else(|| format!("Invalid version string from ldd output: {}", version_str,)) + } + + fn ldd_output_to_version_str(output_str: &str) -> Result<&str, String> { + let version_reg = Regex::new(r#"ldd \(.+\) ([0-9]+\.[0-9]+)"#).unwrap(); + if let Some(captures) = version_reg.captures(output_str) { + Ok(captures.get(1).unwrap().as_str()) + } else { + Err(format!( + "ERROR: failed to detect glibc version. ldd output: {}", + output_str, + )) + } + } + + // Returns Some((major, minor)) if the string is a valid "x.y" version, + // ignoring any extra dot-separated parts. Otherwise return None. + fn parse_glibc_version(version: &str) -> Option { + let mut parsed_ints = version.split('.').map(str::parse::).fuse(); + match (parsed_ints.next(), parsed_ints.next()) { + (Some(Ok(major)), Some(Ok(minor))) => Some(Version { major, minor }), + _ => None, + } + } + + #[cfg(test)] + mod tests { + use super::*; + + #[test] + fn parse_ldd_output() { + let ver_str = ldd_output_to_version_str( + r#"ldd (GNU libc) 2.12 +Copyright (C) 2010 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +Written by Roland McGrath and Ulrich Drepper."#, + ) + .unwrap(); + assert_eq!(ver_str, "2.12"); + + let ver_str = ldd_output_to_version_str( + r#"ldd (Ubuntu GLIBC 2.31-0ubuntu9.2) 2.31 + Copyright (C) 2020 Free Software Foundation, Inc. + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + Written by Roland McGrath and Ulrich Drepper."#, + ) + .unwrap(); + assert_eq!(ver_str, "2.31"); + } + } +} + +#[cfg(not(all(target_os = "linux", target_env = "gnu")))] +mod imp { + use super::Version; + pub fn get_version() -> Result { + unimplemented!(); + } +} + +#[inline] +pub fn get_version() -> Result { + imp::get_version() +} diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6319b984e4..a611c13488 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -56,7 +56,7 @@ azure = ["azure_core", "azure_storage", "reqwest"] s3 = ["rusoto_core", "rusoto_credential", "rusoto_s3", "rusoto_sts"] [build-dependencies] -regex = "1" +glibc_version = { path = "../glibc_version" } [dev-dependencies] utime = "0.3" diff --git a/rust/build.rs b/rust/build.rs index 74df66b524..50fb64c859 100644 --- a/rust/build.rs +++ b/rust/build.rs @@ -1,41 +1,8 @@ #[cfg(all(target_os = "linux", target_env = "gnu"))] mod platform_cfg { - // glibc version is taken from std/sys/unix/os.rs - pub fn glibc_version() -> (usize, usize) { - use regex::Regex; - use std::process::Command; - - let output = Command::new("ldd") - .args(&["--version"]) - .output() - .expect("failed to execute ldd"); - let output_str = std::str::from_utf8(&output.stdout).unwrap(); - - let version_reg = Regex::new(r#"ldd \(.+\) ([0-9]+\.[0-9]+)"#).unwrap(); - if let Some(captures) = version_reg.captures(output_str) { - let version_str = captures.get(1).unwrap().as_str(); - parse_glibc_version(version_str).unwrap() - } else { - panic!( - "ERROR: failed to detect glibc version. ldd output: {}", - output_str - ); - } - } - - // Returns Some((major, minor)) if the string is a valid "x.y" version, - // ignoring any extra dot-separated parts. Otherwise return None. - fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { - let mut parsed_ints = version.split('.').map(str::parse::).fuse(); - match (parsed_ints.next(), parsed_ints.next()) { - (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), - _ => None, - } - } - fn detect_glibc_renameat2() { - let (major, minor) = glibc_version(); - if major >= 2 && minor >= 28 { + let ver = glibc_version::get_version().unwrap(); + if ver.major >= 2 && ver.minor >= 28 { println!("cargo:rustc-cfg=glibc_renameat2"); } }