Skip to content

Commit 9dd6dc2

Browse files
authored
cli: check glibc version more correctly on gnu (microsoft#166622)
Fixes microsoft/vscode-remote-release#7495
1 parent 061e754 commit 9dd6dc2

File tree

1 file changed

+57
-26
lines changed

1 file changed

+57
-26
lines changed

cli/src/util/prereqs.rs

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use super::errors::AnyError;
1717
lazy_static! {
1818
static ref LDCONFIG_STDC_RE: Regex = Regex::new(r"libstdc\+\+.* => (.+)").unwrap();
1919
static ref LDD_VERSION_RE: BinRegex = BinRegex::new(r"^ldd.*(.+)\.(.+)\s").unwrap();
20+
static ref GENERIC_VERSION_RE: Regex = Regex::new(r"^([0-9]+)\.([0-9]+)$").unwrap();
2021
static ref LIBSTD_CXX_VERSION_RE: BinRegex =
2122
BinRegex::new(r"GLIBCXX_([0-9]+)\.([0-9]+)(?:\.([0-9]+))?").unwrap();
2223
static ref MIN_CXX_VERSION: SimpleSemver = SimpleSemver::new(3, 4, 18);
@@ -116,13 +117,23 @@ async fn check_musl_interpreter() -> Result<(), String> {
116117

117118
#[allow(dead_code)]
118119
async fn check_glibc_version() -> Result<(), String> {
119-
let ldd_version = capture_command("ldd", ["--version"])
120-
.await
121-
.ok()
122-
.and_then(|o| extract_ldd_version(&o.stdout));
120+
#[cfg(target_env = "gnu")]
121+
let version = {
122+
let v = unsafe { libc::gnu_get_libc_version() };
123+
let v = unsafe { std::ffi::CStr::from_ptr(v) };
124+
let v = v.to_str().unwrap();
125+
extract_generic_version(v)
126+
};
127+
#[cfg(not(target_env = "gnu"))]
128+
let version = {
129+
capture_command("ldd", ["--version"])
130+
.await
131+
.ok()
132+
.and_then(|o| extract_ldd_version(&o.stdout))
133+
};
123134

124-
if let Some(v) = ldd_version {
125-
return if v.gte(&MIN_LDD_VERSION) {
135+
if let Some(v) = version {
136+
return if v >= *MIN_LDD_VERSION {
126137
Ok(())
127138
} else {
128139
Err(format!(
@@ -181,7 +192,7 @@ fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<(), String
181192
})
182193
.collect();
183194

184-
if !all_versions.iter().any(|v| MIN_CXX_VERSION.gte(v)) {
195+
if !all_versions.iter().any(|v| &*MIN_CXX_VERSION >= v) {
185196
return Err(format!(
186197
"find GLIBCXX >= 3.4.18 (but found {} instead) for GNU environments",
187198
all_versions
@@ -195,6 +206,7 @@ fn check_for_sufficient_glibcxx_versions(contents: Vec<u8>) -> Result<(), String
195206
Ok(())
196207
}
197208

209+
#[allow(dead_code)]
198210
fn extract_ldd_version(output: &[u8]) -> Option<SimpleSemver> {
199211
LDD_VERSION_RE.captures(output).map(|m| SimpleSemver {
200212
major: m.get(1).map_or(0, |s| u32_from_bytes(s.as_bytes())),
@@ -203,6 +215,15 @@ fn extract_ldd_version(output: &[u8]) -> Option<SimpleSemver> {
203215
})
204216
}
205217

218+
#[allow(dead_code)]
219+
fn extract_generic_version(output: &str) -> Option<SimpleSemver> {
220+
GENERIC_VERSION_RE.captures(output).map(|m| SimpleSemver {
221+
major: m.get(1).map_or(0, |s| s.as_str().parse().unwrap()),
222+
minor: m.get(2).map_or(0, |s| s.as_str().parse().unwrap()),
223+
patch: 0,
224+
})
225+
}
226+
206227
fn extract_libstd_from_ldconfig(output: &[u8]) -> Option<String> {
207228
String::from_utf8_lossy(output)
208229
.lines()
@@ -215,13 +236,35 @@ fn u32_from_bytes(b: &[u8]) -> u32 {
215236
String::from_utf8_lossy(b).parse::<u32>().unwrap_or(0)
216237
}
217238

218-
#[derive(Debug, PartialEq)]
239+
#[derive(Debug, Default, PartialEq, Eq)]
219240
struct SimpleSemver {
220241
major: u32,
221242
minor: u32,
222243
patch: u32,
223244
}
224245

246+
impl PartialOrd for SimpleSemver {
247+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
248+
Some(self.cmp(other))
249+
}
250+
}
251+
252+
impl Ord for SimpleSemver {
253+
fn cmp(&self, other: &Self) -> Ordering {
254+
let major = self.major.cmp(&other.major);
255+
if major != Ordering::Equal {
256+
return major;
257+
}
258+
259+
let minor = self.minor.cmp(&other.minor);
260+
if minor != Ordering::Equal {
261+
return minor;
262+
}
263+
264+
self.patch.cmp(&other.patch)
265+
}
266+
}
267+
225268
impl From<&SimpleSemver> for String {
226269
fn from(s: &SimpleSemver) -> Self {
227270
format!("v{}.{}.{}", s.major, s.minor, s.patch)
@@ -243,18 +286,6 @@ impl SimpleSemver {
243286
patch,
244287
}
245288
}
246-
247-
fn gte(&self, other: &SimpleSemver) -> bool {
248-
match self.major.cmp(&other.major) {
249-
Ordering::Greater => true,
250-
Ordering::Less => false,
251-
Ordering::Equal => match self.minor.cmp(&other.minor) {
252-
Ordering::Greater => true,
253-
Ordering::Less => false,
254-
Ordering::Equal => self.patch >= other.patch,
255-
},
256-
}
257-
}
258289
}
259290

260291
#[cfg(test)]
@@ -284,13 +315,13 @@ mod tests {
284315

285316
#[test]
286317
fn test_gte() {
287-
assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 2, 3)));
288-
assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(0, 10, 10)));
289-
assert!(SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 1, 10)));
318+
assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(1, 2, 3));
319+
assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(0, 10, 10));
320+
assert!(SimpleSemver::new(1, 2, 3) >= SimpleSemver::new(1, 1, 10));
290321

291-
assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 2, 10)));
292-
assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(1, 3, 1)));
293-
assert!(!SimpleSemver::new(1, 2, 3).gte(&SimpleSemver::new(2, 2, 1)));
322+
assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(1, 2, 10));
323+
assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(1, 3, 1));
324+
assert!(SimpleSemver::new(1, 2, 3) < SimpleSemver::new(2, 2, 1));
294325
}
295326

296327
#[test]

0 commit comments

Comments
 (0)