summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt3
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CTest/cmCTestUpdateHandler.cxx4
-rw-r--r--Source/CTest/cmCTestUploadHandler.cxx2
-rw-r--r--Source/CTest/cmProcess.cxx46
-rw-r--r--Source/cmCTest.cxx2
-rw-r--r--Source/cmExecuteProcessCommand.cxx57
-rw-r--r--Source/cmGeneratorExpressionNode.cxx10
-rw-r--r--Source/cmGetPipes.cxx48
-rw-r--r--Source/cmGetPipes.h8
-rw-r--r--Source/cmMessageCommand.cxx52
-rw-r--r--Source/cmQtAutoMocUic.cxx6
-rw-r--r--Source/cmServerProtocol.cxx5
-rw-r--r--Source/cmSourceGroupCommand.cxx5
-rw-r--r--Source/cmSystemTools.cxx8
-rw-r--r--Source/cmSystemTools.h3
-rw-r--r--Source/cmTargetLinkLibrariesCommand.cxx4
-rw-r--r--Source/cmUVHandlePtr.cxx54
-rw-r--r--Source/cmUVHandlePtr.h40
-rw-r--r--Source/cmUVStreambuf.h219
-rw-r--r--Source/cmWorkerPool.cxx261
-rw-r--r--Source/cmWorkerPool.h47
-rw-r--r--Source/cmake.cxx27
-rw-r--r--Source/cmake.h20
-rw-r--r--Source/cmakemain.cxx2
25 files changed, 698 insertions, 237 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 49f237f..01c6cd7 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -264,6 +264,8 @@ set(SRCS
cmGeneratorExpression.h
cmGeneratorTarget.cxx
cmGeneratorTarget.h
+ cmGetPipes.cxx
+ cmGetPipes.h
cmGlobalCommonGenerator.cxx
cmGlobalCommonGenerator.h
cmGlobalGenerator.cxx
@@ -386,6 +388,7 @@ set(SRCS
cmUuid.cxx
cmUVHandlePtr.cxx
cmUVHandlePtr.h
+ cmUVStreambuf.h
cmUVSignalHackRAII.h
cmVariableWatch.cxx
cmVariableWatch.h
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index af246df..1b34ba5 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 14)
-set(CMake_VERSION_PATCH 20190422)
+set(CMake_VERSION_PATCH 20190502)
#set(CMake_VERSION_RC 1)
diff --git a/Source/CTest/cmCTestUpdateHandler.cxx b/Source/CTest/cmCTestUpdateHandler.cxx
index e3b7e9e..5cfc4a7 100644
--- a/Source/CTest/cmCTestUpdateHandler.cxx
+++ b/Source/CTest/cmCTestUpdateHandler.cxx
@@ -199,6 +199,10 @@ int cmCTestUpdateHandler::ProcessHandler()
xml.Element("UpdateCommand", vc->GetUpdateCommandLine());
xml.Element("UpdateType",
cmCTestUpdateHandlerUpdateToString(this->UpdateType));
+ std::string changeId = this->CTest->GetCTestConfiguration("ChangeId");
+ if (!changeId.empty()) {
+ xml.Element("ChangeId", changeId);
+ }
bool loadedMods = vc->WriteXML(xml);
diff --git a/Source/CTest/cmCTestUploadHandler.cxx b/Source/CTest/cmCTestUploadHandler.cxx
index ee9ee91..9efdf70 100644
--- a/Source/CTest/cmCTestUploadHandler.cxx
+++ b/Source/CTest/cmCTestUploadHandler.cxx
@@ -51,7 +51,7 @@ int cmCTestUploadHandler::ProcessHandler()
this->CTest->GetTestModelString());
xml.Attribute("Name", this->CTest->GetCTestConfiguration("Site"));
xml.Attribute("Generator",
- std::string("ctest") + cmVersion::GetCMakeVersion());
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
this->CTest->AddSiteProperties(xml);
xml.StartElement("Upload");
diff --git a/Source/CTest/cmProcess.cxx b/Source/CTest/cmProcess.cxx
index bfe8d70..a2c30bb 100644
--- a/Source/CTest/cmProcess.cxx
+++ b/Source/CTest/cmProcess.cxx
@@ -5,61 +5,19 @@
#include "cmCTest.h"
#include "cmCTestRunTest.h"
#include "cmCTestTestHandler.h"
+#include "cmGetPipes.h"
#include "cmsys/Process.h"
-#include <fcntl.h>
#include <iostream>
#include <signal.h>
#include <string>
#if defined(_WIN32)
# include "cm_kwiml.h"
-#else
-# include <unistd.h>
#endif
#include <utility>
#define CM_PROCESS_BUF_SIZE 65536
-#if defined(_WIN32) && !defined(__CYGWIN__)
-# include <io.h>
-
-static int cmProcessGetPipes(int* fds)
-{
- SECURITY_ATTRIBUTES attr;
- HANDLE readh, writeh;
- attr.nLength = sizeof(attr);
- attr.lpSecurityDescriptor = nullptr;
- attr.bInheritHandle = FALSE;
- if (!CreatePipe(&readh, &writeh, &attr, 0))
- return uv_translate_sys_error(GetLastError());
- fds[0] = _open_osfhandle((intptr_t)readh, 0);
- fds[1] = _open_osfhandle((intptr_t)writeh, 0);
- if (fds[0] == -1 || fds[1] == -1) {
- CloseHandle(readh);
- CloseHandle(writeh);
- return uv_translate_sys_error(GetLastError());
- }
- return 0;
-}
-#else
-# include <errno.h>
-
-static int cmProcessGetPipes(int* fds)
-{
- if (pipe(fds) == -1) {
- return uv_translate_sys_error(errno);
- }
-
- if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
- fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
- close(fds[0]);
- close(fds[1]);
- return uv_translate_sys_error(errno);
- }
- return 0;
-}
-#endif
-
cmProcess::cmProcess(cmCTestRunTest& runner)
: Runner(runner)
, Conv(cmProcessOutput::UTF8, CM_PROCESS_BUF_SIZE)
@@ -120,7 +78,7 @@ bool cmProcess::StartProcess(uv_loop_t& loop, std::vector<size_t>* affinity)
pipe_reader.init(loop, 0, this);
int fds[2] = { -1, -1 };
- status = cmProcessGetPipes(fds);
+ status = cmGetPipes(fds);
if (status != 0) {
cmCTestLog(this->Runner.GetCTest(), ERROR_MESSAGE,
"Error initializing pipe: " << uv_strerror(status)
diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx
index 709feac..003ebdc 100644
--- a/Source/cmCTest.cxx
+++ b/Source/cmCTest.cxx
@@ -1523,7 +1523,7 @@ int cmCTest::GenerateCTestNotesOutput(cmXMLWriter& xml,
this->Impl->CurrentTag + "-" + this->GetTestModelString());
xml.Attribute("Name", this->GetCTestConfiguration("Site"));
xml.Attribute("Generator",
- std::string("ctest") + cmVersion::GetCMakeVersion());
+ std::string("ctest-") + cmVersion::GetCMakeVersion());
this->AddSiteProperties(xml);
xml.StartElement("Notes");
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index ff6340f..0d9859e 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -6,11 +6,13 @@
#include "cmsys/Process.h"
#include <algorithm>
#include <ctype.h> /* isspace */
+#include <iostream>
#include <stdio.h>
#include "cmAlgorithms.h"
#include "cmArgumentParser.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmProcessOutput.h"
#include "cmSystemTools.h"
@@ -47,6 +49,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
std::string OutputFile;
std::string ErrorFile;
std::string Timeout;
+ std::string CommandEcho;
bool OutputQuiet = false;
bool ErrorQuiet = false;
bool OutputStripTrailingWhitespace = false;
@@ -57,6 +60,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
static auto const parser =
cmArgumentParser<Arguments>{}
.Bind("COMMAND"_s, &Arguments::Commands)
+ .Bind("COMMAND_ECHO"_s, &Arguments::CommandEcho)
.Bind("OUTPUT_VARIABLE"_s, &Arguments::OutputVariable)
.Bind("ERROR_VARIABLE"_s, &Arguments::ErrorVariable)
.Bind("RESULT_VARIABLE"_s, &Arguments::ResultVariable)
@@ -117,9 +121,10 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
return false;
}
}
-
// Create a process instance.
- cmsysProcess* cp = cmsysProcess_New();
+ std::unique_ptr<cmsysProcess, void (*)(cmsysProcess*)> cp_ptr(
+ cmsysProcess_New(), cmsysProcess_Delete);
+ cmsysProcess* cp = cp_ptr.get();
// Set the command sequence.
for (std::vector<std::string> const& cmd : arguments.Commands) {
@@ -169,6 +174,51 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
cmsysProcess_SetTimeout(cp, timeout);
}
+ bool echo_stdout = false;
+ bool echo_stderr = false;
+ bool echo_output_from_variable = true;
+ std::string echo_output =
+ this->Makefile->GetSafeDefinition("CMAKE_EXECUTE_PROCESS_COMMAND_ECHO");
+ if (!arguments.CommandEcho.empty()) {
+ echo_output_from_variable = false;
+ echo_output = arguments.CommandEcho;
+ }
+
+ if (!echo_output.empty()) {
+ if (echo_output == "STDERR") {
+ echo_stderr = true;
+ } else if (echo_output == "STDOUT") {
+ echo_stdout = true;
+ } else if (echo_output != "NONE") {
+ std::string error;
+ if (echo_output_from_variable) {
+ error = "CMAKE_EXECUTE_PROCESS_COMMAND_ECHO set to '";
+ } else {
+ error = " called with '";
+ }
+ error += echo_output;
+ error += "' expected STDERR|STDOUT|NONE";
+ if (!echo_output_from_variable) {
+ error += " for COMMAND_ECHO.";
+ }
+ this->Makefile->IssueMessage(MessageType::FATAL_ERROR, error);
+ return true;
+ }
+ }
+ if (echo_stdout || echo_stderr) {
+ std::string command;
+ for (auto& cmd : arguments.Commands) {
+ command += "'";
+ command += cmJoin(cmd, "' '");
+ command += "'";
+ command += "\n";
+ }
+ if (echo_stdout) {
+ std::cout << command;
+ } else if (echo_stderr) {
+ std::cerr << command;
+ }
+ }
// Start the process.
cmsysProcess_Execute(cp);
@@ -297,9 +347,6 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
}
}
- // Delete the process instance.
- cmsysProcess_Delete(cp);
-
return true;
}
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index 8b3d9d6..8803830 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -1600,10 +1600,16 @@ static const struct TargetObjectsNode : public cmGeneratorExpressionNode
reportError(context, content->GetOriginalExpression(), e.str());
return std::string();
}
- if (gt->GetType() != cmStateEnums::OBJECT_LIBRARY) {
+ cmStateEnums::TargetType type = gt->GetType();
+ if (type != cmStateEnums::EXECUTABLE &&
+ type != cmStateEnums::STATIC_LIBRARY &&
+ type != cmStateEnums::SHARED_LIBRARY &&
+ type != cmStateEnums::MODULE_LIBRARY &&
+ type != cmStateEnums::OBJECT_LIBRARY) {
std::ostringstream e;
e << "Objects of target \"" << tgtName
- << "\" referenced but is not an OBJECT library.";
+ << "\" referenced but is not an allowed library types (EXECUTABLE, "
+ << "STATIC, SHARED, MODULE, OBJECT).";
reportError(context, content->GetOriginalExpression(), e.str());
return std::string();
}
diff --git a/Source/cmGetPipes.cxx b/Source/cmGetPipes.cxx
new file mode 100644
index 0000000..ad323f7
--- /dev/null
+++ b/Source/cmGetPipes.cxx
@@ -0,0 +1,48 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmGetPipes.h"
+
+#include "cm_uv.h"
+
+#include <fcntl.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# include <io.h>
+
+int cmGetPipes(int* fds)
+{
+ SECURITY_ATTRIBUTES attr;
+ HANDLE readh, writeh;
+ attr.nLength = sizeof(attr);
+ attr.lpSecurityDescriptor = nullptr;
+ attr.bInheritHandle = FALSE;
+ if (!CreatePipe(&readh, &writeh, &attr, 0))
+ return uv_translate_sys_error(GetLastError());
+ fds[0] = _open_osfhandle((intptr_t)readh, 0);
+ fds[1] = _open_osfhandle((intptr_t)writeh, 0);
+ if (fds[0] == -1 || fds[1] == -1) {
+ CloseHandle(readh);
+ CloseHandle(writeh);
+ return uv_translate_sys_error(GetLastError());
+ }
+ return 0;
+}
+#else
+# include <errno.h>
+# include <unistd.h>
+
+int cmGetPipes(int* fds)
+{
+ if (pipe(fds) == -1) {
+ return uv_translate_sys_error(errno);
+ }
+
+ if (fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
+ fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
+ close(fds[0]);
+ close(fds[1]);
+ return uv_translate_sys_error(errno);
+ }
+ return 0;
+}
+#endif
diff --git a/Source/cmGetPipes.h b/Source/cmGetPipes.h
new file mode 100644
index 0000000..2a46b51
--- /dev/null
+++ b/Source/cmGetPipes.h
@@ -0,0 +1,8 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmGetPipes_h
+#define cmGetPipes_h
+
+int cmGetPipes(int* fds);
+
+#endif
diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx
index 2724030..5320ec5 100644
--- a/Source/cmMessageCommand.cxx
+++ b/Source/cmMessageCommand.cxx
@@ -8,6 +8,9 @@
#include "cmMessenger.h"
#include "cmRange.h"
#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cassert>
class cmExecutionStatus;
@@ -19,49 +22,88 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args,
this->SetError("called with incorrect number of arguments");
return false;
}
- std::vector<std::string>::const_iterator i = args.begin();
+ auto i = args.cbegin();
- MessageType type = MessageType::MESSAGE;
- bool status = false;
- bool fatal = false;
+ auto type = MessageType::MESSAGE;
+ auto status = false;
+ auto fatal = false;
+ auto level = cmake::LogLevel::LOG_UNDEFINED;
if (*i == "SEND_ERROR") {
type = MessageType::FATAL_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
++i;
} else if (*i == "FATAL_ERROR") {
fatal = true;
type = MessageType::FATAL_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
++i;
} else if (*i == "WARNING") {
type = MessageType::WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
++i;
} else if (*i == "AUTHOR_WARNING") {
if (this->Makefile->IsSet("CMAKE_SUPPRESS_DEVELOPER_ERRORS") &&
!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_ERRORS")) {
fatal = true;
type = MessageType::AUTHOR_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
} else if (!this->Makefile->IsOn("CMAKE_SUPPRESS_DEVELOPER_WARNINGS")) {
type = MessageType::AUTHOR_WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
} else if (*i == "STATUS") {
status = true;
+ level = cmake::LogLevel::LOG_STATUS;
+ ++i;
+ } else if (*i == "VERBOSE") {
+ status = true;
+ level = cmake::LogLevel::LOG_VERBOSE;
+ ++i;
+ } else if (*i == "DEBUG") {
+ status = true;
+ level = cmake::LogLevel::LOG_DEBUG;
+ ++i;
+ } else if (*i == "TRACE") {
+ status = true;
+ level = cmake::LogLevel::LOG_TRACE;
++i;
} else if (*i == "DEPRECATION") {
if (this->Makefile->IsOn("CMAKE_ERROR_DEPRECATED")) {
fatal = true;
type = MessageType::DEPRECATION_ERROR;
+ level = cmake::LogLevel::LOG_ERROR;
} else if ((!this->Makefile->IsSet("CMAKE_WARN_DEPRECATED") ||
this->Makefile->IsOn("CMAKE_WARN_DEPRECATED"))) {
type = MessageType::DEPRECATION_WARNING;
+ level = cmake::LogLevel::LOG_WARNING;
} else {
return true;
}
++i;
+ } else if (*i == "NOTICE") {
+ // `NOTICE` message type is going to be output to stderr
+ level = cmake::LogLevel::LOG_NOTICE;
+ ++i;
+ } else {
+ // Messages w/o any type are `NOTICE`s
+ level = cmake::LogLevel::LOG_NOTICE;
+ }
+ assert("Message log level expected to be set" &&
+ level != cmake::LogLevel::LOG_UNDEFINED);
+
+ auto desiredLevel = this->Makefile->GetCMakeInstance()->GetLogLevel();
+ assert("Expected a valid log level here" &&
+ desiredLevel != cmake::LogLevel::LOG_UNDEFINED);
+
+ if (desiredLevel < level) {
+ // Suppress the message
+ return true;
}
- std::string message = cmJoin(cmMakeRange(i, args.end()), std::string());
+ auto message = cmJoin(cmMakeRange(i, args.cend()), "");
if (type != MessageType::MESSAGE) {
// we've overridden the message type, above, so display it directly
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index 75c5d8a..005c27d 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -1186,6 +1186,7 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile)
num = std::min<unsigned long>(num, ParallelMax);
Base_.NumThreads = static_cast<unsigned int>(num);
}
+ WorkerPool_.SetThreadCount(Base_.NumThreads);
}
// - Files and directories
@@ -1482,15 +1483,12 @@ bool cmQtAutoMocUic::Process()
if (!CreateDirectories()) {
return false;
}
-
- if (!WorkerPool_.Process(Base().NumThreads, this)) {
+ if (!WorkerPool_.Process(this)) {
return false;
}
-
if (JobError_) {
return false;
}
-
return SettingsFileWrite();
}
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 203ee93..dad8821 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -8,6 +8,7 @@
#include "cmGlobalGenerator.h"
#include "cmJsonObjectDictionary.h"
#include "cmJsonObjects.h"
+#include "cmMessageType.h"
#include "cmServer.h"
#include "cmServerDictionary.h"
#include "cmState.h"
@@ -600,6 +601,10 @@ cmServerResponse cmServerProtocol1::ProcessConfigure(
}
int ret = cm->Configure();
+ cm->IssueMessage(
+ MessageType::DEPRECATION_WARNING,
+ "The 'cmake-server(7)' is deprecated. "
+ "Please port clients to use the 'cmake-file-api(7)' instead.");
if (ret < 0) {
return request.ReportError("Configuration failed.");
}
diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx
index 2bc4c39..5cdacaa 100644
--- a/Source/cmSourceGroupCommand.cxx
+++ b/Source/cmSourceGroupCommand.cxx
@@ -80,7 +80,10 @@ std::vector<std::string> prepareFilesPathsForTree(
prepared.reserve(filesPaths.size());
for (auto const& filePath : filesPaths) {
- prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir));
+ // If provided file path is actually not a file, silently ignore it.
+ if (cmSystemTools::FileExists(filePath, /*isFile=*/true)) {
+ prepared.push_back(prepareFilePathForTree(filePath, currentSourceDir));
+ }
}
return prepared;
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 212608d..bc853b7 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -168,7 +168,6 @@ bool cmSystemTools::s_RunCommandHideConsole = false;
bool cmSystemTools::s_DisableRunCommandOutput = false;
bool cmSystemTools::s_ErrorOccured = false;
bool cmSystemTools::s_FatalErrorOccured = false;
-bool cmSystemTools::s_DisableMessages = false;
bool cmSystemTools::s_ForceUnixPaths = false;
// replace replace with with as many times as it shows up in source.
@@ -326,14 +325,11 @@ void cmSystemTools::Stdout(const std::string& s)
void cmSystemTools::Message(const std::string& m, const char* title)
{
- if (s_DisableMessages) {
- return;
- }
if (s_MessageCallback) {
s_MessageCallback(m, title);
- return;
+ } else {
+ std::cerr << m << std::endl;
}
- std::cerr << m << std::endl << std::flush;
}
void cmSystemTools::ReportLastSystemError(const char* msg)
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index a8b2d37..05bd351 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -266,8 +266,6 @@ public:
static size_t CalculateCommandLineLengthLimit();
- static void EnableMessages() { s_DisableMessages = false; }
- static void DisableMessages() { s_DisableMessages = true; }
static void DisableRunCommandOutput() { s_DisableRunCommandOutput = true; }
static void EnableRunCommandOutput() { s_DisableRunCommandOutput = false; }
static bool GetRunCommandOutput() { return s_DisableRunCommandOutput; }
@@ -540,7 +538,6 @@ private:
static bool s_RunCommandHideConsole;
static bool s_ErrorOccured;
static bool s_FatalErrorOccured;
- static bool s_DisableMessages;
static bool s_DisableRunCommandOutput;
};
diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx
index 5c7b95c..3883b52 100644
--- a/Source/cmTargetLinkLibrariesCommand.cxx
+++ b/Source/cmTargetLinkLibrariesCommand.cxx
@@ -456,8 +456,8 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib,
this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) {
std::string configLib =
this->Target->GetDebugGeneratorExpressions(libRef, llt);
- if (cmGeneratorExpression::IsValidTargetName(libRef) ||
- cmGeneratorExpression::Find(libRef) != std::string::npos) {
+ if (cmGeneratorExpression::IsValidTargetName(lib) ||
+ cmGeneratorExpression::Find(lib) != std::string::npos) {
configLib = "$<LINK_ONLY:" + configLib + ">";
}
this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES",
diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx
index fd07d2d..27069ee 100644
--- a/Source/cmUVHandlePtr.cxx
+++ b/Source/cmUVHandlePtr.cxx
@@ -11,19 +11,59 @@
namespace cm {
-static void close_delete(uv_handle_t* h)
+struct uv_loop_deleter
{
- free(h);
+ void operator()(uv_loop_t* loop) const;
+};
+
+void uv_loop_deleter::operator()(uv_loop_t* loop) const
+{
+ uv_run(loop, UV_RUN_DEFAULT);
+ int result = uv_loop_close(loop);
+ (void)result;
+ assert(result >= 0);
+ free(loop);
+}
+
+int uv_loop_ptr::init(void* data)
+{
+ this->reset();
+
+ this->loop.reset(static_cast<uv_loop_t*>(calloc(1, sizeof(uv_loop_t))),
+ uv_loop_deleter());
+ this->loop->data = data;
+
+ return uv_loop_init(this->loop.get());
+}
+
+void uv_loop_ptr::reset()
+{
+ this->loop.reset();
+}
+
+uv_loop_ptr::operator uv_loop_t*()
+{
+ return this->loop.get();
+}
+
+uv_loop_t* uv_loop_ptr::operator->() const noexcept
+{
+ return this->loop.get();
+}
+
+uv_loop_t* uv_loop_ptr::get() const
+{
+ return this->loop.get();
}
template <typename T>
-static void default_delete(T* type_handle)
+static void handle_default_delete(T* type_handle)
{
auto handle = reinterpret_cast<uv_handle_t*>(type_handle);
if (handle) {
assert(!uv_is_closing(handle));
if (!uv_is_closing(handle)) {
- uv_close(handle, &close_delete);
+ uv_close(handle, [](uv_handle_t* h) { free(h); });
}
}
}
@@ -34,7 +74,7 @@ static void default_delete(T* type_handle)
template <typename T>
struct uv_handle_deleter
{
- void operator()(T* type_handle) const { default_delete(type_handle); }
+ void operator()(T* type_handle) const { handle_default_delete(type_handle); }
};
template <typename T>
@@ -107,7 +147,7 @@ struct uv_handle_deleter<uv_async_t>
void operator()(uv_async_t* handle)
{
std::lock_guard<std::mutex> lock(*handleMutex);
- default_delete(handle);
+ handle_default_delete(handle);
}
};
@@ -136,7 +176,7 @@ struct uv_handle_deleter<uv_signal_t>
{
if (handle) {
uv_signal_stop(handle);
- default_delete(handle);
+ handle_default_delete(handle);
}
}
};
diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h
index 992c429..c09e4bf 100644
--- a/Source/cmUVHandlePtr.h
+++ b/Source/cmUVHandlePtr.h
@@ -30,7 +30,45 @@
namespace cm {
/***
- * RAII class to simplify and insure the safe usage of uv_*_t types. This
+ * RAII class to simplify and ensure the safe usage of uv_loop_t. This includes
+ * making sure resources are properly freed.
+ */
+class uv_loop_ptr
+{
+protected:
+ std::shared_ptr<uv_loop_t> loop;
+
+public:
+ uv_loop_ptr(uv_loop_ptr const&) = delete;
+ uv_loop_ptr& operator=(uv_loop_ptr const&) = delete;
+ uv_loop_ptr(uv_loop_ptr&&) noexcept;
+ uv_loop_ptr& operator=(uv_loop_ptr&&) noexcept;
+
+ // Dtor and ctor need to be inline defined like this for default ctors and
+ // dtors to work. Some compilers do not like '= default' here.
+ uv_loop_ptr() {} // NOLINT(modernize-use-equals-default)
+ uv_loop_ptr(std::nullptr_t) {}
+ ~uv_loop_ptr() { this->reset(); }
+
+ int init(void* data = nullptr);
+
+ /**
+ * Properly close the handle if needed and sets the inner handle to nullptr
+ */
+ void reset();
+
+ /**
+ * Allow less verbose calling of uv_loop_* functions
+ * @return reinterpreted handle
+ */
+ operator uv_loop_t*();
+
+ uv_loop_t* get() const;
+ uv_loop_t* operator->() const noexcept;
+};
+
+/***
+ * RAII class to simplify and ensure the safe usage of uv_*_t types. This
* includes making sure resources are properly freed and contains casting
* operators which allow for passing into relevant uv_* functions.
*
diff --git a/Source/cmUVStreambuf.h b/Source/cmUVStreambuf.h
new file mode 100644
index 0000000..29e4fde
--- /dev/null
+++ b/Source/cmUVStreambuf.h
@@ -0,0 +1,219 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmUVStreambuf_h
+#define cmUVStreambuf_h
+
+#include "cmUVHandlePtr.h"
+
+#include "cm_uv.h"
+
+#include <algorithm>
+#include <cstring>
+#include <streambuf>
+#include <vector>
+
+/*
+ * This file is based on example code from:
+ *
+ * http://www.voidcn.com/article/p-vjnlygmc-gy.html
+ *
+ * The example code was distributed under the following license:
+ *
+ * Copyright 2007 Edd Dawson.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+template <typename CharT, typename Traits = std::char_traits<CharT>>
+class cmBasicUVStreambuf : public std::basic_streambuf<CharT, Traits>
+{
+public:
+ cmBasicUVStreambuf(std::size_t bufSize = 256, std::size_t putBack = 8);
+ ~cmBasicUVStreambuf() override;
+
+ bool is_open() const;
+
+ cmBasicUVStreambuf* open(uv_stream_t* stream);
+
+ cmBasicUVStreambuf* close();
+
+protected:
+ typename cmBasicUVStreambuf::int_type underflow() override;
+ std::streamsize showmanyc() override;
+
+ // FIXME: Add write support
+
+private:
+ uv_stream_t* Stream = nullptr;
+ void* OldStreamData;
+ const std::size_t PutBack;
+ std::vector<CharT> InputBuffer;
+ bool EndOfFile;
+
+ void StreamReadStartStop();
+
+ void StreamRead(ssize_t nread);
+ void HandleAlloc(uv_buf_t* buf);
+};
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>::cmBasicUVStreambuf(std::size_t bufSize,
+ std::size_t putBack)
+ : PutBack(std::max<std::size_t>(putBack, 1))
+ , InputBuffer(std::max<std::size_t>(this->PutBack, bufSize) + this->PutBack)
+{
+ this->close();
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>::~cmBasicUVStreambuf()
+{
+ this->close();
+}
+
+template <typename CharT, typename Traits>
+bool cmBasicUVStreambuf<CharT, Traits>::is_open() const
+{
+ return this->Stream != nullptr;
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::open(
+ uv_stream_t* stream)
+{
+ this->close();
+ this->Stream = stream;
+ this->EndOfFile = false;
+ if (this->Stream) {
+ this->OldStreamData = this->Stream->data;
+ this->Stream->data = this;
+ }
+ this->StreamReadStartStop();
+ return this;
+}
+
+template <typename CharT, typename Traits>
+cmBasicUVStreambuf<CharT, Traits>* cmBasicUVStreambuf<CharT, Traits>::close()
+{
+ if (this->Stream) {
+ uv_read_stop(this->Stream);
+ this->Stream->data = this->OldStreamData;
+ }
+ this->Stream = nullptr;
+ CharT* readEnd = this->InputBuffer.data() + this->InputBuffer.size();
+ this->setg(readEnd, readEnd, readEnd);
+ return this;
+}
+
+template <typename CharT, typename Traits>
+typename cmBasicUVStreambuf<CharT, Traits>::int_type
+cmBasicUVStreambuf<CharT, Traits>::underflow()
+{
+ if (!this->is_open()) {
+ return Traits::eof();
+ }
+
+ if (this->gptr() < this->egptr()) {
+ return Traits::to_int_type(*this->gptr());
+ }
+
+ this->StreamReadStartStop();
+ while (this->in_avail() == 0) {
+ uv_run(this->Stream->loop, UV_RUN_ONCE);
+ }
+ if (this->in_avail() == -1) {
+ return Traits::eof();
+ }
+ return Traits::to_int_type(*this->gptr());
+}
+
+template <typename CharT, typename Traits>
+std::streamsize cmBasicUVStreambuf<CharT, Traits>::showmanyc()
+{
+ if (!this->is_open() || this->EndOfFile) {
+ return -1;
+ }
+ return 0;
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::StreamReadStartStop()
+{
+ if (this->Stream) {
+ uv_read_stop(this->Stream);
+ if (this->gptr() >= this->egptr()) {
+ uv_read_start(
+ this->Stream,
+ [](uv_handle_t* handle, size_t /* unused */, uv_buf_t* buf) {
+ auto streambuf =
+ static_cast<cmBasicUVStreambuf<CharT, Traits>*>(handle->data);
+ streambuf->HandleAlloc(buf);
+ },
+ [](uv_stream_t* stream2, ssize_t nread, const uv_buf_t* /* unused */) {
+ auto streambuf =
+ static_cast<cmBasicUVStreambuf<CharT, Traits>*>(stream2->data);
+ streambuf->StreamRead(nread);
+ });
+ }
+ }
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::HandleAlloc(uv_buf_t* buf)
+{
+ auto size = this->egptr() - this->gptr();
+ std::memmove(this->InputBuffer.data(), this->gptr(),
+ this->egptr() - this->gptr());
+ this->setg(this->InputBuffer.data(), this->InputBuffer.data(),
+ this->InputBuffer.data() + size);
+ buf->base = this->egptr();
+#ifdef _WIN32
+# define BUF_LEN_TYPE ULONG
+#else
+# define BUF_LEN_TYPE size_t
+#endif
+ buf->len = BUF_LEN_TYPE(
+ (this->InputBuffer.data() + this->InputBuffer.size() - this->egptr()) *
+ sizeof(CharT));
+#undef BUF_LEN_TYPE
+}
+
+template <typename CharT, typename Traits>
+void cmBasicUVStreambuf<CharT, Traits>::StreamRead(ssize_t nread)
+{
+ if (nread > 0) {
+ this->setg(this->eback(), this->gptr(),
+ this->egptr() + nread / sizeof(CharT));
+ uv_read_stop(this->Stream);
+ } else if (nread < 0 || nread == UV_EOF) {
+ this->EndOfFile = true;
+ uv_read_stop(this->Stream);
+ }
+}
+
+using cmUVStreambuf = cmBasicUVStreambuf<char>;
+
+#endif
diff --git a/Source/cmWorkerPool.cxx b/Source/cmWorkerPool.cxx
index 464182c..cbf070e 100644
--- a/Source/cmWorkerPool.cxx
+++ b/Source/cmWorkerPool.cxx
@@ -371,137 +371,62 @@ void cmUVReadOnlyProcess::UVTryFinish()
}
/**
- * @brief Private worker pool internals
+ * @brief Worker pool worker thread
*/
-class cmWorkerPoolInternal
+class cmWorkerPoolWorker
{
public:
- // -- Types
-
- /**
- * @brief Worker thread
- */
- class WorkerT
- {
- public:
- WorkerT(unsigned int index);
- ~WorkerT();
-
- WorkerT(WorkerT const&) = delete;
- WorkerT& operator=(WorkerT const&) = delete;
-
- /**
- * Start the thread
- */
- void Start(cmWorkerPoolInternal* internal);
-
- /**
- * @brief Run an external process
- */
- bool RunProcess(cmWorkerPool::ProcessResultT& result,
- std::vector<std::string> const& command,
- std::string const& workingDirectory);
-
- // -- Accessors
- unsigned int Index() const { return Index_; }
- cmWorkerPool::JobHandleT& JobHandle() { return JobHandle_; }
-
- private:
- // -- Libuv callbacks
- static void UVProcessStart(uv_async_t* handle);
- void UVProcessFinished();
-
- private:
- //! @brief Job handle
- cmWorkerPool::JobHandleT JobHandle_;
- //! @brief Worker index
- unsigned int Index_;
- // -- Process management
- struct
- {
- std::mutex Mutex;
- cm::uv_async_ptr Request;
- std::condition_variable Condition;
- std::unique_ptr<cmUVReadOnlyProcess> ROP;
- } Proc_;
- // -- System thread
- std::thread Thread_;
- };
-
-public:
- // -- Constructors
- cmWorkerPoolInternal(cmWorkerPool* pool);
- ~cmWorkerPoolInternal();
-
- /**
- * @brief Runs the libuv loop
- */
- bool Process();
+ cmWorkerPoolWorker(uv_loop_t& uvLoop);
+ ~cmWorkerPoolWorker();
- /**
- * @brief Clear queue and abort threads
- */
- void Abort();
+ cmWorkerPoolWorker(cmWorkerPoolWorker const&) = delete;
+ cmWorkerPoolWorker& operator=(cmWorkerPoolWorker const&) = delete;
/**
- * @brief Push a job to the queue and notify a worker
+ * Set the internal thread
*/
- bool PushJob(cmWorkerPool::JobHandleT&& jobHandle);
+ void SetThread(std::thread&& aThread) { Thread_ = std::move(aThread); }
/**
- * @brief Worker thread main loop method
+ * Run an external process
*/
- void Work(WorkerT* worker);
-
- // -- Request slots
- static void UVSlotBegin(uv_async_t* handle);
- static void UVSlotEnd(uv_async_t* handle);
-
-public:
- // -- UV loop
-#ifdef CMAKE_UV_SIGNAL_HACK
- std::unique_ptr<cmUVSignalHackRAII> UVHackRAII;
-#endif
- std::unique_ptr<uv_loop_t> UVLoop;
- cm::uv_async_ptr UVRequestBegin;
- cm::uv_async_ptr UVRequestEnd;
+ bool RunProcess(cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory);
- // -- Thread pool and job queue
- std::mutex Mutex;
- bool Aborting = false;
- bool FenceProcessing = false;
- unsigned int WorkersRunning = 0;
- unsigned int WorkersIdle = 0;
- unsigned int JobsProcessing = 0;
- std::deque<cmWorkerPool::JobHandleT> Queue;
- std::condition_variable Condition;
- std::vector<std::unique_ptr<WorkerT>> Workers;
+private:
+ // -- Libuv callbacks
+ static void UVProcessStart(uv_async_t* handle);
+ void UVProcessFinished();
- // -- References
- cmWorkerPool* Pool = nullptr;
+private:
+ // -- Process management
+ struct
+ {
+ std::mutex Mutex;
+ cm::uv_async_ptr Request;
+ std::condition_variable Condition;
+ std::unique_ptr<cmUVReadOnlyProcess> ROP;
+ } Proc_;
+ // -- System thread
+ std::thread Thread_;
};
-cmWorkerPoolInternal::WorkerT::WorkerT(unsigned int index)
- : Index_(index)
+cmWorkerPoolWorker::cmWorkerPoolWorker(uv_loop_t& uvLoop)
{
+ Proc_.Request.init(uvLoop, &cmWorkerPoolWorker::UVProcessStart, this);
}
-cmWorkerPoolInternal::WorkerT::~WorkerT()
+cmWorkerPoolWorker::~cmWorkerPoolWorker()
{
if (Thread_.joinable()) {
Thread_.join();
}
}
-void cmWorkerPoolInternal::WorkerT::Start(cmWorkerPoolInternal* internal)
-{
- Proc_.Request.init(*(internal->UVLoop), &WorkerT::UVProcessStart, this);
- Thread_ = std::thread(&cmWorkerPoolInternal::Work, internal, this);
-}
-
-bool cmWorkerPoolInternal::WorkerT::RunProcess(
- cmWorkerPool::ProcessResultT& result,
- std::vector<std::string> const& command, std::string const& workingDirectory)
+bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result,
+ std::vector<std::string> const& command,
+ std::string const& workingDirectory)
{
if (command.empty()) {
return false;
@@ -524,9 +449,9 @@ bool cmWorkerPoolInternal::WorkerT::RunProcess(
return !result.error();
}
-void cmWorkerPoolInternal::WorkerT::UVProcessStart(uv_async_t* handle)
+void cmWorkerPoolWorker::UVProcessStart(uv_async_t* handle)
{
- auto* wrk = reinterpret_cast<WorkerT*>(handle->data);
+ auto* wrk = reinterpret_cast<cmWorkerPoolWorker*>(handle->data);
bool startFailed = false;
{
auto& Proc = wrk->Proc_;
@@ -542,7 +467,7 @@ void cmWorkerPoolInternal::WorkerT::UVProcessStart(uv_async_t* handle)
}
}
-void cmWorkerPoolInternal::WorkerT::UVProcessFinished()
+void cmWorkerPoolWorker::UVProcessFinished()
{
{
std::lock_guard<std::mutex> lock(Proc_.Mutex);
@@ -554,6 +479,65 @@ void cmWorkerPoolInternal::WorkerT::UVProcessFinished()
Proc_.Condition.notify_one();
}
+/**
+ * @brief Private worker pool internals
+ */
+class cmWorkerPoolInternal
+{
+public:
+ // -- Constructors
+ cmWorkerPoolInternal(cmWorkerPool* pool);
+ ~cmWorkerPoolInternal();
+
+ /**
+ * Runs the libuv loop.
+ */
+ bool Process();
+
+ /**
+ * Clear queue and abort threads.
+ */
+ void Abort();
+
+ /**
+ * Push a job to the queue and notify a worker.
+ */
+ bool PushJob(cmWorkerPool::JobHandleT&& jobHandle);
+
+ /**
+ * Worker thread main loop method.
+ */
+ void Work(unsigned int workerIndex);
+
+ // -- Request slots
+ static void UVSlotBegin(uv_async_t* handle);
+ static void UVSlotEnd(uv_async_t* handle);
+
+public:
+ // -- UV loop
+#ifdef CMAKE_UV_SIGNAL_HACK
+ std::unique_ptr<cmUVSignalHackRAII> UVHackRAII;
+#endif
+ std::unique_ptr<uv_loop_t> UVLoop;
+ cm::uv_async_ptr UVRequestBegin;
+ cm::uv_async_ptr UVRequestEnd;
+
+ // -- Thread pool and job queue
+ std::mutex Mutex;
+ bool Processing = false;
+ bool Aborting = false;
+ bool FenceProcessing = false;
+ unsigned int WorkersRunning = 0;
+ unsigned int WorkersIdle = 0;
+ unsigned int JobsProcessing = 0;
+ std::deque<cmWorkerPool::JobHandleT> Queue;
+ std::condition_variable Condition;
+ std::vector<std::unique_ptr<cmWorkerPoolWorker>> Workers;
+
+ // -- References
+ cmWorkerPool* Pool = nullptr;
+};
+
void cmWorkerPool::ProcessResultT::reset()
{
ExitStatus = 0;
@@ -591,7 +575,8 @@ cmWorkerPoolInternal::~cmWorkerPoolInternal()
bool cmWorkerPoolInternal::Process()
{
- // Reset state
+ // Reset state flags
+ Processing = true;
Aborting = false;
// Initialize libuv asynchronous request
UVRequestBegin.init(*UVLoop, &cmWorkerPoolInternal::UVSlotBegin, this);
@@ -599,23 +584,27 @@ bool cmWorkerPoolInternal::Process()
// Send begin request
UVRequestBegin.send();
// Run libuv loop
- return (uv_run(UVLoop.get(), UV_RUN_DEFAULT) == 0);
+ bool success = (uv_run(UVLoop.get(), UV_RUN_DEFAULT) == 0);
+ // Update state flags
+ Processing = false;
+ Aborting = false;
+ return success;
}
void cmWorkerPoolInternal::Abort()
{
- bool firstCall = false;
+ bool notifyThreads = false;
// Clear all jobs and set abort flag
{
std::lock_guard<std::mutex> guard(Mutex);
- if (!Aborting) {
+ if (Processing && !Aborting) {
// Register abort and clear queue
Aborting = true;
Queue.clear();
- firstCall = true;
+ notifyThreads = true;
}
}
- if (firstCall) {
+ if (notifyThreads) {
// Wake threads
Condition.notify_all();
}
@@ -627,15 +616,13 @@ inline bool cmWorkerPoolInternal::PushJob(cmWorkerPool::JobHandleT&& jobHandle)
if (Aborting) {
return false;
}
-
// Append the job to the queue
Queue.emplace_back(std::move(jobHandle));
-
// Notify an idle worker if there's one
if (WorkersIdle != 0) {
Condition.notify_one();
}
-
+ // Return success
return true;
}
@@ -648,11 +635,13 @@ void cmWorkerPoolInternal::UVSlotBegin(uv_async_t* handle)
// Create workers
gint.Workers.reserve(num);
for (unsigned int ii = 0; ii != num; ++ii) {
- gint.Workers.emplace_back(cm::make_unique<WorkerT>(ii));
+ gint.Workers.emplace_back(
+ cm::make_unique<cmWorkerPoolWorker>(*gint.UVLoop));
}
- // Start workers
- for (auto& wrk : gint.Workers) {
- wrk->Start(&gint);
+ // Start worker threads
+ for (unsigned int ii = 0; ii != num; ++ii) {
+ gint.Workers[ii]->SetThread(
+ std::thread(&cmWorkerPoolInternal::Work, &gint, ii));
}
}
// Destroy begin request
@@ -668,8 +657,9 @@ void cmWorkerPoolInternal::UVSlotEnd(uv_async_t* handle)
gint.UVRequestEnd.reset();
}
-void cmWorkerPoolInternal::Work(WorkerT* worker)
+void cmWorkerPoolInternal::Work(unsigned int workerIndex)
{
+ cmWorkerPool::JobHandleT jobHandle;
std::unique_lock<std::mutex> uLock(Mutex);
// Increment running workers count
++WorkersRunning;
@@ -698,15 +688,15 @@ void cmWorkerPoolInternal::Work(WorkerT* worker)
}
// Pop next job from queue
- worker->JobHandle() = std::move(Queue.front());
+ jobHandle = std::move(Queue.front());
Queue.pop_front();
// Unlocked scope for job processing
++JobsProcessing;
{
uLock.unlock();
- worker->JobHandle()->Work(Pool, worker->Index()); // Process job
- worker->JobHandle().reset(); // Destroy job
+ jobHandle->Work(Pool, workerIndex); // Process job
+ jobHandle.reset(); // Destroy job
uLock.lock();
}
--JobsProcessing;
@@ -743,19 +733,22 @@ cmWorkerPool::cmWorkerPool()
cmWorkerPool::~cmWorkerPool() = default;
-bool cmWorkerPool::Process(unsigned int threadCount, void* userData)
+void cmWorkerPool::SetThreadCount(unsigned int threadCount)
+{
+ if (!Int_->Processing) {
+ ThreadCount_ = (threadCount > 0) ? threadCount : 1u;
+ }
+}
+
+bool cmWorkerPool::Process(void* userData)
{
// Setup user data
UserData_ = userData;
- ThreadCount_ = (threadCount > 0) ? threadCount : 1u;
-
// Run libuv loop
bool success = Int_->Process();
-
// Clear user data
UserData_ = nullptr;
- ThreadCount_ = 0;
-
+ // Return
return success;
}
diff --git a/Source/cmWorkerPool.h b/Source/cmWorkerPool.h
index 71c7d84..f08bb4f 100644
--- a/Source/cmWorkerPool.h
+++ b/Source/cmWorkerPool.h
@@ -50,12 +50,12 @@ public:
JobT& operator=(JobT const&) = delete;
/**
- * @brief Virtual destructor.
+ * Virtual destructor.
*/
virtual ~JobT();
/**
- * @brief Fence job flag
+ * Fence job flag
*
* Fence jobs require that:
* - all jobs before in the queue have been processed
@@ -66,7 +66,7 @@ public:
protected:
/**
- * @brief Protected default constructor
+ * Protected default constructor
*/
JobT(bool fence = false)
: Fence_(fence)
@@ -125,12 +125,12 @@ public:
};
/**
- * @brief Job handle type
+ * Job handle type
*/
typedef std::unique_ptr<JobT> JobHandleT;
/**
- * @brief Fence job base class
+ * Fence job base class
*/
class JobFenceT : public JobT
{
@@ -144,8 +144,9 @@ public:
};
/**
- * @brief Fence job that aborts the worker pool.
- * This class is useful as the last job in the job queue.
+ * Fence job that aborts the worker pool.
+ *
+ * Useful as the last job in the job queue.
*/
class JobEndT : JobFenceT
{
@@ -160,23 +161,29 @@ public:
~cmWorkerPool();
/**
- * @brief Blocking function that starts threads to process all Jobs in
- * the queue.
+ * Number of worker threads.
+ */
+ unsigned int ThreadCount() const { return ThreadCount_; }
+
+ /**
+ * Set the number of worker threads.
*
- * This method blocks until a job calls the Abort() method.
- * @arg threadCount Number of threads to process jobs.
- * @arg userData Common user data pointer available in all Jobs.
+ * Calling this method during Process() has no effect.
*/
- bool Process(unsigned int threadCount, void* userData = nullptr);
+ void SetThreadCount(unsigned int threadCount);
/**
- * Number of worker threads passed to Process().
- * Only valid during Process().
+ * Blocking function that starts threads to process all Jobs in the queue.
+ *
+ * This method blocks until a job calls the Abort() method.
+ * @arg threadCount Number of threads to process jobs.
+ * @arg userData Common user data pointer available in all Jobs.
*/
- unsigned int ThreadCount() const { return ThreadCount_; }
+ bool Process(void* userData = nullptr);
/**
* User data reference passed to Process().
+ *
* Only valid during Process().
*/
void* UserData() const { return UserData_; }
@@ -184,14 +191,14 @@ public:
// -- Job processing interface
/**
- * @brief Clears the job queue and aborts all worker threads.
+ * Clears the job queue and aborts all worker threads.
*
* This method is thread safe and can be called from inside a job.
*/
void Abort();
/**
- * @brief Push job to the queue.
+ * Push job to the queue.
*
* This method is thread safe and can be called from inside a job or before
* Process().
@@ -199,7 +206,7 @@ public:
bool PushJob(JobHandleT&& jobHandle);
/**
- * @brief Push job to the queue
+ * Push job to the queue
*
* This method is thread safe and can be called from inside a job or before
* Process().
@@ -212,7 +219,7 @@ public:
private:
void* UserData_ = nullptr;
- unsigned int ThreadCount_ = 0;
+ unsigned int ThreadCount_ = 1;
std::unique_ptr<cmWorkerPoolInternal> Int_;
};
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index fc24ac0..121d12d 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -718,6 +718,14 @@ void cmake::SetArgs(const std::vector<std::string>& args)
} else if (arg.find("--debug-output", 0) == 0) {
std::cout << "Running with debug output on.\n";
this->SetDebugOutputOn(true);
+ } else if (arg.find("--loglevel=", 0) == 0) {
+ const auto logLevel =
+ StringToLogLevel(arg.substr(sizeof("--loglevel=") - 1));
+ if (logLevel == LogLevel::LOG_UNDEFINED) {
+ cmSystemTools::Error("Invalid level specified for --loglevel");
+ return;
+ }
+ this->SetLogLevel(logLevel);
} else if (arg.find("--trace-expand", 0) == 0) {
std::cout << "Running with expanded trace output on.\n";
this->SetTrace(true);
@@ -828,6 +836,25 @@ void cmake::SetArgs(const std::vector<std::string>& args)
}
}
+cmake::LogLevel cmake::StringToLogLevel(const std::string& levelStr)
+{
+ using LevelsPair = std::pair<std::string, LogLevel>;
+ static const std::vector<LevelsPair> levels = {
+ { "error", LogLevel::LOG_ERROR }, { "warning", LogLevel::LOG_WARNING },
+ { "notice", LogLevel::LOG_NOTICE }, { "status", LogLevel::LOG_STATUS },
+ { "verbose", LogLevel::LOG_VERBOSE }, { "debug", LogLevel::LOG_DEBUG },
+ { "trace", LogLevel::LOG_TRACE }
+ };
+
+ const auto levelStrLowCase = cmSystemTools::LowerCase(levelStr);
+
+ const auto it = std::find_if(levels.cbegin(), levels.cend(),
+ [&levelStrLowCase](const LevelsPair& p) {
+ return p.first == levelStrLowCase;
+ });
+ return (it != levels.cend()) ? it->second : LogLevel::LOG_UNDEFINED;
+}
+
void cmake::SetDirectoriesFromFile(const char* arg)
{
// Check if the argument refers to a CMakeCache.txt or
diff --git a/Source/cmake.h b/Source/cmake.h
index 8b4b396..4a345cf 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -96,6 +96,19 @@ public:
FIND_PACKAGE_MODE
};
+ /** \brief Define log level constants. */
+ enum LogLevel
+ {
+ LOG_UNDEFINED,
+ LOG_ERROR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_STATUS,
+ LOG_VERBOSE,
+ LOG_DEBUG,
+ LOG_TRACE
+ };
+
struct GeneratorInfo
{
std::string name;
@@ -331,6 +344,11 @@ public:
*/
cmFileTimeCache* GetFileTimeCache() { return this->FileTimeCache; }
+ // Get the selected log level for `message()` commands during the cmake run.
+ LogLevel GetLogLevel() const { return this->MessageLogLevel; }
+ void SetLogLevel(LogLevel level) { this->MessageLogLevel = level; }
+ static LogLevel StringToLogLevel(const std::string& levelStr);
+
// Do we want debug output during the cmake run.
bool GetDebugOutput() { return this->DebugOutput; }
void SetDebugOutputOn(bool b) { this->DebugOutput = b; }
@@ -524,6 +542,8 @@ private:
std::vector<std::string> TraceOnlyThisSources;
+ LogLevel MessageLogLevel = LogLevel::LOG_STATUS;
+
void UpdateConversionPathTable();
// Print a list of valid generators to stderr.
diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx
index d70c9d9..5631d10 100644
--- a/Source/cmakemain.cxx
+++ b/Source/cmakemain.cxx
@@ -95,6 +95,8 @@ static const char* cmDocumentationOptions[][2] = {
"Generate graphviz of dependencies, see "
"CMakeGraphVizOptions.cmake for more." },
{ "--system-information [file]", "Dump information about this system." },
+ { "--loglevel=<error|warn|notice|status|verbose|debug|trace>",
+ "Set the verbosity of messages from CMake files." },
{ "--debug-trycompile",
"Do not delete the try_compile build tree. Only "
"useful on one try_compile at a time." },