From e277a879905dd33dd375d94557a74b99ec26bffd Mon Sep 17 00:00:00 2001 From: "Evgeniy A. Dushistov" Date: Wed, 3 Jun 2020 15:08:42 +0300 Subject: [PATCH 1/2] test for reset cache problem --- .github/workflows/main.yml | 10 +++ Cargo.toml | 4 ++ tests/handling_reset_cache_after_set_var.rs | 68 +++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 tests/handling_reset_cache_after_set_var.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e5b2ffc..51a7c4d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,6 +12,16 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} + - name: Check versions + run: | + set -e + cargo --version + rustc --version + cmake --version + gcc --version + clang --version + echo "end of versions checking" + shell: bash - run: cargo test rustfmt: diff --git a/Cargo.toml b/Cargo.toml index 8224ea4..c6f82da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,7 @@ categories = ["development-tools::build-utils"] [dependencies] cc = "1.0.41" + +[dev-dependencies] +tempfile = "3.1.0" + diff --git a/tests/handling_reset_cache_after_set_var.rs b/tests/handling_reset_cache_after_set_var.rs new file mode 100644 index 0000000..7f87549 --- /dev/null +++ b/tests/handling_reset_cache_after_set_var.rs @@ -0,0 +1,68 @@ +extern crate tempfile; + +use std::{env, error::Error, fs, path::Path}; + +#[test] +fn handling_reset_cache_after_set_var() { + let tmp_dir = tempfile::tempdir().unwrap(); + + fill_dir(tmp_dir.path()).unwrap(); + + if cfg!(all( + target_os = "linux", + target_arch = "x86_64", + target_vendor = "unknown" + )) { + env::set_var("TARGET", "x86_64-unknown-linux-gnu"); + env::set_var("HOST", "x86_64-unknown-linux-gnu"); + env::set_var("OUT_DIR", tmp_dir.path()); + env::set_var("PROFILE", "debug"); + env::set_var("OPT_LEVEL", "0"); + env::set_var("DEBUG", "true"); + let dst = cmake::Config::new(tmp_dir.path()) + .define("OPT1", "False") + .build_target("all") + .build() + .join("build"); + + assert!(fs::read_to_string(dst.join("CMakeCache.txt")) + .unwrap() + .contains("OPT1:BOOL=False")); + env::set_var("CC", "clang"); + env::set_var("CXX", "clang++"); + let dst = cmake::Config::new(tmp_dir.path()) + .define("OPT1", "False") + .build_target("all") + .build() + .join("build"); + + assert!(fs::read_to_string(dst.join("CMakeCache.txt")) + .unwrap() + .contains("OPT1:BOOL=False")); + } +} + +fn fill_dir(tmp_dir: &Path) -> Result<(), Box> { + fs::write( + tmp_dir.join("CMakeLists.txt"), + r#" +project(xyz) +cmake_minimum_required(VERSION 3.9) + +option(OPT1 "some option" ON) +add_executable(xyz main.cpp) +"#, + )?; + fs::write( + tmp_dir.join("main.cpp"), + r#" +#include +#define DO_STRINGIFY(x) #x +#define STRINGIFY(x) DO_STRINGIFY(x) +int main() { + printf("option: %s\n", STRINGIFY(OPT1)); +} +"#, + )?; + Ok(()) +} From 3ea1b68ef05e75ed391eb706a7b83fc962488dd9 Mon Sep 17 00:00:00 2001 From: "Evgeniy A. Dushistov" Date: Wed, 3 Jun 2020 16:56:45 +0300 Subject: [PATCH 2/2] run cmake twice if there is need for that --- src/lib.rs | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ae8770f..98286bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,10 +49,10 @@ extern crate cc; use std::env; use std::ffi::{OsStr, OsString}; use std::fs::{self, File}; -use std::io::prelude::*; use std::io::ErrorKind; +use std::io::{self, prelude::*}; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, ExitStatus}; /// Builder style configuration for a pending CMake build. pub struct Config { @@ -695,7 +695,7 @@ impl Config { } if self.always_configure || !build.join("CMakeCache.txt").exists() { - run(cmd.env("CMAKE_PREFIX_PATH", cmake_prefix_path), "cmake"); + run_configure(cmd.env("CMAKE_PREFIX_PATH", cmake_prefix_path), "cmake"); } else { println!("CMake project was already configured. Skipping configuration step."); } @@ -847,9 +847,37 @@ impl Config { } } -fn run(cmd: &mut Command, program: &str) { +fn run_configure(cmd: &mut Command, program: &str) { println!("running: {:?}", cmd); - let status = match cmd.status() { + let output = match cmd.output() { + Ok(output) => { + handle_cmake_exec_result(Ok(output.status), program); + output + } + Err(err) => { + handle_cmake_exec_result(Err(err), program); + return; + } + }; + static RESET_MSG: &[u8] = b"Configure will be re-run and you may have to reset some variables"; + if contains(&output.stderr, RESET_MSG) || contains(&output.stdout, RESET_MSG) { + println!("looks like cmake reset all variables, time to reconfigure"); + handle_cmake_exec_result(cmd.status(), program); + } +} + +fn contains(haystack: &[u8], needle: &[u8]) -> bool { + haystack + .windows(needle.len()) + .any(|window| window == needle) +} + +fn run(cmd: &mut Command, program: &str) { + handle_cmake_exec_result(cmd.status(), program); +} + +fn handle_cmake_exec_result(r: Result, program: &str) { + let status = match r { Ok(status) => status, Err(ref e) if e.kind() == ErrorKind::NotFound => { fail(&format!(