diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeVersion.cmake | 2 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 22 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 5 | ||||
-rw-r--r-- | Source/cmGlobalNinjaGenerator.cxx | 34 | ||||
-rw-r--r-- | Source/cmGlobalNinjaGenerator.h | 3 | ||||
-rw-r--r-- | Source/cmLocalCommonGenerator.cxx | 3 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 6 | ||||
-rw-r--r-- | Source/cmNinjaNormalTargetGenerator.cxx | 9 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 5 | ||||
-rw-r--r-- | Source/kwsys/testConsoleBuf.cxx | 225 | ||||
-rw-r--r-- | Source/kwsys/testConsoleBuf.hxx | 3 | ||||
-rw-r--r-- | Source/kwsys/testConsoleBufChild.cxx | 14 |
12 files changed, 242 insertions, 89 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 90d0d0e..d725626 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160920) +set(CMake_VERSION_PATCH 20160921) #set(CMake_VERSION_RC 1) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 1e21ac4..f181cf6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -3883,23 +3883,35 @@ void cmGeneratorTarget::GetTargetVersion(bool soversion, int& major, } } -std::string cmGeneratorTarget::GetFortranModuleDirectory() const +std::string cmGeneratorTarget::GetFortranModuleDirectory( + std::string const& working_dir) const { if (!this->FortranModuleDirectoryCreated) { this->FortranModuleDirectory = true; - this->FortranModuleDirectory = this->CreateFortranModuleDirectory(); + this->FortranModuleDirectory = + this->CreateFortranModuleDirectory(working_dir); } return this->FortranModuleDirectory; } -std::string cmGeneratorTarget::CreateFortranModuleDirectory() const +std::string cmGeneratorTarget::CreateFortranModuleDirectory( + std::string const& working_dir) const { std::string mod_dir; - const char* target_mod_dir = this->GetProperty("Fortran_MODULE_DIRECTORY"); + std::string target_mod_dir; + if (const char* prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) { + target_mod_dir = prop; + } else { + std::string const& default_mod_dir = + this->LocalGenerator->GetCurrentBinaryDirectory(); + if (default_mod_dir != working_dir) { + target_mod_dir = default_mod_dir; + } + } const char* moddir_flag = this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG"); - if (target_mod_dir && moddir_flag) { + if (!target_mod_dir.empty() && moddir_flag) { // Compute the full path to the module directory. if (cmSystemTools::FileIsFullPath(target_mod_dir)) { // Already a full path. diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 715220e..8e17b8f 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -537,12 +537,13 @@ public: void GetTargetVersion(bool soversion, int& major, int& minor, int& patch) const; - std::string GetFortranModuleDirectory() const; + std::string GetFortranModuleDirectory(std::string const& working_dir) const; private: void AddSourceCommon(const std::string& src); - std::string CreateFortranModuleDirectory() const; + std::string CreateFortranModuleDirectory( + std::string const& working_dir) const; mutable bool FortranModuleDirectoryCreated; mutable std::string FortranModuleDirectory; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index bd65366..b913621 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -140,10 +140,10 @@ std::string cmGlobalNinjaGenerator::EncodeDepfileSpace(const std::string& path) void cmGlobalNinjaGenerator::WriteBuild( std::ostream& os, const std::string& comment, const std::string& rule, - const cmNinjaDeps& outputs, const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps, - const cmNinjaVars& variables, const std::string& rspfile, int cmdLineLimit, - bool* usedResponseFile) + const cmNinjaDeps& outputs, const cmNinjaDeps& implicitOuts, + const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, + const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables, + const std::string& rspfile, int cmdLineLimit, bool* usedResponseFile) { // Make sure there is a rule. if (rule.empty()) { @@ -204,6 +204,13 @@ void cmGlobalNinjaGenerator::WriteBuild( this->CombinedBuildOutputs.insert(EncodePath(*i)); } } + if (!implicitOuts.empty()) { + build += " |"; + for (cmNinjaDeps::const_iterator i = implicitOuts.begin(); + i != implicitOuts.end(); ++i) { + build += " " + EncodeIdent(EncodePath(*i), os); + } + } build += ":"; // Write the rule. @@ -244,7 +251,8 @@ void cmGlobalNinjaGenerator::WritePhonyBuild( const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables) { - this->WriteBuild(os, comment, "phony", outputs, explicitDeps, implicitDeps, + this->WriteBuild(os, comment, "phony", outputs, + /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps, variables); } @@ -288,7 +296,8 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( vars["depfile"] = depfile; } this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs, - deps, cmNinjaDeps(), orderOnly, vars); + /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(), + orderOnly, vars); if (this->ComputingUnknownDependencies) { // we need to track every dependency that comes in, since we are trying @@ -330,7 +339,8 @@ void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input, cmNinjaVars vars; this->WriteBuild(*this->BuildFileStream, "", "COPY_OSX_CONTENT", outputs, - deps, cmNinjaDeps(), cmNinjaDeps(), cmNinjaVars()); + /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(), + cmNinjaDeps(), cmNinjaVars()); } void cmGlobalNinjaGenerator::WriteRule( @@ -1271,6 +1281,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) this->WriteBuild(os, "Re-run CMake if any of its inputs changed.", "RERUN_CMAKE", /*outputs=*/cmNinjaDeps(1, ninjaBuildFile), + /*implicitOuts=*/cmNinjaDeps(), /*explicitDeps=*/cmNinjaDeps(), implicitDeps, /*orderOnlyDeps=*/cmNinjaDeps(), variables); @@ -1295,6 +1306,13 @@ bool cmGlobalNinjaGenerator::SupportsConsolePool() const RequiredNinjaVersionForConsolePool().c_str()); } +bool cmGlobalNinjaGenerator::SupportsImplicitOuts() const +{ + return !cmSystemTools::VersionCompare( + cmSystemTools::OP_LESS, this->NinjaVersion.c_str(), + this->RequiredNinjaVersionForImplicitOuts().c_str()); +} + void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) { WriteRule(*this->RulesFileStream, "CLEAN", ninjaCmd() + " -t clean", @@ -1308,6 +1326,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) /*generator=*/false); WriteBuild(os, "Clean all the built files.", "CLEAN", /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("clean")), + /*implicitOuts=*/cmNinjaDeps(), /*explicitDeps=*/cmNinjaDeps(), /*implicitDeps=*/cmNinjaDeps(), /*orderOnlyDeps=*/cmNinjaDeps(), @@ -1327,6 +1346,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) /*generator=*/false); WriteBuild(os, "Print all primary targets available.", "HELP", /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("help")), + /*implicitOuts=*/cmNinjaDeps(), /*explicitDeps=*/cmNinjaDeps(), /*implicitDeps=*/cmNinjaDeps(), /*orderOnlyDeps=*/cmNinjaDeps(), diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index a0fad64..0201685 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -106,6 +106,7 @@ public: */ void WriteBuild(std::ostream& os, const std::string& comment, const std::string& rule, const cmNinjaDeps& outputs, + const cmNinjaDeps& implicitOuts, const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps, @@ -338,7 +339,9 @@ public: // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3 static std::string RequiredNinjaVersion() { return "1.3"; } static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; } + static std::string RequiredNinjaVersionForImplicitOuts() { return "1.7"; } bool SupportsConsolePool() const; + bool SupportsImplicitOuts() const; std::string NinjaOutputPath(std::string const& path); bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); } diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 97323c9..b75ce62 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -54,7 +54,8 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags( } // Add a module output directory flag if necessary. - std::string mod_dir = target->GetFortranModuleDirectory(); + std::string mod_dir = + target->GetFortranModuleDirectory(this->WorkingDirectory); if (!mod_dir.empty()) { mod_dir = this->ConvertToOutputFormat( this->ConvertToRelativePath(this->WorkingDirectory, mod_dir), diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 014feb9..e0d9fda 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -993,12 +993,16 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() *this->InfoFileStream << " )\n"; } + std::string const& working_dir = + this->LocalGenerator->GetCurrentBinaryDirectory(); + /* clang-format off */ *this->InfoFileStream << "\n" << "# Fortran module output directory.\n" << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" - << this->GeneratorTarget->GetFortranModuleDirectory() << "\")\n"; + << this->GeneratorTarget->GetFortranModuleDirectory(working_dir) + << "\")\n"; /* clang-format on */ // and now write the rule to use it diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index f87a788..dbd84cb 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -691,7 +691,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // Write the build statement for this target. bool usedResponseFile = false; globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(), - this->LanguageLinkerRule(), outputs, explicitDeps, + this->LanguageLinkerRule(), outputs, + /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps, vars, rspfile, commandLineLengthLimit, &usedResponseFile); this->WriteLinkRule(usedResponseFile); @@ -702,7 +703,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() this->GetBuildFileStream(), "Create executable symlink " + targetOutput, "CMAKE_SYMLINK_EXECUTABLE", cmNinjaDeps(1, targetOutput), - cmNinjaDeps(1, targetOutputReal), emptyDeps, emptyDeps, symlinkVars); + /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal), + emptyDeps, emptyDeps, symlinkVars); } else { cmNinjaDeps symlinks; std::string const soName = @@ -717,7 +719,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() symlinks.push_back(targetOutput); globalGen.WriteBuild( this->GetBuildFileStream(), "Create library symlink " + targetOutput, - "CMAKE_SYMLINK_LIBRARY", symlinks, cmNinjaDeps(1, targetOutputReal), + "CMAKE_SYMLINK_LIBRARY", symlinks, + /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal), emptyDeps, emptyDeps, symlinkVars); } } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 6ac59d5..fb09bfe 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -607,8 +607,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( std::string const rspfile = objectFileName + ".rsp"; this->GetGlobalGenerator()->WriteBuild( - this->GetBuildFileStream(), comment, rule, outputs, explicitDeps, - implicitDeps, orderOnlyDeps, vars, rspfile, commandLineLengthLimit); + this->GetBuildFileStream(), comment, rule, outputs, + /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps, + vars, rspfile, commandLineLengthLimit); if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { std::vector<std::string> outputList; diff --git a/Source/kwsys/testConsoleBuf.cxx b/Source/kwsys/testConsoleBuf.cxx index 3dec0973..3dc3337 100644 --- a/Source/kwsys/testConsoleBuf.cxx +++ b/Source/kwsys/testConsoleBuf.cxx @@ -31,6 +31,7 @@ #include <string.h> #include <wchar.h> #include <iostream> +#include <iomanip> #include <stdexcept> #include "testConsoleBuf.hxx" @@ -44,10 +45,67 @@ static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE; static const DWORD waitTimeout = 10 * 1000; static STARTUPINFO startupInfo; static PROCESS_INFORMATION processInfo; -static HANDLE syncEvent; +static HANDLE beforeInputEvent; +static HANDLE afterOutputEvent; static std::string encodedInputTestString; static std::string encodedTestString; +static void displayError(DWORD errorCode) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "Failed with error: 0x" << errorCode << "!" << std::endl; + LPWSTR message; + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errorCode, + 0, + (LPWSTR)&message, 0, + NULL) + ) { + std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message) << std::endl; + HeapFree(GetProcessHeap(), 0, message); + } else { + std::cerr << "FormatMessage() failed with error: 0x" << GetLastError() << "!" << std::endl; + } + std::cerr.unsetf(std::ios::hex); +} + +std::basic_streambuf<char> *errstream(const char *unused) { + static_cast<void>(unused); + return std::cerr.rdbuf(); +} + +std::basic_streambuf<wchar_t> *errstream(const wchar_t *unused) { + static_cast<void>(unused); + return std::wcerr.rdbuf(); +} + +//---------------------------------------------------------------------------- +template<typename T> +static void dumpBuffers(const T *expected, const T *received, size_t size) { + std::basic_ostream<T> err(errstream(expected)); + err << "Expected output: '" << std::basic_string<T>(expected, size) << "'" << std::endl; + if (err.fail()) { + err.clear(); + err << "--- Error while outputting ---" << std::endl; + } + err << "Received output: '" << std::basic_string<T>(received, size) << "'" << std::endl; + if (err.fail()) { + err.clear(); + err << "--- Error while outputting ---" << std::endl; + } + std::cerr << "Expected output | Received output" << std::endl; + for (size_t i = 0; i < size; i++) { + std::cerr << std::setbase(16) << std::setfill('0') << " " << + "0x" << std::setw(8) << static_cast<unsigned int>(expected[i]) << " | " << + "0x" << std::setw(8) << static_cast<unsigned int>(received[i]); + if (static_cast<unsigned int>(expected[i]) != static_cast<unsigned int>(received[i])) { + std::cerr << " MISMATCH!"; + } + std::cerr << std::endl; + } + std::cerr << std::endl << std::flush; +} + //---------------------------------------------------------------------------- static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr) { @@ -89,23 +147,8 @@ static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr) &processInfo) != 0; // Pointer to PROCESS_INFORMATION structure if (!success) { DWORD lastError = GetLastError(); - std::cerr.setf(std::ios::hex, std::ios::basefield); - std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) - << ") failed with error: 0x" << lastError << "!" << std::endl; - LPWSTR message; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - lastError, - 0, - (LPWSTR)&message, 0, - NULL) - ) { - std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message) << std::endl; - HeapFree(GetProcessHeap(), 0, message); - } else { - std::cerr << "FormatMessage() failed with error: 0x" << GetLastError() << "!" << std::endl; - } - std::cerr.unsetf(std::ios::hex); + std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) << ")" << std::endl; + displayError(lastError); } return success; } @@ -162,8 +205,9 @@ static HANDLE createFile(LPCWSTR fileName) FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); // no template if (file == INVALID_HANDLE_VALUE) { - std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) - << ") failed!" << std::endl; + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) << ")" << std::endl; + displayError(lastError); } return file; } @@ -232,6 +276,7 @@ static int testPipe() HANDLE errPipeWrite = INVALID_HANDLE_VALUE; UINT currentCodepage = GetConsoleCP(); char buffer[200]; + char buffer2[200]; try { if (!createPipe(&inPipeRead, &inPipeWrite) || !createPipe(&outPipeRead, &outPipeWrite) || @@ -254,20 +299,23 @@ static int testPipe() if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) { try { - Sleep(100); - if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) { + DWORD status; + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" << status << std::endl; + std::cerr.unsetf(std::ios::hex); throw std::runtime_error("WaitForSingleObject failed!"); } DWORD bytesRead = 0; if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, NULL) || bytesRead == 0) { - throw std::runtime_error("ReadFile failed!"); + throw std::runtime_error("ReadFile#1 failed!"); } if ((bytesRead < encodedTestString.size() + 1 + encodedInputTestString.size() && !ReadFile(outPipeRead, buffer + bytesRead, sizeof(buffer) - bytesRead, &bytesRead, NULL)) || bytesRead == 0) { - throw std::runtime_error("ReadFile failed!"); + throw std::runtime_error("ReadFile#2 failed!"); } if (memcmp(buffer, encodedTestString.c_str(), encodedTestString.size()) == 0 && @@ -275,23 +323,30 @@ static int testPipe() encodedInputTestString.c_str(), encodedInputTestString.size()) == 0) { bytesRead = 0; - if (!ReadFile(errPipeRead, buffer, sizeof(buffer), &bytesRead, NULL) + if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead, NULL) || bytesRead == 0) { - throw std::runtime_error("ReadFile failed!"); + throw std::runtime_error("ReadFile#3 failed!"); } - buffer[bytesRead - 1] = 0; - didFail = encodedTestString.compare(buffer) == 0 ? 0 : 1; + buffer2[bytesRead - 1] = 0; + didFail = encodedTestString.compare(buffer2) == 0 ? 0 : 1; } if (didFail != 0) { std::cerr << "Pipe's output didn't match expected output!" << std::endl << std::flush; + dumpBuffers<char>(encodedTestString.c_str(), buffer, encodedTestString.size()); + dumpBuffers<char>(encodedInputTestString.c_str(), buffer + encodedTestString.size() + 1, encodedInputTestString.size()); + dumpBuffers<char>(encodedTestString.c_str(), buffer2, encodedTestString.size()); } } catch (const std::runtime_error &ex) { - std::cerr << ex.what() << std::endl << std::flush; + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); } finishProcess(didFail == 0); } } catch (const std::runtime_error &ex) { - std::cerr << ex.what() << std::endl << std::flush; + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); } finishPipe(inPipeRead, inPipeWrite); finishPipe(outPipeRead, outPipeWrite); @@ -316,6 +371,7 @@ static int testFile() int length = 0; DWORD bytesWritten = 0; char buffer[200]; + char buffer2[200]; if ((length = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1, buffer, sizeof(buffer), @@ -334,17 +390,20 @@ static int testFile() if (createProcess(inFile, outFile, errFile)) { DWORD bytesRead = 0; try { - Sleep(100); - if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) { + DWORD status; + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" << status << std::endl; + std::cerr.unsetf(std::ios::hex); throw std::runtime_error("WaitForSingleObject failed!"); } if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { - throw std::runtime_error("SetFilePointer failed!"); + throw std::runtime_error("SetFilePointer#1 failed!"); } if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, NULL) || bytesRead == 0) { - throw std::runtime_error("ReadFile failed!"); + throw std::runtime_error("ReadFile#1 failed!"); } buffer[bytesRead - 1] = 0; if (memcmp(buffer, encodedTestString.c_str(), @@ -355,25 +414,32 @@ static int testFile() bytesRead = 0; if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { - throw std::runtime_error("SetFilePointer failed!"); + throw std::runtime_error("SetFilePointer#2 failed!"); } - if (!ReadFile(errFile, buffer, sizeof(buffer), &bytesRead, NULL) + if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, NULL) || bytesRead == 0) { - throw std::runtime_error("ReadFile failed!"); + throw std::runtime_error("ReadFile#2 failed!"); } - buffer[bytesRead - 1] = 0; - didFail = encodedTestString.compare(buffer) == 0 ? 0 : 1; + buffer2[bytesRead - 1] = 0; + didFail = encodedTestString.compare(buffer2) == 0 ? 0 : 1; } if (didFail != 0) { std::cerr << "File's output didn't match expected output!" << std::endl << std::flush; + dumpBuffers<char>(encodedTestString.c_str(), buffer, encodedTestString.size()); + dumpBuffers<char>(encodedInputTestString.c_str(), buffer + encodedTestString.size() + 1, encodedInputTestString.size() - 1); + dumpBuffers<char>(encodedTestString.c_str(), buffer2, encodedTestString.size()); } } catch (const std::runtime_error &ex) { - std::cerr << ex.what() << std::endl << std::flush; + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); } finishProcess(didFail == 0); } } catch (const std::runtime_error &ex) { - std::cerr << ex.what() << std::endl << std::flush; + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); } finishFile(inFile); finishFile(outFile); @@ -403,6 +469,7 @@ static int testConsole() const DWORD TestFontSize = 0x000c0000; HKEY hConsoleKey; WCHAR FaceName[200]; + FaceName[0] = 0; DWORD FaceNameSize = sizeof(FaceName); DWORD FontFamily = TestFontFamily; DWORD FontSize = TestFontSize; @@ -459,10 +526,20 @@ static int testConsole() securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); securityAttributes.bInheritHandle = TRUE; securityAttributes.lpSecurityDescriptor = NULL; - hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, 0, + hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, OPEN_EXISTING, 0, NULL); - hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, 0, + if (hIn == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(CONIN$)" << std::endl; + displayError(lastError); + } + hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &securityAttributes, OPEN_EXISTING, 0, NULL); + if (hOut == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(CONOUT$)" << std::endl; + displayError(lastError); + } SetStdHandle(STD_INPUT_HANDLE, hIn); SetStdHandle(STD_OUTPUT_HANDLE, hOut); SetStdHandle(STD_ERROR_HANDLE, hOut); @@ -496,8 +573,12 @@ static int testConsole() KEY_WRITE, &hConsoleKey) == ERROR_SUCCESS) { RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, (BYTE *)&FontFamily, sizeof(FontFamily)); - RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, - (BYTE *)FaceName, FaceNameSize); + if (FaceName[0] != 0) { + RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, + (BYTE *)FaceName, FaceNameSize); + } else { + RegDeleteValueW(hConsoleKey, L"FaceName"); + } RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, (BYTE *)&FontSize, sizeof(FontSize)); RegCloseKey(hConsoleKey); @@ -508,8 +589,12 @@ static int testConsole() if (createProcess(NULL, NULL, NULL)) { try { - if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) { - throw std::runtime_error("WaitForSingleObject failed!"); + DWORD status; + if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) != WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject#1 failed!"); } INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) / sizeof(UnicodeInputTestString[0])) * 2]; @@ -521,13 +606,18 @@ static int testConsole() } writeInputKeyEvent(&inputBuffer[i*2], VK_RETURN); DWORD eventsWritten = 0; + // We need to wait a bit before writing to console so child process have started waiting for input on stdin. + Sleep(300); if (!WriteConsoleInputW(hIn, inputBuffer, sizeof(inputBuffer) / sizeof(inputBuffer[0]), &eventsWritten) || eventsWritten == 0) { throw std::runtime_error("WriteConsoleInput failed!"); } - if (WaitForSingleObject(syncEvent, waitTimeout) != WAIT_OBJECT_0) { - throw std::runtime_error("WaitForSingleObject failed!"); + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject#2 failed!"); } CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo; if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) { @@ -547,22 +637,30 @@ static int testConsole() } std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString); std::wstring wideInputTestString = kwsys::Encoding::ToWide(encodedInputTestString); - if (memcmp(outputBuffer, wideTestString.c_str(), wideTestString.size()) == 0 && + if (memcmp(outputBuffer, wideTestString.c_str(), + wideTestString.size() * sizeof(wchar_t)) == 0 && memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1, - wideTestString.c_str(), wideTestString.size()) == 0 && + wideTestString.c_str(), wideTestString.size() * sizeof(wchar_t)) == 0 && memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2, UnicodeInputTestString, sizeof(UnicodeInputTestString) - sizeof(WCHAR)) == 0 && memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3, - wideInputTestString.c_str(), wideInputTestString.size() - 1) == 0 + wideInputTestString.c_str(), + (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0 ) { didFail = 0; } else { std::cerr << "Console's output didn't match expected output!" << std::endl << std::flush; + dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer, wideTestString.size()); + dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer + screenBufferInfo.dwSize.X * 1, wideTestString.size()); + dumpBuffers<wchar_t>(UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2, (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR)); + dumpBuffers<wchar_t>(wideInputTestString.c_str(), outputBuffer + screenBufferInfo.dwSize.X * 3, wideInputTestString.size() - 1); } delete[] outputBuffer; } catch (const std::runtime_error &ex) { - std::cerr << ex.what() << std::endl << std::flush; + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); } finishProcess(didFail == 0); } @@ -585,12 +683,18 @@ int testConsoleBuf(int, char*[]) int ret = 0; #if defined(_WIN32) - syncEvent = CreateEventW(NULL, - FALSE, // auto-reset event - FALSE, // initial state is nonsignaled - SyncEventName); // object name - if (!syncEvent) { - std::cerr << "CreateEvent failed " << GetLastError() << std::endl; + beforeInputEvent = CreateEventW(NULL, + FALSE, // auto-reset event + FALSE, // initial state is nonsignaled + BeforeInputEventName); // object name + if (!beforeInputEvent) { + std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl; + return 1; + } + + afterOutputEvent = CreateEventW(NULL, FALSE, FALSE, AfterOutputEventName); + if (!afterOutputEvent) { + std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl; return 1; } @@ -602,7 +706,8 @@ int testConsoleBuf(int, char*[]) ret |= testFile(); ret |= testConsole(); - CloseHandle(syncEvent); + CloseHandle(beforeInputEvent); + CloseHandle(afterOutputEvent); #endif return ret; diff --git a/Source/kwsys/testConsoleBuf.hxx b/Source/kwsys/testConsoleBuf.hxx index 855028b..7c2f4c6 100644 --- a/Source/kwsys/testConsoleBuf.hxx +++ b/Source/kwsys/testConsoleBuf.hxx @@ -14,7 +14,8 @@ static const wchar_t cmdConsoleBufChild[] = L"testConsoleBufChild"; -static const wchar_t SyncEventName[] = L"SyncEvent"; +static const wchar_t BeforeInputEventName[] = L"BeforeInputEvent"; +static const wchar_t AfterOutputEventName[] = L"AfterOutputEvent"; // यूनिकोड είναι здорово! static const wchar_t UnicodeTestString[] = L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 " diff --git a/Source/kwsys/testConsoleBufChild.cxx b/Source/kwsys/testConsoleBufChild.cxx index 3b9ab71..2da39f2 100644 --- a/Source/kwsys/testConsoleBufChild.cxx +++ b/Source/kwsys/testConsoleBufChild.cxx @@ -42,16 +42,18 @@ int main(int argc, const char* argv[]) } std::string input; - HANDLE syncEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, SyncEventName); - if (syncEvent) { - SetEvent(syncEvent); + HANDLE event = OpenEventW(EVENT_MODIFY_STATE, FALSE, BeforeInputEventName); + if (event) { + SetEvent(event); + CloseHandle(event); } std::cin >> input; std::cout << input << std::endl; - if (syncEvent) { - SetEvent(syncEvent); - CloseHandle(syncEvent); + event = OpenEventW(EVENT_MODIFY_STATE, FALSE, AfterOutputEventName); + if (event) { + SetEvent(event); + CloseHandle(event); } #else static_cast<void>(argc); |