From 1df09e57732501454ac2bee900d2aad963a84969 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 18 Feb 2013 09:51:40 -0500 Subject: [PATCH 1/3] Delete entire CMakeFiles directory when deleting CMakeCache.txt (#13756) Since commit e015df7d (...delete CMakeFiles directory when cache is deleted, 2006-02-20) we deleted the files in the CMakeFiles directory when deleting CMakeCache.txt in order to reset the build tree to a fresh state. This allowed commit fd33bf93 (fix for bug 6102, allow users to change the compiler, 2007-12-13) to delete CMakeCache.txt when the user changes the compiler and CMakeFiles/CMakeCompiler.cmake and other platform information files would go with it to allow a fresh start. Then commit 7195aca5 (Make platform information files specific to the CMake version, 2012-08-24) moved the platform information files to a subdirectory e.g. CMakeFiles//CMakeCompiler.cmake where is the current CMake version. This causes the compiler change logic to fail to remove all old compiler information. Then on the next configuration CMakeCompiler.cmake would set CMAKE__COMPILER back to the old value and re-trigger the compiler change logic. This causes an infinite loop of cache deletion and compiler reset. Fix this simply by teaching cmCacheManager::DeleteCache to remove the entire CMakeFiles directory recursively whenever it removes an existing CMakeCache.txt. This fully resets the build tree to configure with a fresh compiler. --- Source/cmCacheManager.cxx | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/Source/cmCacheManager.cxx b/Source/cmCacheManager.cxx index 423124340..3d5b24b84 100644 --- a/Source/cmCacheManager.cxx +++ b/Source/cmCacheManager.cxx @@ -584,23 +584,15 @@ bool cmCacheManager::DeleteCache(const char* path) cmSystemTools::ConvertToUnixSlashes(cacheFile); std::string cmakeFiles = cacheFile; cacheFile += "/CMakeCache.txt"; - cmSystemTools::RemoveFile(cacheFile.c_str()); - // now remove the files in the CMakeFiles directory - // this cleans up language cache files - cmsys::Directory dir; - cmakeFiles += cmake::GetCMakeFilesDirectory(); - dir.Load(cmakeFiles.c_str()); - for (unsigned long fileNum = 0; - fileNum < dir.GetNumberOfFiles(); - ++fileNum) + if(cmSystemTools::FileExists(cacheFile.c_str())) { - if(!cmSystemTools:: - FileIsDirectory(dir.GetFile(fileNum))) + cmSystemTools::RemoveFile(cacheFile.c_str()); + // now remove the files in the CMakeFiles directory + // this cleans up language cache files + cmakeFiles += cmake::GetCMakeFilesDirectory(); + if(cmSystemTools::FileIsDirectory(cmakeFiles.c_str())) { - std::string fullPath = cmakeFiles; - fullPath += "/"; - fullPath += dir.GetFile(fileNum); - cmSystemTools::RemoveFile(fullPath.c_str()); + cmSystemTools::RemoveADirectory(cmakeFiles.c_str()); } } return true; From c307e1c911dbbafb1673799212a4e5f4e211b9f8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 18 Feb 2013 10:43:40 -0500 Subject: [PATCH 2/3] Tests/RunCMake: Allow tests to control build tree behavior Teach the run_cmake to allow tests to set a custom test build directory. Also add an option to skip removing the build directory. --- Tests/RunCMake/RunCMake.cmake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake index 40b98d426..00faa4ca7 100644 --- a/Tests/RunCMake/RunCMake.cmake +++ b/Tests/RunCMake/RunCMake.cmake @@ -26,8 +26,12 @@ function(run_cmake test) endif() endforeach() set(RunCMake_TEST_SOURCE_DIR "${top_src}") - set(RunCMake_TEST_BINARY_DIR "${top_bin}/${test}-build") - file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + if(NOT RunCMake_TEST_BINARY_DIR) + set(RunCMake_TEST_BINARY_DIR "${top_bin}/${test}-build") + endif() + if(NOT RunCMake_TEST_NO_CLEAN) + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + endif() file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") if(NOT DEFINED RunCMake_TEST_OPTIONS) set(RunCMake_TEST_OPTIONS "") From e83e6a1c8c572548b2a8ce1e54f4fd0f60f32a70 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 18 Feb 2013 10:35:53 -0500 Subject: [PATCH 3/3] Test Unix Makefiles generator support for changing compilers Add RunCMake.CompilerChange test to cover use of -DCMAKE_C_COMPILER=cc to change the compiler of an existing build tree. Also test for proper failure with -DCMAKE_C_COMPILER="" and no CC in the environment. --- Tests/RunCMake/CMakeLists.txt | 3 + Tests/RunCMake/CompilerChange/CMakeLists.txt | 6 ++ .../CompilerChange/EmptyCompiler-result.txt | 1 + .../CompilerChange/EmptyCompiler-stderr.txt | 5 ++ .../CompilerChange/EmptyCompiler.cmake | 3 + .../CompilerChange/FindCompiler.cmake | 2 + .../CompilerChange/FirstCompiler-stdout.txt | 1 + .../CompilerChange/FirstCompiler.cmake | 3 + .../CompilerChange/RunCMakeTest.cmake | 58 +++++++++++++++++++ .../CompilerChange/SecondCompiler-stderr.txt | 4 ++ .../CompilerChange/SecondCompiler-stdout.txt | 1 + .../CompilerChange/SecondCompiler.cmake | 3 + Tests/RunCMake/CompilerChange/cc.sh.in | 2 + 13 files changed, 92 insertions(+) create mode 100644 Tests/RunCMake/CompilerChange/CMakeLists.txt create mode 100644 Tests/RunCMake/CompilerChange/EmptyCompiler-result.txt create mode 100644 Tests/RunCMake/CompilerChange/EmptyCompiler-stderr.txt create mode 100644 Tests/RunCMake/CompilerChange/EmptyCompiler.cmake create mode 100644 Tests/RunCMake/CompilerChange/FindCompiler.cmake create mode 100644 Tests/RunCMake/CompilerChange/FirstCompiler-stdout.txt create mode 100644 Tests/RunCMake/CompilerChange/FirstCompiler.cmake create mode 100644 Tests/RunCMake/CompilerChange/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/CompilerChange/SecondCompiler-stderr.txt create mode 100644 Tests/RunCMake/CompilerChange/SecondCompiler-stdout.txt create mode 100644 Tests/RunCMake/CompilerChange/SecondCompiler.cmake create mode 100755 Tests/RunCMake/CompilerChange/cc.sh.in diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 320ebccff..c55bb3aad 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -52,6 +52,9 @@ if(XCODE_VERSION AND "${XCODE_VERSION}" VERSION_LESS 3) endif() add_RunCMake_test(CMP0019) +if(UNIX AND "${CMAKE_TEST_GENERATOR}" MATCHES "Unix Makefiles") + add_RunCMake_test(CompilerChange) +endif() add_RunCMake_test(ExternalData) add_RunCMake_test(GeneratorExpression) add_RunCMake_test(GeneratorToolset) diff --git a/Tests/RunCMake/CompilerChange/CMakeLists.txt b/Tests/RunCMake/CompilerChange/CMakeLists.txt new file mode 100644 index 000000000..3b925188d --- /dev/null +++ b/Tests/RunCMake/CompilerChange/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 2.8) +if(NOT RunCMake_TEST) + set(RunCMake_TEST "$ENV{RunCMake_TEST}") # needed when cache is deleted +endif() +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CompilerChange/EmptyCompiler-result.txt b/Tests/RunCMake/CompilerChange/EmptyCompiler-result.txt new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/EmptyCompiler-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CompilerChange/EmptyCompiler-stderr.txt b/Tests/RunCMake/CompilerChange/EmptyCompiler-stderr.txt new file mode 100644 index 000000000..4745b254d --- /dev/null +++ b/Tests/RunCMake/CompilerChange/EmptyCompiler-stderr.txt @@ -0,0 +1,5 @@ +You have changed variables that require your cache to be deleted. +Configure will be re-run and you may have to reset some variables. +The following variables have changed: +CMAKE_C_COMPILER= *( +|$) diff --git a/Tests/RunCMake/CompilerChange/EmptyCompiler.cmake b/Tests/RunCMake/CompilerChange/EmptyCompiler.cmake new file mode 100644 index 000000000..c87ec4952 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/EmptyCompiler.cmake @@ -0,0 +1,3 @@ +enable_language(C) +message(STATUS "CMAKE_C_COMPILER is \"${CMAKE_C_COMPILER}\"") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cc.cmake" "set(CMAKE_C_COMPILER \"${CMAKE_C_COMPILER}\")\n") diff --git a/Tests/RunCMake/CompilerChange/FindCompiler.cmake b/Tests/RunCMake/CompilerChange/FindCompiler.cmake new file mode 100644 index 000000000..297ab2fa5 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/FindCompiler.cmake @@ -0,0 +1,2 @@ +enable_language(C) +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cc.cmake" "set(CMAKE_C_COMPILER \"${CMAKE_C_COMPILER}\")\n") diff --git a/Tests/RunCMake/CompilerChange/FirstCompiler-stdout.txt b/Tests/RunCMake/CompilerChange/FirstCompiler-stdout.txt new file mode 100644 index 000000000..17621b7e5 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/FirstCompiler-stdout.txt @@ -0,0 +1 @@ +-- CMAKE_C_COMPILER is ".*/Tests/RunCMake/CompilerChange/cc1.sh" diff --git a/Tests/RunCMake/CompilerChange/FirstCompiler.cmake b/Tests/RunCMake/CompilerChange/FirstCompiler.cmake new file mode 100644 index 000000000..c87ec4952 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/FirstCompiler.cmake @@ -0,0 +1,3 @@ +enable_language(C) +message(STATUS "CMAKE_C_COMPILER is \"${CMAKE_C_COMPILER}\"") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cc.cmake" "set(CMAKE_C_COMPILER \"${CMAKE_C_COMPILER}\")\n") diff --git a/Tests/RunCMake/CompilerChange/RunCMakeTest.cmake b/Tests/RunCMake/CompilerChange/RunCMakeTest.cmake new file mode 100644 index 000000000..d38371680 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/RunCMakeTest.cmake @@ -0,0 +1,58 @@ +include(RunCMake) + +# Detect the compiler in use in the current environment. +run_cmake(FindCompiler) +include(${RunCMake_BINARY_DIR}/FindCompiler-build/cc.cmake) +if(NOT CMAKE_C_COMPILER) + message(FATAL_ERROR "FindCompiler provided no compiler!") +endif() +if(NOT IS_ABSOLUTE "${CMAKE_C_COMPILER}") + message(FATAL_ERROR "FindCompiler provided non-absolute path \"${CMAKE_C_COMPILER}\"!") +endif() +if(NOT EXISTS "${CMAKE_C_COMPILER}") + message(FATAL_ERROR "FindCompiler provided non-existing path \"${CMAKE_C_COMPILER}\"!") +endif() + +# Now that we have the full compiler path, hide CC. +unset(ENV{CC}) + +# Wrap around the real compiler so we can change the compiler +# path without changing the underlying compiler. +set(ccIn ${RunCMake_SOURCE_DIR}/cc.sh.in) +set(cc1 ${RunCMake_BINARY_DIR}/cc1.sh) +set(cc2 ${RunCMake_BINARY_DIR}/cc2.sh) +set(cc3 CMAKE_C_COMPILER-NOTFOUND) +configure_file(${ccIn} ${cc1} @ONLY IMMEDIATE) +configure_file(${ccIn} ${cc2} @ONLY IMMEDIATE) + +# Use a single build tree for remaining tests without cleaning. +set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/ChangeCompiler-build) +set(RunCMake_TEST_NO_CLEAN 1) +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + +# Check build with compiler wrapper 1. +set(RunCMake_TEST_OPTIONS -DCMAKE_C_COMPILER=${cc1}) +set(ENV{RunCMake_TEST} "FirstCompiler") +run_cmake(FirstCompiler) +include(${RunCMake_TEST_BINARY_DIR}/cc.cmake) +if(NOT "${CMAKE_C_COMPILER}" STREQUAL "${cc1}") + message(FATAL_ERROR "FirstCompiler built with compiler:\n ${CMAKE_C_COMPILER}\nand not with:\n ${cc1}") +endif() + +# Check rebuild with compiler wrapper 2. +set(RunCMake_TEST_OPTIONS -DCMAKE_C_COMPILER=${cc2}) +set(ENV{RunCMake_TEST} "SecondCompiler") +run_cmake(SecondCompiler) +include(${RunCMake_TEST_BINARY_DIR}/cc.cmake) +if(NOT "${CMAKE_C_COMPILER}" STREQUAL "${cc2}") + message(FATAL_ERROR "SecondCompiler built with compiler:\n ${CMAKE_C_COMPILER}\nand not with:\n ${cc2}") +endif() + +# Check failure with an empty compiler string. +set(RunCMake_TEST_OPTIONS -DCMAKE_C_COMPILER=) +set(ENV{RunCMake_TEST} "EmptyCompiler") +run_cmake(EmptyCompiler) +include(${RunCMake_TEST_BINARY_DIR}/cc.cmake) +if(NOT "${CMAKE_C_COMPILER}" STREQUAL "${cc3}") + message(FATAL_ERROR "Empty built with compiler:\n ${CMAKE_C_COMPILER}\nand not with:\n ${cc3}") +endif() diff --git a/Tests/RunCMake/CompilerChange/SecondCompiler-stderr.txt b/Tests/RunCMake/CompilerChange/SecondCompiler-stderr.txt new file mode 100644 index 000000000..3a01c53f1 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/SecondCompiler-stderr.txt @@ -0,0 +1,4 @@ +You have changed variables that require your cache to be deleted. +Configure will be re-run and you may have to reset some variables. +The following variables have changed: +CMAKE_C_COMPILER=.*/Tests/RunCMake/CompilerChange/cc2.sh diff --git a/Tests/RunCMake/CompilerChange/SecondCompiler-stdout.txt b/Tests/RunCMake/CompilerChange/SecondCompiler-stdout.txt new file mode 100644 index 000000000..26ca96438 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/SecondCompiler-stdout.txt @@ -0,0 +1 @@ +-- CMAKE_C_COMPILER is ".*/Tests/RunCMake/CompilerChange/cc2.sh" diff --git a/Tests/RunCMake/CompilerChange/SecondCompiler.cmake b/Tests/RunCMake/CompilerChange/SecondCompiler.cmake new file mode 100644 index 000000000..c87ec4952 --- /dev/null +++ b/Tests/RunCMake/CompilerChange/SecondCompiler.cmake @@ -0,0 +1,3 @@ +enable_language(C) +message(STATUS "CMAKE_C_COMPILER is \"${CMAKE_C_COMPILER}\"") +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cc.cmake" "set(CMAKE_C_COMPILER \"${CMAKE_C_COMPILER}\")\n") diff --git a/Tests/RunCMake/CompilerChange/cc.sh.in b/Tests/RunCMake/CompilerChange/cc.sh.in new file mode 100755 index 000000000..1d400e6ba --- /dev/null +++ b/Tests/RunCMake/CompilerChange/cc.sh.in @@ -0,0 +1,2 @@ +#!/bin/sh +exec "@CMAKE_C_COMPILER@" "$@"