From 2dc17f88dd2de900154f153f521b803ec9b7c377 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 12 Feb 2013 10:46:22 -0500 Subject: [PATCH] VS: Replace generation timestamp file atomically Since commit 34c882a9 (Allow VS 7 project Rebuild and Solution Rebuild to work, 2007-11-10) we use a "CMakeFiles/generated.stamp" and some associated files in the build tree to avoid re-running CMake when the inputs have not changed but VS has cleaned the outputs it knows about. When we do not really need to re-run we restore the generated.stamp file. The non-re-run case can happen in multiple targets in parallel in VS >= 10 so we must restore the file atomically to avoid races. Write the stamp file to a random temporary name and then atomically rename it to the real stamp file. --- Source/cmake.cxx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Source/cmake.cxx b/Source/cmake.cxx index d57e981b6..3071aeb93 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -4033,10 +4033,18 @@ static bool cmakeCheckStampFile(const char* stampName) } // The build system is up to date. The stamp file has been removed - // by the VS IDE due to a "rebuild" request. Just restore it. - std::ofstream stamp(stampName); + // by the VS IDE due to a "rebuild" request. Restore it atomically. + cmOStringStream stampTempStream; + stampTempStream << stampName << ".tmp" << cmSystemTools::RandomSeed(); + std::string stampTempString = stampTempStream.str(); + const char* stampTemp = stampTempString.c_str(); + { + // TODO: Teach cmGeneratedFileStream to use a random temp file (with + // multiple tries in unlikely case of conflict) and use that here. + std::ofstream stamp(stampTemp); stamp << "# CMake generation timestamp file this directory.\n"; - if(stamp) + } + if(cmSystemTools::RenameFile(stampTemp, stampName)) { // Notify the user why CMake is not re-running. It is safe to // just print to stdout here because this code is only reachable @@ -4047,6 +4055,7 @@ static bool cmakeCheckStampFile(const char* stampName) } else { + cmSystemTools::RemoveFile(stampTemp); cmSystemTools::Error("Cannot restore timestamp ", stampName); return false; }