summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/cmGeneratorTarget.cxx22
-rw-r--r--Source/cmGeneratorTarget.h5
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx34
-rw-r--r--Source/cmGlobalNinjaGenerator.h3
-rw-r--r--Source/cmLocalCommonGenerator.cxx3
-rw-r--r--Source/cmMakefileTargetGenerator.cxx6
-rw-r--r--Source/cmNinjaNormalTargetGenerator.cxx9
-rw-r--r--Source/cmNinjaTargetGenerator.cxx5
-rw-r--r--Source/kwsys/testConsoleBuf.cxx225
-rw-r--r--Source/kwsys/testConsoleBuf.hxx3
-rw-r--r--Source/kwsys/testConsoleBufChild.cxx14
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);