From 3c221b57d27aaee1bf134abab9e17dd6fb5f0d64 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 1 Mar 2022 15:50:16 +0900 Subject: [PATCH] Do not pass --parallel option to old cmake --- src/lib.rs | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7ab9547..d43ec24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -517,6 +517,8 @@ impl Config { .unwrap_or(OsString::from("cmake")); let mut cmd = Command::new(&executable); + let version = Version::from_command(&executable).unwrap_or_default(); + if self.verbose_cmake { cmd.arg("-Wdev"); cmd.arg("--debug-output"); @@ -811,9 +813,13 @@ impl Config { cmd.arg("--config").arg(&profile); - if let Ok(s) = env::var("NUM_JOBS") { - // See https://cmake.org/cmake/help/v3.12/manual/cmake.1.html#build-tool-mode - cmd.arg("--parallel").arg(s); + // --parallel requires CMake 3.12: + // https://cmake.org/cmake/help/latest/release/3.12.html#id4 + if version >= Version::new(3, 12) { + if let Ok(s) = env::var("NUM_JOBS") { + // See https://cmake.org/cmake/help/v3.12/manual/cmake.1.html#build-tool-mode + cmd.arg("--parallel").arg(s); + } } if !&self.build_args.is_empty() { @@ -928,6 +934,53 @@ impl Config { } } +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +struct Version { + major: u32, + minor: u32, +} + +impl Version { + fn new(major: u32, minor: u32) -> Self { + Self { major, minor } + } + + fn parse(s: &str) -> Option { + // As of 3.22, the format of the version output is "cmake version ..". + // ``` + // $ cmake --version + // cmake version 3.22.2 + // + // CMake suite maintained and supported by Kitware (kitware.com/cmake). + // ``` + let version = s.lines().find(|s| s.starts_with("cmake version "))?; + let version = &version["cmake version ".len()..]; // strip prefix + let mut digits = version.splitn(3, '.'); // split version string to major minor patch + let major = digits.next()?.parse::().ok()?; + let minor = digits.next()?.parse::().ok()?; + // Ignore the patch version because it does not change the API. + Some(Version::new(major, minor)) + } + + fn from_command(executable: &OsStr) -> Option { + let output = Command::new(executable).arg("--version").output().ok()?; + if !output.status.success() { + return None; + } + let stdout = core::str::from_utf8(&output.stdout).ok()?; + Self::parse(stdout) + } +} + +impl Default for Version { + fn default() -> Self { + // If the version parsing fails, we assume that it is the latest known + // version. This is because the failure of version parsing may be due to + // the version output being changed. + Self::new(3, 22) + } +} + fn run(cmd: &mut Command, program: &str) { println!("running: {:?}", cmd); let status = match cmd.status() { @@ -965,3 +1018,22 @@ fn getenv_unwrap(v: &str) -> String { fn fail(s: &str) -> ! { panic!("\n{}\n\nbuild script failed, must exit now", s) } + +#[cfg(test)] +mod tests { + use super::Version; + + #[test] + fn test_cmake_version() { + let text = "cmake version 3.22.2 + +CMake suite maintained and supported by Kitware (kitware.com/cmake). +"; + let v = Version::parse(text).unwrap(); + assert_eq!(v, Version::new(3, 22)); + assert!(Version::new(3, 22) > Version::new(3, 21)); + assert!(Version::new(3, 22) < Version::new(3, 23)); + + let _v = Version::from_command("cmake".as_ref()).unwrap(); + } +}