summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake.1.rst30
-rw-r--r--Help/release/3.9.rst7
-rw-r--r--Help/release/dev/cmake-command-mode-shasum.rst5
-rw-r--r--Modules/FindLibXml2.cmake46
-rw-r--r--Modules/Platform/GHS-MULTI-Initialize.cmake2
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx9
-rw-r--r--Source/CTest/cmCTestSubmitHandler.cxx12
-rw-r--r--Source/cmConnection.cxx158
-rw-r--r--Source/cmConnection.h118
-rw-r--r--Source/cmFileMonitor.cxx4
-rw-r--r--Source/cmGeneratorTarget.cxx11
-rw-r--r--Source/cmGeneratorTarget.h5
-rw-r--r--Source/cmGlobalXCodeGenerator.cxx11
-rw-r--r--Source/cmPipeConnection.cxx80
-rw-r--r--Source/cmPipeConnection.h28
-rw-r--r--Source/cmServer.cxx242
-rw-r--r--Source/cmServer.h98
-rw-r--r--Source/cmServerConnection.cxx391
-rw-r--r--Source/cmServerConnection.h94
-rw-r--r--Source/cmServerProtocol.cxx6
-rw-r--r--Source/cmServerProtocol.h5
-rw-r--r--Source/cmSystemTools.cxx14
-rw-r--r--Source/cmSystemTools.h6
-rw-r--r--Source/cmcmd.cxx76
-rw-r--r--Source/cmcmd.h3
-rw-r--r--Templates/TestDriver.cxx.in4
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-mixed-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-mixed-stderr.txt2
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-mixed-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_md5sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha1sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha224sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha256sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha384sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-dir-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-dir-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-no-file-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-no-file-stderr.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-result.txt1
-rw-r--r--Tests/RunCMake/CommandLine/E_sha512sum-stdout.txt1
-rw-r--r--Tests/RunCMake/CommandLine/RunCMakeTest.cmake24
-rw-r--r--Tests/RunCMake/ObjectLibrary/OwnSources-result.txt1
-rw-r--r--Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt5
-rw-r--r--Tests/RunCMake/ObjectLibrary/OwnSources.cmake2
-rw-r--r--Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake1
-rw-r--r--Tests/Server/server-test.py2
-rw-r--r--Utilities/IWYU/mapping.imp1
74 files changed, 1052 insertions, 493 deletions
diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst
index ba925e8..8aece23 100644
--- a/Help/manual/cmake.1.rst
+++ b/Help/manual/cmake.1.rst
@@ -262,6 +262,36 @@ Available commands are:
351abe79cd3800b38cdfb25d45015a15 file1.txt
052f86c15bbde68af55c7f7b340ab639 file2.txt
+``sha1sum <file>...``
+ Create SHA1 checksum of files in ``sha1sum`` compatible format::
+
+ 4bb7932a29e6f73c97bb9272f2bdc393122f86e0 file1.txt
+ 1df4c8f318665f9a5f2ed38f55adadb7ef9f559c file2.txt
+
+``sha224sum <file>...``
+ Create SHA224 checksum of files in ``sha224sum`` compatible format::
+
+ b9b9346bc8437bbda630b0b7ddfc5ea9ca157546dbbf4c613192f930 file1.txt
+ 6dfbe55f4d2edc5fe5c9197bca51ceaaf824e48eba0cc453088aee24 file2.txt
+
+``sha256sum <file>...``
+ Create SHA256 checksum of files in ``sha256sum`` compatible format::
+
+ 76713b23615d31680afeb0e9efe94d47d3d4229191198bb46d7485f9cb191acc file1.txt
+ 15b682ead6c12dedb1baf91231e1e89cfc7974b3787c1e2e01b986bffadae0ea file2.txt
+
+``sha384sum <file>...``
+ Create SHA384 checksum of files in ``sha384sum`` compatible format::
+
+ acc049fedc091a22f5f2ce39a43b9057fd93c910e9afd76a6411a28a8f2b8a12c73d7129e292f94fc0329c309df49434 file1.txt
+ 668ddeb108710d271ee21c0f3acbd6a7517e2b78f9181c6a2ff3b8943af92b0195dcb7cce48aa3e17893173c0a39e23d file2.txt
+
+``sha512sum <file>...``
+ Create SHA512 checksum of files in ``sha512sum`` compatible format::
+
+ 2a78d7a6c5328cfb1467c63beac8ff21794213901eaadafd48e7800289afbc08e5fb3e86aa31116c945ee3d7bf2a6194489ec6101051083d1108defc8e1dba89 file1.txt
+ 7a0b54896fe5e70cca6dd643ad6f672614b189bf26f8153061c4d219474b05dad08c4e729af9f4b009f1a1a280cb625454bf587c690f4617c27e3aebdf3b7a2d file2.txt
+
``remove [-f] <file>...``
Remove the file(s). If any of the listed files already do not
exist, the command returns a non-zero exit code, but no message
diff --git a/Help/release/3.9.rst b/Help/release/3.9.rst
index c31f533..14e8699 100644
--- a/Help/release/3.9.rst
+++ b/Help/release/3.9.rst
@@ -34,6 +34,8 @@ Generators
This is an experimental feature and can be activated by setting the
:variable:`CMAKE_XCODE_GENERATE_SCHEME` variable to a ``TRUE`` value.
+* The :generator:`Xcode` generator now supports Xcode 9.
+
Commands
--------
@@ -319,3 +321,8 @@ Other Changes
* On macOS, ``RPATH`` settings such as :prop_tgt:`BUILD_WITH_INSTALL_RPATH`
no longer affect the ``install_name`` field. See policy :policy:`CMP0068`.
+
+* The :generator:`Visual Studio 14 2015` generator has been taught about
+ a change to the ``v140`` toolset made by a VS 2015 update. VS changed
+ the set of values it understands for the ``GenerateDebugInformation``
+ linker setting that produces the ``-DEBUG`` linker flag variants.
diff --git a/Help/release/dev/cmake-command-mode-shasum.rst b/Help/release/dev/cmake-command-mode-shasum.rst
new file mode 100644
index 0000000..681e0c0
--- /dev/null
+++ b/Help/release/dev/cmake-command-mode-shasum.rst
@@ -0,0 +1,5 @@
+cmake-command-mode-shasum
+-------------------------
+
+* Added sha1sum, sha224sum, sha256sum, sha384sum and sha512sum
+ as an equivalent to existing md5sum to cmake command mode.
diff --git a/Modules/FindLibXml2.cmake b/Modules/FindLibXml2.cmake
index 613f927..f68628d 100644
--- a/Modules/FindLibXml2.cmake
+++ b/Modules/FindLibXml2.cmake
@@ -5,18 +5,37 @@
# FindLibXml2
# -----------
#
-# Try to find the LibXml2 xml processing library
+# Find the XML processing library (libxml2).
#
-# Once done this will define
+# Result variables
+# ^^^^^^^^^^^^^^^^
#
-# ::
+# This module will set the following variables in your project:
#
-# LIBXML2_FOUND - System has LibXml2
-# LIBXML2_INCLUDE_DIR - The LibXml2 include directory
-# LIBXML2_LIBRARIES - The libraries needed to use LibXml2
-# LIBXML2_DEFINITIONS - Compiler switches required for using LibXml2
-# LIBXML2_XMLLINT_EXECUTABLE - The XML checking tool xmllint coming with LibXml2
-# LIBXML2_VERSION_STRING - the version of LibXml2 found (since CMake 2.8.8)
+# ``LIBXML2_FOUND``
+# true if libxml2 headers and libraries were found
+# ``LIBXML2_INCLUDE_DIR``
+# the directory containing LibXml2 headers
+# ``LIBXML2_INCLUDE_DIRS``
+# list of the include directories needed to use LibXml2
+# ``LIBXML2_LIBRARIES``
+# LibXml2 libraries to be linked
+# ``LIBXML2_DEFINITIONS``
+# the compiler switches required for using LibXml2
+# ``LIBXML2_XMLLINT_EXECUTABLE``
+# path to the XML checking tool xmllint coming with LibXml2
+# ``LIBXML2_VERSION_STRING``
+# the version of LibXml2 found (since CMake 2.8.8)
+#
+# Cache variables
+# ^^^^^^^^^^^^^^^
+#
+# The following cache variables may also be set:
+#
+# ``LIBXML2_INCLUDE_DIR``
+# the directory containing LibXml2 headers
+# ``LIBXML2_LIBRARY``
+# path to the LibXml2 library
# use pkg-config to get the directories and then use these values
# in the find_path() and find_library() calls
@@ -31,7 +50,7 @@ find_path(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h
PATH_SUFFIXES libxml2
)
-find_library(LIBXML2_LIBRARIES NAMES xml2 libxml2
+find_library(LIBXML2_LIBRARY NAMES xml2 libxml2
HINTS
${PC_LIBXML_LIBDIR}
${PC_LIBXML_LIBRARY_DIRS}
@@ -52,9 +71,12 @@ elseif(LIBXML2_INCLUDE_DIR AND EXISTS "${LIBXML2_INCLUDE_DIR}/libxml/xmlversion.
unset(libxml2_version_str)
endif()
+set(LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR} ${PC_LIBXML_INCLUDE_DIRS})
+set(LIBXML2_LIBRARIES ${LIBXML2_LIBRARY})
+
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2
- REQUIRED_VARS LIBXML2_LIBRARIES LIBXML2_INCLUDE_DIR
+ REQUIRED_VARS LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR
VERSION_VAR LIBXML2_VERSION_STRING)
-mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARIES LIBXML2_XMLLINT_EXECUTABLE)
+mark_as_advanced(LIBXML2_INCLUDE_DIR LIBXML2_LIBRARY LIBXML2_XMLLINT_EXECUTABLE)
diff --git a/Modules/Platform/GHS-MULTI-Initialize.cmake b/Modules/Platform/GHS-MULTI-Initialize.cmake
index fcda6f6..bf61d7b 100644
--- a/Modules/Platform/GHS-MULTI-Initialize.cmake
+++ b/Modules/Platform/GHS-MULTI-Initialize.cmake
@@ -10,7 +10,7 @@ if (NOT GHS_INT_DIRECTORY)
if (EXISTS ${GHS_EXPECTED_ROOT})
FILE(GLOB GHS_CANDIDATE_INT_DIRS RELATIVE
${GHS_EXPECTED_ROOT} ${GHS_EXPECTED_ROOT}/*)
- string(REGEX MATCHALL "int[0-9][0-9][0-9][0-9]" GHS_CANDIDATE_INT_DIRS
+ string(REGEX MATCHALL "int[0-9][0-9][0-9][0-9a-z]" GHS_CANDIDATE_INT_DIRS
${GHS_CANDIDATE_INT_DIRS})
if (GHS_CANDIDATE_INT_DIRS)
list(SORT GHS_CANDIDATE_INT_DIRS)
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index e556ca6..d35b7fb 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -1012,7 +1012,9 @@ target_link_libraries(cmake CMakeLib)
if(CMake_ENABLE_SERVER_MODE)
add_library(CMakeServerLib
+ cmConnection.h cmConnection.cxx
cmFileMonitor.cxx cmFileMonitor.h
+ cmPipeConnection.cxx cmPipeConnection.h
cmServer.cxx cmServer.h
cmServerConnection.cxx cmServerConnection.h
cmServerProtocol.cxx cmServerProtocol.h
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 1772ae5..1f0d469 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 9)
-set(CMake_VERSION_PATCH 20170714)
+set(CMake_VERSION_PATCH 20170720)
#set(CMake_VERSION_RC 1)
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index 00d017e..0705460 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -6,6 +6,7 @@
#include "cmCPackComponentGroup.h"
#include "cmCPackGenerator.h"
#include "cmCPackLog.h"
+#include "cmCryptoHash.h"
#include "cmGeneratedFileStream.h"
#include "cmSystemTools.h"
#include "cm_sys_stat.h"
@@ -527,15 +528,13 @@ int cmCPackDebGenerator::createDeb()
continue;
}
- char md5sum[33];
- if (!cmSystemTools::ComputeFileMD5(*fileIt, md5sum)) {
+ std::string output =
+ cmSystemTools::ComputeFileHash(*fileIt, cmCryptoHash::AlgoMD5);
+ if (output.empty()) {
cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem computing the md5 of "
<< *fileIt << std::endl);
}
- md5sum[32] = 0;
-
- std::string output(md5sum);
output += " " + *fileIt + "\n";
// debian md5sums entries are like this:
// 014f3604694729f3bf19263bac599765 usr/bin/ccmake
diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx
index 8d62fa1..689668d 100644
--- a/Source/CTest/cmCTestSubmitHandler.cxx
+++ b/Source/CTest/cmCTestSubmitHandler.cxx
@@ -13,6 +13,7 @@
#include "cmCTest.h"
#include "cmCTestCurl.h"
#include "cmCTestScriptHandler.h"
+#include "cmCryptoHash.h"
#include "cmCurl.h"
#include "cmGeneratedFileStream.h"
#include "cmProcessOutput.h"
@@ -428,10 +429,8 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix,
if (cmSystemTools::IsOn(this->GetOption("InternalTest"))) {
upload_as += "bad_md5sum";
} else {
- char md5[33];
- cmSystemTools::ComputeFileMD5(local_file, md5);
- md5[32] = 0;
- upload_as += md5;
+ upload_as +=
+ cmSystemTools::ComputeFileHash(local_file, cmCryptoHash::AlgoMD5);
}
if (!cmSystemTools::FileExists(local_file.c_str())) {
@@ -1058,9 +1057,8 @@ int cmCTestSubmitHandler::HandleCDashUploadFile(std::string const& file,
}
}
- char md5sum[33];
- md5sum[32] = 0;
- cmSystemTools::ComputeFileMD5(file, md5sum);
+ std::string md5sum =
+ cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5);
// 1. request the buildid and check to see if the file
// has already been uploaded
// TODO I added support for subproject. You would need to add
diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx
new file mode 100644
index 0000000..00cf283
--- /dev/null
+++ b/Source/cmConnection.cxx
@@ -0,0 +1,158 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmConnection.h"
+
+#include "cmServer.h"
+#include "cm_uv.h"
+
+#include <cassert>
+#include <cstring>
+
+struct write_req_t
+{
+ uv_write_t req;
+ uv_buf_t buf;
+};
+
+void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf)
+{
+ (void)(handle);
+ char* rawBuffer = new char[suggested_size];
+ *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
+}
+
+void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread,
+ const uv_buf_t* buf)
+{
+ auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data);
+ if (conn) {
+ if (nread >= 0) {
+ conn->ReadData(std::string(buf->base, buf->base + nread));
+ } else {
+ conn->OnDisconnect((int)nread);
+ }
+ }
+
+ delete[](buf->base);
+}
+
+void cmEventBasedConnection::on_close_delete(uv_handle_t* handle)
+{
+ delete handle;
+}
+
+void cmEventBasedConnection::on_close(uv_handle_t* /*handle*/)
+{
+}
+
+void cmEventBasedConnection::on_write(uv_write_t* req, int status)
+{
+ (void)(status);
+
+ // Free req and buffer
+ write_req_t* wr = reinterpret_cast<write_req_t*>(req);
+ delete[](wr->buf.base);
+ delete wr;
+}
+
+void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status)
+{
+ (void)(status);
+ auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data);
+
+ if (conn) {
+ conn->Connect(stream);
+ }
+}
+
+bool cmEventBasedConnection::IsOpen() const
+{
+ return this->WriteStream != CM_NULLPTR;
+}
+
+void cmEventBasedConnection::WriteData(const std::string& data)
+{
+ assert(this->WriteStream);
+
+ auto ds = data.size();
+
+ write_req_t* req = new write_req_t;
+ req->req.data = this;
+ req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds));
+ memcpy(req->buf.base, data.c_str(), ds);
+ uv_write(reinterpret_cast<uv_write_t*>(req),
+ static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1,
+ on_write);
+}
+
+void cmEventBasedConnection::ReadData(const std::string& data)
+{
+ this->RawReadBuffer += data;
+ if (BufferStrategy) {
+ std::string packet = BufferStrategy->BufferMessage(this->RawReadBuffer);
+ do {
+ ProcessRequest(packet);
+ packet = BufferStrategy->BufferMessage(this->RawReadBuffer);
+ } while (!packet.empty());
+
+ } else {
+ ProcessRequest(this->RawReadBuffer);
+ this->RawReadBuffer.clear();
+ }
+}
+
+cmEventBasedConnection::cmEventBasedConnection(
+ cmConnectionBufferStrategy* bufferStrategy)
+ : BufferStrategy(bufferStrategy)
+{
+}
+
+void cmEventBasedConnection::Connect(uv_stream_t* server)
+{
+ (void)server;
+ Server->OnConnected(nullptr);
+}
+
+void cmEventBasedConnection::OnDisconnect(int onerror)
+{
+ (void)onerror;
+ this->OnConnectionShuttingDown();
+ this->Server->OnDisconnect(this);
+}
+
+cmConnection::~cmConnection()
+{
+}
+
+bool cmConnection::OnConnectionShuttingDown()
+{
+ return true;
+}
+
+void cmConnection::SetServer(cmServerBase* s)
+{
+ Server = s;
+}
+
+void cmConnection::ProcessRequest(const std::string& request)
+{
+ Server->ProcessRequest(this, request);
+}
+
+bool cmConnection::OnServeStart(std::string* errString)
+{
+ (void)errString;
+ return true;
+}
+
+bool cmEventBasedConnection::OnConnectionShuttingDown()
+{
+ this->WriteStream->data = nullptr;
+ this->ReadStream->data = nullptr;
+
+ this->ReadStream = nullptr;
+ this->WriteStream = nullptr;
+ return true;
+}
diff --git a/Source/cmConnection.h b/Source/cmConnection.h
new file mode 100644
index 0000000..4b8fcb3
--- /dev/null
+++ b/Source/cmConnection.h
@@ -0,0 +1,118 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include "cmConfigure.h"
+
+#include "cm_uv.h"
+
+#include <cstddef>
+#include <memory>
+#include <string>
+
+class cmServerBase;
+
+/***
+ * Given a sequence of bytes with any kind of buffering, instances of this
+ * class arrange logical chunks according to whatever the use case is for
+ * the connection.
+ */
+class cmConnectionBufferStrategy
+{
+public:
+ virtual ~cmConnectionBufferStrategy();
+
+ /***
+ * Called whenever with an active raw buffer. If a logical chunk
+ * becomes available, that chunk is returned and that portion is
+ * removed from the rawBuffer
+ *
+ * @param rawBuffer in/out parameter. Receive buffer; the buffer strategy is
+ * free to manipulate this buffer anyway it needs to.
+ *
+ * @return Next chunk from the stream. Returns the empty string if a chunk
+ * isn't ready yet. Users of this interface should repeatedly call this
+ * function until an empty string is returned since its entirely possible
+ * multiple chunks come in a single raw buffer.
+ */
+ virtual std::string BufferMessage(std::string& rawBuffer) = 0;
+
+ /***
+ * Resets the internal state of the buffering
+ */
+ virtual void clear();
+
+ // TODO: There should be a callback / flag set for errors
+};
+
+class cmConnection
+{
+ CM_DISABLE_COPY(cmConnection)
+
+public:
+ cmConnection() {}
+
+ virtual void WriteData(const std::string& data) = 0;
+
+ virtual ~cmConnection();
+
+ virtual bool OnConnectionShuttingDown();
+
+ virtual bool IsOpen() const = 0;
+
+ virtual void SetServer(cmServerBase* s);
+
+ virtual void ProcessRequest(const std::string& request);
+
+ virtual bool OnServeStart(std::string* pString);
+
+protected:
+ cmServerBase* Server = nullptr;
+};
+
+/***
+ * Abstraction of a connection; ties in event callbacks from libuv and notifies
+ * the server when appropriate
+ */
+class cmEventBasedConnection : public cmConnection
+{
+
+public:
+ /***
+ * @param bufferStrategy If no strategy is given, it will process the raw
+ * chunks as they come in. The connection
+ * owns the pointer given.
+ */
+ cmEventBasedConnection(cmConnectionBufferStrategy* bufferStrategy = nullptr);
+
+ virtual void Connect(uv_stream_t* server);
+
+ virtual void ReadData(const std::string& data);
+
+ bool IsOpen() const override;
+
+ void WriteData(const std::string& data) override;
+ bool OnConnectionShuttingDown() override;
+
+ virtual void OnDisconnect(int errorCode);
+ uv_stream_t* ReadStream = nullptr;
+ uv_stream_t* WriteStream = nullptr;
+
+ static void on_close(uv_handle_t* handle);
+ static void on_close_delete(uv_handle_t* handle);
+
+protected:
+ std::string RawReadBuffer;
+
+ std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy;
+
+ static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf);
+
+ static void on_write(uv_write_t* req, int status);
+
+ static void on_new_connection(uv_stream_t* stream, int status);
+
+ static void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size,
+ uv_buf_t* buf);
+};
diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx
index 8027535..c0401d7 100644
--- a/Source/cmFileMonitor.cxx
+++ b/Source/cmFileMonitor.cxx
@@ -171,7 +171,9 @@ public:
{
if (this->Handle) {
uv_fs_event_stop(this->Handle);
- uv_close(reinterpret_cast<uv_handle_t*>(this->Handle), &on_fs_close);
+ if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(this->Handle))) {
+ uv_close(reinterpret_cast<uv_handle_t*>(this->Handle), &on_fs_close);
+ }
this->Handle = nullptr;
}
cmVirtualDirectoryWatcher::StopWatching();
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 1802da4..329c7a9 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -1025,12 +1025,23 @@ cmGeneratorTarget::KindedSources const& cmGeneratorTarget::GetKindedSources(
std::string const key = cmSystemTools::UpperCase(config);
KindedSourcesMapType::iterator it = this->KindedSourcesMap.find(key);
if (it != this->KindedSourcesMap.end()) {
+ if (!it->second.Initialized) {
+ std::ostringstream e;
+ e << "The SOURCES of \"" << this->GetName()
+ << "\" use a generator expression that depends on the "
+ "SOURCES themselves.";
+ this->GlobalGenerator->GetCMakeInstance()->IssueMessage(
+ cmake::FATAL_ERROR, e.str(), this->GetBacktrace());
+ static KindedSources empty;
+ return empty;
+ }
return it->second;
}
// Add an entry to the map for this configuration.
KindedSources& files = this->KindedSourcesMap[key];
this->ComputeKindedSources(files, config);
+ files.Initialized = true;
return files;
}
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index c04d62b..52147e3 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -107,6 +107,11 @@ public:
std::set<std::string> ExpectedResxHeaders;
std::set<std::string> ExpectedXamlHeaders;
std::set<std::string> ExpectedXamlSources;
+ bool Initialized;
+ KindedSources()
+ : Initialized(false)
+ {
+ }
};
/** Get all sources needed for a configuration with kinds assigned. */
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx
index 4be3c80..071d49c 100644
--- a/Source/cmGlobalXCodeGenerator.cxx
+++ b/Source/cmGlobalXCodeGenerator.cxx
@@ -1517,6 +1517,17 @@ void cmGlobalXCodeGenerator::AddCommandsToBuildPhase(
makecmd += " all";
buildphase->AddAttribute("shellScript", this->CreateString(makecmd));
buildphase->AddAttribute("showEnvVarsInLog", this->CreateString("0"));
+
+ cmXCodeObject* outputFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
+ for (std::vector<cmCustomCommand>::const_iterator i = commands.begin();
+ i != commands.end(); ++i) {
+ std::vector<std::string> const& outputs = i->GetOutputs();
+ for (std::vector<std::string>::const_iterator j = outputs.begin();
+ j != outputs.end(); ++j) {
+ outputFiles->AddObject(this->CreateString(*j));
+ }
+ }
+ buildphase->AddAttribute("outputPaths", outputFiles);
}
void cmGlobalXCodeGenerator::CreateCustomRulesMakefile(
diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx
new file mode 100644
index 0000000..cc82438
--- /dev/null
+++ b/Source/cmPipeConnection.cxx
@@ -0,0 +1,80 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmPipeConnection.h"
+
+#include "cmConfigure.h"
+#include "cmServer.h"
+
+cmPipeConnection::cmPipeConnection(const std::string& name,
+ cmConnectionBufferStrategy* bufferStrategy)
+ : cmEventBasedConnection(bufferStrategy)
+ , PipeName(name)
+{
+}
+
+void cmPipeConnection::Connect(uv_stream_t* server)
+{
+ if (this->ClientPipe) {
+ // Accept and close all pipes but the first:
+ uv_pipe_t* rejectPipe = new uv_pipe_t();
+
+ uv_pipe_init(this->Server->GetLoop(), rejectPipe, 0);
+ uv_accept(server, reinterpret_cast<uv_stream_t*>(rejectPipe));
+ uv_close(reinterpret_cast<uv_handle_t*>(rejectPipe), &on_close_delete);
+ return;
+ }
+
+ this->ClientPipe = new uv_pipe_t();
+ uv_pipe_init(this->Server->GetLoop(), this->ClientPipe, 0);
+ this->ClientPipe->data = static_cast<cmEventBasedConnection*>(this);
+ auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe);
+ if (uv_accept(server, client) != 0) {
+ uv_close(reinterpret_cast<uv_handle_t*>(client), &on_close_delete);
+ this->ClientPipe = CM_NULLPTR;
+ return;
+ }
+ this->ReadStream = client;
+ this->WriteStream = client;
+
+ uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
+ Server->OnConnected(this);
+}
+
+bool cmPipeConnection::OnServeStart(std::string* errorMessage)
+{
+ this->ServerPipe = new uv_pipe_t();
+ uv_pipe_init(this->Server->GetLoop(), this->ServerPipe, 0);
+ this->ServerPipe->data = static_cast<cmEventBasedConnection*>(this);
+
+ int r;
+ if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) {
+ *errorMessage = std::string("Internal Error with ") + this->PipeName +
+ ": " + uv_err_name(r);
+ return false;
+ }
+ auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe);
+ if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) {
+ *errorMessage = std::string("Internal Error listening on ") +
+ this->PipeName + ": " + uv_err_name(r);
+ return false;
+ }
+
+ return cmConnection::OnServeStart(errorMessage);
+}
+
+bool cmPipeConnection::OnConnectionShuttingDown()
+{
+ if (this->ClientPipe) {
+ uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe),
+ &on_close_delete);
+ this->WriteStream->data = nullptr;
+ }
+ uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), &on_close_delete);
+
+ this->ClientPipe = nullptr;
+ this->ServerPipe = nullptr;
+ this->WriteStream = nullptr;
+ this->ReadStream = nullptr;
+
+ return cmConnection::OnConnectionShuttingDown();
+}
diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h
new file mode 100644
index 0000000..fea85b5
--- /dev/null
+++ b/Source/cmPipeConnection.h
@@ -0,0 +1,28 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+
+#pragma once
+
+#include "cmConnection.h"
+
+#include "cm_uv.h"
+
+#include <string>
+
+class cmPipeConnection : public cmEventBasedConnection
+{
+public:
+ cmPipeConnection(const std::string& name,
+ cmConnectionBufferStrategy* bufferStrategy = nullptr);
+
+ bool OnServeStart(std::string* pString) override;
+
+ bool OnConnectionShuttingDown() override;
+
+ void Connect(uv_stream_t* server) override;
+
+private:
+ const std::string PipeName;
+ uv_pipe_t* ServerPipe = nullptr;
+ uv_pipe_t* ClientPipe = nullptr;
+};
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index 5283dfc..ccb9af6 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -2,7 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmServer.h"
-#include "cmServerConnection.h"
+#include "cmConnection.h"
+#include "cmFileMonitor.h"
#include "cmServerDictionary.h"
#include "cmServerProtocol.h"
#include "cmSystemTools.h"
@@ -14,8 +15,23 @@
#include <algorithm>
#include <cassert>
#include <cstdint>
+#include <memory>
#include <utility>
+void on_signal(uv_signal_t* signal, int signum)
+{
+ auto conn = reinterpret_cast<cmServerBase*>(signal->data);
+ conn->OnSignal(signum);
+}
+
+static void on_walk_to_shutdown(uv_handle_t* handle, void* arg)
+{
+ (void)arg;
+ if (!uv_is_closing(handle)) {
+ uv_close(handle, &cmEventBasedConnection::on_close);
+ }
+}
+
class cmServer::DebugInfo
{
public:
@@ -30,11 +46,10 @@ public:
uint64_t StartTime;
};
-cmServer::cmServer(cmServerConnection* conn, bool supportExperimental)
- : Connection(conn)
+cmServer::cmServer(cmConnection* conn, bool supportExperimental)
+ : cmServerBase(conn)
, SupportExperimental(supportExperimental)
{
- this->Connection->SetServer(this);
// Register supported protocols:
this->RegisterProtocol(new cmServerProtocol1);
}
@@ -48,23 +63,15 @@ cmServer::~cmServer()
for (cmServerProtocol* p : this->SupportedProtocols) {
delete p;
}
-
- delete this->Connection;
}
-void cmServer::PopOne()
+void cmServer::ProcessRequest(cmConnection* connection,
+ const std::string& input)
{
- if (this->Queue.empty()) {
- return;
- }
-
Json::Reader reader;
Json::Value value;
- const std::string input = this->Queue.front();
- this->Queue.erase(this->Queue.begin());
-
if (!reader.parse(input, value)) {
- this->WriteParseError("Failed to parse JSON input.");
+ this->WriteParseError(connection, "Failed to parse JSON input.");
return;
}
@@ -76,13 +83,13 @@ void cmServer::PopOne()
debug->PrintStatistics = debugValue["showStats"].asBool();
}
- const cmServerRequest request(this, value[kTYPE_KEY].asString(),
+ const cmServerRequest request(this, connection, value[kTYPE_KEY].asString(),
value[kCOOKIE_KEY].asString(), value);
if (request.Type == "") {
cmServerResponse response(request);
response.SetError("No type given in request.");
- this->WriteResponse(response, nullptr);
+ this->WriteResponse(connection, response, nullptr);
return;
}
@@ -91,9 +98,11 @@ void cmServer::PopOne()
if (this->Protocol) {
this->Protocol->CMakeInstance()->SetProgressCallback(
reportProgress, const_cast<cmServerRequest*>(&request));
- this->WriteResponse(this->Protocol->Process(request), debug.get());
+ this->WriteResponse(connection, this->Protocol->Process(request),
+ debug.get());
} else {
- this->WriteResponse(this->SetProtocolVersion(request), debug.get());
+ this->WriteResponse(connection, this->SetProtocolVersion(request),
+ debug.get());
}
}
@@ -115,7 +124,7 @@ void cmServer::RegisterProtocol(cmServerProtocol* protocol)
}
}
-void cmServer::PrintHello() const
+void cmServer::PrintHello(cmConnection* connection) const
{
Json::Value hello = Json::objectValue;
hello[kTYPE_KEY] = "hello";
@@ -134,13 +143,7 @@ void cmServer::PrintHello() const
protocolVersions.append(tmp);
}
- this->WriteJsonObject(hello, nullptr);
-}
-
-void cmServer::QueueRequest(const std::string& request)
-{
- this->Queue.push_back(request);
- this->PopOne();
+ this->WriteJsonObject(connection, hello, nullptr);
}
void cmServer::reportProgress(const char* msg, float progress, void* data)
@@ -232,17 +235,26 @@ bool cmServer::Serve(std::string* errorMessage)
}
assert(!this->Protocol);
- return Connection->ProcessEvents(errorMessage);
+ return cmServerBase::Serve(errorMessage);
}
cmFileMonitor* cmServer::FileMonitor() const
{
- return Connection->FileMonitor();
+ return fileMonitor.get();
}
void cmServer::WriteJsonObject(const Json::Value& jsonValue,
const DebugInfo* debug) const
{
+ for (auto& connection : this->Connections) {
+ WriteJsonObject(connection.get(), jsonValue, debug);
+ }
+}
+
+void cmServer::WriteJsonObject(cmConnection* connection,
+ const Json::Value& jsonValue,
+ const DebugInfo* debug) const
+{
Json::FastWriter writer;
auto beforeJson = uv_hrtime();
@@ -272,7 +284,7 @@ void cmServer::WriteJsonObject(const Json::Value& jsonValue,
}
}
- Connection->WriteData(std::string("\n") + kSTART_MAGIC + std::string("\n") +
+ connection->WriteData(std::string("\n") + kSTART_MAGIC + std::string("\n") +
result + kEND_MAGIC + std::string("\n"));
}
@@ -311,7 +323,7 @@ void cmServer::WriteProgress(const cmServerRequest& request, int min,
obj[kPROGRESS_MAXIMUM_KEY] = max;
obj[kPROGRESS_CURRENT_KEY] = current;
- this->WriteJsonObject(obj, nullptr);
+ this->WriteJsonObject(request.Connection, obj, nullptr);
}
void cmServer::WriteMessage(const cmServerRequest& request,
@@ -331,10 +343,11 @@ void cmServer::WriteMessage(const cmServerRequest& request,
obj[kTITLE_KEY] = title;
}
- WriteJsonObject(obj, nullptr);
+ WriteJsonObject(request.Connection, obj, nullptr);
}
-void cmServer::WriteParseError(const std::string& message) const
+void cmServer::WriteParseError(cmConnection* connection,
+ const std::string& message) const
{
Json::Value obj = Json::objectValue;
obj[kTYPE_KEY] = kERROR_TYPE;
@@ -342,7 +355,7 @@ void cmServer::WriteParseError(const std::string& message) const
obj[kREPLY_TO_KEY] = "";
obj[kCOOKIE_KEY] = "";
- this->WriteJsonObject(obj, nullptr);
+ this->WriteJsonObject(connection, obj, nullptr);
}
void cmServer::WriteSignal(const std::string& name,
@@ -358,7 +371,8 @@ void cmServer::WriteSignal(const std::string& name,
WriteJsonObject(obj, nullptr);
}
-void cmServer::WriteResponse(const cmServerResponse& response,
+void cmServer::WriteResponse(cmConnection* connection,
+ const cmServerResponse& response,
const DebugInfo* debug) const
{
assert(response.IsComplete());
@@ -371,5 +385,161 @@ void cmServer::WriteResponse(const cmServerResponse& response,
obj[kERROR_MESSAGE_KEY] = response.ErrorMessage();
}
- this->WriteJsonObject(obj, debug);
+ this->WriteJsonObject(connection, obj, debug);
+}
+
+void cmServer::OnConnected(cmConnection* connection)
+{
+ PrintHello(connection);
+}
+
+void cmServer::OnServeStart()
+{
+ cmServerBase::OnServeStart();
+ fileMonitor = std::make_shared<cmFileMonitor>(GetLoop());
+}
+
+void cmServer::StartShutDown()
+{
+ if (fileMonitor) {
+ fileMonitor->StopMonitoring();
+ fileMonitor.reset();
+ }
+ cmServerBase::StartShutDown();
+}
+
+static void __start_thread(void* arg)
+{
+ auto server = reinterpret_cast<cmServerBase*>(arg);
+ std::string error;
+ server->Serve(&error);
+}
+
+bool cmServerBase::StartServeThread()
+{
+ ServeThreadRunning = true;
+ uv_thread_create(&ServeThread, __start_thread, this);
+ return true;
+}
+
+bool cmServerBase::Serve(std::string* errorMessage)
+{
+ errorMessage->clear();
+
+ uv_signal_init(&Loop, &this->SIGINTHandler);
+ uv_signal_init(&Loop, &this->SIGHUPHandler);
+
+ this->SIGINTHandler.data = this;
+ this->SIGHUPHandler.data = this;
+
+ uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT);
+ uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP);
+
+ OnServeStart();
+
+ for (auto& connection : Connections) {
+ if (!connection->OnServeStart(errorMessage)) {
+ return false;
+ }
+ }
+
+ if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
+ *errorMessage = "Internal Error: Event loop stopped in unclean state.";
+ StartShutDown();
+ return false;
+ }
+
+ ServeThreadRunning = false;
+ return true;
+}
+
+void cmServerBase::OnConnected(cmConnection*)
+{
+}
+
+void cmServerBase::OnDisconnect()
+{
+}
+
+void cmServerBase::OnServeStart()
+{
+ uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT);
+ uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP);
+}
+
+void cmServerBase::StartShutDown()
+{
+ if (!uv_is_closing((const uv_handle_t*)&this->SIGINTHandler)) {
+ uv_signal_stop(&this->SIGINTHandler);
+ }
+
+ if (!uv_is_closing((const uv_handle_t*)&this->SIGHUPHandler)) {
+ uv_signal_stop(&this->SIGHUPHandler);
+ }
+
+ for (auto& connection : Connections) {
+ connection->OnConnectionShuttingDown();
+ }
+ Connections.clear();
+
+ uv_stop(&Loop);
+
+ uv_walk(&Loop, on_walk_to_shutdown, CM_NULLPTR);
+
+ uv_run(&Loop, UV_RUN_DEFAULT);
+}
+
+bool cmServerBase::OnSignal(int signum)
+{
+ (void)signum;
+ StartShutDown();
+ return true;
+}
+
+cmServerBase::cmServerBase(cmConnection* connection)
+{
+ uv_loop_init(&Loop);
+
+ uv_signal_init(&Loop, &this->SIGINTHandler);
+ uv_signal_init(&Loop, &this->SIGHUPHandler);
+
+ this->SIGINTHandler.data = this;
+ this->SIGHUPHandler.data = this;
+
+ AddNewConnection(connection);
+}
+
+cmServerBase::~cmServerBase()
+{
+
+ if (ServeThreadRunning) {
+ StartShutDown();
+ uv_thread_join(&ServeThread);
+ }
+
+ uv_loop_close(&Loop);
+}
+
+void cmServerBase::AddNewConnection(cmConnection* ownedConnection)
+{
+ Connections.emplace_back(ownedConnection);
+ ownedConnection->SetServer(this);
+}
+
+uv_loop_t* cmServerBase::GetLoop()
+{
+ return &Loop;
+}
+
+void cmServerBase::OnDisconnect(cmConnection* pConnection)
+{
+ auto pred = [pConnection](const std::unique_ptr<cmConnection>& m) {
+ return m.get() == pConnection;
+ };
+ Connections.erase(
+ std::remove_if(Connections.begin(), Connections.end(), pred),
+ Connections.end());
+ if (Connections.empty()) {
+ StartShutDown();
+ }
}
diff --git a/Source/cmServer.h b/Source/cmServer.h
index b814050..0000704 100644
--- a/Source/cmServer.h
+++ b/Source/cmServer.h
@@ -7,26 +7,83 @@
#include "cm_jsoncpp_value.h"
#include "cm_uv.h"
+#include <memory> // IWYU pragma: keep
#include <string>
#include <vector>
+class cmConnection;
class cmFileMonitor;
-class cmServerConnection;
class cmServerProtocol;
class cmServerRequest;
class cmServerResponse;
-class cmServer
+/***
+ * This essentially hold and manages a libuv event queue and responds to
+ * messages
+ * on any of its connections.
+ */
+class cmServerBase
+{
+public:
+ cmServerBase(cmConnection* connection);
+ virtual ~cmServerBase();
+
+ virtual void AddNewConnection(cmConnection* ownedConnection);
+
+ /***
+ * The main override responsible for tailoring behavior towards
+ * whatever the given server is supposed to do
+ *
+ * This should almost always be called by the given connections
+ * directly.
+ *
+ * @param connection The connectiont the request was received on
+ * @param request The actual request
+ */
+ virtual void ProcessRequest(cmConnection* connection,
+ const std::string& request) = 0;
+ virtual void OnConnected(cmConnection* connection);
+ virtual void OnDisconnect();
+
+ /***
+ * Start a dedicated thread. If this is used to start the server, it will
+ * join on the
+ * servers dtor.
+ */
+ virtual bool StartServeThread();
+ virtual bool Serve(std::string* errorMessage);
+
+ virtual void OnServeStart();
+ virtual void StartShutDown();
+
+ virtual bool OnSignal(int signum);
+ uv_loop_t* GetLoop();
+
+ void OnDisconnect(cmConnection* pConnection);
+
+protected:
+ std::vector<std::unique_ptr<cmConnection> > Connections;
+
+ bool ServeThreadRunning = false;
+ uv_thread_t ServeThread;
+
+ uv_loop_t Loop;
+
+ uv_signal_t SIGINTHandler;
+ uv_signal_t SIGHUPHandler;
+};
+
+class cmServer : public cmServerBase
{
CM_DISABLE_COPY(cmServer)
public:
class DebugInfo;
- cmServer(cmServerConnection* conn, bool supportExperimental);
- ~cmServer();
+ cmServer(cmConnection* conn, bool supportExperimental);
+ ~cmServer() override;
- bool Serve(std::string* errorMessage);
+ bool Serve(std::string* errorMessage) override;
cmFileMonitor* FileMonitor() const;
@@ -34,9 +91,20 @@ private:
void RegisterProtocol(cmServerProtocol* protocol);
// Callbacks from cmServerConnection:
- void PopOne();
- void QueueRequest(const std::string& request);
+ void ProcessRequest(cmConnection* connection,
+ const std::string& request) override;
+ std::shared_ptr<cmFileMonitor> fileMonitor;
+
+public:
+ void OnServeStart() override;
+
+ void StartShutDown() override;
+
+public:
+ void OnConnected(cmConnection* connection) override;
+
+private:
static void reportProgress(const char* msg, float progress, void* data);
static void reportMessage(const char* msg, const char* title, bool& cancel,
void* data);
@@ -44,36 +112,37 @@ private:
// Handle requests:
cmServerResponse SetProtocolVersion(const cmServerRequest& request);
- void PrintHello() const;
+ void PrintHello(cmConnection* connection) const;
// Write responses:
void WriteProgress(const cmServerRequest& request, int min, int current,
int max, const std::string& message) const;
void WriteMessage(const cmServerRequest& request, const std::string& message,
const std::string& title) const;
- void WriteResponse(const cmServerResponse& response,
+ void WriteResponse(cmConnection* connection,
+ const cmServerResponse& response,
const DebugInfo* debug) const;
- void WriteParseError(const std::string& message) const;
+ void WriteParseError(cmConnection* connection,
+ const std::string& message) const;
void WriteSignal(const std::string& name, const Json::Value& obj) const;
void WriteJsonObject(Json::Value const& jsonValue,
const DebugInfo* debug) const;
+ void WriteJsonObject(cmConnection* connection, Json::Value const& jsonValue,
+ const DebugInfo* debug) const;
+
static cmServerProtocol* FindMatchingProtocol(
const std::vector<cmServerProtocol*>& protocols, int major, int minor);
- cmServerConnection* Connection = nullptr;
const bool SupportExperimental;
cmServerProtocol* Protocol = nullptr;
std::vector<cmServerProtocol*> SupportedProtocols;
- std::vector<std::string> Queue;
std::string DataBuffer;
std::string JsonData;
- uv_loop_t* Loop = nullptr;
-
typedef union
{
uv_tty_t tty;
@@ -87,7 +156,6 @@ private:
mutable bool Writing = false;
- friend class cmServerConnection;
friend class cmServerProtocol;
friend class cmServerRequest;
};
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
index 36312ed..4891131 100644
--- a/Source/cmServerConnection.cxx
+++ b/Source/cmServerConnection.cxx
@@ -2,376 +2,123 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmServerConnection.h"
-#include "cmFileMonitor.h"
#include "cmServer.h"
#include "cmServerDictionary.h"
-#include <assert.h>
-#include <string.h>
-
-namespace {
-
-struct write_req_t
+cmStdIoConnection::cmStdIoConnection(
+ cmConnectionBufferStrategy* bufferStrategy)
+ : cmEventBasedConnection(bufferStrategy)
+ , Input()
+ , Output()
{
- uv_write_t req;
- uv_buf_t buf;
-};
-
-void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
-{
- (void)(handle);
- char* rawBuffer = new char[suggested_size];
- *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
-}
-
-void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)
-{
- auto conn = reinterpret_cast<cmServerConnection*>(stream->data);
- if (nread >= 0) {
- conn->ReadData(std::string(buf->base, buf->base + nread));
- } else {
- conn->TriggerShutdown();
- }
-
- delete[](buf->base);
}
-void on_write(uv_write_t* req, int status)
+void cmStdIoConnection::SetServer(cmServerBase* s)
{
- (void)(status);
- auto conn = reinterpret_cast<cmServerConnection*>(req->data);
-
- // Free req and buffer
- write_req_t* wr = reinterpret_cast<write_req_t*>(req);
- delete[](wr->buf.base);
- delete wr;
+ cmConnection::SetServer(s);
- conn->ProcessNextRequest();
-}
+ if (uv_guess_handle(1) == UV_TTY) {
+ usesTty = true;
-void on_new_connection(uv_stream_t* stream, int status)
-{
- (void)(status);
- auto conn = reinterpret_cast<cmServerConnection*>(stream->data);
- conn->Connect(stream);
-}
+ this->Input.tty = new uv_tty_t();
+ uv_tty_init(this->Server->GetLoop(), this->Input.tty, 0, 1);
+ uv_tty_set_mode(this->Input.tty, UV_TTY_MODE_NORMAL);
+ this->Input.tty->data = static_cast<cmEventBasedConnection*>(this);
+ this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.tty);
-void on_signal(uv_signal_t* signal, int signum)
-{
- auto conn = reinterpret_cast<cmServerConnection*>(signal->data);
- (void)(signum);
- conn->TriggerShutdown();
-}
+ this->Output.tty = new uv_tty_t();
+ uv_tty_init(this->Server->GetLoop(), this->Output.tty, 1, 0);
+ uv_tty_set_mode(this->Output.tty, UV_TTY_MODE_NORMAL);
+ this->Output.tty->data = static_cast<cmEventBasedConnection*>(this);
+ this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.tty);
+ } else {
+ usesTty = false;
-void on_signal_close(uv_handle_t* handle)
-{
- delete reinterpret_cast<uv_signal_t*>(handle);
-}
+ this->Input.pipe = new uv_pipe_t();
+ uv_pipe_init(this->Server->GetLoop(), this->Input.pipe, 0);
+ uv_pipe_open(this->Input.pipe, 0);
+ this->Input.pipe->data = static_cast<cmEventBasedConnection*>(this);
+ this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.pipe);
-void on_pipe_close(uv_handle_t* handle)
-{
- delete reinterpret_cast<uv_pipe_t*>(handle);
+ this->Output.pipe = new uv_pipe_t();
+ uv_pipe_init(this->Server->GetLoop(), this->Output.pipe, 0);
+ uv_pipe_open(this->Output.pipe, 1);
+ this->Output.pipe->data = static_cast<cmEventBasedConnection*>(this);
+ this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.pipe);
+ }
}
-void on_tty_close(uv_handle_t* handle)
+bool cmStdIoConnection::OnServeStart(std::string* pString)
{
- delete reinterpret_cast<uv_tty_t*>(handle);
+ uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
+ Server->OnConnected(this);
+ return cmConnection::OnServeStart(pString);
}
-} // namespace
-
-class LoopGuard
+bool cmStdIoConnection::OnConnectionShuttingDown()
{
-public:
- LoopGuard(cmServerConnection* connection)
- : Connection(connection)
- {
- this->Connection->mLoop = uv_default_loop();
- if (!this->Connection->mLoop) {
- return;
- }
- this->Connection->mFileMonitor =
- new cmFileMonitor(this->Connection->mLoop);
- }
-
- ~LoopGuard()
- {
- if (!this->Connection->mLoop) {
- return;
- }
+ cmEventBasedConnection::OnConnectionShuttingDown();
- if (this->Connection->mFileMonitor) {
- delete this->Connection->mFileMonitor;
- }
- uv_loop_close(this->Connection->mLoop);
- this->Connection->mLoop = nullptr;
+ if (usesTty) {
+ uv_read_stop(reinterpret_cast<uv_stream_t*>(this->Input.tty));
+ uv_close(reinterpret_cast<uv_handle_t*>(this->Input.tty),
+ &on_close_delete);
+ uv_close(reinterpret_cast<uv_handle_t*>(this->Output.tty),
+ &on_close_delete);
+ } else {
+ uv_close(reinterpret_cast<uv_handle_t*>(this->Input.pipe),
+ &on_close_delete);
+ uv_close(reinterpret_cast<uv_handle_t*>(this->Output.pipe),
+ &on_close_delete);
}
-private:
- cmServerConnection* Connection;
-};
+ return true;
+}
-cmServerConnection::cmServerConnection()
+cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
+ : cmPipeConnection(name, new cmServerBufferStrategy)
{
}
-cmServerConnection::~cmServerConnection()
+cmServerStdIoConnection::cmServerStdIoConnection()
+ : cmStdIoConnection(new cmServerBufferStrategy)
{
}
-void cmServerConnection::SetServer(cmServer* s)
+cmConnectionBufferStrategy::~cmConnectionBufferStrategy()
{
- this->Server = s;
}
-bool cmServerConnection::ProcessEvents(std::string* errorMessage)
+void cmConnectionBufferStrategy::clear()
{
- assert(this->Server);
- errorMessage->clear();
-
- this->RawReadBuffer.clear();
- this->RequestBuffer.clear();
-
- LoopGuard guard(this);
- (void)(guard);
- if (!this->mLoop) {
- *errorMessage = "Internal Error: Failed to create event loop.";
- return false;
- }
-
- this->SIGINTHandler = new uv_signal_t;
- uv_signal_init(this->mLoop, this->SIGINTHandler);
- this->SIGINTHandler->data = static_cast<void*>(this);
- uv_signal_start(this->SIGINTHandler, &on_signal, SIGINT);
-
- this->SIGHUPHandler = new uv_signal_t;
- uv_signal_init(this->mLoop, this->SIGHUPHandler);
- this->SIGHUPHandler->data = static_cast<void*>(this);
- uv_signal_start(this->SIGHUPHandler, &on_signal, SIGHUP);
-
- if (!DoSetup(errorMessage)) {
- return false;
- }
-
- if (uv_run(this->mLoop, UV_RUN_DEFAULT) != 0) {
- *errorMessage = "Internal Error: Event loop stopped in unclean state.";
- return false;
- }
-
- // These need to be cleaned up by now:
- assert(!this->ReadStream);
- assert(!this->WriteStream);
-
- this->RawReadBuffer.clear();
- this->RequestBuffer.clear();
-
- return true;
}
-void cmServerConnection::ReadData(const std::string& data)
+std::string cmServerBufferStrategy::BufferMessage(std::string& RawReadBuffer)
{
- this->RawReadBuffer += data;
-
for (;;) {
- auto needle = this->RawReadBuffer.find('\n');
+ auto needle = RawReadBuffer.find('\n');
if (needle == std::string::npos) {
- return;
+ return "";
}
- std::string line = this->RawReadBuffer.substr(0, needle);
+ std::string line = RawReadBuffer.substr(0, needle);
const auto ls = line.size();
if (ls > 1 && line.at(ls - 1) == '\r') {
line.erase(ls - 1, 1);
}
- this->RawReadBuffer.erase(this->RawReadBuffer.begin(),
- this->RawReadBuffer.begin() +
- static_cast<long>(needle) + 1);
+ RawReadBuffer.erase(RawReadBuffer.begin(),
+ RawReadBuffer.begin() + static_cast<long>(needle) + 1);
if (line == kSTART_MAGIC) {
- this->RequestBuffer.clear();
+ RequestBuffer.clear();
continue;
}
if (line == kEND_MAGIC) {
- this->Server->QueueRequest(this->RequestBuffer);
- this->RequestBuffer.clear();
- } else {
- this->RequestBuffer += line;
- this->RequestBuffer += "\n";
+ std::string rtn;
+ rtn.swap(this->RequestBuffer);
+ return rtn;
}
- }
-}
-void cmServerConnection::TriggerShutdown()
-{
- this->FileMonitor()->StopMonitoring();
-
- uv_signal_stop(this->SIGINTHandler);
- uv_signal_stop(this->SIGHUPHandler);
-
- uv_close(reinterpret_cast<uv_handle_t*>(this->SIGINTHandler),
- &on_signal_close); // delete handle
- uv_close(reinterpret_cast<uv_handle_t*>(this->SIGHUPHandler),
- &on_signal_close); // delete handle
-
- this->SIGINTHandler = nullptr;
- this->SIGHUPHandler = nullptr;
-
- this->TearDown();
-}
-
-void cmServerConnection::WriteData(const std::string& data)
-{
- assert(this->WriteStream);
-
- auto ds = data.size();
-
- write_req_t* req = new write_req_t;
- req->req.data = this;
- req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds));
- memcpy(req->buf.base, data.c_str(), ds);
-
- uv_write(reinterpret_cast<uv_write_t*>(req),
- static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1,
- on_write);
-}
-
-void cmServerConnection::ProcessNextRequest()
-{
- Server->PopOne();
-}
-
-void cmServerConnection::SendGreetings()
-{
- Server->PrintHello();
-}
-
-cmServerStdIoConnection::cmServerStdIoConnection()
-{
- this->Input.tty = nullptr;
- this->Output.tty = nullptr;
-}
-
-bool cmServerStdIoConnection::DoSetup(std::string* errorMessage)
-{
- (void)(errorMessage);
-
- if (uv_guess_handle(1) == UV_TTY) {
- usesTty = true;
- this->Input.tty = new uv_tty_t;
- uv_tty_init(this->Loop(), this->Input.tty, 0, 1);
- uv_tty_set_mode(this->Input.tty, UV_TTY_MODE_NORMAL);
- Input.tty->data = this;
- this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.tty);
-
- this->Output.tty = new uv_tty_t;
- uv_tty_init(this->Loop(), this->Output.tty, 1, 0);
- uv_tty_set_mode(this->Output.tty, UV_TTY_MODE_NORMAL);
- Output.tty->data = this;
- this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.tty);
- } else {
- usesTty = false;
- this->Input.pipe = new uv_pipe_t;
- uv_pipe_init(this->Loop(), this->Input.pipe, 0);
- uv_pipe_open(this->Input.pipe, 0);
- Input.pipe->data = this;
- this->ReadStream = reinterpret_cast<uv_stream_t*>(this->Input.pipe);
-
- this->Output.pipe = new uv_pipe_t;
- uv_pipe_init(this->Loop(), this->Output.pipe, 0);
- uv_pipe_open(this->Output.pipe, 1);
- Output.pipe->data = this;
- this->WriteStream = reinterpret_cast<uv_stream_t*>(this->Output.pipe);
+ this->RequestBuffer += line;
+ this->RequestBuffer += "\n";
}
-
- SendGreetings();
- uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
-
- return true;
-}
-
-void cmServerStdIoConnection::TearDown()
-{
- if (usesTty) {
- uv_close(reinterpret_cast<uv_handle_t*>(this->Input.tty), &on_tty_close);
- uv_close(reinterpret_cast<uv_handle_t*>(this->Output.tty), &on_tty_close);
- this->Input.tty = nullptr;
- this->Output.tty = nullptr;
- } else {
- uv_close(reinterpret_cast<uv_handle_t*>(this->Input.pipe), &on_pipe_close);
- uv_close(reinterpret_cast<uv_handle_t*>(this->Output.pipe),
- &on_pipe_close);
- this->Input.pipe = nullptr;
- this->Input.pipe = nullptr;
- }
- this->ReadStream = nullptr;
- this->WriteStream = nullptr;
-}
-
-cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
- : PipeName(name)
-{
-}
-
-bool cmServerPipeConnection::DoSetup(std::string* errorMessage)
-{
- this->ServerPipe = new uv_pipe_t;
- uv_pipe_init(this->Loop(), this->ServerPipe, 0);
- this->ServerPipe->data = this;
-
- int r;
- if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) {
- *errorMessage = std::string("Internal Error with ") + this->PipeName +
- ": " + uv_err_name(r);
- return false;
- }
- auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe);
- if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) {
- *errorMessage = std::string("Internal Error listening on ") +
- this->PipeName + ": " + uv_err_name(r);
- return false;
- }
-
- return true;
-}
-
-void cmServerPipeConnection::TearDown()
-{
- if (this->ClientPipe) {
- uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe), &on_pipe_close);
- this->WriteStream->data = nullptr;
- }
- uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), &on_pipe_close);
-
- this->ClientPipe = nullptr;
- this->ServerPipe = nullptr;
- this->WriteStream = nullptr;
- this->ReadStream = nullptr;
-}
-
-void cmServerPipeConnection::Connect(uv_stream_t* server)
-{
- if (this->ClientPipe) {
- // Accept and close all pipes but the first:
- uv_pipe_t* rejectPipe = new uv_pipe_t;
-
- uv_pipe_init(this->Loop(), rejectPipe, 0);
- auto rejecter = reinterpret_cast<uv_stream_t*>(rejectPipe);
- uv_accept(server, rejecter);
- uv_close(reinterpret_cast<uv_handle_t*>(rejecter), &on_pipe_close);
- return;
- }
-
- this->ClientPipe = new uv_pipe_t;
- uv_pipe_init(this->Loop(), this->ClientPipe, 0);
- this->ClientPipe->data = this;
- auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe);
- if (uv_accept(server, client) != 0) {
- uv_close(reinterpret_cast<uv_handle_t*>(client), nullptr);
- return;
- }
- this->ReadStream = client;
- this->WriteStream = client;
-
- uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
-
- this->SendGreetings();
}
diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h
index b96bf3c..0804f0e 100644
--- a/Source/cmServerConnection.h
+++ b/Source/cmServerConnection.h
@@ -2,68 +2,46 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
-#include "cmConfigure.h"
+#include "cmConnection.h"
+#include "cmPipeConnection.h"
#include "cm_uv.h"
#include <string>
-class cmFileMonitor;
-class cmServer;
+class cmServerBase;
-class cmServerConnection
+/***
+ * This connection buffer strategy accepts messages in the form of
+ * [== "CMake Server" ==[
+{
+ ... some JSON message ...
+}
+]== "CMake Server" ==]
+ * and only passes on the core json; it discards the envelope.
+ */
+class cmServerBufferStrategy : public cmConnectionBufferStrategy
{
- CM_DISABLE_COPY(cmServerConnection)
-
public:
- cmServerConnection();
- virtual ~cmServerConnection();
-
- void SetServer(cmServer* s);
-
- bool ProcessEvents(std::string* errorMessage);
-
- void ReadData(const std::string& data);
- void TriggerShutdown();
- void WriteData(const std::string& data);
- void ProcessNextRequest();
-
- virtual void Connect(uv_stream_t* server) { (void)(server); }
-
- cmFileMonitor* FileMonitor() const { return this->mFileMonitor; }
-
-protected:
- virtual bool DoSetup(std::string* errorMessage) = 0;
- virtual void TearDown() = 0;
-
- void SendGreetings();
-
- uv_loop_t* Loop() const { return mLoop; }
-
-protected:
- std::string RawReadBuffer;
- std::string RequestBuffer;
-
- uv_stream_t* ReadStream = nullptr;
- uv_stream_t* WriteStream = nullptr;
+ std::string BufferMessage(std::string& rawBuffer) override;
private:
- uv_loop_t* mLoop = nullptr;
- cmFileMonitor* mFileMonitor = nullptr;
- cmServer* Server = nullptr;
- uv_signal_t* SIGINTHandler = nullptr;
- uv_signal_t* SIGHUPHandler = nullptr;
-
- friend class LoopGuard;
+ std::string RequestBuffer;
};
-class cmServerStdIoConnection : public cmServerConnection
+/***
+ * Generic connection over std io interfaces -- tty
+ */
+class cmStdIoConnection : public cmEventBasedConnection
{
public:
- cmServerStdIoConnection();
- bool DoSetup(std::string* errorMessage) override;
+ cmStdIoConnection(cmConnectionBufferStrategy* bufferStrategy);
+
+ void SetServer(cmServerBase* s) override;
+
+ bool OnConnectionShuttingDown() override;
- void TearDown() override;
+ bool OnServeStart(std::string* pString) override;
private:
typedef union
@@ -78,18 +56,18 @@ private:
InOutUnion Output;
};
-class cmServerPipeConnection : public cmServerConnection
+/***
+ * These specific connections use the cmake server
+ * buffering strategy.
+ */
+class cmServerStdIoConnection : public cmStdIoConnection
{
public:
- cmServerPipeConnection(const std::string& name);
- bool DoSetup(std::string* errorMessage) override;
-
- void TearDown() override;
-
- void Connect(uv_stream_t* server) override;
+ cmServerStdIoConnection();
+};
-private:
- const std::string PipeName;
- uv_pipe_t* ServerPipe = nullptr;
- uv_pipe_t* ClientPipe = nullptr;
+class cmServerPipeConnection : public cmPipeConnection
+{
+public:
+ cmServerPipeConnection(const std::string& name);
};
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 21b69cf..8ad4916 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -128,11 +128,13 @@ void getCMakeInputs(const cmGlobalGenerator* gg, const std::string& sourceDir,
} // namespace
-cmServerRequest::cmServerRequest(cmServer* server, const std::string& t,
- const std::string& c, const Json::Value& d)
+cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection,
+ const std::string& t, const std::string& c,
+ const Json::Value& d)
: Type(t)
, Cookie(c)
, Data(d)
+ , Connection(connection)
, m_Server(server)
{
}
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
index 4e57bb6..145708c 100644
--- a/Source/cmServerProtocol.h
+++ b/Source/cmServerProtocol.h
@@ -11,6 +11,7 @@
#include <string>
#include <utility>
+class cmConnection;
class cmFileMonitor;
class cmServer;
class cmServerRequest;
@@ -52,9 +53,11 @@ public:
const std::string Type;
const std::string Cookie;
const Json::Value Data;
+ cmConnection* Connection;
private:
- cmServerRequest(cmServer* server, const std::string& t, const std::string& c,
+ cmServerRequest(cmServer* server, cmConnection* connection,
+ const std::string& t, const std::string& c,
const Json::Value& d);
void ReportProgress(int min, int current, int max,
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index f7192e0..9f214c3 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -934,19 +934,17 @@ bool cmSystemTools::RenameFile(const char* oldname, const char* newname)
#endif
}
-bool cmSystemTools::ComputeFileMD5(const std::string& source, char* md5out)
+std::string cmSystemTools::ComputeFileHash(const std::string& source,
+ cmCryptoHash::Algo algo)
{
#if defined(CMAKE_BUILD_WITH_CMAKE)
- cmCryptoHash md5(cmCryptoHash::AlgoMD5);
- std::string const str = md5.HashFile(source);
- strncpy(md5out, str.c_str(), 32);
- return !str.empty();
+ cmCryptoHash hash(algo);
+ return hash.HashFile(source);
#else
(void)source;
- (void)md5out;
- cmSystemTools::Message("md5sum not supported in bootstrapping mode",
+ cmSystemTools::Message("hashsum not supported in bootstrapping mode",
"Error");
- return false;
+ return std::string();
#endif
}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index 9de7967..e163c91 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -5,6 +5,7 @@
#include "cmConfigure.h"
+#include "cmCryptoHash.h"
#include "cmProcessOutput.h"
#include "cmsys/Process.h"
#include "cmsys/SystemTools.hxx" // IWYU pragma: export
@@ -179,8 +180,9 @@ public:
if possible). */
static bool RenameFile(const char* oldname, const char* newname);
- ///! Compute the md5sum of a file
- static bool ComputeFileMD5(const std::string& source, char* md5out);
+ ///! Compute the hash of a file
+ static std::string ComputeFileHash(const std::string& source,
+ cmCryptoHash::Algo algo);
/** Compute the md5sum of a string. */
static std::string ComputeStringMD5(const std::string& input);
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index d5b0861..c546c7e 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -44,6 +44,8 @@
#include <stdlib.h>
#include <time.h>
+class cmConnection;
+
int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg,
std::vector<std::string>::const_iterator argEnd);
int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg,
@@ -88,6 +90,11 @@ void CMakeCommandUsage(const char* program)
<< " environment - display the current environment\n"
<< " make_directory <dir>... - create parent and <dir> directories\n"
<< " md5sum <file>... - create MD5 checksum of files\n"
+ << " sha1sum <file>... - create SHA1 checksum of files\n"
+ << " sha224sum <file>... - create SHA224 checksum of files\n"
+ << " sha256sum <file>... - create SHA256 checksum of files\n"
+ << " sha384sum <file>... - create SHA384 checksum of files\n"
+ << " sha512sum <file>... - create SHA512 checksum of files\n"
<< " remove [-f] <file>... - remove the file(s), use -f to force "
"it\n"
<< " remove_directory dir - remove a directory and its contents\n"
@@ -641,24 +648,28 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
// Command to calculate the md5sum of a file
if (args[1] == "md5sum" && args.size() >= 3) {
- char md5out[32];
- int retval = 0;
- for (std::string::size_type cc = 2; cc < args.size(); cc++) {
- const char* filename = args[cc].c_str();
- // Cannot compute md5sum of a directory
- if (cmSystemTools::FileIsDirectory(filename)) {
- std::cerr << "Error: " << filename << " is a directory" << std::endl;
- retval++;
- } else if (!cmSystemTools::ComputeFileMD5(filename, md5out)) {
- // To mimic md5sum behavior in a shell:
- std::cerr << filename << ": No such file or directory" << std::endl;
- retval++;
- } else {
- std::cout << std::string(md5out, 32) << " " << filename
- << std::endl;
- }
- }
- return retval;
+ return HashSumFile(args, cmCryptoHash::AlgoMD5);
+ }
+
+ // Command to calculate the sha1sum of a file
+ if (args[1] == "sha1sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA1);
+ }
+
+ if (args[1] == "sha224sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA224);
+ }
+
+ if (args[1] == "sha256sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA256);
+ }
+
+ if (args[1] == "sha384sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA384);
+ }
+
+ if (args[1] == "sha512sum" && args.size() >= 3) {
+ return HashSumFile(args, cmCryptoHash::AlgoSHA512);
}
// Command to change directory and run a program.
@@ -1013,7 +1024,7 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
}
}
#if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE
- cmServerConnection* conn;
+ cmConnection* conn;
if (isDebug) {
conn = new cmServerStdIoConnection;
} else {
@@ -1074,6 +1085,33 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
return 1;
}
+int cmcmd::HashSumFile(std::vector<std::string>& args, cmCryptoHash::Algo algo)
+{
+ if (args.size() < 3) {
+ return -1;
+ }
+ int retval = 0;
+
+ for (std::string::size_type cc = 2; cc < args.size(); cc++) {
+ const char* filename = args[cc].c_str();
+ // Cannot compute sum of a directory
+ if (cmSystemTools::FileIsDirectory(filename)) {
+ std::cerr << "Error: " << filename << " is a directory" << std::endl;
+ retval++;
+ } else {
+ std::string value = cmSystemTools::ComputeFileHash(filename, algo);
+ if (value.empty()) {
+ // To mimic "md5sum/shasum" behavior in a shell:
+ std::cerr << filename << ": No such file or directory" << std::endl;
+ retval++;
+ } else {
+ std::cout << value << " " << filename << std::endl;
+ }
+ }
+ }
+ return retval;
+}
+
int cmcmd::SymlinkLibrary(std::vector<std::string>& args)
{
int result = 0;
diff --git a/Source/cmcmd.h b/Source/cmcmd.h
index 929f1ae..faac1d2 100644
--- a/Source/cmcmd.h
+++ b/Source/cmcmd.h
@@ -4,6 +4,7 @@
#define cmcmd_h
#include "cmConfigure.h" // IWYU pragma: keep
+#include "cmCryptoHash.h"
#include <string>
#include <vector>
@@ -18,6 +19,8 @@ public:
static int ExecuteCMakeCommand(std::vector<std::string>&);
protected:
+ static int HashSumFile(std::vector<std::string>& args,
+ cmCryptoHash::Algo algo);
static int SymlinkLibrary(std::vector<std::string>& args);
static int SymlinkExecutable(std::vector<std::string>& args);
static bool SymlinkInternal(std::string const& file,
diff --git a/Templates/TestDriver.cxx.in b/Templates/TestDriver.cxx.in
index 0d3f44f..bf61be4 100644
--- a/Templates/TestDriver.cxx.in
+++ b/Templates/TestDriver.cxx.in
@@ -32,8 +32,8 @@ static functionMapEntry cmakeGeneratedFunctionMapEntries[] = {
{ NULL, NULL } /* NOLINT */
};
-static const int NumTests =
- (sizeof(cmakeGeneratedFunctionMapEntries) / sizeof(functionMapEntry)) - 1;
+static const int NumTests = CM_CAST(int,
+ sizeof(cmakeGeneratedFunctionMapEntries) / sizeof(functionMapEntry)) - 1;
/* Allocate and create a lowercased copy of string
(note that it has to be free'd manually) */
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_md5sum-dir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_md5sum-dir-stderr.txt
new file mode 100644
index 0000000..061fd64
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-dir-stderr.txt
@@ -0,0 +1 @@
+Error: . is a directory
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-mixed-result.txt b/Tests/RunCMake/CommandLine/E_md5sum-mixed-result.txt
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-mixed-result.txt
@@ -0,0 +1 @@
+2
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-mixed-stderr.txt b/Tests/RunCMake/CommandLine/E_md5sum-mixed-stderr.txt
new file mode 100644
index 0000000..b6b84c3
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-mixed-stderr.txt
@@ -0,0 +1,2 @@
+Error: . is a directory
+nonexisting: No such file or directory
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-mixed-stdout.txt b/Tests/RunCMake/CommandLine/E_md5sum-mixed-stdout.txt
new file mode 100644
index 0000000..18e49be
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-mixed-stdout.txt
@@ -0,0 +1 @@
+275876e34cf609db118f3d84b799a790 ../dummy
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_md5sum-no-file-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-no-file-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_md5sum-no-file-stderr.txt
new file mode 100644
index 0000000..732e8c4
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-no-file-stderr.txt
@@ -0,0 +1 @@
+nonexisting: No such file or directory
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-result.txt b/Tests/RunCMake/CommandLine/E_md5sum-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_md5sum-stdout.txt b/Tests/RunCMake/CommandLine/E_md5sum-stdout.txt
new file mode 100644
index 0000000..18e49be
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_md5sum-stdout.txt
@@ -0,0 +1 @@
+275876e34cf609db118f3d84b799a790 ../dummy
diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha1sum-dir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha1sum-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha1sum-dir-stderr.txt
new file mode 100644
index 0000000..061fd64
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha1sum-dir-stderr.txt
@@ -0,0 +1 @@
+Error: . is a directory
diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha1sum-no-file-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha1sum-no-file-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha1sum-no-file-stderr.txt
new file mode 100644
index 0000000..732e8c4
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha1sum-no-file-stderr.txt
@@ -0,0 +1 @@
+nonexisting: No such file or directory
diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-result.txt b/Tests/RunCMake/CommandLine/E_sha1sum-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha1sum-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_sha1sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha1sum-stdout.txt
new file mode 100644
index 0000000..689b85b
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha1sum-stdout.txt
@@ -0,0 +1 @@
+829c3804401b0727f70f73d4415e162400cbe57b ../dummy
diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha224sum-dir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha224sum-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha224sum-dir-stderr.txt
new file mode 100644
index 0000000..061fd64
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha224sum-dir-stderr.txt
@@ -0,0 +1 @@
+Error: . is a directory
diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha224sum-no-file-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha224sum-no-file-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha224sum-no-file-stderr.txt
new file mode 100644
index 0000000..732e8c4
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha224sum-no-file-stderr.txt
@@ -0,0 +1 @@
+nonexisting: No such file or directory
diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-result.txt b/Tests/RunCMake/CommandLine/E_sha224sum-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha224sum-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_sha224sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha224sum-stdout.txt
new file mode 100644
index 0000000..5b3e217
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha224sum-stdout.txt
@@ -0,0 +1 @@
+37d32c6dbabed711cb1d4620b64090fef0ef63ab16a4a51d668259e6 ../dummy
diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha256sum-dir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha256sum-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha256sum-dir-stderr.txt
new file mode 100644
index 0000000..061fd64
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha256sum-dir-stderr.txt
@@ -0,0 +1 @@
+Error: . is a directory
diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha256sum-no-file-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha256sum-no-file-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha256sum-no-file-stderr.txt
new file mode 100644
index 0000000..732e8c4
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha256sum-no-file-stderr.txt
@@ -0,0 +1 @@
+nonexisting: No such file or directory
diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-result.txt b/Tests/RunCMake/CommandLine/E_sha256sum-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha256sum-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_sha256sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha256sum-stdout.txt
new file mode 100644
index 0000000..9a18770
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha256sum-stdout.txt
@@ -0,0 +1 @@
+b5a2c96250612366ea272ffac6d9744aaf4b45aacd96aa7cfcb931ee3b558259 ../dummy
diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha384sum-dir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha384sum-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha384sum-dir-stderr.txt
new file mode 100644
index 0000000..061fd64
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha384sum-dir-stderr.txt
@@ -0,0 +1 @@
+Error: . is a directory
diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha384sum-no-file-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha384sum-no-file-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha384sum-no-file-stderr.txt
new file mode 100644
index 0000000..732e8c4
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha384sum-no-file-stderr.txt
@@ -0,0 +1 @@
+nonexisting: No such file or directory
diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-result.txt b/Tests/RunCMake/CommandLine/E_sha384sum-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha384sum-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_sha384sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha384sum-stdout.txt
new file mode 100644
index 0000000..b706ac5
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha384sum-stdout.txt
@@ -0,0 +1 @@
+43c1835ceba2e29596f05e3859d4fe2b6d124a181ed670f68e914bd3ed251b02b4be609608a13f23ec3d98da6c4eb8cd ../dummy
diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-dir-result.txt b/Tests/RunCMake/CommandLine/E_sha512sum-dir-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha512sum-dir-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-dir-stderr.txt b/Tests/RunCMake/CommandLine/E_sha512sum-dir-stderr.txt
new file mode 100644
index 0000000..061fd64
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha512sum-dir-stderr.txt
@@ -0,0 +1 @@
+Error: . is a directory
diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-no-file-result.txt b/Tests/RunCMake/CommandLine/E_sha512sum-no-file-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha512sum-no-file-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-no-file-stderr.txt b/Tests/RunCMake/CommandLine/E_sha512sum-no-file-stderr.txt
new file mode 100644
index 0000000..732e8c4
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha512sum-no-file-stderr.txt
@@ -0,0 +1 @@
+nonexisting: No such file or directory
diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-result.txt b/Tests/RunCMake/CommandLine/E_sha512sum-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha512sum-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CommandLine/E_sha512sum-stdout.txt b/Tests/RunCMake/CommandLine/E_sha512sum-stdout.txt
new file mode 100644
index 0000000..4305383
--- /dev/null
+++ b/Tests/RunCMake/CommandLine/E_sha512sum-stdout.txt
@@ -0,0 +1 @@
+1692526aab84461a8aebcefddcba2b33fb5897ab180c53e8b345ae125484d0aaa35baf60487050be21ed8909a48eace93851bf139087ce1f7a87d97b6120a651 ../dummy
diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
index f94b10a..6efcc12 100644
--- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake
@@ -172,6 +172,30 @@ run_cmake_command(E_env-bad-arg1 ${CMAKE_COMMAND} -E env -bad-arg1)
run_cmake_command(E_env-set ${CMAKE_COMMAND} -E env TEST_ENV=1 ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-set.cmake)
run_cmake_command(E_env-unset ${CMAKE_COMMAND} -E env TEST_ENV=1 ${CMAKE_COMMAND} -E env --unset=TEST_ENV ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/E_env-unset.cmake)
+run_cmake_command(E_md5sum-dir ${CMAKE_COMMAND} -E md5sum .)
+run_cmake_command(E_sha1sum-dir ${CMAKE_COMMAND} -E sha1sum .)
+run_cmake_command(E_sha224sum-dir ${CMAKE_COMMAND} -E sha224sum .)
+run_cmake_command(E_sha256sum-dir ${CMAKE_COMMAND} -E sha256sum .)
+run_cmake_command(E_sha384sum-dir ${CMAKE_COMMAND} -E sha384sum .)
+run_cmake_command(E_sha512sum-dir ${CMAKE_COMMAND} -E sha512sum .)
+
+run_cmake_command(E_md5sum-no-file ${CMAKE_COMMAND} -E md5sum nonexisting)
+run_cmake_command(E_sha1sum-no-file ${CMAKE_COMMAND} -E sha1sum nonexisting)
+run_cmake_command(E_sha224sum-no-file ${CMAKE_COMMAND} -E sha224sum nonexisting)
+run_cmake_command(E_sha256sum-no-file ${CMAKE_COMMAND} -E sha256sum nonexisting)
+run_cmake_command(E_sha384sum-no-file ${CMAKE_COMMAND} -E sha384sum nonexisting)
+run_cmake_command(E_sha512sum-no-file ${CMAKE_COMMAND} -E sha512sum nonexisting)
+
+file(WRITE "${RunCMake_BINARY_DIR}/dummy" "dummy")
+run_cmake_command(E_md5sum ${CMAKE_COMMAND} -E md5sum ../dummy)
+run_cmake_command(E_md5sum-mixed ${CMAKE_COMMAND} -E md5sum . ../dummy nonexisting)
+run_cmake_command(E_sha1sum ${CMAKE_COMMAND} -E sha1sum ../dummy)
+run_cmake_command(E_sha224sum ${CMAKE_COMMAND} -E sha224sum ../dummy)
+run_cmake_command(E_sha256sum ${CMAKE_COMMAND} -E sha256sum ../dummy)
+run_cmake_command(E_sha384sum ${CMAKE_COMMAND} -E sha384sum ../dummy)
+run_cmake_command(E_sha512sum ${CMAKE_COMMAND} -E sha512sum ../dummy)
+file(REMOVE "${RunCMake_BINARY_DIR}/dummy")
+
set(RunCMake_DEFAULT_stderr ".")
run_cmake_command(E_sleep-no-args ${CMAKE_COMMAND} -E sleep)
unset(RunCMake_DEFAULT_stderr)
diff --git a/Tests/RunCMake/ObjectLibrary/OwnSources-result.txt b/Tests/RunCMake/ObjectLibrary/OwnSources-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/OwnSources-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt b/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt
new file mode 100644
index 0000000..40d650e
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/OwnSources-stderr.txt
@@ -0,0 +1,5 @@
+^CMake Error at OwnSources.cmake:[0-9]+ \(add_library\):
+ The SOURCES of "A" use a generator expression that depends on the SOURCES
+ themselves.
+Call Stack \(most recent call first\):
+ CMakeLists.txt:[0-9]+ \(include\)$
diff --git a/Tests/RunCMake/ObjectLibrary/OwnSources.cmake b/Tests/RunCMake/ObjectLibrary/OwnSources.cmake
new file mode 100644
index 0000000..e7bdf8d
--- /dev/null
+++ b/Tests/RunCMake/ObjectLibrary/OwnSources.cmake
@@ -0,0 +1,2 @@
+add_library(A OBJECT a.c)
+target_sources(A PRIVATE $<TARGET_OBJECTS:A>)
diff --git a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
index fe708ce..b8eed73 100644
--- a/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
+++ b/Tests/RunCMake/ObjectLibrary/RunCMakeTest.cmake
@@ -19,6 +19,7 @@ run_cmake(LinkObjRHS1)
run_cmake(LinkObjRHS2)
run_cmake(MissingSource)
run_cmake(ObjWithObj)
+run_cmake(OwnSources)
run_cmake(PostBuild)
run_cmake(PreBuild)
run_cmake(PreLink)
diff --git a/Tests/Server/server-test.py b/Tests/Server/server-test.py
index 62d9008..5621111 100644
--- a/Tests/Server/server-test.py
+++ b/Tests/Server/server-test.py
@@ -117,4 +117,4 @@ except:
proc.terminate()
raise
-sys.exit(0)
+sys.exit(proc.returncode)
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
index fe0f7df..23ca091 100644
--- a/Utilities/IWYU/mapping.imp
+++ b/Utilities/IWYU/mapping.imp
@@ -21,6 +21,7 @@
{ include: [ "<wctype.h>", public, "<cwctype>", public ] },
# HACK: check whether this can be removed with next iwyu release.
+ { include: [ "<bits/shared_ptr.h>", private, "<memory>", public ] },
{ include: [ "<bits/std_function.h>", private, "<functional>", public ] },
{ include: [ "<bits/time.h>", private, "<time.h>", public ] },
{ include: [ "<bits/types/clock_t.h>", private, "<time.h>", public ] },