summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2020-10-20 18:51:42 (GMT)
committerKyle Edwards <kyle.edwards@kitware.com>2020-10-20 18:51:42 (GMT)
commitcf6ac2d365dcfb00b32a0a10ac0c48a401d42ef5 (patch)
treea25f17669a4dfa68880e0bf56f9d70fe46870c40 /Source
parent21bc2fd945aa06c640bd609bf1e57cc208d6d6bd (diff)
parent8bb8c9fb138c0eb94f05f069577b16afc37faa46 (diff)
downloadCMake-cf6ac2d365dcfb00b32a0a10ac0c48a401d42ef5.zip
CMake-cf6ac2d365dcfb00b32a0a10ac0c48a401d42ef5.tar.gz
CMake-cf6ac2d365dcfb00b32a0a10ac0c48a401d42ef5.tar.bz2
Merge branch 'master' into cmakepresets-schema
Diffstat (limited to 'Source')
-rw-r--r--Source/CMakeLists.txt16
-rw-r--r--Source/CMakeVersion.cmake4
-rw-r--r--Source/LexerParser/cmGccDepfileLexer.cxx2
-rw-r--r--Source/LexerParser/cmGccDepfileLexer.in.l2
-rw-r--r--Source/cmAddCustomCommandCommand.cxx13
-rw-r--r--Source/cmConnection.cxx173
-rw-r--r--Source/cmConnection.h137
-rw-r--r--Source/cmCustomCommandGenerator.cxx73
-rw-r--r--Source/cmCustomCommandGenerator.h4
-rw-r--r--Source/cmExportFileGenerator.cxx4
-rw-r--r--Source/cmFileCommand.cxx102
-rw-r--r--Source/cmFileMonitor.cxx383
-rw-r--r--Source/cmFileMonitor.h35
-rw-r--r--Source/cmGccDepfileLexerHelper.cxx33
-rw-r--r--Source/cmGccDepfileLexerHelper.h3
-rw-r--r--Source/cmGccDepfileReader.cxx9
-rw-r--r--Source/cmGccDepfileReader.h4
-rw-r--r--Source/cmGeneratorTarget.cxx13
-rw-r--r--Source/cmGhsMultiTargetGenerator.cxx6
-rw-r--r--Source/cmGlobalGenerator.h6
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx33
-rw-r--r--Source/cmGlobalNinjaGenerator.h8
-rw-r--r--Source/cmJsonObjectDictionary.h45
-rw-r--r--Source/cmJsonObjects.cxx692
-rw-r--r--Source/cmJsonObjects.h24
-rw-r--r--Source/cmLocalGenerator.cxx200
-rw-r--r--Source/cmLocalGenerator.h73
-rw-r--r--Source/cmLocalNinjaGenerator.cxx45
-rw-r--r--Source/cmMakefile.cxx254
-rw-r--r--Source/cmMakefile.h93
-rw-r--r--Source/cmPipeConnection.cxx71
-rw-r--r--Source/cmPipeConnection.h29
-rw-r--r--Source/cmPolicies.h7
-rw-r--r--Source/cmQtAutoMocUic.cxx8
-rw-r--r--Source/cmServer.cxx570
-rw-r--r--Source/cmServer.h162
-rw-r--r--Source/cmServerConnection.cxx165
-rw-r--r--Source/cmServerConnection.h67
-rw-r--r--Source/cmServerDictionary.h67
-rw-r--r--Source/cmServerProtocol.cxx760
-rw-r--r--Source/cmServerProtocol.h162
-rw-r--r--Source/cmSourceFile.cxx61
-rw-r--r--Source/cmSourceFile.h5
-rw-r--r--Source/cmTransformDepfile.cxx114
-rw-r--r--Source/cmTransformDepfile.h14
-rw-r--r--Source/cmake.cxx2
-rw-r--r--Source/cmcmd.cxx66
47 files changed, 753 insertions, 4066 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 1194318..cb954e5 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -441,6 +441,8 @@ set(SRCS
cmTest.h
cmTestGenerator.cxx
cmTestGenerator.h
+ cmTransformDepfile.cxx
+ cmTransformDepfile.h
cmUuid.cxx
cmUVHandlePtr.cxx
cmUVHandlePtr.h
@@ -1156,20 +1158,6 @@ add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE})
list(APPEND _tools cmake)
target_link_libraries(cmake CMakeLib)
-add_library(CMakeServerLib
- cmConnection.h cmConnection.cxx
- cmFileMonitor.cxx cmFileMonitor.h
- cmJsonObjectDictionary.h
- cmJsonObjects.h
- cmJsonObjects.cxx
- cmPipeConnection.cxx cmPipeConnection.h
- cmServer.cxx cmServer.h
- cmServerConnection.cxx cmServerConnection.h
- cmServerProtocol.cxx cmServerProtocol.h
- )
-target_link_libraries(CMakeServerLib CMakeLib)
-target_link_libraries(cmake CMakeServerLib)
-
# Build CTest executable
add_executable(ctest ctest.cxx ${MANIFEST_FILE})
list(APPEND _tools ctest)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 30b9512..41c84af 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,8 +1,8 @@
# CMake version number components.
set(CMake_VERSION_MAJOR 3)
set(CMake_VERSION_MINOR 19)
-set(CMake_VERSION_PATCH 0)
-set(CMake_VERSION_RC 1)
+set(CMake_VERSION_PATCH 20201020)
+#set(CMake_VERSION_RC 0)
set(CMake_VERSION_IS_DIRTY 0)
# Start with the full version number used in tags. It has no dev info.
diff --git a/Source/LexerParser/cmGccDepfileLexer.cxx b/Source/LexerParser/cmGccDepfileLexer.cxx
index a98969d..3630f4e 100644
--- a/Source/LexerParser/cmGccDepfileLexer.cxx
+++ b/Source/LexerParser/cmGccDepfileLexer.cxx
@@ -994,7 +994,7 @@ case 5:
YY_RULE_SETUP
{
// A line continuation ends the current file name.
- yyextra->newDependency();
+ yyextra->newRuleOrDependency();
}
YY_BREAK
case 6:
diff --git a/Source/LexerParser/cmGccDepfileLexer.in.l b/Source/LexerParser/cmGccDepfileLexer.in.l
index 08f8577..c83cb75 100644
--- a/Source/LexerParser/cmGccDepfileLexer.in.l
+++ b/Source/LexerParser/cmGccDepfileLexer.in.l
@@ -42,7 +42,7 @@ NEWLINE \r?\n
}
{WSPACE}*\\{NEWLINE} {
// A line continuation ends the current file name.
- yyextra->newDependency();
+ yyextra->newRuleOrDependency();
}
{NEWLINE} {
// A newline ends the current file name and the current rule.
diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx
index 231a2d6..bea89c0 100644
--- a/Source/cmAddCustomCommandCommand.cxx
+++ b/Source/cmAddCustomCommandCommand.cxx
@@ -314,16 +314,9 @@ bool cmAddCustomCommandCommand(std::vector<std::string> const& args,
// Check for an append request.
if (append) {
- if (mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,
- commandLines)) {
- return true;
- }
-
- // No command for this output exists.
- status.SetError(
- cmStrCat("given APPEND option with output\n ", output[0],
- "\nwhich is not already a custom command output."));
- return false;
+ mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends,
+ commandLines);
+ return true;
}
if (uses_terminal && !job_pool.empty()) {
diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx
deleted file mode 100644
index e4d0cf1..0000000
--- a/Source/cmConnection.cxx
+++ /dev/null
@@ -1,173 +0,0 @@
-/* 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 <cassert>
-#include <cstring>
-
-#include <cm3p/uv.h>
-
-#include "cmServer.h"
-
-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);
-#ifndef __clang_analyzer__
- char* rawBuffer = new char[suggested_size];
- *buf = uv_buf_init(rawBuffer, static_cast<unsigned int>(suggested_size));
-#else
- (void)(suggested_size);
- (void)(buf);
-#endif /* __clang_analyzer__ */
-}
-
-void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread,
- const uv_buf_t* buf)
-{
- auto conn = static_cast<cmEventBasedConnection*>(stream->data);
- if (conn) {
- if (nread >= 0) {
- conn->ReadData(std::string(buf->base, buf->base + nread));
- } else {
- conn->OnDisconnect(static_cast<int>(nread));
- }
- }
-
- delete[](buf->base);
-}
-
-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 = static_cast<cmEventBasedConnection*>(stream->data);
-
- if (conn) {
- conn->Connect(stream);
- }
-}
-
-bool cmEventBasedConnection::IsOpen() const
-{
- return this->WriteStream != nullptr;
-}
-
-void cmEventBasedConnection::WriteData(const std::string& _data)
-{
-#ifndef NDEBUG
- auto curr_thread_id = uv_thread_self();
- assert(this->Server);
- assert(uv_thread_equal(&curr_thread_id, &this->Server->ServeThreadId));
-#endif
-
-#ifndef __clang_analyzer__
- auto data = _data;
- assert(this->WriteStream.get());
- if (BufferStrategy) {
- data = BufferStrategy->BufferOutMessage(data);
- }
-
- 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), this->WriteStream, &req->buf, 1,
- on_write);
-#else
- (void)(_data);
-#endif /* __clang_analyzer__ */
-}
-
-void cmEventBasedConnection::ReadData(const std::string& data)
-{
- this->RawReadBuffer += data;
- if (BufferStrategy) {
- std::string packet = BufferStrategy->BufferMessage(this->RawReadBuffer);
- while (!packet.empty()) {
- ProcessRequest(packet);
- packet = BufferStrategy->BufferMessage(this->RawReadBuffer);
- }
- } 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();
- if (this->Server) {
- this->Server->OnDisconnect(this);
- }
-}
-
-cmConnection::~cmConnection() = default;
-
-bool cmConnection::OnConnectionShuttingDown()
-{
- this->Server = nullptr;
- 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()
-{
- if (this->WriteStream.get()) {
- this->WriteStream->data = nullptr;
- }
-
- WriteStream.reset();
-
- return true;
-}
diff --git a/Source/cmConnection.h b/Source/cmConnection.h
deleted file mode 100644
index 5335a7f..0000000
--- a/Source/cmConnection.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* 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" // IWYU pragma: keep
-
-#include <cstddef>
-#include <memory>
-#include <string>
-
-#include <cm3p/uv.h>
-
-#include "cmUVHandlePtr.h"
-
-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;
-
- /***
- * Called to properly buffer an outgoing message.
- *
- * @param rawBuffer Message to format in the correct way
- *
- * @return Formatted message
- */
- virtual std::string BufferOutMessage(const std::string& rawBuffer) const
- {
- return rawBuffer;
- };
- /***
- * Resets the internal state of the buffering
- */
- virtual void clear();
-
- // TODO: There should be a callback / flag set for errors
-};
-
-class cmConnection
-{
-public:
- cmConnection() = default;
-
- cmConnection(cmConnection const&) = delete;
- cmConnection& operator=(cmConnection const&) = delete;
-
- 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);
-
- static void on_close(uv_handle_t* handle);
-
- template <typename T>
- static void on_close_delete(uv_handle_t* handle)
- {
- delete reinterpret_cast<T*>(handle);
- }
-
-protected:
- cm::uv_stream_ptr WriteStream;
-
- 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/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 60504ba..d8307f6 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -6,18 +6,22 @@
#include <memory>
#include <utility>
+#include <cm/optional>
#include <cmext/algorithm>
+#include "cmCryptoHash.h"
#include "cmCustomCommand.h"
#include "cmCustomCommandLines.h"
#include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmProperty.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmTransformDepfile.h"
namespace {
void AppendPaths(const std::vector<std::string>& inputs,
@@ -42,7 +46,8 @@ void AppendPaths(const std::vector<std::string>& inputs,
cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
std::string config,
- cmLocalGenerator* lg)
+ cmLocalGenerator* lg,
+ bool transformDepfile)
: CC(cc)
, Config(std::move(config))
, LG(lg)
@@ -75,6 +80,36 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
this->CommandLines.push_back(std::move(argv));
}
+ if (transformDepfile && !this->CommandLines.empty() &&
+ !cc.GetDepfile().empty() &&
+ this->LG->GetGlobalGenerator()->DepfileFormat()) {
+ cmCustomCommandLine argv;
+ argv.push_back(cmSystemTools::GetCMakeCommand());
+ argv.emplace_back("-E");
+ argv.emplace_back("cmake_transform_depfile");
+ switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) {
+ case cmDepfileFormat::GccDepfile:
+ argv.emplace_back("gccdepfile");
+ break;
+ case cmDepfileFormat::VsTlog:
+ argv.emplace_back("vstlog");
+ break;
+ }
+ if (this->LG->GetCurrentBinaryDirectory() ==
+ this->LG->GetBinaryDirectory()) {
+ argv.emplace_back("./");
+ } else {
+ argv.push_back(cmStrCat(this->LG->MaybeConvertToRelativePath(
+ this->LG->GetBinaryDirectory(),
+ this->LG->GetCurrentBinaryDirectory()),
+ '/'));
+ }
+ argv.push_back(this->GetFullDepfile());
+ argv.push_back(this->GetInternalDepfile());
+
+ this->CommandLines.push_back(std::move(argv));
+ }
+
AppendPaths(cc.GetByproducts(), ge, this->LG, this->Config,
this->Byproducts);
AppendPaths(cc.GetDepends(), ge, this->LG, this->Config, this->Depends);
@@ -97,7 +132,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
{
- return static_cast<unsigned int>(this->CC.GetCommandLines().size());
+ return static_cast<unsigned int>(this->CommandLines.size());
}
void cmCustomCommandGenerator::FillEmulatorsWithArguments()
@@ -234,6 +269,40 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
}
}
+std::string cmCustomCommandGenerator::GetFullDepfile() const
+{
+ std::string depfile = this->CC.GetDepfile();
+ if (depfile.empty()) {
+ return "";
+ }
+
+ if (!cmSystemTools::FileIsFullPath(depfile)) {
+ depfile = cmStrCat(this->LG->GetCurrentBinaryDirectory(), '/', depfile);
+ }
+ return cmSystemTools::CollapseFullPath(depfile);
+}
+
+std::string cmCustomCommandGenerator::GetInternalDepfile() const
+{
+ std::string depfile = this->GetFullDepfile();
+ if (depfile.empty()) {
+ return "";
+ }
+
+ cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+ std::string extension;
+ switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) {
+ case cmDepfileFormat::GccDepfile:
+ extension = ".d";
+ break;
+ case cmDepfileFormat::VsTlog:
+ extension = ".tlog";
+ break;
+ }
+ return cmStrCat(this->LG->GetBinaryDirectory(), "/CMakeFiles/d/",
+ hash.HashString(depfile), extension);
+}
+
const char* cmCustomCommandGenerator::GetComment() const
{
return this->CC.GetComment();
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index 412eba8..8b5259d 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -31,7 +31,7 @@ class cmCustomCommandGenerator
public:
cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config,
- cmLocalGenerator* lg);
+ cmLocalGenerator* lg, bool transformDepfile = true);
cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =
delete;
@@ -45,4 +45,6 @@ public:
std::vector<std::string> const& GetByproducts() const;
std::vector<std::string> const& GetDepends() const;
bool HasOnlyEmptyCommandLines() const;
+ std::string GetFullDepfile() const;
+ std::string GetInternalDepfile() const;
};
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index cbae4e5..a853bb1 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -924,13 +924,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os)
// Isolate the file policy level.
// Support CMake versions as far back as 2.6 but also support using NEW
- // policy settings for up to CMake 3.17 (this upper limit may be reviewed
+ // policy settings for up to CMake 3.18 (this upper limit may be reviewed
// and increased from time to time). This reduces the opportunity for CMake
// warnings when an older export file is later used with newer CMake
// versions.
/* clang-format off */
os << "cmake_policy(PUSH)\n"
- << "cmake_policy(VERSION 2.6...3.17)\n";
+ << "cmake_policy(VERSION 2.6...3.18)\n";
/* clang-format on */
}
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 8a3aad2..cd440ad 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -15,6 +15,7 @@
#include <vector>
#include <cm/memory>
+#include <cm/string_view>
#include <cmext/algorithm>
#include <cmext/string_view>
@@ -2314,49 +2315,92 @@ bool HandleGenerateCommand(std::vector<std::string> const& args,
status.SetError("Incorrect arguments to GENERATE subcommand.");
return false;
}
- if (args[1] != "OUTPUT") {
+
+ struct Arguments
+ {
+ std::string Output;
+ std::string Input;
+ std::string Content;
+ std::string Condition;
+ std::string Target;
+ };
+
+ static auto const parser = cmArgumentParser<Arguments>{}
+ .Bind("OUTPUT"_s, &Arguments::Output)
+ .Bind("INPUT"_s, &Arguments::Input)
+ .Bind("CONTENT"_s, &Arguments::Content)
+ .Bind("CONDITION"_s, &Arguments::Condition)
+ .Bind("TARGET"_s, &Arguments::Target);
+
+ std::vector<std::string> unparsedArguments;
+ std::vector<std::string> keywordsMissingValues;
+ std::vector<std::string> parsedKeywords;
+ Arguments const arguments =
+ parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments,
+ &keywordsMissingValues, &parsedKeywords);
+
+ if (!keywordsMissingValues.empty()) {
status.SetError("Incorrect arguments to GENERATE subcommand.");
return false;
}
- std::string condition;
- std::string target;
-
- for (std::size_t i = 5; i < args.size();) {
- const std::string& arg = args[i++];
+ if (!unparsedArguments.empty()) {
+ status.SetError("Unknown argument to GENERATE subcommand.");
+ return false;
+ }
- if (args.size() - i == 0) {
- status.SetError("Incorrect arguments to GENERATE subcommand.");
- return false;
+ bool mandatoryOptionsSpecified = false;
+ if (parsedKeywords.size() > 1) {
+ const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s;
+ const bool inputOrContentSpecified =
+ parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s;
+ if (outputOprionSpecified && inputOrContentSpecified) {
+ mandatoryOptionsSpecified = true;
}
+ }
+ if (!mandatoryOptionsSpecified) {
+ status.SetError("Incorrect arguments to GENERATE subcommand.");
+ return false;
+ }
- const std::string& value = args[i++];
-
- if (value.empty()) {
- status.SetError(
- arg + " of sub-command GENERATE must not be empty if specified.");
- return false;
- }
+ const bool conditionOptionSpecified =
+ std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) !=
+ parsedKeywords.end();
+ if (conditionOptionSpecified && arguments.Condition.empty()) {
+ status.SetError("CONDITION of sub-command GENERATE must not be empty "
+ "if specified.");
+ return false;
+ }
- if (arg == "CONDITION") {
- condition = value;
- } else if (arg == "TARGET") {
- target = value;
- } else {
- status.SetError("Unknown argument to GENERATE subcommand.");
- return false;
- }
+ const bool targetOptionSpecified =
+ std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) !=
+ parsedKeywords.end();
+ if (targetOptionSpecified && arguments.Target.empty()) {
+ status.SetError("TARGET of sub-command GENERATE must not be empty "
+ "if specified.");
+ return false;
}
- std::string output = args[2];
- const bool inputIsContent = args[3] != "INPUT";
- if (inputIsContent && args[3] != "CONTENT") {
+ const bool outputOptionSpecified =
+ std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) !=
+ parsedKeywords.end();
+ if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) {
status.SetError("Incorrect arguments to GENERATE subcommand.");
return false;
}
- std::string input = args[4];
- AddEvaluationFile(input, target, output, condition, inputIsContent, status);
+ const bool inputIsContent = parsedKeywords[1] != "INPUT"_s;
+ if (inputIsContent && parsedKeywords[1] != "CONTENT") {
+ status.SetError("Unknown argument to GENERATE subcommand.");
+ }
+
+ std::string input = arguments.Input;
+ if (inputIsContent) {
+ input = arguments.Content;
+ }
+
+ AddEvaluationFile(input, arguments.Target, arguments.Output,
+ arguments.Condition, inputIsContent, status);
return true;
}
diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx
deleted file mode 100644
index 8cfdb2d..0000000
--- a/Source/cmFileMonitor.cxx
+++ /dev/null
@@ -1,383 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmFileMonitor.h"
-
-#include <cassert>
-#include <cstddef>
-#include <unordered_map>
-#include <utility>
-
-#include <cm/memory>
-
-#include "cmsys/SystemTools.hxx"
-
-namespace {
-void on_directory_change(uv_fs_event_t* handle, const char* filename,
- int events, int status);
-void on_fs_close(uv_handle_t* handle);
-} // namespace
-
-class cmIBaseWatcher
-{
-public:
- virtual ~cmIBaseWatcher() = default;
-
- virtual void Trigger(const std::string& pathSegment, int events,
- int status) const = 0;
- virtual std::string Path() const = 0;
- virtual uv_loop_t* Loop() const = 0;
-
- virtual void StartWatching() = 0;
- virtual void StopWatching() = 0;
-
- virtual std::vector<std::string> WatchedFiles() const = 0;
- virtual std::vector<std::string> WatchedDirectories() const = 0;
-};
-
-class cmVirtualDirectoryWatcher : public cmIBaseWatcher
-{
-public:
- ~cmVirtualDirectoryWatcher() override = default;
-
- cmIBaseWatcher* Find(const std::string& ps)
- {
- const auto i = this->Children.find(ps);
- return (i == this->Children.end()) ? nullptr : i->second.get();
- }
-
- void Trigger(const std::string& pathSegment, int events,
- int status) const final
- {
- if (pathSegment.empty()) {
- for (auto const& child : this->Children) {
- child.second->Trigger(std::string(), events, status);
- }
- } else {
- const auto i = this->Children.find(pathSegment);
- if (i != this->Children.end()) {
- i->second->Trigger(std::string(), events, status);
- }
- }
- }
-
- void StartWatching() override
- {
- for (auto const& child : this->Children) {
- child.second->StartWatching();
- }
- }
-
- void StopWatching() override
- {
- for (auto const& child : this->Children) {
- child.second->StopWatching();
- }
- }
-
- std::vector<std::string> WatchedFiles() const final
- {
- std::vector<std::string> result;
- for (auto const& child : this->Children) {
- for (std::string const& f : child.second->WatchedFiles()) {
- result.push_back(f);
- }
- }
- return result;
- }
-
- std::vector<std::string> WatchedDirectories() const override
- {
- std::vector<std::string> result;
- for (auto const& child : this->Children) {
- for (std::string const& dir : child.second->WatchedDirectories()) {
- result.push_back(dir);
- }
- }
- return result;
- }
-
- void Reset() { this->Children.clear(); }
-
- void AddChildWatcher(const std::string& ps, cmIBaseWatcher* watcher)
- {
- assert(!ps.empty());
- assert(this->Children.find(ps) == this->Children.end());
- assert(watcher);
-
- this->Children.emplace(ps, std::unique_ptr<cmIBaseWatcher>(watcher));
- }
-
-private:
- std::unordered_map<std::string, std::unique_ptr<cmIBaseWatcher>>
- Children; // owned!
-};
-
-// Root of all the different (on windows!) root directories:
-class cmRootWatcher : public cmVirtualDirectoryWatcher
-{
-public:
- cmRootWatcher(uv_loop_t* loop)
- : mLoop(loop)
- {
- assert(loop);
- }
-
- std::string Path() const final
- {
- assert(false);
- return std::string();
- }
- uv_loop_t* Loop() const final { return this->mLoop; }
-
-private:
- uv_loop_t* const mLoop; // no ownership!
-};
-
-// Real directories:
-class cmRealDirectoryWatcher : public cmVirtualDirectoryWatcher
-{
-public:
- cmRealDirectoryWatcher(cmVirtualDirectoryWatcher* p, const std::string& ps)
- : Parent(p)
- , PathSegment(ps)
- {
- assert(p);
- assert(!ps.empty());
-
- p->AddChildWatcher(ps, this);
- }
-
- void StartWatching() final
- {
- if (!this->Handle) {
- this->Handle = new uv_fs_event_t;
-
- uv_fs_event_init(this->Loop(), this->Handle);
- this->Handle->data = this;
- uv_fs_event_start(this->Handle, &on_directory_change, Path().c_str(), 0);
- }
- cmVirtualDirectoryWatcher::StartWatching();
- }
-
- void StopWatching() final
- {
- if (this->Handle) {
- uv_fs_event_stop(this->Handle);
- 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();
- }
-
- uv_loop_t* Loop() const final { return this->Parent->Loop(); }
-
- std::vector<std::string> WatchedDirectories() const override
- {
- std::vector<std::string> result = { Path() };
- for (std::string const& dir :
- cmVirtualDirectoryWatcher::WatchedDirectories()) {
- result.push_back(dir);
- }
- return result;
- }
-
-protected:
- cmVirtualDirectoryWatcher* const Parent;
- const std::string PathSegment;
-
-private:
- uv_fs_event_t* Handle = nullptr; // owner!
-};
-
-// Root directories:
-class cmRootDirectoryWatcher : public cmRealDirectoryWatcher
-{
-public:
- cmRootDirectoryWatcher(cmRootWatcher* p, const std::string& ps)
- : cmRealDirectoryWatcher(p, ps)
- {
- }
-
- std::string Path() const final { return this->PathSegment; }
-};
-
-// Normal directories below root:
-class cmDirectoryWatcher : public cmRealDirectoryWatcher
-{
-public:
- cmDirectoryWatcher(cmRealDirectoryWatcher* p, const std::string& ps)
- : cmRealDirectoryWatcher(p, ps)
- {
- }
-
- std::string Path() const final
- {
- return this->Parent->Path() + this->PathSegment + "/";
- }
-};
-
-class cmFileWatcher : public cmIBaseWatcher
-{
-public:
- cmFileWatcher(cmRealDirectoryWatcher* p, const std::string& ps,
- cmFileMonitor::Callback cb)
- : Parent(p)
- , PathSegment(ps)
- , CbList({ std::move(cb) })
- {
- assert(p);
- assert(!ps.empty());
- p->AddChildWatcher(ps, this);
- }
-
- void StartWatching() final {}
-
- void StopWatching() final {}
-
- void AppendCallback(cmFileMonitor::Callback const& cb)
- {
- this->CbList.push_back(cb);
- }
-
- std::string Path() const final
- {
- return this->Parent->Path() + this->PathSegment;
- }
-
- std::vector<std::string> WatchedDirectories() const final { return {}; }
-
- std::vector<std::string> WatchedFiles() const final
- {
- return { this->Path() };
- }
-
- void Trigger(const std::string& ps, int events, int status) const final
- {
- assert(ps.empty());
- assert(status == 0);
- static_cast<void>(ps);
-
- const std::string path = this->Path();
- for (cmFileMonitor::Callback const& cb : this->CbList) {
- cb(path, events, status);
- }
- }
-
- uv_loop_t* Loop() const final { return this->Parent->Loop(); }
-
-private:
- cmRealDirectoryWatcher* Parent;
- const std::string PathSegment;
- std::vector<cmFileMonitor::Callback> CbList;
-};
-
-namespace {
-
-void on_directory_change(uv_fs_event_t* handle, const char* filename,
- int events, int status)
-{
- const cmIBaseWatcher* const watcher =
- static_cast<const cmIBaseWatcher*>(handle->data);
- const std::string pathSegment(filename ? filename : "");
- watcher->Trigger(pathSegment, events, status);
-}
-
-void on_fs_close(uv_handle_t* handle)
-{
- delete reinterpret_cast<uv_fs_event_t*>(handle);
-}
-
-} // namespace
-
-cmFileMonitor::cmFileMonitor(uv_loop_t* l)
- : Root(cm::make_unique<cmRootWatcher>(l))
-{
-}
-
-cmFileMonitor::~cmFileMonitor() = default;
-
-void cmFileMonitor::MonitorPaths(const std::vector<std::string>& paths,
- Callback const& cb)
-{
- for (std::string const& p : paths) {
- std::vector<std::string> pathSegments;
- cmsys::SystemTools::SplitPath(p, pathSegments, true);
- const bool pathIsFile = !cmsys::SystemTools::FileIsDirectory(p);
-
- const size_t segmentCount = pathSegments.size();
- if (segmentCount < 2) { // Expect at least rootdir and filename
- continue;
- }
- cmVirtualDirectoryWatcher* currentWatcher = this->Root.get();
- for (size_t i = 0; i < segmentCount; ++i) {
- assert(currentWatcher);
-
- const bool fileSegment = (i == segmentCount - 1 && pathIsFile);
- const bool rootSegment = (i == 0);
- assert(
- !(fileSegment &&
- rootSegment)); // Can not be both filename and root part of the path!
-
- const std::string& currentSegment = pathSegments[i];
- if (currentSegment.empty()) {
- continue;
- }
-
- cmIBaseWatcher* nextWatcher = currentWatcher->Find(currentSegment);
- if (!nextWatcher) {
- if (rootSegment) { // Root part
- assert(currentWatcher == this->Root.get());
- nextWatcher =
- new cmRootDirectoryWatcher(this->Root.get(), currentSegment);
- assert(currentWatcher->Find(currentSegment) == nextWatcher);
- } else if (fileSegment) { // File part
- assert(currentWatcher != this->Root.get());
- nextWatcher = new cmFileWatcher(
- dynamic_cast<cmRealDirectoryWatcher*>(currentWatcher),
- currentSegment, cb);
- assert(currentWatcher->Find(currentSegment) == nextWatcher);
- } else { // Any normal directory in between
- nextWatcher = new cmDirectoryWatcher(
- dynamic_cast<cmRealDirectoryWatcher*>(currentWatcher),
- currentSegment);
- assert(currentWatcher->Find(currentSegment) == nextWatcher);
- }
- } else {
- if (fileSegment) {
- auto filePtr = dynamic_cast<cmFileWatcher*>(nextWatcher);
- assert(filePtr);
- filePtr->AppendCallback(cb);
- continue;
- }
- }
- currentWatcher = dynamic_cast<cmVirtualDirectoryWatcher*>(nextWatcher);
- }
- }
- this->Root->StartWatching();
-}
-
-void cmFileMonitor::StopMonitoring()
-{
- this->Root->StopWatching();
- this->Root->Reset();
-}
-
-std::vector<std::string> cmFileMonitor::WatchedFiles() const
-{
- std::vector<std::string> result;
- if (this->Root) {
- result = this->Root->WatchedFiles();
- }
- return result;
-}
-
-std::vector<std::string> cmFileMonitor::WatchedDirectories() const
-{
- std::vector<std::string> result;
- if (this->Root) {
- result = this->Root->WatchedDirectories();
- }
- return result;
-}
diff --git a/Source/cmFileMonitor.h b/Source/cmFileMonitor.h
deleted file mode 100644
index fc75b0c..0000000
--- a/Source/cmFileMonitor.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* 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" // IWYU pragma: keep
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <cm3p/uv.h>
-
-class cmRootWatcher;
-
-class cmFileMonitor
-{
-
-public:
- cmFileMonitor(uv_loop_t* l);
- ~cmFileMonitor();
-
- cmFileMonitor(cmFileMonitor const&) = delete;
- cmFileMonitor& operator=(cmFileMonitor const&) = delete;
-
- using Callback = std::function<void(const std::string&, int, int)>;
- void MonitorPaths(const std::vector<std::string>& paths, Callback const& cb);
- void StopMonitoring();
-
- std::vector<std::string> WatchedFiles() const;
- std::vector<std::string> WatchedDirectories() const;
-
-private:
- std::unique_ptr<cmRootWatcher> Root;
-};
diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx
index 957896f..c782bcd 100644
--- a/Source/cmGccDepfileLexerHelper.cxx
+++ b/Source/cmGccDepfileLexerHelper.cxx
@@ -27,23 +27,30 @@ bool cmGccDepfileLexerHelper::readFile(const char* filePath)
if (!file) {
return false;
}
- newEntry();
+ this->newEntry();
yyscan_t scanner;
cmGccDepfile_yylex_init(&scanner);
cmGccDepfile_yyset_extra(this, scanner);
cmGccDepfile_yyrestart(file, scanner);
cmGccDepfile_yylex(scanner);
cmGccDepfile_yylex_destroy(scanner);
- sanitizeContent();
+ this->sanitizeContent();
fclose(file);
- return true;
+ return this->HelperState != State::Failed;
}
void cmGccDepfileLexerHelper::newEntry()
{
+ if (this->HelperState == State::Rule && !this->Content.empty()) {
+ if (!this->Content.back().rules.empty() &&
+ !this->Content.back().rules.back().empty()) {
+ this->HelperState = State::Failed;
+ }
+ return;
+ }
this->HelperState = State::Rule;
this->Content.emplace_back();
- newRule();
+ this->newRule();
}
void cmGccDepfileLexerHelper::newRule()
@@ -56,20 +63,22 @@ void cmGccDepfileLexerHelper::newRule()
void cmGccDepfileLexerHelper::newDependency()
{
- // printf("NEW DEP\n");
+ if (this->HelperState == State::Failed) {
+ return;
+ }
this->HelperState = State::Dependency;
- if (this->Content.back().paths.empty() ||
- !this->Content.back().paths.back().empty()) {
- this->Content.back().paths.emplace_back();
+ auto& entry = this->Content.back();
+ if (entry.paths.empty() || !entry.paths.back().empty()) {
+ entry.paths.emplace_back();
}
}
void cmGccDepfileLexerHelper::newRuleOrDependency()
{
if (this->HelperState == State::Rule) {
- newRule();
- } else {
- newDependency();
+ this->newRule();
+ } else if (this->HelperState == State::Dependency) {
+ this->newDependency();
}
}
@@ -93,6 +102,8 @@ void cmGccDepfileLexerHelper::addToCurrentPath(const char* s)
}
dst = &dep->paths.back();
} break;
+ case State::Failed:
+ return;
}
dst->append(s);
}
diff --git a/Source/cmGccDepfileLexerHelper.h b/Source/cmGccDepfileLexerHelper.h
index 07ca61d..91132f5 100644
--- a/Source/cmGccDepfileLexerHelper.h
+++ b/Source/cmGccDepfileLexerHelper.h
@@ -29,7 +29,8 @@ private:
enum class State
{
Rule,
- Dependency
+ Dependency,
+ Failed,
};
State HelperState = State::Rule;
};
diff --git a/Source/cmGccDepfileReader.cxx b/Source/cmGccDepfileReader.cxx
index 9d70ede..eb3511a 100644
--- a/Source/cmGccDepfileReader.cxx
+++ b/Source/cmGccDepfileReader.cxx
@@ -5,14 +5,15 @@
#include <type_traits>
#include <utility>
+#include <cm/optional>
+
#include "cmGccDepfileLexerHelper.h"
-cmGccDepfileContent cmReadGccDepfile(const char* filePath)
+cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath)
{
- cmGccDepfileContent result;
cmGccDepfileLexerHelper helper;
if (helper.readFile(filePath)) {
- result = std::move(helper).extractContent();
+ return cm::make_optional(std::move(helper).extractContent());
}
- return result;
+ return cm::nullopt;
}
diff --git a/Source/cmGccDepfileReader.h b/Source/cmGccDepfileReader.h
index 395dd77..59ed7fd 100644
--- a/Source/cmGccDepfileReader.h
+++ b/Source/cmGccDepfileReader.h
@@ -2,6 +2,8 @@
file Copyright.txt or https://cmake.org/licensing for details. */
#pragma once
+#include <cm/optional>
+
#include "cmGccDepfileReaderTypes.h"
-cmGccDepfileContent cmReadGccDepfile(const char* filePath);
+cm::optional<cmGccDepfileContent> cmReadGccDepfile(const char* filePath);
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index bdea9fa..3b47550 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -1539,10 +1539,14 @@ bool processSources(cmGeneratorTarget const* tgt,
for (std::string& src : entry.Values) {
cmSourceFile* sf = mf->GetOrCreateSource(src);
std::string e;
- std::string fullPath = sf->ResolveFullPath(&e);
+ std::string w;
+ std::string fullPath = sf->ResolveFullPath(&e, &w);
+ cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
+ if (!w.empty()) {
+ cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace());
+ }
if (fullPath.empty()) {
if (!e.empty()) {
- cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance();
cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace());
}
return contextDependent;
@@ -2986,7 +2990,8 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
auto i = this->NameMap.lower_bound(name);
if (i == this->NameMap.end() || i->first != name) {
// Check if we know how to generate this file.
- cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name);
+ cmSourcesWithOutput sources =
+ this->LocalGenerator->GetSourcesWithOutput(name);
// If we failed to find a target or source and we have a relative path, it
// might be a valid source if made relative to the current binary
// directory.
@@ -2996,7 +3001,7 @@ void cmTargetTraceDependencies::FollowName(std::string const& name)
cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name);
fullname = cmSystemTools::CollapseFullPath(
fullname, this->Makefile->GetHomeOutputDirectory());
- sources = this->Makefile->GetSourcesWithOutput(fullname);
+ sources = this->LocalGenerator->GetSourcesWithOutput(fullname);
}
i = this->NameMap.emplace_hint(i, name, sources);
}
diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx
index a8f8f57..ed50067 100644
--- a/Source/cmGhsMultiTargetGenerator.cxx
+++ b/Source/cmGhsMultiTargetGenerator.cxx
@@ -763,9 +763,9 @@ bool cmGhsMultiTargetGenerator::VisitCustomCommand(
/* set temporary mark; check if revisit*/
if (temp.insert(si).second) {
for (auto& di : si->GetCustomCommand()->GetDepends()) {
- cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator()
- ->GetMakefile()
- ->GetSourceFileWithOutput(di);
+ cmSourceFile const* sf =
+ this->GeneratorTarget->GetLocalGenerator()->GetSourceFileWithOutput(
+ di);
/* if sf exists then visit */
if (sf && this->VisitCustomCommand(temp, perm, order, sf)) {
return true;
diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h
index b532a43..de5eba7 100644
--- a/Source/cmGlobalGenerator.h
+++ b/Source/cmGlobalGenerator.h
@@ -14,6 +14,7 @@
#include <utility>
#include <vector>
+#include <cm/optional>
#include <cmext/algorithm>
#include "cm_codecvt.hxx"
@@ -26,6 +27,7 @@
#include "cmSystemTools.h"
#include "cmTarget.h"
#include "cmTargetDepend.h"
+#include "cmTransformDepfile.h"
#if !defined(CMAKE_BOOTSTRAP)
# include <cm3p/json/value.h>
@@ -452,6 +454,10 @@ public:
virtual bool ShouldStripResourcePath(cmMakefile*) const;
virtual bool SupportsCustomCommandDepfile() const { return false; }
+ virtual cm::optional<cmDepfileFormat> DepfileFormat() const
+ {
+ return cm::nullopt;
+ }
std::string GetSharedLibFlagsForLanguage(std::string const& lang) const;
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index 985f430..9e25a54 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -2650,30 +2650,17 @@ void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs(
bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables()
{
- this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_BUILD_TYPE");
- this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_CROSS_CONFIGS");
- this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_CONFIGS");
- return this->ReadCacheEntriesForBuild(*this->Makefiles.front()->GetState());
-}
-
-std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const
-{
- return "";
-}
-
-bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
- const cmState& state)
-{
std::vector<std::string> configsVec;
- cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CONFIGURATION_TYPES"),
- configsVec);
+ cmExpandList(
+ this->Makefiles.front()->GetSafeDefinition("CMAKE_CONFIGURATION_TYPES"),
+ configsVec);
if (configsVec.empty()) {
configsVec.emplace_back();
}
std::set<std::string> configs(configsVec.cbegin(), configsVec.cend());
this->DefaultFileConfig =
- state.GetSafeCacheEntryValue("CMAKE_DEFAULT_BUILD_TYPE");
+ this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_BUILD_TYPE");
if (this->DefaultFileConfig.empty()) {
this->DefaultFileConfig = configsVec.front();
}
@@ -2688,8 +2675,9 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
}
std::vector<std::string> crossConfigsVec;
- cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CROSS_CONFIGS"),
- crossConfigsVec);
+ cmExpandList(
+ this->Makefiles.front()->GetSafeDefinition("CMAKE_CROSS_CONFIGS"),
+ crossConfigsVec);
auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec);
if (!crossConfigs) {
std::ostringstream msg;
@@ -2702,7 +2690,7 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
this->CrossConfigs = *crossConfigs;
auto defaultConfigsString =
- state.GetSafeCacheEntryValue("CMAKE_DEFAULT_CONFIGS");
+ this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_CONFIGS");
if (defaultConfigsString.empty()) {
defaultConfigsString = this->DefaultFileConfig;
}
@@ -2736,6 +2724,11 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild(
return true;
}
+std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const
+{
+ return "";
+}
+
std::string cmGlobalNinjaMultiGenerator::OrderDependsTargetForTarget(
cmGeneratorTarget const* target, const std::string& config) const
{
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 884a711..8d6ebdc 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -24,6 +24,7 @@
#include "cmNinjaTypes.h"
#include "cmPolicies.h"
#include "cmStringAlgorithms.h"
+#include "cmTransformDepfile.h"
class cmCustomCommand;
class cmGeneratorTarget;
@@ -31,7 +32,6 @@ class cmLinkLineComputer;
class cmLocalGenerator;
class cmMakefile;
class cmOutputConverter;
-class cmState;
class cmStateDirectory;
class cmake;
struct cmDocumentationEntry;
@@ -211,6 +211,10 @@ public:
const char* GetCleanTargetName() const override { return "clean"; }
bool SupportsCustomCommandDepfile() const override { return true; }
+ cm::optional<cmDepfileFormat> DepfileFormat() const override
+ {
+ return cmDepfileFormat::GccDepfile;
+ }
virtual cmGeneratedFileStream* GetImplFileStream(
const std::string& /*config*/) const
@@ -647,8 +651,6 @@ public:
std::string GetDefaultBuildConfig() const override;
- bool ReadCacheEntriesForBuild(const cmState& state) override;
-
bool SupportsDefaultBuildType() const override { return true; }
bool SupportsCrossConfigs() const override { return true; }
bool SupportsDefaultConfigs() const override { return true; }
diff --git a/Source/cmJsonObjectDictionary.h b/Source/cmJsonObjectDictionary.h
deleted file mode 100644
index 8a2b529..0000000
--- a/Source/cmJsonObjectDictionary.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#pragma once
-
-#include <string>
-
-// Vocabulary:
-
-static const std::string kARTIFACTS_KEY = "artifacts";
-static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
-static const std::string kCOMPILE_FLAGS_KEY = "compileFlags";
-static const std::string kCONFIGURATIONS_KEY = "configurations";
-static const std::string kDEFINES_KEY = "defines";
-static const std::string kFILE_GROUPS_KEY = "fileGroups";
-static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath";
-static const std::string kFULL_NAME_KEY = "fullName";
-static const std::string kINCLUDE_PATH_KEY = "includePath";
-static const std::string kIS_CMAKE_KEY = "isCMake";
-static const std::string kIS_GENERATED_KEY = "isGenerated";
-static const std::string kIS_SYSTEM_KEY = "isSystem";
-static const std::string kIS_TEMPORARY_KEY = "isTemporary";
-static const std::string kKEY_KEY = "key";
-static const std::string kLANGUAGE_KEY = "language";
-static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage";
-static const std::string kLINK_FLAGS_KEY = "linkFlags";
-static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags";
-static const std::string kLINK_LIBRARIES_KEY = "linkLibraries";
-static const std::string kLINK_PATH_KEY = "linkPath";
-static const std::string kNAME_KEY = "name";
-static const std::string kPATH_KEY = "path";
-static const std::string kPROJECTS_KEY = "projects";
-static const std::string kPROPERTIES_KEY = "properties";
-static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
-static const std::string kSOURCES_KEY = "sources";
-static const std::string kSYSROOT_KEY = "sysroot";
-static const std::string kTARGETS_KEY = "targets";
-static const std::string kTYPE_KEY = "type";
-static const std::string kVALUE_KEY = "value";
-static const std::string kHAS_INSTALL_RULE = "hasInstallRule";
-static const std::string kINSTALL_PATHS = "installPaths";
-static const std::string kCTEST_NAME = "ctestName";
-static const std::string kCTEST_COMMAND = "ctestCommand";
-static const std::string kCTEST_INFO = "ctestInfo";
-static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion";
-static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided";
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
deleted file mode 100644
index 3a7ae0c..0000000
--- a/Source/cmJsonObjects.cxx
+++ /dev/null
@@ -1,692 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmJsonObjects.h" // IWYU pragma: keep
-
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <functional>
-#include <limits>
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include <cmext/algorithm>
-
-#include "cmGeneratorExpression.h"
-#include "cmGeneratorTarget.h"
-#include "cmGlobalGenerator.h"
-#include "cmInstallGenerator.h"
-#include "cmInstallSubdirectoryGenerator.h"
-#include "cmInstallTargetGenerator.h"
-#include "cmJsonObjectDictionary.h"
-#include "cmJsonObjects.h"
-#include "cmLinkLineComputer.h"
-#include "cmLocalGenerator.h"
-#include "cmMakefile.h"
-#include "cmProperty.h"
-#include "cmPropertyMap.h"
-#include "cmSourceFile.h"
-#include "cmState.h"
-#include "cmStateDirectory.h"
-#include "cmStateSnapshot.h"
-#include "cmStateTypes.h"
-#include "cmStringAlgorithms.h"
-#include "cmSystemTools.h"
-#include "cmTarget.h"
-#include "cmTest.h"
-#include "cmake.h"
-
-namespace {
-
-std::vector<std::string> getConfigurations(const cmake* cm)
-{
- std::vector<std::string> configurations;
- const auto& makefiles = cm->GetGlobalGenerator()->GetMakefiles();
- if (makefiles.empty()) {
- return configurations;
- }
-
- return makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
-}
-
-bool hasString(const Json::Value& v, const std::string& s)
-{
- return !v.isNull() &&
- std::any_of(v.begin(), v.end(),
- [s](const Json::Value& i) { return i.asString() == s; });
-}
-
-template <class T>
-Json::Value fromStringList(const T& in)
-{
- Json::Value result = Json::arrayValue;
- for (std::string const& i : in) {
- result.append(i);
- }
- return result;
-}
-
-} // namespace
-
-void cmGetCMakeInputs(const cmGlobalGenerator* gg,
- const std::string& sourceDir,
- const std::string& buildDir,
- std::vector<std::string>* internalFiles,
- std::vector<std::string>* explicitFiles,
- std::vector<std::string>* tmpFiles)
-{
- const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/';
- auto const& makefiles = gg->GetMakefiles();
- for (const auto& mf : makefiles) {
- for (std::string const& lf : mf->GetListFiles()) {
-
- const std::string startOfFile = lf.substr(0, cmakeRootDir.size());
- const bool isInternal = (startOfFile == cmakeRootDir);
- const bool isTemporary =
- !isInternal && (cmHasPrefix(lf, buildDir + '/'));
-
- std::string toAdd = lf;
- if (!sourceDir.empty()) {
- const std::string& relative =
- cmSystemTools::RelativePath(sourceDir, lf);
- if (toAdd.size() > relative.size()) {
- toAdd = relative;
- }
- }
-
- if (isInternal) {
- if (internalFiles) {
- internalFiles->push_back(std::move(toAdd));
- }
- } else {
- if (isTemporary) {
- if (tmpFiles) {
- tmpFiles->push_back(std::move(toAdd));
- }
- } else {
- if (explicitFiles) {
- explicitFiles->push_back(std::move(toAdd));
- }
- }
- }
- }
- }
-}
-
-Json::Value cmDumpCMakeInputs(const cmake* cm)
-{
- const cmGlobalGenerator* gg = cm->GetGlobalGenerator();
- const std::string& buildDir = cm->GetHomeOutputDirectory();
- const std::string& sourceDir = cm->GetHomeDirectory();
-
- std::vector<std::string> internalFiles;
- std::vector<std::string> explicitFiles;
- std::vector<std::string> tmpFiles;
- cmGetCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles,
- &tmpFiles);
-
- Json::Value array = Json::arrayValue;
-
- Json::Value tmp = Json::objectValue;
- tmp[kIS_CMAKE_KEY] = true;
- tmp[kIS_TEMPORARY_KEY] = false;
- tmp[kSOURCES_KEY] = fromStringList(internalFiles);
- array.append(tmp);
-
- tmp = Json::objectValue;
- tmp[kIS_CMAKE_KEY] = false;
- tmp[kIS_TEMPORARY_KEY] = false;
- tmp[kSOURCES_KEY] = fromStringList(explicitFiles);
- array.append(tmp);
-
- tmp = Json::objectValue;
- tmp[kIS_CMAKE_KEY] = false;
- tmp[kIS_TEMPORARY_KEY] = true;
- tmp[kSOURCES_KEY] = fromStringList(tmpFiles);
- array.append(tmp);
-
- return array;
-}
-
-class LanguageData
-{
-public:
- bool operator==(const LanguageData& other) const;
-
- void SetDefines(const std::set<std::string>& defines);
-
- bool IsGenerated = false;
- std::string Language;
- std::string Flags;
- std::vector<std::string> Defines;
- std::vector<std::pair<std::string, bool>> IncludePathList;
-};
-
-bool LanguageData::operator==(const LanguageData& other) const
-{
- return Language == other.Language && Defines == other.Defines &&
- Flags == other.Flags && IncludePathList == other.IncludePathList &&
- IsGenerated == other.IsGenerated;
-}
-
-void LanguageData::SetDefines(const std::set<std::string>& defines)
-{
- std::vector<std::string> result;
- result.reserve(defines.size());
- for (std::string const& i : defines) {
- result.push_back(i);
- }
- std::sort(result.begin(), result.end());
- Defines = std::move(result);
-}
-
-namespace std {
-
-template <>
-struct hash<LanguageData>
-{
- std::size_t operator()(const LanguageData& in) const
- {
- using std::hash;
- size_t result =
- hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags);
- for (auto const& i : in.IncludePathList) {
- result = result ^
- (hash<std::string>()(i.first) ^
- (i.second ? std::numeric_limits<size_t>::max() : 0));
- }
- for (auto const& i : in.Defines) {
- result = result ^ hash<std::string>()(i);
- }
- result =
- result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0);
- return result;
- }
-};
-
-} // namespace std
-
-static Json::Value DumpSourceFileGroup(const LanguageData& data,
- const std::vector<std::string>& files,
- const std::string& baseDir)
-{
- Json::Value result = Json::objectValue;
-
- if (!data.Language.empty()) {
- result[kLANGUAGE_KEY] = data.Language;
- if (!data.Flags.empty()) {
- result[kCOMPILE_FLAGS_KEY] = data.Flags;
- }
- if (!data.IncludePathList.empty()) {
- Json::Value includes = Json::arrayValue;
- for (auto const& i : data.IncludePathList) {
- Json::Value tmp = Json::objectValue;
- tmp[kPATH_KEY] = i.first;
- if (i.second) {
- tmp[kIS_SYSTEM_KEY] = i.second;
- }
- includes.append(tmp);
- }
- result[kINCLUDE_PATH_KEY] = includes;
- }
- if (!data.Defines.empty()) {
- result[kDEFINES_KEY] = fromStringList(data.Defines);
- }
- }
-
- result[kIS_GENERATED_KEY] = data.IsGenerated;
-
- Json::Value sourcesValue = Json::arrayValue;
- for (auto const& i : files) {
- const std::string relPath = cmSystemTools::RelativePath(baseDir, i);
- sourcesValue.append(relPath.size() < i.size() ? relPath : i);
- }
-
- result[kSOURCES_KEY] = sourcesValue;
- return result;
-}
-
-static Json::Value DumpSourceFilesList(
- cmGeneratorTarget* target, const std::string& config,
- const std::map<std::string, LanguageData>& languageDataMap)
-{
- // Collect sourcefile groups:
-
- std::vector<cmSourceFile*> files;
- target->GetSourceFiles(files, config);
-
- std::unordered_map<LanguageData, std::vector<std::string>> fileGroups;
- for (cmSourceFile* file : files) {
- LanguageData fileData;
- fileData.Language = file->GetOrDetermineLanguage();
- if (!fileData.Language.empty()) {
- const LanguageData& ld = languageDataMap.at(fileData.Language);
- cmLocalGenerator* lg = target->GetLocalGenerator();
- cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
- fileData.Language);
-
- std::string compileFlags = ld.Flags;
- const std::string COMPILE_FLAGS("COMPILE_FLAGS");
- if (cmProp cflags = file->GetProperty(COMPILE_FLAGS)) {
- lg->AppendFlags(compileFlags,
- genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS));
- }
- const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
- if (cmProp coptions = file->GetProperty(COMPILE_OPTIONS)) {
- lg->AppendCompileOptions(
- compileFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS));
- }
- fileData.Flags = compileFlags;
-
- // Add include directories from source file properties.
- std::vector<std::string> includes;
-
- const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
- if (cmProp cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) {
- const std::string& evaluatedIncludes =
- genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES);
- lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file);
-
- for (const auto& include : includes) {
- fileData.IncludePathList.emplace_back(
- include,
- target->IsSystemIncludeDirectory(include, config,
- fileData.Language));
- }
- }
-
- fileData.IncludePathList.insert(fileData.IncludePathList.end(),
- ld.IncludePathList.begin(),
- ld.IncludePathList.end());
-
- const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
- std::set<std::string> defines;
- if (cmProp defs = file->GetProperty(COMPILE_DEFINITIONS)) {
- lg->AppendDefines(
- defines, genexInterpreter.Evaluate(*defs, COMPILE_DEFINITIONS));
- }
-
- const std::string defPropName =
- "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
- if (cmProp config_defs = file->GetProperty(defPropName)) {
- lg->AppendDefines(
- defines,
- genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS));
- }
-
- defines.insert(ld.Defines.begin(), ld.Defines.end());
-
- fileData.SetDefines(defines);
- }
-
- fileData.IsGenerated = file->GetIsGenerated();
- std::vector<std::string>& groupFileList = fileGroups[fileData];
- groupFileList.push_back(file->ResolveFullPath());
- }
-
- const std::string& baseDir = target->Makefile->GetCurrentSourceDirectory();
- Json::Value result = Json::arrayValue;
- for (auto const& it : fileGroups) {
- Json::Value group = DumpSourceFileGroup(it.first, it.second, baseDir);
- if (!group.isNull()) {
- result.append(group);
- }
- }
-
- return result;
-}
-
-static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo,
- const std::string& config)
-{
- Json::Value result = Json::objectValue;
- result[kCTEST_NAME] = testInfo->GetName();
-
- // Concat command entries together. After the first should be the arguments
- // for the command
- std::string command;
- for (auto const& cmd : testInfo->GetCommand()) {
- command.append(cmd);
- command.append(" ");
- }
-
- // Remove any config specific variables from the output.
- result[kCTEST_COMMAND] =
- cmGeneratorExpression::Evaluate(command, lg, config);
-
- // Build up the list of properties that may have been specified
- Json::Value properties = Json::arrayValue;
- for (auto& prop : testInfo->GetProperties().GetList()) {
- Json::Value entry = Json::objectValue;
- entry[kKEY_KEY] = prop.first;
-
- // Remove config variables from the value too.
- entry[kVALUE_KEY] =
- cmGeneratorExpression::Evaluate(prop.second, lg, config);
- properties.append(entry);
- }
- result[kPROPERTIES_KEY] = properties;
-
- return result;
-}
-
-static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config,
- Json::Value* result)
-{
- auto mf = lg->GetMakefile();
- std::vector<cmTest*> tests;
- mf->GetTests(config, tests);
- for (auto test : tests) {
- Json::Value tmp = DumpCTestInfo(lg, test, config);
- if (!tmp.isNull()) {
- result->append(tmp);
- }
- }
-}
-
-static Json::Value DumpCTestProjectList(const cmake* cm,
- std::string const& config)
-{
- Json::Value result = Json::arrayValue;
-
- auto globalGen = cm->GetGlobalGenerator();
-
- for (const auto& projectIt : globalGen->GetProjectMap()) {
- Json::Value pObj = Json::objectValue;
- pObj[kNAME_KEY] = projectIt.first;
-
- Json::Value tests = Json::arrayValue;
-
- // Gather tests for every generator
- for (const auto& lg : projectIt.second) {
- // Make sure they're generated.
- lg->GenerateTestFiles();
- DumpMakefileTests(lg, config, &tests);
- }
-
- pObj[kCTEST_INFO] = tests;
-
- result.append(pObj);
- }
-
- return result;
-}
-
-static Json::Value DumpCTestConfiguration(const cmake* cm,
- const std::string& config)
-{
- Json::Value result = Json::objectValue;
- result[kNAME_KEY] = config;
-
- result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config);
-
- return result;
-}
-
-static Json::Value DumpCTestConfigurationsList(const cmake* cm)
-{
- Json::Value result = Json::arrayValue;
-
- for (const std::string& c : getConfigurations(cm)) {
- result.append(DumpCTestConfiguration(cm, c));
- }
-
- return result;
-}
-
-Json::Value cmDumpCTestInfo(const cmake* cm)
-{
- Json::Value result = Json::objectValue;
- result[kCONFIGURATIONS_KEY] = DumpCTestConfigurationsList(cm);
- return result;
-}
-
-static Json::Value DumpTarget(cmGeneratorTarget* target,
- const std::string& config)
-{
- cmLocalGenerator* lg = target->GetLocalGenerator();
-
- const cmStateEnums::TargetType type = target->GetType();
- const std::string typeName = cmState::GetTargetTypeName(type);
-
- Json::Value ttl = Json::arrayValue;
- ttl.append("EXECUTABLE");
- ttl.append("STATIC_LIBRARY");
- ttl.append("SHARED_LIBRARY");
- ttl.append("MODULE_LIBRARY");
- ttl.append("OBJECT_LIBRARY");
- ttl.append("UTILITY");
- ttl.append("INTERFACE_LIBRARY");
-
- if (!hasString(ttl, typeName) || target->IsImported()) {
- return Json::Value();
- }
-
- Json::Value result = Json::objectValue;
- result[kNAME_KEY] = target->GetName();
- result[kIS_GENERATOR_PROVIDED_KEY] =
- target->Target->GetIsGeneratorProvided();
- result[kTYPE_KEY] = typeName;
- result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory();
- result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory();
-
- if (type == cmStateEnums::INTERFACE_LIBRARY) {
- return result;
- }
-
- result[kFULL_NAME_KEY] = target->GetFullName(config);
-
- if (target->Target->GetHaveInstallRule()) {
- result[kHAS_INSTALL_RULE] = true;
-
- Json::Value installPaths = Json::arrayValue;
- for (const auto& installGenerator :
- target->Makefile->GetInstallGenerators()) {
- auto installTargetGenerator =
- dynamic_cast<cmInstallTargetGenerator*>(installGenerator.get());
- if (installTargetGenerator != nullptr &&
- installTargetGenerator->GetTarget()->Target == target->Target) {
- auto dest = installTargetGenerator->GetDestination(config);
-
- std::string installPath;
- if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) {
- installPath = dest;
- } else {
- installPath = cmStrCat(
- target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"), '/',
- dest);
- }
-
- installPaths.append(installPath);
- }
- }
-
- result[kINSTALL_PATHS] = installPaths;
- }
-
- if (target->HaveWellDefinedOutputFiles()) {
- Json::Value artifacts = Json::arrayValue;
- artifacts.append(
- target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact));
- if (target->HasImportLibrary(config)) {
- artifacts.append(
- target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
- }
- if (target->IsDLLPlatform()) {
- const cmGeneratorTarget::OutputInfo* output =
- target->GetOutputInfo(config);
- if (output && !output->PdbDir.empty()) {
- artifacts.append(output->PdbDir + '/' + target->GetPDBName(config));
- }
- }
- result[kARTIFACTS_KEY] = artifacts;
-
- result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config);
-
- std::string linkLibs;
- std::string linkFlags;
- std::string linkLanguageFlags;
- std::string frameworkPath;
- std::string linkPath;
- cmLinkLineComputer linkLineComputer(lg,
- lg->GetStateSnapshot().GetDirectory());
- lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags,
- linkFlags, frameworkPath, linkPath, target);
-
- linkLibs = cmTrimWhitespace(linkLibs);
- linkFlags = cmTrimWhitespace(linkFlags);
- linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags);
- frameworkPath = cmTrimWhitespace(frameworkPath);
- linkPath = cmTrimWhitespace(linkPath);
-
- if (!cmTrimWhitespace(linkLibs).empty()) {
- result[kLINK_LIBRARIES_KEY] = linkLibs;
- }
- if (!cmTrimWhitespace(linkFlags).empty()) {
- result[kLINK_FLAGS_KEY] = linkFlags;
- }
- if (!cmTrimWhitespace(linkLanguageFlags).empty()) {
- result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags;
- }
- if (!frameworkPath.empty()) {
- result[kFRAMEWORK_PATH_KEY] = frameworkPath;
- }
- if (!linkPath.empty()) {
- result[kLINK_PATH_KEY] = linkPath;
- }
- const std::string sysroot =
- lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT");
- if (!sysroot.empty()) {
- result[kSYSROOT_KEY] = sysroot;
- }
- }
-
- std::set<std::string> languages;
- target->GetLanguages(languages, config);
- std::map<std::string, LanguageData> languageDataMap;
-
- for (std::string const& lang : languages) {
- LanguageData& ld = languageDataMap[lang];
- ld.Language = lang;
- lg->GetTargetCompileFlags(target, config, lang, ld.Flags);
- std::set<std::string> defines;
- lg->GetTargetDefines(target, config, lang, defines);
- ld.SetDefines(defines);
- std::vector<std::string> includePathList;
- lg->GetIncludeDirectories(includePathList, target, lang, config);
- for (std::string const& i : includePathList) {
- ld.IncludePathList.emplace_back(
- i, target->IsSystemIncludeDirectory(i, config, lang));
- }
- }
-
- Json::Value sourceGroupsValue =
- DumpSourceFilesList(target, config, languageDataMap);
- if (!sourceGroupsValue.empty()) {
- result[kFILE_GROUPS_KEY] = sourceGroupsValue;
- }
-
- return result;
-}
-
-static Json::Value DumpTargetsList(
- const std::vector<cmLocalGenerator*>& generators, const std::string& config)
-{
- Json::Value result = Json::arrayValue;
-
- std::vector<cmGeneratorTarget*> targetList;
- for (auto const& lgIt : generators) {
- cm::append(targetList, lgIt->GetGeneratorTargets());
- }
- std::sort(targetList.begin(), targetList.end());
-
- for (cmGeneratorTarget* target : targetList) {
- Json::Value tmp = DumpTarget(target, config);
- if (!tmp.isNull()) {
- result.append(tmp);
- }
- }
-
- return result;
-}
-
-static Json::Value DumpProjectList(const cmake* cm, std::string const& config)
-{
- Json::Value result = Json::arrayValue;
-
- auto globalGen = cm->GetGlobalGenerator();
-
- for (auto const& projectIt : globalGen->GetProjectMap()) {
- Json::Value pObj = Json::objectValue;
- pObj[kNAME_KEY] = projectIt.first;
-
- // All Projects must have at least one local generator
- assert(!projectIt.second.empty());
- const cmLocalGenerator* lg = projectIt.second.at(0);
-
- // Project structure information:
- const cmMakefile* mf = lg->GetMakefile();
- auto minVersion = mf->GetSafeDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
- pObj[kMINIMUM_CMAKE_VERSION] = minVersion;
- pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory();
- pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory();
- pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config);
-
- // For a project-level install rule it might be defined in any of its
- // associated generators.
- bool hasInstallRule = false;
- for (const auto generator : projectIt.second) {
- for (const auto& installGen :
- generator->GetMakefile()->GetInstallGenerators()) {
- if (!dynamic_cast<cmInstallSubdirectoryGenerator*>(installGen.get())) {
- hasInstallRule = true;
- break;
- }
- }
-
- if (hasInstallRule) {
- break;
- }
- }
-
- pObj[kHAS_INSTALL_RULE] = hasInstallRule;
-
- result.append(pObj);
- }
-
- return result;
-}
-
-static Json::Value DumpConfiguration(const cmake* cm,
- const std::string& config)
-{
- Json::Value result = Json::objectValue;
- result[kNAME_KEY] = config;
-
- result[kPROJECTS_KEY] = DumpProjectList(cm, config);
-
- return result;
-}
-
-static Json::Value DumpConfigurationsList(const cmake* cm)
-{
- Json::Value result = Json::arrayValue;
-
- for (std::string const& c : getConfigurations(cm)) {
- result.append(DumpConfiguration(cm, c));
- }
-
- return result;
-}
-
-Json::Value cmDumpCodeModel(const cmake* cm)
-{
- Json::Value result = Json::objectValue;
- result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(cm);
- return result;
-}
diff --git a/Source/cmJsonObjects.h b/Source/cmJsonObjects.h
deleted file mode 100644
index 80a4834..0000000
--- a/Source/cmJsonObjects.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 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" // IWYU pragma: keep
-
-#include <string>
-#include <vector>
-
-#include <cm3p/json/value.h>
-
-class cmake;
-class cmGlobalGenerator;
-
-extern void cmGetCMakeInputs(const cmGlobalGenerator* gg,
- const std::string& sourceDir,
- const std::string& buildDir,
- std::vector<std::string>* internalFiles,
- std::vector<std::string>* explicitFiles,
- std::vector<std::string>* tmpFiles);
-
-extern Json::Value cmDumpCodeModel(const cmake* cm);
-extern Json::Value cmDumpCTestInfo(const cmake* cm);
-extern Json::Value cmDumpCMakeInputs(const cmake* cm);
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 4e6010c..b7ad78a 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -3918,10 +3918,35 @@ cmSourceFile* AddCustomCommand(
cc->SetJobPool(job_pool);
file->SetCustomCommand(std::move(cc));
- mf->AddSourceOutputs(file, outputs, byproducts);
+ lg.AddSourceOutputs(file, outputs, byproducts);
}
return file;
}
+
+bool AnyOutputMatches(const std::string& name,
+ const std::vector<std::string>& outputs)
+{
+ for (std::string const& output : outputs) {
+ std::string::size_type pos = output.rfind(name);
+ // If the output matches exactly
+ if (pos != std::string::npos && pos == output.size() - name.size() &&
+ (pos == 0 || output[pos - 1] == '/')) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AnyTargetCommandOutputMatches(
+ const std::string& name, const std::vector<cmCustomCommand>& commands)
+{
+ for (cmCustomCommand const& command : commands) {
+ if (AnyOutputMatches(name, command.GetByproducts())) {
+ return true;
+ }
+ }
+ return false;
+}
}
namespace detail {
@@ -3937,8 +3962,6 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
const std::string& job_pool,
bool command_expand_lists, bool stdPipesUTF8)
{
- cmMakefile* mf = lg.GetMakefile();
-
// Always create the byproduct sources and mark them generated.
CreateGeneratedSources(lg, byproducts, origin, lfbt);
@@ -3964,7 +3987,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg,
break;
}
- mf->AddTargetByproducts(target, byproducts);
+ lg.AddTargetByproducts(target, byproducts);
}
cmSourceFile* AddCustomCommandToOutput(
@@ -3996,7 +4019,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
const cmCustomCommandLines& commandLines)
{
// Lookup an existing command.
- if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) {
+ if (cmSourceFile* sf = lg.GetSourceFileWithOutput(output)) {
if (cmCustomCommand* cc = sf->GetCustomCommand()) {
cc->AppendCommands(commandLines);
cc->AppendDepends(depends);
@@ -4008,7 +4031,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
// No existing command found.
lg.GetCMakeInstance()->IssueMessage(
MessageType::FATAL_ERROR,
- cmStrCat("Attempt to append to output\n ", output,
+ cmStrCat("Attempt to APPEND to custom command with output\n ", output,
"\nwhich is not already a custom command output."),
lfbt);
}
@@ -4040,7 +4063,7 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
/*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists,
/*depfile=*/"", job_pool, stdPipesUTF8);
if (rule) {
- lg.GetMakefile()->AddTargetByproducts(target, byproducts);
+ lg.AddTargetByproducts(target, byproducts);
}
if (!force.NameCMP0049.empty()) {
@@ -4088,3 +4111,166 @@ std::vector<std::string> ComputeISPCExtraObjects(
return computedObjects;
}
}
+
+cmSourcesWithOutput cmLocalGenerator::GetSourcesWithOutput(
+ const std::string& name) const
+{
+ // Linear search? Also see GetSourceFileWithOutput for detail.
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ cmSourcesWithOutput sources;
+ sources.Target = this->LinearGetTargetWithOutput(name);
+ sources.Source = this->LinearGetSourceFileWithOutput(
+ name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
+ return sources;
+ }
+ // Otherwise we use an efficient lookup map.
+ auto o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end()) {
+ return o->second.Sources;
+ }
+ return {};
+}
+
+cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput(
+ const std::string& name, cmSourceOutputKind kind) const
+{
+ // If the queried path is not absolute we use the backward compatible
+ // linear-time search for an output with a matching suffix.
+ if (!cmSystemTools::FileIsFullPath(name)) {
+ bool byproduct = false;
+ return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
+ }
+ // Otherwise we use an efficient lookup map.
+ auto o = this->OutputToSource.find(name);
+ if (o != this->OutputToSource.end() &&
+ (!o->second.Sources.SourceIsByproduct ||
+ kind == cmSourceOutputKind::OutputOrByproduct)) {
+ // Source file could also be null pointer for example if we found the
+ // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
+ // command of a target, or a not yet created custom command.
+ return o->second.Sources.Source;
+ }
+ return nullptr;
+}
+
+void cmLocalGenerator::AddTargetByproducts(
+ cmTarget* target, const std::vector<std::string>& byproducts)
+{
+ for (std::string const& o : byproducts) {
+ this->UpdateOutputToSourceMap(o, target);
+ }
+}
+
+void cmLocalGenerator::AddSourceOutputs(
+ cmSourceFile* source, const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts)
+{
+ for (std::string const& o : outputs) {
+ this->UpdateOutputToSourceMap(o, source, false);
+ }
+ for (std::string const& o : byproducts) {
+ this->UpdateOutputToSourceMap(o, source, true);
+ }
+}
+
+void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct,
+ cmTarget* target)
+{
+ SourceEntry entry;
+ entry.Sources.Target = target;
+
+ auto pr = this->OutputToSource.emplace(byproduct, entry);
+ if (!pr.second) {
+ SourceEntry& current = pr.first->second;
+ // Has the target already been set?
+ if (!current.Sources.Target) {
+ current.Sources.Target = target;
+ } else {
+ // Multiple custom commands/targets produce the same output (source file
+ // or target). See also comment in other UpdateOutputToSourceMap
+ // overload.
+ //
+ // TODO: Warn the user about this case.
+ }
+ }
+}
+
+void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output,
+ cmSourceFile* source,
+ bool byproduct)
+{
+ SourceEntry entry;
+ entry.Sources.Source = source;
+ entry.Sources.SourceIsByproduct = byproduct;
+
+ auto pr = this->OutputToSource.emplace(output, entry);
+ if (!pr.second) {
+ SourceEntry& current = pr.first->second;
+ // Outputs take precedence over byproducts
+ if (!current.Sources.Source ||
+ (current.Sources.SourceIsByproduct && !byproduct)) {
+ current.Sources.Source = source;
+ current.Sources.SourceIsByproduct = false;
+ } else {
+ // Multiple custom commands produce the same output but may
+ // be attached to a different source file (MAIN_DEPENDENCY).
+ // LinearGetSourceFileWithOutput would return the first one,
+ // so keep the mapping for the first one.
+ //
+ // TODO: Warn the user about this case. However, the VS 8 generator
+ // triggers it for separate generate.stamp rules in ZERO_CHECK and
+ // individual targets.
+ }
+ }
+}
+
+cmTarget* cmLocalGenerator::LinearGetTargetWithOutput(
+ const std::string& name) const
+{
+ // We go through the ordered vector of targets to get reproducible results
+ // should multiple names match.
+ for (cmTarget* t : this->Makefile->GetOrderedTargets()) {
+ // Does the output of any command match the source file name?
+ if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
+ return t;
+ }
+ if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
+ return t;
+ }
+ if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
+ return t;
+ }
+ }
+ return nullptr;
+}
+
+cmSourceFile* cmLocalGenerator::LinearGetSourceFileWithOutput(
+ const std::string& name, cmSourceOutputKind kind, bool& byproduct) const
+{
+ // Outputs take precedence over byproducts.
+ byproduct = false;
+ cmSourceFile* fallback = nullptr;
+
+ // Look through all the source files that have custom commands and see if the
+ // custom command has the passed source file as an output.
+ for (const auto& src : this->Makefile->GetSourceFiles()) {
+ // Does this source file have a custom command?
+ if (src->GetCustomCommand()) {
+ // Does the output of the custom command match the source file name?
+ if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
+ // Return the first matching output.
+ return src.get();
+ }
+ if (kind == cmSourceOutputKind::OutputOrByproduct) {
+ if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
+ // Do not return the source yet as there might be a matching output.
+ fallback = src.get();
+ }
+ }
+ }
+ }
+
+ // Did we find a byproduct?
+ byproduct = fallback != nullptr;
+ return fallback;
+}
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 22d3599..162e70f 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -36,6 +36,24 @@ class cmState;
class cmTarget;
class cmake;
+/** Flag if byproducts shall also be considered. */
+enum class cmSourceOutputKind
+{
+ OutputOnly,
+ OutputOrByproduct
+};
+
+/** Target and source file which have a specific output. */
+struct cmSourcesWithOutput
+{
+ /** Target with byproduct. */
+ cmTarget* Target = nullptr;
+
+ /** Source file with output or byproduct. */
+ cmSourceFile* Source = nullptr;
+ bool SourceIsByproduct = false;
+};
+
/** \class cmLocalGenerator
* \brief Create required build files for a directory.
*
@@ -337,6 +355,34 @@ public:
bool command_expand_lists = false, const std::string& job_pool = "",
bool stdPipesUTF8 = false);
+ /**
+ * Add target byproducts.
+ */
+ void AddTargetByproducts(cmTarget* target,
+ const std::vector<std::string>& byproducts);
+
+ /**
+ * Add source file outputs.
+ */
+ void AddSourceOutputs(cmSourceFile* source,
+ const std::vector<std::string>& outputs,
+ const std::vector<std::string>& byproducts);
+
+ /**
+ * Return the target if the provided source name is a byproduct of a utility
+ * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
+ * Return the source file which has the provided source name as output.
+ */
+ cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
+
+ /**
+ * Is there a source file that has the provided source name as an output?
+ * If so then return it.
+ */
+ cmSourceFile* GetSourceFileWithOutput(
+ const std::string& name,
+ cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
+
std::string GetProjectName() const;
/** Compute the language used to compile the given source file. */
@@ -532,6 +578,33 @@ protected:
bool BackwardsCompatibilityFinal;
private:
+ /**
+ * See LinearGetSourceFileWithOutput for background information
+ */
+ cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
+
+ /**
+ * Generalized old version of GetSourceFileWithOutput kept for
+ * backward-compatibility. It implements a linear search and supports
+ * relative file paths. It is used as a fall back by GetSourceFileWithOutput
+ * and GetSourcesWithOutput.
+ */
+ cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
+ cmSourceOutputKind kind,
+ bool& byproduct) const;
+ struct SourceEntry
+ {
+ cmSourcesWithOutput Sources;
+ };
+
+ // A map for fast output to input look up.
+ using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
+ OutputToSourceMap OutputToSource;
+
+ void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target);
+ void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
+ bool byproduct);
+
void AddSharedFlags(std::string& flags, const std::string& lang,
bool shared);
bool GetShouldUseOldFlags(bool shared, const std::string& lang) const;
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index ad782ee..ce85320 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -22,7 +22,9 @@
#include "cmGlobalNinjaGenerator.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
+#include "cmMessageType.h"
#include "cmNinjaTargetGenerator.h"
+#include "cmPolicies.h"
#include "cmProperty.h"
#include "cmRulePlaceholderExpander.h"
#include "cmSourceFile.h"
@@ -573,7 +575,20 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
return;
}
- cmCustomCommandGenerator ccg(*cc, config, this);
+ bool transformDepfile = false;
+ auto cmp0116 = this->GetPolicyStatus(cmPolicies::CMP0116);
+ switch (cmp0116) {
+ case cmPolicies::OLD:
+ case cmPolicies::WARN:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ transformDepfile = true;
+ break;
+ }
+
+ cmCustomCommandGenerator ccg(*cc, config, this, transformDepfile);
const std::vector<std::string>& outputs = ccg.GetOutputs();
const std::vector<std::string>& byproducts = ccg.GetByproducts();
@@ -623,10 +638,36 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
+ std::string depfile = cc->GetDepfile();
+ if (!depfile.empty()) {
+ switch (cmp0116) {
+ case cmPolicies::WARN:
+ if (this->GetCurrentBinaryDirectory() !=
+ this->GetBinaryDirectory() ||
+ this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0116")) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0116),
+ cc->GetBacktrace());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ cmSystemTools::MakeDirectory(
+ cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles/d"));
+ depfile = ccg.GetInternalDepfile();
+ break;
+ }
+ }
+
gg->WriteCustomCommandBuild(
this->BuildCommandLine(cmdLines, customStep),
this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
- cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(),
+ depfile, cc->GetJobPool(), cc->GetUsesTerminal(),
/*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, config,
ninjaDeps, orderOnlyDeps);
}
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 0e4f888..22594bd 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -939,8 +939,6 @@ void cmMakefile::DoGenerate(cmLocalGenerator& lg)
action.Value(lg, action.Backtrace);
}
this->GeneratorActionsInvoked = true;
- this->DelayedOutputFiles.clear();
- this->DelayedOutputFilesHaveGenex = false;
// go through all configured files and see which ones still exist.
// we don't want cmake to re-run if a configured file is created and deleted
@@ -1104,7 +1102,7 @@ cmTarget* cmMakefile::AddCustomCommandToTarget(
}
// Always create the byproduct sources and mark them generated.
- this->CreateGeneratedByproducts(byproducts);
+ this->CreateGeneratedOutputs(byproducts);
// Strings could be moved into the callback function with C++14.
cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -1163,7 +1161,7 @@ void cmMakefile::AddCustomCommandToOutput(
// Always create the output sources and mark them generated.
this->CreateGeneratedOutputs(outputs);
- this->CreateGeneratedByproducts(byproducts);
+ this->CreateGeneratedOutputs(byproducts);
// Strings could be moved into the callback function with C++14.
cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -1247,16 +1245,11 @@ void cmMakefile::AddCustomCommandOldStyle(
}
}
-bool cmMakefile::AppendCustomCommandToOutput(
+void cmMakefile::AppendCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const cmImplicitDependsList& implicit_depends,
const cmCustomCommandLines& commandLines)
{
- // Check as good as we can if there will be a command for this output.
- if (!this->MightHaveCustomCommand(output)) {
- return false;
- }
-
// Validate custom commands.
if (this->ValidateCustomCommand(commandLines)) {
// Dispatch command creation to allow generator expressions in outputs.
@@ -1267,8 +1260,6 @@ bool cmMakefile::AppendCustomCommandToOutput(
implicit_depends, commandLines);
});
}
-
- return true;
}
cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
@@ -1313,7 +1304,7 @@ cmTarget* cmMakefile::AddUtilityCommand(
this->GetOrCreateGeneratedSource(force.Name);
// Always create the byproduct sources and mark them generated.
- this->CreateGeneratedByproducts(byproducts);
+ this->CreateGeneratedOutputs(byproducts);
// Strings could be moved into the callback function with C++14.
cm::optional<std::string> commentStr = MakeOptionalString(comment);
@@ -2154,213 +2145,6 @@ cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName,
}
namespace {
-bool AnyOutputMatches(const std::string& name,
- const std::vector<std::string>& outputs)
-{
- for (std::string const& output : outputs) {
- std::string::size_type pos = output.rfind(name);
- // If the output matches exactly
- if (pos != std::string::npos && pos == output.size() - name.size() &&
- (pos == 0 || output[pos - 1] == '/')) {
- return true;
- }
- }
- return false;
-}
-
-bool AnyTargetCommandOutputMatches(
- const std::string& name, const std::vector<cmCustomCommand>& commands)
-{
- for (cmCustomCommand const& command : commands) {
- if (AnyOutputMatches(name, command.GetByproducts())) {
- return true;
- }
- }
- return false;
-}
-}
-
-cmTarget* cmMakefile::LinearGetTargetWithOutput(const std::string& name) const
-{
- // We go through the ordered vector of targets to get reproducible results
- // should multiple names match.
- for (cmTarget* t : this->OrderedTargets) {
- // Does the output of any command match the source file name?
- if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) {
- return t;
- }
- if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) {
- return t;
- }
- if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) {
- return t;
- }
- }
- return nullptr;
-}
-
-cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput(
- const std::string& name, cmSourceOutputKind kind, bool& byproduct) const
-{
- // Outputs take precedence over byproducts.
- byproduct = false;
- cmSourceFile* fallback = nullptr;
-
- // Look through all the source files that have custom commands and see if the
- // custom command has the passed source file as an output.
- for (const auto& src : this->SourceFiles) {
- // Does this source file have a custom command?
- if (src->GetCustomCommand()) {
- // Does the output of the custom command match the source file name?
- if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) {
- // Return the first matching output.
- return src.get();
- }
- if (kind == cmSourceOutputKind::OutputOrByproduct) {
- if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) {
- // Do not return the source yet as there might be a matching output.
- fallback = src.get();
- }
- }
- }
- }
-
- // Did we find a byproduct?
- byproduct = fallback != nullptr;
- return fallback;
-}
-
-cmSourcesWithOutput cmMakefile::GetSourcesWithOutput(
- const std::string& name) const
-{
- // Linear search? Also see GetSourceFileWithOutput for detail.
- if (!cmSystemTools::FileIsFullPath(name)) {
- cmSourcesWithOutput sources;
- sources.Target = this->LinearGetTargetWithOutput(name);
- sources.Source = this->LinearGetSourceFileWithOutput(
- name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct);
- return sources;
- }
- // Otherwise we use an efficient lookup map.
- auto o = this->OutputToSource.find(name);
- if (o != this->OutputToSource.end()) {
- return o->second.Sources;
- }
- return {};
-}
-
-cmSourceFile* cmMakefile::GetSourceFileWithOutput(
- const std::string& name, cmSourceOutputKind kind) const
-{
- // If the queried path is not absolute we use the backward compatible
- // linear-time search for an output with a matching suffix.
- if (!cmSystemTools::FileIsFullPath(name)) {
- bool byproduct = false;
- return this->LinearGetSourceFileWithOutput(name, kind, byproduct);
- }
- // Otherwise we use an efficient lookup map.
- auto o = this->OutputToSource.find(name);
- if (o != this->OutputToSource.end() &&
- (!o->second.Sources.SourceIsByproduct ||
- kind == cmSourceOutputKind::OutputOrByproduct)) {
- // Source file could also be null pointer for example if we found the
- // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD
- // command of a target, or a not yet created custom command.
- return o->second.Sources.Source;
- }
- return nullptr;
-}
-
-bool cmMakefile::MightHaveCustomCommand(const std::string& name) const
-{
- if (this->DelayedOutputFilesHaveGenex ||
- cmGeneratorExpression::Find(name) != std::string::npos) {
- // Could be more restrictive, but for now we assume that there could always
- // be a match when generator expressions are involved.
- return true;
- }
- // Also see LinearGetSourceFileWithOutput.
- if (!cmSystemTools::FileIsFullPath(name)) {
- return AnyOutputMatches(name, this->DelayedOutputFiles);
- }
- // Otherwise we use an efficient lookup map.
- auto o = this->OutputToSource.find(name);
- if (o != this->OutputToSource.end()) {
- return o->second.SourceMightBeOutput;
- }
- return false;
-}
-
-void cmMakefile::AddTargetByproducts(
- cmTarget* target, const std::vector<std::string>& byproducts)
-{
- for (std::string const& o : byproducts) {
- this->UpdateOutputToSourceMap(o, target);
- }
-}
-
-void cmMakefile::AddSourceOutputs(cmSourceFile* source,
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& byproducts)
-{
- for (std::string const& o : outputs) {
- this->UpdateOutputToSourceMap(o, source, false);
- }
- for (std::string const& o : byproducts) {
- this->UpdateOutputToSourceMap(o, source, true);
- }
-}
-
-void cmMakefile::UpdateOutputToSourceMap(std::string const& byproduct,
- cmTarget* target)
-{
- SourceEntry entry;
- entry.Sources.Target = target;
-
- auto pr = this->OutputToSource.emplace(byproduct, entry);
- if (!pr.second) {
- SourceEntry& current = pr.first->second;
- // Has the target already been set?
- if (!current.Sources.Target) {
- current.Sources.Target = target;
- } else {
- // Multiple custom commands/targets produce the same output (source file
- // or target). See also comment in other UpdateOutputToSourceMap
- // overload.
- //
- // TODO: Warn the user about this case.
- }
- }
-}
-
-void cmMakefile::UpdateOutputToSourceMap(std::string const& output,
- cmSourceFile* source, bool byproduct)
-{
- SourceEntry entry;
- entry.Sources.Source = source;
- entry.Sources.SourceIsByproduct = byproduct;
- entry.SourceMightBeOutput = !byproduct;
-
- auto pr = this->OutputToSource.emplace(output, entry);
- if (!pr.second) {
- SourceEntry& current = pr.first->second;
- // Outputs take precedence over byproducts
- if (!current.Sources.Source ||
- (current.Sources.SourceIsByproduct && !byproduct)) {
- current.Sources.Source = source;
- current.Sources.SourceIsByproduct = false;
- current.SourceMightBeOutput = true;
- } else {
- // Multiple custom commands produce the same output but may
- // be attached to a different source file (MAIN_DEPENDENCY).
- // LinearGetSourceFileWithOutput would return the first one,
- // so keep the mapping for the first one.
- //
- // TODO: Warn the user about this case. However, the VS 8 generator
- // triggers it for separate generate.stamp rules in ZERO_CHECK and
- // individual targets.
- }
- }
}
#if !defined(CMAKE_BOOTSTRAP)
@@ -3675,38 +3459,10 @@ void cmMakefile::CreateGeneratedOutputs(
for (std::string const& o : outputs) {
if (cmGeneratorExpression::Find(o) == std::string::npos) {
this->GetOrCreateGeneratedSource(o);
- this->AddDelayedOutput(o);
- } else {
- this->DelayedOutputFilesHaveGenex = true;
}
}
}
-void cmMakefile::CreateGeneratedByproducts(
- const std::vector<std::string>& byproducts)
-{
- for (std::string const& o : byproducts) {
- if (cmGeneratorExpression::Find(o) == std::string::npos) {
- this->GetOrCreateGeneratedSource(o);
- }
- }
-}
-
-void cmMakefile::AddDelayedOutput(std::string const& output)
-{
- // Note that this vector might contain the output names in a different order
- // than in source file iteration order.
- this->DelayedOutputFiles.push_back(output);
-
- SourceEntry entry;
- entry.SourceMightBeOutput = true;
-
- auto pr = this->OutputToSource.emplace(output, entry);
- if (!pr.second) {
- pr.first->second.SourceMightBeOutput = true;
- }
-}
-
void cmMakefile::AddTargetObject(std::string const& tgtName,
std::string const& objFile)
{
@@ -4670,7 +4426,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
// Deprecate old policies, especially those that require a lot
// of code to maintain the old behavior.
- if (status == cmPolicies::OLD && id <= cmPolicies::CMP0072 &&
+ if (status == cmPolicies::OLD && id <= cmPolicies::CMP0075 &&
!(this->GetCMakeInstance()->GetIsInTryCompile() &&
(
// Policies set by cmCoreTryCompile::TryCompileCode.
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index c7940fb..ecc6aab 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -59,24 +59,6 @@ class cmTestGenerator;
class cmVariableWatch;
class cmake;
-/** Flag if byproducts shall also be considered. */
-enum class cmSourceOutputKind
-{
- OutputOnly,
- OutputOrByproduct
-};
-
-/** Target and source file which have a specific output. */
-struct cmSourcesWithOutput
-{
- /** Target with byproduct. */
- cmTarget* Target = nullptr;
-
- /** Source file with output or byproduct. */
- cmSourceFile* Source = nullptr;
- bool SourceIsByproduct = false;
-};
-
/** A type-safe wrapper for a string representing a directory id. */
class cmDirectoryId
{
@@ -225,25 +207,12 @@ public:
const std::string& source,
const cmCustomCommandLines& commandLines,
const char* comment);
- bool AppendCustomCommandToOutput(
+ void AppendCustomCommandToOutput(
const std::string& output, const std::vector<std::string>& depends,
const cmImplicitDependsList& implicit_depends,
const cmCustomCommandLines& commandLines);
/**
- * Add target byproducts.
- */
- void AddTargetByproducts(cmTarget* target,
- const std::vector<std::string>& byproducts);
-
- /**
- * Add source file outputs.
- */
- void AddSourceOutputs(cmSourceFile* source,
- const std::vector<std::string>& outputs,
- const std::vector<std::string>& byproducts);
-
- /**
* Add a define flag to the build.
*/
void AddDefineFlag(std::string const& definition);
@@ -753,20 +722,10 @@ public:
return this->SourceFiles;
}
- /**
- * Return the target if the provided source name is a byproduct of a utility
- * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command.
- * Return the source file which has the provided source name as output.
- */
- cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const;
-
- /**
- * Is there a source file that has the provided source name as an output?
- * If so then return it.
- */
- cmSourceFile* GetSourceFileWithOutput(
- const std::string& name,
- cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const;
+ std::vector<cmTarget*> const& GetOrderedTargets() const
+ {
+ return this->OrderedTargets;
+ }
//! Add a new cmTest to the list of tests for this makefile.
cmTest* CreateTest(const std::string& testName);
@@ -983,8 +942,7 @@ protected:
mutable cmTargetMap Targets;
std::map<std::string, std::string> AliasTargets;
- using TargetsVec = std::vector<cmTarget*>;
- TargetsVec OrderedTargets;
+ std::vector<cmTarget*> OrderedTargets;
std::vector<std::unique_ptr<cmSourceFile>> SourceFiles;
@@ -1129,48 +1087,9 @@ private:
bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const;
void CreateGeneratedOutputs(const std::vector<std::string>& outputs);
- void CreateGeneratedByproducts(const std::vector<std::string>& byproducts);
std::vector<BT<GeneratorAction>> GeneratorActions;
bool GeneratorActionsInvoked = false;
- bool DelayedOutputFilesHaveGenex = false;
- std::vector<std::string> DelayedOutputFiles;
-
- void AddDelayedOutput(std::string const& output);
-
- /**
- * See LinearGetSourceFileWithOutput for background information
- */
- cmTarget* LinearGetTargetWithOutput(const std::string& name) const;
-
- /**
- * Generalized old version of GetSourceFileWithOutput kept for
- * backward-compatibility. It implements a linear search and supports
- * relative file paths. It is used as a fall back by GetSourceFileWithOutput
- * and GetSourcesWithOutput.
- */
- cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name,
- cmSourceOutputKind kind,
- bool& byproduct) const;
-
- struct SourceEntry
- {
- cmSourcesWithOutput Sources;
- bool SourceMightBeOutput = false;
- };
-
- // A map for fast output to input look up.
- using OutputToSourceMap = std::unordered_map<std::string, SourceEntry>;
- OutputToSourceMap OutputToSource;
-
- void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target);
- void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source,
- bool byproduct);
-
- /**
- * Return if the provided source file might have a custom command.
- */
- bool MightHaveCustomCommand(const std::string& name) const;
bool CheckSystemVars;
bool CheckCMP0000;
diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx
deleted file mode 100644
index 1eede13..0000000
--- a/Source/cmPipeConnection.cxx
+++ /dev/null
@@ -1,71 +0,0 @@
-/* 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 <utility>
-
-#include "cmServer.h"
-
-cmPipeConnection::cmPipeConnection(std::string name,
- cmConnectionBufferStrategy* bufferStrategy)
- : cmEventBasedConnection(bufferStrategy)
- , PipeName(std::move(name))
-{
-}
-
-void cmPipeConnection::Connect(uv_stream_t* server)
-{
- if (this->WriteStream.get()) {
- // Accept and close all pipes but the first:
- cm::uv_pipe_ptr rejectPipe;
-
- rejectPipe.init(*this->Server->GetLoop(), 0);
- uv_accept(server, rejectPipe);
-
- return;
- }
-
- cm::uv_pipe_ptr ClientPipe;
- ClientPipe.init(*this->Server->GetLoop(), 0,
- static_cast<cmEventBasedConnection*>(this));
-
- if (uv_accept(server, ClientPipe) != 0) {
- return;
- }
-
- uv_read_start(ClientPipe, on_alloc_buffer, on_read);
- WriteStream = std::move(ClientPipe);
- Server->OnConnected(this);
-}
-
-bool cmPipeConnection::OnServeStart(std::string* errorMessage)
-{
- this->ServerPipe.init(*this->Server->GetLoop(), 0,
- 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;
- }
-
- if ((r = uv_listen(this->ServerPipe, 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->WriteStream.get()) {
- this->WriteStream->data = nullptr;
- }
-
- this->ServerPipe.reset();
-
- return cmEventBasedConnection::OnConnectionShuttingDown();
-}
diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h
deleted file mode 100644
index 1215716..0000000
--- a/Source/cmPipeConnection.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* 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" // IWYU pragma: keep
-
-#include <string>
-
-#include <cm3p/uv.h>
-
-#include "cmConnection.h"
-#include "cmUVHandlePtr.h"
-
-class cmPipeConnection : public cmEventBasedConnection
-{
-public:
- cmPipeConnection(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;
- cm::uv_pipe_ptr ServerPipe;
-};
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index 18ce9c3..5ef0ff7 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -340,7 +340,12 @@ class cmMakefile;
3, 19, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0114, \
"ExternalProject step targets fully adopt their steps.", 3, 19, 0, \
- cmPolicies::WARN)
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0115, "Source file extensions must be explicit.", 3, 20, \
+ 0, cmPolicies::WARN) \
+ SELECT(POLICY, CMP0116, \
+ "Ninja generators transform DEPFILEs from add_custom_command().", 3, \
+ 20, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx
index 9cb172b..b27bb88 100644
--- a/Source/cmQtAutoMocUic.cxx
+++ b/Source/cmQtAutoMocUic.cxx
@@ -15,6 +15,7 @@
#include <vector>
#include <cm/memory>
+#include <cm/optional>
#include <cm/string_view>
#include <cmext/algorithm>
@@ -26,7 +27,6 @@
#include "cmCryptoHash.h"
#include "cmFileTime.h"
#include "cmGccDepfileReader.h"
-#include "cmGccDepfileReaderTypes.h"
#include "cmGeneratedFileStream.h"
#include "cmQtAutoGen.h"
#include "cmQtAutoGenerator.h"
@@ -2841,14 +2841,14 @@ bool cmQtAutoMocUicT::CreateDirectories()
std::vector<std::string> cmQtAutoMocUicT::dependenciesFromDepFile(
const char* filePath)
{
- cmGccDepfileContent content = cmReadGccDepfile(filePath);
- if (content.empty()) {
+ auto const content = cmReadGccDepfile(filePath);
+ if (!content || content->empty()) {
return {};
}
// Moc outputs a depfile with exactly one rule.
// Discard the rule and return the dependencies.
- return content.front().paths;
+ return content->front().paths;
}
void cmQtAutoMocUicT::Abort(bool error)
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
deleted file mode 100644
index 7f97406..0000000
--- a/Source/cmServer.cxx
+++ /dev/null
@@ -1,570 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmServer.h"
-
-#include <algorithm>
-#include <cassert>
-#include <csignal>
-#include <cstdint>
-#include <iostream>
-#include <mutex>
-#include <utility>
-
-#include <cm/memory>
-#include <cm/shared_mutex>
-
-#include <cm3p/json/reader.h>
-#include <cm3p/json/writer.h>
-
-#include "cmsys/FStream.hxx"
-
-#include "cmConnection.h"
-#include "cmFileMonitor.h"
-#include "cmJsonObjectDictionary.h"
-#include "cmServerDictionary.h"
-#include "cmServerProtocol.h"
-#include "cmSystemTools.h"
-#include "cmake.h"
-
-void on_signal(uv_signal_t* signal, int signum)
-{
- auto conn = static_cast<cmServerBase*>(signal->data);
- conn->OnSignal(signum);
-}
-
-static void on_walk_to_shutdown(uv_handle_t* handle, void* arg)
-{
- (void)arg;
- assert(uv_is_closing(handle));
- if (!uv_is_closing(handle)) {
- uv_close(handle, &cmEventBasedConnection::on_close);
- }
-}
-
-class cmServer::DebugInfo
-{
-public:
- DebugInfo()
- : StartTime(uv_hrtime())
- {
- }
-
- bool PrintStatistics = false;
-
- std::string OutputFile;
- uint64_t StartTime;
-};
-
-cmServer::cmServer(cmConnection* conn, bool supportExperimental)
- : cmServerBase(conn)
- , SupportExperimental(supportExperimental)
-{
- // Register supported protocols:
- this->RegisterProtocol(cm::make_unique<cmServerProtocol1>());
-}
-
-cmServer::~cmServer()
-{
- Close();
-}
-
-void cmServer::ProcessRequest(cmConnection* connection,
- const std::string& input)
-{
- Json::Reader reader;
- Json::Value value;
- if (!reader.parse(input, value)) {
- this->WriteParseError(connection, "Failed to parse JSON input.");
- return;
- }
-
- std::unique_ptr<DebugInfo> debug;
- Json::Value debugValue = value["debug"];
- if (!debugValue.isNull()) {
- debug = cm::make_unique<DebugInfo>();
- debug->OutputFile = debugValue["dumpToFile"].asString();
- debug->PrintStatistics = debugValue["showStats"].asBool();
- }
-
- const cmServerRequest request(this, connection, value[kTYPE_KEY].asString(),
- value[kCOOKIE_KEY].asString(), value);
-
- if (request.Type.empty()) {
- cmServerResponse response(request);
- response.SetError("No type given in request.");
- this->WriteResponse(connection, response, nullptr);
- return;
- }
-
- cmSystemTools::SetMessageCallback(
- [&request](const std::string& msg, const char* title) {
- reportMessage(msg, title, request);
- });
-
- if (this->Protocol) {
- this->Protocol->CMakeInstance()->SetProgressCallback(
- [&request](const std::string& msg, float prog) {
- reportProgress(msg, prog, request);
- });
- this->WriteResponse(connection, this->Protocol->Process(request),
- debug.get());
- } else {
- this->WriteResponse(connection, this->SetProtocolVersion(request),
- debug.get());
- }
-}
-
-void cmServer::RegisterProtocol(std::unique_ptr<cmServerProtocol> protocol)
-{
- if (protocol->IsExperimental() && !this->SupportExperimental) {
- protocol.reset();
- return;
- }
- auto version = protocol->ProtocolVersion();
- assert(version.first >= 0);
- assert(version.second >= 0);
- auto it = std::find_if(
- this->SupportedProtocols.begin(), this->SupportedProtocols.end(),
- [version](const std::unique_ptr<cmServerProtocol>& p) {
- return p->ProtocolVersion() == version;
- });
- if (it == this->SupportedProtocols.end()) {
- this->SupportedProtocols.push_back(std::move(protocol));
- }
-}
-
-void cmServer::PrintHello(cmConnection* connection) const
-{
- Json::Value hello = Json::objectValue;
- hello[kTYPE_KEY] = "hello";
-
- Json::Value& protocolVersions = hello[kSUPPORTED_PROTOCOL_VERSIONS] =
- Json::arrayValue;
-
- for (auto const& proto : this->SupportedProtocols) {
- auto version = proto->ProtocolVersion();
- Json::Value tmp = Json::objectValue;
- tmp[kMAJOR_KEY] = version.first;
- tmp[kMINOR_KEY] = version.second;
- if (proto->IsExperimental()) {
- tmp[kIS_EXPERIMENTAL_KEY] = true;
- }
- protocolVersions.append(tmp);
- }
-
- this->WriteJsonObject(connection, hello, nullptr);
-}
-
-void cmServer::reportProgress(const std::string& msg, float progress,
- const cmServerRequest& request)
-{
- if (progress < 0.0f || progress > 1.0f) {
- request.ReportMessage(msg, "");
- } else {
- request.ReportProgress(0, static_cast<int>(progress * 1000), 1000, msg);
- }
-}
-
-void cmServer::reportMessage(const std::string& msg, const char* title,
- const cmServerRequest& request)
-{
- std::string titleString;
- if (title) {
- titleString = title;
- }
- request.ReportMessage(msg, titleString);
-}
-
-cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request)
-{
- if (request.Type != kHANDSHAKE_TYPE) {
- return request.ReportError("Waiting for type \"" + kHANDSHAKE_TYPE +
- "\".");
- }
-
- Json::Value requestedProtocolVersion = request.Data[kPROTOCOL_VERSION_KEY];
- if (requestedProtocolVersion.isNull()) {
- return request.ReportError("\"" + kPROTOCOL_VERSION_KEY +
- "\" is required for \"" + kHANDSHAKE_TYPE +
- "\".");
- }
-
- if (!requestedProtocolVersion.isObject()) {
- return request.ReportError("\"" + kPROTOCOL_VERSION_KEY +
- "\" must be a JSON object.");
- }
-
- Json::Value majorValue = requestedProtocolVersion[kMAJOR_KEY];
- if (!majorValue.isInt()) {
- return request.ReportError("\"" + kMAJOR_KEY +
- "\" must be set and an integer.");
- }
-
- Json::Value minorValue = requestedProtocolVersion[kMINOR_KEY];
- if (!minorValue.isNull() && !minorValue.isInt()) {
- return request.ReportError("\"" + kMINOR_KEY +
- "\" must be unset or an integer.");
- }
-
- const int major = majorValue.asInt();
- const int minor = minorValue.isNull() ? -1 : minorValue.asInt();
- if (major < 0) {
- return request.ReportError("\"" + kMAJOR_KEY + "\" must be >= 0.");
- }
- if (!minorValue.isNull() && minor < 0) {
- return request.ReportError("\"" + kMINOR_KEY +
- "\" must be >= 0 when set.");
- }
-
- this->Protocol =
- cmServer::FindMatchingProtocol(this->SupportedProtocols, major, minor);
- if (!this->Protocol) {
- return request.ReportError("Protocol version not supported.");
- }
-
- std::string errorMessage;
- if (!this->Protocol->Activate(this, request, &errorMessage)) {
- this->Protocol = nullptr;
- return request.ReportError("Failed to activate protocol version: " +
- errorMessage);
- }
- return request.Reply(Json::objectValue);
-}
-
-bool cmServer::Serve(std::string* errorMessage)
-{
- if (this->SupportedProtocols.empty()) {
- *errorMessage =
- "No protocol versions defined. Maybe you need --experimental?";
- return false;
- }
- assert(!this->Protocol);
-
- return cmServerBase::Serve(errorMessage);
-}
-
-cmFileMonitor* cmServer::FileMonitor() const
-{
- return fileMonitor.get();
-}
-
-void cmServer::WriteJsonObject(const Json::Value& jsonValue,
- const DebugInfo* debug) const
-{
- cm::shared_lock<cm::shared_mutex> lock(ConnectionsMutex);
- 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();
- std::string result = writer.write(jsonValue);
-
- if (debug) {
- Json::Value copy = jsonValue;
- if (debug->PrintStatistics) {
- Json::Value stats = Json::objectValue;
- auto endTime = uv_hrtime();
-
- stats["jsonSerialization"] = double(endTime - beforeJson) / 1000000.0;
- stats["totalTime"] = double(endTime - debug->StartTime) / 1000000.0;
- stats["size"] = static_cast<int>(result.size());
- if (!debug->OutputFile.empty()) {
- stats["dumpFile"] = debug->OutputFile;
- }
-
- copy["zzzDebug"] = stats;
-
- result = writer.write(copy); // Update result to include debug info
- }
-
- if (!debug->OutputFile.empty()) {
- cmsys::ofstream myfile(debug->OutputFile.c_str());
- myfile << result;
- }
- }
-
- connection->WriteData(result);
-}
-
-cmServerProtocol* cmServer::FindMatchingProtocol(
- const std::vector<std::unique_ptr<cmServerProtocol>>& protocols, int major,
- int minor)
-{
- cmServerProtocol* bestMatch = nullptr;
- for (const auto& protocol : protocols) {
- auto version = protocol->ProtocolVersion();
- if (major != version.first) {
- continue;
- }
- if (minor == version.second) {
- return protocol.get();
- }
- if (!bestMatch || bestMatch->ProtocolVersion().second < version.second) {
- bestMatch = protocol.get();
- }
- }
- return minor < 0 ? bestMatch : nullptr;
-}
-
-void cmServer::WriteProgress(const cmServerRequest& request, int min,
- int current, int max,
- const std::string& message) const
-{
- assert(min <= current && current <= max);
- assert(message.length() != 0);
-
- Json::Value obj = Json::objectValue;
- obj[kTYPE_KEY] = kPROGRESS_TYPE;
- obj[kREPLY_TO_KEY] = request.Type;
- obj[kCOOKIE_KEY] = request.Cookie;
- obj[kPROGRESS_MESSAGE_KEY] = message;
- obj[kPROGRESS_MINIMUM_KEY] = min;
- obj[kPROGRESS_MAXIMUM_KEY] = max;
- obj[kPROGRESS_CURRENT_KEY] = current;
-
- this->WriteJsonObject(request.Connection, obj, nullptr);
-}
-
-void cmServer::WriteMessage(const cmServerRequest& request,
- const std::string& message,
- const std::string& title) const
-{
- if (message.empty()) {
- return;
- }
-
- Json::Value obj = Json::objectValue;
- obj[kTYPE_KEY] = kMESSAGE_TYPE;
- obj[kREPLY_TO_KEY] = request.Type;
- obj[kCOOKIE_KEY] = request.Cookie;
- obj[kMESSAGE_KEY] = message;
- if (!title.empty()) {
- obj[kTITLE_KEY] = title;
- }
-
- WriteJsonObject(request.Connection, obj, nullptr);
-}
-
-void cmServer::WriteParseError(cmConnection* connection,
- const std::string& message) const
-{
- Json::Value obj = Json::objectValue;
- obj[kTYPE_KEY] = kERROR_TYPE;
- obj[kERROR_MESSAGE_KEY] = message;
- obj[kREPLY_TO_KEY] = "";
- obj[kCOOKIE_KEY] = "";
-
- this->WriteJsonObject(connection, obj, nullptr);
-}
-
-void cmServer::WriteSignal(const std::string& name,
- const Json::Value& data) const
-{
- assert(data.isObject());
- Json::Value obj = data;
- obj[kTYPE_KEY] = kSIGNAL_TYPE;
- obj[kREPLY_TO_KEY] = "";
- obj[kCOOKIE_KEY] = "";
- obj[kNAME_KEY] = name;
-
- WriteJsonObject(obj, nullptr);
-}
-
-void cmServer::WriteResponse(cmConnection* connection,
- const cmServerResponse& response,
- const DebugInfo* debug) const
-{
- assert(response.IsComplete());
-
- Json::Value obj = response.Data();
- obj[kCOOKIE_KEY] = response.Cookie;
- obj[kTYPE_KEY] = response.IsError() ? kERROR_TYPE : kREPLY_TYPE;
- obj[kREPLY_TO_KEY] = response.Type;
- if (response.IsError()) {
- obj[kERROR_MESSAGE_KEY] = response.ErrorMessage();
- }
-
- 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 = static_cast<cmServerBase*>(arg);
- std::string error;
- bool success = server->Serve(&error);
- if (!success || !error.empty()) {
- std::cerr << "Error during serve: " << error << std::endl;
- }
-}
-
-bool cmServerBase::StartServeThread()
-{
- ServeThreadRunning = true;
- uv_thread_create(&ServeThread, __start_thread, this);
- return true;
-}
-
-static void __shutdownThread(uv_async_t* arg)
-{
- auto server = static_cast<cmServerBase*>(arg->data);
- server->StartShutDown();
-}
-
-bool cmServerBase::Serve(std::string* errorMessage)
-{
-#ifndef NDEBUG
- uv_thread_t blank_thread_t = {};
- assert(uv_thread_equal(&blank_thread_t, &ServeThreadId));
- ServeThreadId = uv_thread_self();
-#endif
-
- errorMessage->clear();
-
- ShutdownSignal.init(Loop, __shutdownThread, this);
-
- SIGINTHandler.init(Loop, this);
- SIGHUPHandler.init(Loop, this);
-
- SIGINTHandler.start(&on_signal, SIGINT);
- SIGHUPHandler.start(&on_signal, SIGHUP);
-
- OnServeStart();
-
- {
- cm::shared_lock<cm::shared_mutex> lock(ConnectionsMutex);
- for (auto& connection : Connections) {
- if (!connection->OnServeStart(errorMessage)) {
- return false;
- }
- }
- }
-
- if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) {
- // It is important we don't ever let the event loop exit with open handles
- // at best this is a memory leak, but it can also introduce race conditions
- // which can hang the program.
- assert(false && "Event loop stopped in unclean state.");
-
- *errorMessage = "Internal Error: Event loop stopped in unclean state.";
- return false;
- }
-
- return true;
-}
-
-void cmServerBase::OnConnected(cmConnection*)
-{
-}
-
-void cmServerBase::OnServeStart()
-{
-}
-
-void cmServerBase::StartShutDown()
-{
- ShutdownSignal.reset();
- SIGINTHandler.reset();
- SIGHUPHandler.reset();
-
- {
- std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex);
- for (auto& connection : Connections) {
- connection->OnConnectionShuttingDown();
- }
- Connections.clear();
- }
-
- uv_walk(&Loop, on_walk_to_shutdown, nullptr);
-}
-
-bool cmServerBase::OnSignal(int signum)
-{
- (void)signum;
- StartShutDown();
- return true;
-}
-
-cmServerBase::cmServerBase(cmConnection* connection)
-{
- auto err = uv_loop_init(&Loop);
- (void)err;
- Loop.data = this;
- assert(err == 0);
-
- AddNewConnection(connection);
-}
-
-void cmServerBase::Close()
-{
- if (Loop.data) {
- if (ServeThreadRunning) {
- this->ShutdownSignal.send();
- uv_thread_join(&ServeThread);
- }
-
- uv_loop_close(&Loop);
- Loop.data = nullptr;
- }
-}
-cmServerBase::~cmServerBase()
-{
- Close();
-}
-
-void cmServerBase::AddNewConnection(cmConnection* ownedConnection)
-{
- {
- std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex);
- 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;
- };
- {
- std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex);
- Connections.erase(
- std::remove_if(Connections.begin(), Connections.end(), pred),
- Connections.end());
- }
-
- if (Connections.empty()) {
- this->ShutdownSignal.send();
- }
-}
diff --git a/Source/cmServer.h b/Source/cmServer.h
deleted file mode 100644
index 9543329..0000000
--- a/Source/cmServer.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* 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" // IWYU pragma: keep
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <cm/shared_mutex>
-
-#include <cm3p/json/value.h>
-#include <cm3p/uv.h>
-
-#include "cmUVHandlePtr.h"
-
-class cmConnection;
-class cmFileMonitor;
-class cmServerProtocol;
-class cmServerRequest;
-class cmServerResponse;
-
-/***
- * 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 connection 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);
-
- /***
- * 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 Close();
- void OnDisconnect(cmConnection* pConnection);
-
-protected:
- mutable cm::shared_mutex ConnectionsMutex;
- std::vector<std::unique_ptr<cmConnection>> Connections;
-
- bool ServeThreadRunning = false;
- uv_thread_t ServeThread;
- cm::uv_async_ptr ShutdownSignal;
-#ifndef NDEBUG
-public:
- // When the server starts it will mark down it's current thread ID,
- // which is useful in other contexts to just assert that operations
- // are performed on that same thread.
- uv_thread_t ServeThreadId = {};
-
-protected:
-#endif
-
- uv_loop_t Loop;
-
- cm::uv_signal_ptr SIGINTHandler;
- cm::uv_signal_ptr SIGHUPHandler;
-};
-
-class cmServer : public cmServerBase
-{
-public:
- class DebugInfo;
-
- cmServer(cmConnection* conn, bool supportExperimental);
- ~cmServer() override;
-
- cmServer(cmServer const&) = delete;
- cmServer& operator=(cmServer const&) = delete;
-
- bool Serve(std::string* errorMessage) override;
-
- cmFileMonitor* FileMonitor() const;
-
-private:
- void RegisterProtocol(std::unique_ptr<cmServerProtocol> protocol);
-
- // Callbacks from cmServerConnection:
-
- 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 std::string& msg, float progress,
- const cmServerRequest& request);
- static void reportMessage(const std::string& msg, const char* title,
- const cmServerRequest& request);
-
- // Handle requests:
- cmServerResponse SetProtocolVersion(const cmServerRequest& request);
-
- 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(cmConnection* connection,
- const cmServerResponse& response,
- const DebugInfo* debug) 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<std::unique_ptr<cmServerProtocol>>& protocols, int major,
- int minor);
-
- const bool SupportExperimental;
-
- cmServerProtocol* Protocol = nullptr;
- std::vector<std::unique_ptr<cmServerProtocol>> SupportedProtocols;
-
- friend class cmServerProtocol;
- friend class cmServerRequest;
-};
diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx
deleted file mode 100644
index b4f41a0..0000000
--- a/Source/cmServerConnection.cxx
+++ /dev/null
@@ -1,165 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmConfigure.h"
-
-#include "cmServerConnection.h"
-
-#include <cm3p/uv.h>
-
-#include "cmServer.h"
-#include "cmServerDictionary.h"
-
-#ifdef _WIN32
-# include "io.h"
-#else
-# include <unistd.h>
-#endif
-#include <cassert>
-#include <utility>
-
-cmStdIoConnection::cmStdIoConnection(
- cmConnectionBufferStrategy* bufferStrategy)
- : cmEventBasedConnection(bufferStrategy)
-{
-}
-
-cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id)
-{
- switch (uv_guess_handle(file_id)) {
- case UV_TTY: {
- cm::uv_tty_ptr tty;
- tty.init(*this->Server->GetLoop(), file_id, file_id == 0,
- static_cast<cmEventBasedConnection*>(this));
- uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL);
- return { std::move(tty) };
- }
- case UV_FILE:
- if (file_id == 0) {
- return nullptr;
- }
- // Intentional fallthrough; stdin can _not_ be treated as a named
- // pipe, however stdout can be.
- CM_FALLTHROUGH;
- case UV_NAMED_PIPE: {
- cm::uv_pipe_ptr pipe;
- pipe.init(*this->Server->GetLoop(), 0,
- static_cast<cmEventBasedConnection*>(this));
- uv_pipe_open(pipe, file_id);
- return { std::move(pipe) };
- }
- default:
- assert(false && "Unable to determine stream type");
- return nullptr;
- }
-}
-
-void cmStdIoConnection::SetServer(cmServerBase* s)
-{
- cmConnection::SetServer(s);
- if (!s) {
- return;
- }
-
- this->ReadStream = SetupStream(0);
- this->WriteStream = SetupStream(1);
-}
-
-void shutdown_connection(uv_prepare_t* prepare)
-{
- cmStdIoConnection* connection =
- static_cast<cmStdIoConnection*>(prepare->data);
-
- if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(prepare))) {
- uv_close(reinterpret_cast<uv_handle_t*>(prepare),
- &cmEventBasedConnection::on_close_delete<uv_prepare_t>);
- }
- connection->OnDisconnect(0);
-}
-
-bool cmStdIoConnection::OnServeStart(std::string* pString)
-{
- Server->OnConnected(this);
- if (this->ReadStream.get()) {
- uv_read_start(this->ReadStream, on_alloc_buffer, on_read);
- } else if (uv_guess_handle(0) == UV_FILE) {
- char buffer[1024];
- while (auto len = read(0, buffer, sizeof(buffer))) {
- ReadData(std::string(buffer, buffer + len));
- }
-
- // We can't start the disconnect from here, add a prepare hook to do that
- // for us
- auto prepare = new uv_prepare_t();
- prepare->data = this;
- uv_prepare_init(Server->GetLoop(), prepare);
- uv_prepare_start(prepare, shutdown_connection);
- }
- return cmConnection::OnServeStart(pString);
-}
-
-bool cmStdIoConnection::OnConnectionShuttingDown()
-{
- if (ReadStream.get()) {
- uv_read_stop(ReadStream);
- ReadStream->data = nullptr;
- }
-
- this->ReadStream.reset();
-
- cmEventBasedConnection::OnConnectionShuttingDown();
-
- return true;
-}
-
-cmServerPipeConnection::cmServerPipeConnection(const std::string& name)
- : cmPipeConnection(name, new cmServerBufferStrategy)
-{
-}
-
-cmServerStdIoConnection::cmServerStdIoConnection()
- : cmStdIoConnection(new cmServerBufferStrategy)
-{
-}
-
-cmConnectionBufferStrategy::~cmConnectionBufferStrategy() = default;
-
-void cmConnectionBufferStrategy::clear()
-{
-}
-
-std::string cmServerBufferStrategy::BufferOutMessage(
- const std::string& rawBuffer) const
-{
- return std::string("\n") + kSTART_MAGIC + std::string("\n") + rawBuffer +
- kEND_MAGIC + std::string("\n");
-}
-
-std::string cmServerBufferStrategy::BufferMessage(std::string& RawReadBuffer)
-{
- for (;;) {
- auto needle = RawReadBuffer.find('\n');
-
- if (needle == std::string::npos) {
- return "";
- }
- 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);
- }
- RawReadBuffer.erase(RawReadBuffer.begin(),
- RawReadBuffer.begin() + static_cast<long>(needle) + 1);
- if (line == kSTART_MAGIC) {
- RequestBuffer.clear();
- continue;
- }
- if (line == kEND_MAGIC) {
- std::string rtn;
- rtn.swap(this->RequestBuffer);
- return rtn;
- }
-
- this->RequestBuffer += line;
- this->RequestBuffer += "\n";
- }
-}
diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h
deleted file mode 100644
index a70edb4..0000000
--- a/Source/cmServerConnection.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* 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" // IWYU pragma: keep
-
-#include <string>
-
-#include "cmConnection.h"
-#include "cmPipeConnection.h"
-#include "cmUVHandlePtr.h"
-
-class cmServerBase;
-
-/***
- * 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
-{
-public:
- std::string BufferMessage(std::string& rawBuffer) override;
- std::string BufferOutMessage(const std::string& rawBuffer) const override;
-
-private:
- std::string RequestBuffer;
-};
-
-/***
- * Generic connection over std io interfaces -- tty
- */
-class cmStdIoConnection : public cmEventBasedConnection
-{
-public:
- cmStdIoConnection(cmConnectionBufferStrategy* bufferStrategy);
-
- void SetServer(cmServerBase* s) override;
-
- bool OnConnectionShuttingDown() override;
-
- bool OnServeStart(std::string* pString) override;
-
-private:
- cm::uv_stream_ptr SetupStream(int file_id);
- cm::uv_stream_ptr ReadStream;
-};
-
-/***
- * These specific connections use the cmake server
- * buffering strategy.
- */
-class cmServerStdIoConnection : public cmStdIoConnection
-{
-public:
- cmServerStdIoConnection();
-};
-
-class cmServerPipeConnection : public cmPipeConnection
-{
-public:
- cmServerPipeConnection(const std::string& name);
-};
diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h
deleted file mode 100644
index 961e4b7..0000000
--- a/Source/cmServerDictionary.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#pragma once
-
-#include <string>
-
-// Vocabulary:
-
-static const std::string kDIRTY_SIGNAL = "dirty";
-static const std::string kFILE_CHANGE_SIGNAL = "fileChange";
-
-static const std::string kCACHE_TYPE = "cache";
-static const std::string kCMAKE_INPUTS_TYPE = "cmakeInputs";
-static const std::string kCODE_MODEL_TYPE = "codemodel";
-static const std::string kCOMPUTE_TYPE = "compute";
-static const std::string kCONFIGURE_TYPE = "configure";
-static const std::string kERROR_TYPE = "error";
-static const std::string kFILESYSTEM_WATCHERS_TYPE = "fileSystemWatchers";
-static const std::string kGLOBAL_SETTINGS_TYPE = "globalSettings";
-static const std::string kHANDSHAKE_TYPE = "handshake";
-static const std::string kMESSAGE_TYPE = "message";
-static const std::string kPROGRESS_TYPE = "progress";
-static const std::string kREPLY_TYPE = "reply";
-static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings";
-static const std::string kSIGNAL_TYPE = "signal";
-static const std::string kCTEST_INFO_TYPE = "ctestInfo";
-
-static const std::string kBUILD_FILES_KEY = "buildFiles";
-static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments";
-static const std::string kCACHE_KEY = "cache";
-static const std::string kCAPABILITIES_KEY = "capabilities";
-static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars";
-static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory";
-static const std::string kCOOKIE_KEY = "cookie";
-static const std::string kDEBUG_OUTPUT_KEY = "debugOutput";
-static const std::string kERROR_MESSAGE_KEY = "errorMessage";
-static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
-static const std::string kGENERATOR_KEY = "generator";
-static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental";
-static const std::string kKEYS_KEY = "keys";
-static const std::string kMAJOR_KEY = "major";
-static const std::string kMESSAGE_KEY = "message";
-static const std::string kMINOR_KEY = "minor";
-static const std::string kPLATFORM_KEY = "platform";
-static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent";
-static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum";
-static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage";
-static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum";
-static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion";
-static const std::string kREPLY_TO_KEY = "inReplyTo";
-static const std::string kSUPPORTED_PROTOCOL_VERSIONS =
- "supportedProtocolVersions";
-static const std::string kTITLE_KEY = "title";
-static const std::string kTOOLSET_KEY = "toolset";
-static const std::string kTRACE_EXPAND_KEY = "traceExpand";
-static const std::string kTRACE_KEY = "trace";
-static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized";
-static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli";
-static const std::string kWARN_UNUSED_KEY = "warnUnused";
-static const std::string kWATCHED_DIRECTORIES_KEY = "watchedDirectories";
-static const std::string kWATCHED_FILES_KEY = "watchedFiles";
-
-static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==[";
-static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]";
-
-static const std::string kRENAME_PROPERTY_VALUE = "rename";
-static const std::string kCHANGE_PROPERTY_VALUE = "change";
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
deleted file mode 100644
index e586fd9..0000000
--- a/Source/cmServerProtocol.cxx
+++ /dev/null
@@ -1,760 +0,0 @@
-/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
-#include "cmServerProtocol.h"
-
-#include <algorithm>
-#include <cassert>
-#include <functional>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <cm/memory>
-#include <cmext/algorithm>
-
-#include <cm3p/uv.h>
-
-#include "cmExternalMakefileProjectGenerator.h"
-#include "cmFileMonitor.h"
-#include "cmGlobalGenerator.h"
-#include "cmJsonObjectDictionary.h"
-#include "cmJsonObjects.h"
-#include "cmMessageType.h"
-#include "cmProperty.h"
-#include "cmServer.h"
-#include "cmServerDictionary.h"
-#include "cmState.h"
-#include "cmSystemTools.h"
-#include "cmake.h"
-
-// Get rid of some windows macros:
-#undef max
-
-namespace {
-
-std::vector<std::string> toStringList(const Json::Value& in)
-{
- std::vector<std::string> result;
- for (auto const& it : in) {
- result.push_back(it.asString());
- }
- return result;
-}
-
-} // namespace
-
-cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection,
- std::string t, std::string c, Json::Value d)
- : Type(std::move(t))
- , Cookie(std::move(c))
- , Data(std::move(d))
- , Connection(connection)
- , m_Server(server)
-{
-}
-
-void cmServerRequest::ReportProgress(int min, int current, int max,
- const std::string& message) const
-{
- this->m_Server->WriteProgress(*this, min, current, max, message);
-}
-
-void cmServerRequest::ReportMessage(const std::string& message,
- const std::string& title) const
-{
- m_Server->WriteMessage(*this, message, title);
-}
-
-cmServerResponse cmServerRequest::Reply(const Json::Value& data) const
-{
- cmServerResponse response(*this);
- response.SetData(data);
- return response;
-}
-
-cmServerResponse cmServerRequest::ReportError(const std::string& message) const
-{
- cmServerResponse response(*this);
- response.SetError(message);
- return response;
-}
-
-cmServerResponse::cmServerResponse(const cmServerRequest& request)
- : Type(request.Type)
- , Cookie(request.Cookie)
-{
-}
-
-void cmServerResponse::SetData(const Json::Value& data)
-{
- assert(this->m_Payload == PAYLOAD_UNKNOWN);
- if (!data[kCOOKIE_KEY].isNull() || !data[kTYPE_KEY].isNull()) {
- this->SetError("Response contains cookie or type field.");
- return;
- }
- this->m_Payload = PAYLOAD_DATA;
- this->m_Data = data;
-}
-
-void cmServerResponse::SetError(const std::string& message)
-{
- assert(this->m_Payload == PAYLOAD_UNKNOWN);
- this->m_Payload = PAYLOAD_ERROR;
- this->m_ErrorMessage = message;
-}
-
-bool cmServerResponse::IsComplete() const
-{
- return this->m_Payload != PAYLOAD_UNKNOWN;
-}
-
-bool cmServerResponse::IsError() const
-{
- assert(this->m_Payload != PAYLOAD_UNKNOWN);
- return this->m_Payload == PAYLOAD_ERROR;
-}
-
-std::string cmServerResponse::ErrorMessage() const
-{
- if (this->m_Payload == PAYLOAD_ERROR) {
- return this->m_ErrorMessage;
- }
- return std::string();
-}
-
-Json::Value cmServerResponse::Data() const
-{
- assert(this->m_Payload != PAYLOAD_UNKNOWN);
- return this->m_Data;
-}
-
-bool cmServerProtocol::Activate(cmServer* server,
- const cmServerRequest& request,
- std::string* errorMessage)
-{
- assert(server);
- this->m_Server = server;
- this->m_CMakeInstance =
- cm::make_unique<cmake>(cmake::RoleProject, cmState::Project);
- this->m_WarnUnused = false;
- const bool result = this->DoActivate(request, errorMessage);
- if (!result) {
- this->m_CMakeInstance = nullptr;
- }
- return result;
-}
-
-cmFileMonitor* cmServerProtocol::FileMonitor() const
-{
- return this->m_Server ? this->m_Server->FileMonitor() : nullptr;
-}
-
-void cmServerProtocol::SendSignal(const std::string& name,
- const Json::Value& data) const
-{
- if (this->m_Server) {
- this->m_Server->WriteSignal(name, data);
- }
-}
-
-cmake* cmServerProtocol::CMakeInstance() const
-{
- return this->m_CMakeInstance.get();
-}
-
-bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/,
- std::string* /*errorMessage*/)
-{
- return true;
-}
-
-std::pair<int, int> cmServerProtocol1::ProtocolVersion() const
-{
- return { 1, 2 };
-}
-
-static void setErrorMessage(std::string* errorMessage, const std::string& text)
-{
- if (errorMessage) {
- *errorMessage = text;
- }
-}
-
-static bool getOrTestHomeDirectory(cmState* state, std::string& value,
- std::string* errorMessage)
-{
- const std::string cachedValue =
- *state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY");
- if (value.empty()) {
- value = cachedValue;
- return true;
- }
- const std::string suffix = "/CMakeLists.txt";
- const std::string cachedValueCML = cachedValue + suffix;
- const std::string valueCML = value + suffix;
- if (!cmSystemTools::SameFile(valueCML, cachedValueCML)) {
- setErrorMessage(errorMessage,
- std::string("\"CMAKE_HOME_DIRECTORY\" is set but "
- "incompatible with configured "
- "source directory value."));
- return false;
- }
- return true;
-}
-
-static bool getOrTestValue(cmState* state, const std::string& key,
- std::string& value,
- const std::string& keyDescription,
- std::string* errorMessage)
-{
- const std::string cachedValue = state->GetSafeCacheEntryValue(key);
- if (value.empty()) {
- value = cachedValue;
- }
- if (!cachedValue.empty() && cachedValue != value) {
- setErrorMessage(errorMessage,
- std::string("\"") + key +
- "\" is set but incompatible with configured " +
- keyDescription + " value.");
- return false;
- }
- return true;
-}
-
-bool cmServerProtocol1::DoActivate(const cmServerRequest& request,
- std::string* errorMessage)
-{
- std::string sourceDirectory = request.Data[kSOURCE_DIRECTORY_KEY].asString();
- std::string buildDirectory = request.Data[kBUILD_DIRECTORY_KEY].asString();
- std::string generator = request.Data[kGENERATOR_KEY].asString();
- std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString();
- std::string toolset = request.Data[kTOOLSET_KEY].asString();
- std::string platform = request.Data[kPLATFORM_KEY].asString();
-
- // normalize source and build directory
- if (!sourceDirectory.empty()) {
- sourceDirectory = cmSystemTools::CollapseFullPath(sourceDirectory);
- cmSystemTools::ConvertToUnixSlashes(sourceDirectory);
- }
- if (!buildDirectory.empty()) {
- buildDirectory = cmSystemTools::CollapseFullPath(buildDirectory);
- cmSystemTools::ConvertToUnixSlashes(buildDirectory);
- }
-
- if (buildDirectory.empty()) {
- setErrorMessage(errorMessage,
- std::string("\"") + kBUILD_DIRECTORY_KEY +
- "\" is missing.");
- return false;
- }
-
- cmake* cm = CMakeInstance();
- if (cmSystemTools::PathExists(buildDirectory)) {
- if (!cmSystemTools::FileIsDirectory(buildDirectory)) {
- setErrorMessage(errorMessage,
- std::string("\"") + kBUILD_DIRECTORY_KEY +
- "\" exists but is not a directory.");
- return false;
- }
-
- const std::string cachePath = cmake::FindCacheFile(buildDirectory);
- if (cm->LoadCache(cachePath)) {
- cmState* state = cm->GetState();
-
- // Check generator:
- if (!getOrTestValue(state, "CMAKE_GENERATOR", generator, "generator",
- errorMessage)) {
- return false;
- }
-
- // check extra generator:
- if (!getOrTestValue(state, "CMAKE_EXTRA_GENERATOR", extraGenerator,
- "extra generator", errorMessage)) {
- return false;
- }
-
- // check sourcedir:
- if (!getOrTestHomeDirectory(state, sourceDirectory, errorMessage)) {
- return false;
- }
-
- // check toolset:
- if (!getOrTestValue(state, "CMAKE_GENERATOR_TOOLSET", toolset, "toolset",
- errorMessage)) {
- return false;
- }
-
- // check platform:
- if (!getOrTestValue(state, "CMAKE_GENERATOR_PLATFORM", platform,
- "platform", errorMessage)) {
- return false;
- }
- }
- }
-
- if (sourceDirectory.empty()) {
- setErrorMessage(errorMessage,
- std::string("\"") + kSOURCE_DIRECTORY_KEY +
- "\" is unset but required.");
- return false;
- }
- if (!cmSystemTools::FileIsDirectory(sourceDirectory)) {
- setErrorMessage(errorMessage,
- std::string("\"") + kSOURCE_DIRECTORY_KEY +
- "\" is not a directory.");
- return false;
- }
- if (generator.empty()) {
- setErrorMessage(errorMessage,
- std::string("\"") + kGENERATOR_KEY +
- "\" is unset but required.");
- return false;
- }
-
- std::vector<cmake::GeneratorInfo> generators;
- cm->GetRegisteredGenerators(generators);
- auto baseIt = std::find_if(generators.begin(), generators.end(),
- [&generator](const cmake::GeneratorInfo& info) {
- return info.name == generator;
- });
- if (baseIt == generators.end()) {
- setErrorMessage(errorMessage,
- std::string("Generator \"") + generator +
- "\" not supported.");
- return false;
- }
- auto extraIt = std::find_if(
- generators.begin(), generators.end(),
- [&generator, &extraGenerator](const cmake::GeneratorInfo& info) {
- return info.baseName == generator && info.extraName == extraGenerator;
- });
- if (extraIt == generators.end()) {
- setErrorMessage(errorMessage,
- std::string("The combination of generator \"" + generator +
- "\" and extra generator \"" + extraGenerator +
- "\" is not supported."));
- return false;
- }
- if (!extraIt->supportsToolset && !toolset.empty()) {
- setErrorMessage(errorMessage,
- std::string("Toolset was provided but is not supported by "
- "the requested generator."));
- return false;
- }
- if (!extraIt->supportsPlatform && !platform.empty()) {
- setErrorMessage(errorMessage,
- std::string("Platform was provided but is not supported "
- "by the requested generator."));
- return false;
- }
-
- this->GeneratorInfo =
- GeneratorInformation(generator, extraGenerator, toolset, platform,
- sourceDirectory, buildDirectory);
-
- this->m_State = STATE_ACTIVE;
- return true;
-}
-
-void cmServerProtocol1::HandleCMakeFileChanges(const std::string& path,
- int event, int status)
-{
- assert(status == 0);
- static_cast<void>(status);
-
- if (!m_isDirty) {
- m_isDirty = true;
- SendSignal(kDIRTY_SIGNAL, Json::objectValue);
- }
- Json::Value obj = Json::objectValue;
- obj[kPATH_KEY] = path;
- Json::Value properties = Json::arrayValue;
- if (event & UV_RENAME) {
- properties.append(kRENAME_PROPERTY_VALUE);
- }
- if (event & UV_CHANGE) {
- properties.append(kCHANGE_PROPERTY_VALUE);
- }
-
- obj[kPROPERTIES_KEY] = properties;
- SendSignal(kFILE_CHANGE_SIGNAL, obj);
-}
-
-cmServerResponse cmServerProtocol1::Process(const cmServerRequest& request)
-{
- assert(this->m_State >= STATE_ACTIVE);
-
- if (request.Type == kCACHE_TYPE) {
- return this->ProcessCache(request);
- }
- if (request.Type == kCMAKE_INPUTS_TYPE) {
- return this->ProcessCMakeInputs(request);
- }
- if (request.Type == kCODE_MODEL_TYPE) {
- return this->ProcessCodeModel(request);
- }
- if (request.Type == kCOMPUTE_TYPE) {
- return this->ProcessCompute(request);
- }
- if (request.Type == kCONFIGURE_TYPE) {
- return this->ProcessConfigure(request);
- }
- if (request.Type == kFILESYSTEM_WATCHERS_TYPE) {
- return this->ProcessFileSystemWatchers(request);
- }
- if (request.Type == kGLOBAL_SETTINGS_TYPE) {
- return this->ProcessGlobalSettings(request);
- }
- if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) {
- return this->ProcessSetGlobalSettings(request);
- }
- if (request.Type == kCTEST_INFO_TYPE) {
- return this->ProcessCTests(request);
- }
-
- return request.ReportError("Unknown command!");
-}
-
-bool cmServerProtocol1::IsExperimental() const
-{
- return true;
-}
-
-cmServerResponse cmServerProtocol1::ProcessCache(
- const cmServerRequest& request)
-{
- cmState* state = this->CMakeInstance()->GetState();
-
- Json::Value result = Json::objectValue;
-
- std::vector<std::string> allKeys = state->GetCacheEntryKeys();
-
- Json::Value list = Json::arrayValue;
- std::vector<std::string> keys = toStringList(request.Data[kKEYS_KEY]);
- if (keys.empty()) {
- keys = allKeys;
- } else {
- for (auto const& i : keys) {
- if (!cm::contains(allKeys, i)) {
- return request.ReportError("Key \"" + i + "\" not found in cache.");
- }
- }
- }
- std::sort(keys.begin(), keys.end());
- for (auto const& key : keys) {
- Json::Value entry = Json::objectValue;
- entry[kKEY_KEY] = key;
- entry[kTYPE_KEY] =
- cmState::CacheEntryTypeToString(state->GetCacheEntryType(key));
- entry[kVALUE_KEY] = *state->GetCacheEntryValue(key);
-
- Json::Value props = Json::objectValue;
- bool haveProperties = false;
- for (auto const& prop : state->GetCacheEntryPropertyList(key)) {
- haveProperties = true;
- props[prop] = *state->GetCacheEntryProperty(key, prop);
- }
- if (haveProperties) {
- entry[kPROPERTIES_KEY] = props;
- }
-
- list.append(entry);
- }
-
- result[kCACHE_KEY] = list;
- return request.Reply(result);
-}
-
-cmServerResponse cmServerProtocol1::ProcessCMakeInputs(
- const cmServerRequest& request)
-{
- if (this->m_State < STATE_CONFIGURED) {
- return request.ReportError("This instance was not yet configured.");
- }
-
- const cmake* cm = this->CMakeInstance();
- const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot();
- const std::string& sourceDir = cm->GetHomeDirectory();
-
- Json::Value result = Json::objectValue;
- result[kSOURCE_DIRECTORY_KEY] = sourceDir;
- result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir;
- result[kBUILD_FILES_KEY] = cmDumpCMakeInputs(cm);
- return request.Reply(result);
-}
-
-cmServerResponse cmServerProtocol1::ProcessCodeModel(
- const cmServerRequest& request)
-{
- if (this->m_State != STATE_COMPUTED) {
- return request.ReportError("No build system was generated yet.");
- }
-
- return request.Reply(cmDumpCodeModel(this->CMakeInstance()));
-}
-
-cmServerResponse cmServerProtocol1::ProcessCompute(
- const cmServerRequest& request)
-{
- if (this->m_State > STATE_CONFIGURED) {
- return request.ReportError("This build system was already generated.");
- }
- if (this->m_State < STATE_CONFIGURED) {
- return request.ReportError("This project was not configured yet.");
- }
-
- cmake* cm = this->CMakeInstance();
- int ret = cm->Generate();
-
- if (ret < 0) {
- return request.ReportError("Failed to compute build system.");
- }
- m_State = STATE_COMPUTED;
- return request.Reply(Json::Value());
-}
-
-cmServerResponse cmServerProtocol1::ProcessConfigure(
- const cmServerRequest& request)
-{
- if (this->m_State == STATE_INACTIVE) {
- return request.ReportError("This instance is inactive.");
- }
-
- FileMonitor()->StopMonitoring();
-
- std::string errorMessage;
- cmake* cm = this->CMakeInstance();
- this->GeneratorInfo.SetupGenerator(cm, &errorMessage);
- if (!errorMessage.empty()) {
- return request.ReportError(errorMessage);
- }
-
- // Make sure the types of cacheArguments matches (if given):
- std::vector<std::string> cacheArgs = { "unused" };
- bool cacheArgumentsError = false;
- const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY];
- if (!passedArgs.isNull()) {
- if (passedArgs.isString()) {
- cacheArgs.push_back(passedArgs.asString());
- } else if (passedArgs.isArray()) {
- for (auto const& arg : passedArgs) {
- if (!arg.isString()) {
- cacheArgumentsError = true;
- break;
- }
- cacheArgs.push_back(arg.asString());
- }
- } else {
- cacheArgumentsError = true;
- }
- }
- if (cacheArgumentsError) {
- request.ReportError(
- "cacheArguments must be unset, a string or an array of strings.");
- }
-
- std::string sourceDir = cm->GetHomeDirectory();
- const std::string buildDir = cm->GetHomeOutputDirectory();
-
- cmGlobalGenerator* gg = cm->GetGlobalGenerator();
-
- if (buildDir.empty()) {
- return request.ReportError("No build directory set via Handshake.");
- }
-
- if (cm->LoadCache(buildDir)) {
- // build directory has been set up before
- cmProp cachedSourceDir =
- cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY");
- if (!cachedSourceDir) {
- return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache.");
- }
- if (sourceDir.empty()) {
- sourceDir = *cachedSourceDir;
- cm->SetHomeDirectory(sourceDir);
- }
-
- cmProp cachedGenerator =
- cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR");
- if (cachedGenerator) {
- if (gg && gg->GetName() != *cachedGenerator) {
- return request.ReportError("Configured generator does not match with "
- "CMAKE_GENERATOR found in cache.");
- }
- }
- } else {
- // build directory has not been set up before
- if (sourceDir.empty()) {
- return request.ReportError("No sourceDirectory set via "
- "setGlobalSettings and no cache found in "
- "buildDirectory.");
- }
- }
-
- cmSystemTools::ResetErrorOccuredFlag(); // Reset error state
-
- if (cm->AddCMakePaths() != 1) {
- return request.ReportError("Failed to set CMake paths.");
- }
-
- if (!cm->SetCacheArgs(cacheArgs)) {
- return request.ReportError("cacheArguments could not be set.");
- }
-
- 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.");
- }
-
- std::vector<std::string> toWatchList;
- cmGetCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList,
- nullptr);
-
- FileMonitor()->MonitorPaths(toWatchList,
- [this](const std::string& p, int e, int s) {
- this->HandleCMakeFileChanges(p, e, s);
- });
-
- m_State = STATE_CONFIGURED;
- m_isDirty = false;
- return request.Reply(Json::Value());
-}
-
-cmServerResponse cmServerProtocol1::ProcessGlobalSettings(
- const cmServerRequest& request)
-{
- cmake* cm = this->CMakeInstance();
- Json::Value obj = Json::objectValue;
-
- // Capabilities information:
- obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson();
-
- obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput();
- obj[kTRACE_KEY] = cm->GetTrace();
- obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand();
- obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized();
- obj[kWARN_UNUSED_KEY] = m_WarnUnused;
- obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli();
- obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars();
-
- obj[kSOURCE_DIRECTORY_KEY] = this->GeneratorInfo.SourceDirectory;
- obj[kBUILD_DIRECTORY_KEY] = this->GeneratorInfo.BuildDirectory;
-
- // Currently used generator:
- obj[kGENERATOR_KEY] = this->GeneratorInfo.GeneratorName;
- obj[kEXTRA_GENERATOR_KEY] = this->GeneratorInfo.ExtraGeneratorName;
-
- return request.Reply(obj);
-}
-
-static void setBool(const cmServerRequest& request, const std::string& key,
- std::function<void(bool)> const& setter)
-{
- if (request.Data[key].isNull()) {
- return;
- }
- setter(request.Data[key].asBool());
-}
-
-cmServerResponse cmServerProtocol1::ProcessSetGlobalSettings(
- const cmServerRequest& request)
-{
- const std::vector<std::string> boolValues = {
- kDEBUG_OUTPUT_KEY, kTRACE_KEY, kTRACE_EXPAND_KEY,
- kWARN_UNINITIALIZED_KEY, kWARN_UNUSED_KEY, kWARN_UNUSED_CLI_KEY,
- kCHECK_SYSTEM_VARS_KEY
- };
- for (std::string const& i : boolValues) {
- if (!request.Data[i].isNull() && !request.Data[i].isBool()) {
- return request.ReportError("\"" + i +
- "\" must be unset or a bool value.");
- }
- }
-
- cmake* cm = this->CMakeInstance();
-
- setBool(request, kDEBUG_OUTPUT_KEY,
- [cm](bool e) { cm->SetDebugOutputOn(e); });
- setBool(request, kTRACE_KEY, [cm](bool e) { cm->SetTrace(e); });
- setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); });
- setBool(request, kWARN_UNINITIALIZED_KEY,
- [cm](bool e) { cm->SetWarnUninitialized(e); });
- setBool(request, kWARN_UNUSED_KEY, [this](bool e) { m_WarnUnused = e; });
- setBool(request, kWARN_UNUSED_CLI_KEY,
- [cm](bool e) { cm->SetWarnUnusedCli(e); });
- setBool(request, kCHECK_SYSTEM_VARS_KEY,
- [cm](bool e) { cm->SetCheckSystemVars(e); });
-
- return request.Reply(Json::Value());
-}
-
-cmServerResponse cmServerProtocol1::ProcessFileSystemWatchers(
- const cmServerRequest& request)
-{
- const cmFileMonitor* const fm = FileMonitor();
- Json::Value result = Json::objectValue;
- Json::Value files = Json::arrayValue;
- for (auto const& f : fm->WatchedFiles()) {
- files.append(f);
- }
- Json::Value directories = Json::arrayValue;
- for (auto const& d : fm->WatchedDirectories()) {
- directories.append(d);
- }
- result[kWATCHED_FILES_KEY] = files;
- result[kWATCHED_DIRECTORIES_KEY] = directories;
-
- return request.Reply(result);
-}
-
-cmServerResponse cmServerProtocol1::ProcessCTests(
- const cmServerRequest& request)
-{
- if (this->m_State < STATE_COMPUTED) {
- return request.ReportError("This instance was not yet computed.");
- }
-
- return request.Reply(cmDumpCTestInfo(this->CMakeInstance()));
-}
-
-cmServerProtocol1::GeneratorInformation::GeneratorInformation(
- std::string generatorName, std::string extraGeneratorName,
- std::string toolset, std::string platform, std::string sourceDirectory,
- std::string buildDirectory)
- : GeneratorName(std::move(generatorName))
- , ExtraGeneratorName(std::move(extraGeneratorName))
- , Toolset(std::move(toolset))
- , Platform(std::move(platform))
- , SourceDirectory(std::move(sourceDirectory))
- , BuildDirectory(std::move(buildDirectory))
-{
-}
-
-void cmServerProtocol1::GeneratorInformation::SetupGenerator(
- cmake* cm, std::string* errorMessage)
-{
- const std::string fullGeneratorName =
- cmExternalMakefileProjectGenerator::CreateFullGeneratorName(
- GeneratorName, ExtraGeneratorName);
-
- cm->SetHomeDirectory(SourceDirectory);
- cm->SetHomeOutputDirectory(BuildDirectory);
-
- auto gg = cm->CreateGlobalGenerator(fullGeneratorName);
- if (!gg) {
- setErrorMessage(
- errorMessage,
- std::string("Could not set up the requested combination of \"") +
- kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\"");
- return;
- }
-
- cm->SetGlobalGenerator(std::move(gg));
-
- cm->SetGeneratorToolset(Toolset);
- cm->SetGeneratorPlatform(Platform);
-}
diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h
deleted file mode 100644
index 6009e23..0000000
--- a/Source/cmServerProtocol.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/* 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" // IWYU pragma: keep
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include <cm3p/json/value.h>
-
-#include "cmake.h"
-
-class cmConnection;
-class cmFileMonitor;
-class cmServer;
-class cmServerRequest;
-
-class cmServerResponse
-{
-public:
- explicit cmServerResponse(const cmServerRequest& request);
-
- void SetData(const Json::Value& data);
- void SetError(const std::string& message);
-
- bool IsComplete() const;
- bool IsError() const;
- std::string ErrorMessage() const;
- Json::Value Data() const;
-
- const std::string Type;
- const std::string Cookie;
-
-private:
- enum PayLoad
- {
- PAYLOAD_UNKNOWN,
- PAYLOAD_ERROR,
- PAYLOAD_DATA
- };
- PayLoad m_Payload = PAYLOAD_UNKNOWN;
- std::string m_ErrorMessage;
- Json::Value m_Data;
-};
-
-class cmServerRequest
-{
-public:
- cmServerResponse Reply(const Json::Value& data) const;
- cmServerResponse ReportError(const std::string& message) const;
-
- const std::string Type;
- const std::string Cookie;
- const Json::Value Data;
- cmConnection* Connection;
-
-private:
- cmServerRequest(cmServer* server, cmConnection* connection, std::string t,
- std::string c, Json::Value d);
-
- void ReportProgress(int min, int current, int max,
- const std::string& message) const;
- void ReportMessage(const std::string& message,
- const std::string& title) const;
-
- cmServer* m_Server;
-
- friend class cmServer;
-};
-
-class cmServerProtocol
-{
-public:
- cmServerProtocol() = default;
- virtual ~cmServerProtocol() = default;
-
- cmServerProtocol(cmServerProtocol const&) = delete;
- cmServerProtocol& operator=(cmServerProtocol const&) = delete;
-
- virtual std::pair<int, int> ProtocolVersion() const = 0;
- virtual bool IsExperimental() const = 0;
- virtual cmServerResponse Process(const cmServerRequest& request) = 0;
-
- bool Activate(cmServer* server, const cmServerRequest& request,
- std::string* errorMessage);
-
- cmFileMonitor* FileMonitor() const;
- void SendSignal(const std::string& name, const Json::Value& data) const;
-
-protected:
- cmake* CMakeInstance() const;
- // Implement protocol specific activation tasks here. Called from Activate().
- virtual bool DoActivate(const cmServerRequest& request,
- std::string* errorMessage);
- bool m_WarnUnused = false; // storage for legacy option
-
-private:
- std::unique_ptr<cmake> m_CMakeInstance;
- cmServer* m_Server = nullptr; // not owned!
-
- friend class cmServer;
-};
-
-class cmServerProtocol1 : public cmServerProtocol
-{
-public:
- std::pair<int, int> ProtocolVersion() const override;
- bool IsExperimental() const override;
- cmServerResponse Process(const cmServerRequest& request) override;
-
-private:
- bool DoActivate(const cmServerRequest& request,
- std::string* errorMessage) override;
-
- void HandleCMakeFileChanges(const std::string& path, int event, int status);
-
- // Handle requests:
- cmServerResponse ProcessCache(const cmServerRequest& request);
- cmServerResponse ProcessCMakeInputs(const cmServerRequest& request);
- cmServerResponse ProcessCodeModel(const cmServerRequest& request);
- cmServerResponse ProcessCompute(const cmServerRequest& request);
- cmServerResponse ProcessConfigure(const cmServerRequest& request);
- cmServerResponse ProcessGlobalSettings(const cmServerRequest& request);
- cmServerResponse ProcessSetGlobalSettings(const cmServerRequest& request);
- cmServerResponse ProcessFileSystemWatchers(const cmServerRequest& request);
- cmServerResponse ProcessCTests(const cmServerRequest& request);
-
- enum State
- {
- STATE_INACTIVE,
- STATE_ACTIVE,
- STATE_CONFIGURED,
- STATE_COMPUTED
- };
- State m_State = STATE_INACTIVE;
-
- bool m_isDirty = false;
-
- struct GeneratorInformation
- {
- public:
- GeneratorInformation() = default;
- GeneratorInformation(std::string generatorName,
- std::string extraGeneratorName, std::string toolset,
- std::string platform, std::string sourceDirectory,
- std::string buildDirectory);
-
- void SetupGenerator(cmake* cm, std::string* errorMessage);
-
- std::string GeneratorName;
- std::string ExtraGeneratorName;
- std::string Toolset;
- std::string Platform;
-
- std::string SourceDirectory;
- std::string BuildDirectory;
- };
-
- GeneratorInformation GeneratorInfo;
-};
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index ef44a57..61f48e9 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -8,6 +8,7 @@
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
+#include "cmPolicies.h"
#include "cmProperty.h"
#include "cmState.h"
#include "cmStringAlgorithms.h"
@@ -93,10 +94,11 @@ cmSourceFileLocation const& cmSourceFile::GetLocation() const
return this->Location;
}
-std::string const& cmSourceFile::ResolveFullPath(std::string* error)
+std::string const& cmSourceFile::ResolveFullPath(std::string* error,
+ std::string* cmp0115Warning)
{
if (this->FullPath.empty()) {
- if (this->FindFullPath(error)) {
+ if (this->FindFullPath(error, cmp0115Warning)) {
this->CheckExtension();
}
}
@@ -108,7 +110,8 @@ std::string const& cmSourceFile::GetFullPath() const
return this->FullPath;
}
-bool cmSourceFile::FindFullPath(std::string* error)
+bool cmSourceFile::FindFullPath(std::string* error,
+ std::string* cmp0115Warning)
{
// If the file is generated compute the location without checking on disk.
if (this->GetIsGenerated()) {
@@ -131,9 +134,11 @@ bool cmSourceFile::FindFullPath(std::string* error)
// List of extension lists
std::vector<std::string> exts =
makefile->GetCMakeInstance()->GetAllExtensions();
+ auto cmp0115 = makefile->GetPolicyStatus(cmPolicies::CMP0115);
// Tries to find the file in a given directory
- auto findInDir = [this, &exts, &lPath](std::string const& dir) -> bool {
+ auto findInDir = [this, &exts, &lPath, cmp0115, cmp0115Warning,
+ makefile](std::string const& dir) -> bool {
// Compute full path
std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir);
// Try full path
@@ -141,13 +146,29 @@ bool cmSourceFile::FindFullPath(std::string* error)
this->FullPath = fullPath;
return true;
}
- // Try full path with extension
- for (std::string const& ext : exts) {
- if (!ext.empty()) {
- std::string extPath = cmStrCat(fullPath, '.', ext);
- if (cmSystemTools::FileExists(extPath)) {
- this->FullPath = extPath;
- return true;
+ // This has to be an if statement due to a bug in Oracle Developer Studio.
+ // See https://community.oracle.com/tech/developers/discussion/4476246/
+ // for details.
+ if (cmp0115 == cmPolicies::OLD || cmp0115 == cmPolicies::WARN) {
+ // Try full path with extension
+ for (std::string const& ext : exts) {
+ if (!ext.empty()) {
+ std::string extPath = cmStrCat(fullPath, '.', ext);
+ if (cmSystemTools::FileExists(extPath)) {
+ this->FullPath = extPath;
+ if (cmp0115 == cmPolicies::WARN) {
+ std::string warning =
+ cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0115),
+ "\nFile:\n ", extPath);
+ if (cmp0115Warning) {
+ *cmp0115Warning = std::move(warning);
+ } else {
+ makefile->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING, warning);
+ }
+ }
+ return true;
+ }
}
}
}
@@ -168,11 +189,19 @@ bool cmSourceFile::FindFullPath(std::string* error)
}
// Compose error
- std::string err =
- cmStrCat("Cannot find source file:\n ", lPath, "\nTried extensions");
- for (std::string const& ext : exts) {
- err += " .";
- err += ext;
+ std::string err = cmStrCat("Cannot find source file:\n ", lPath);
+ switch (cmp0115) {
+ case cmPolicies::OLD:
+ case cmPolicies::WARN:
+ err = cmStrCat(err, "\nTried extensions");
+ for (auto const& ext : exts) {
+ err = cmStrCat(err, " .", ext);
+ }
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ break;
}
if (error != nullptr) {
*error = std::move(err);
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index 39ea8e3..3196b3f 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -77,7 +77,8 @@ public:
* Resolves the full path to the file. Attempts to locate the file on disk
* and finalizes its location.
*/
- std::string const& ResolveFullPath(std::string* error = nullptr);
+ std::string const& ResolveFullPath(std::string* error = nullptr,
+ std::string* cmp0115Warning = nullptr);
/**
* The resolved full path to the file. The returned file name might be empty
@@ -138,7 +139,7 @@ private:
bool FindFullPathFailed = false;
bool IsGenerated = false;
- bool FindFullPath(std::string* error);
+ bool FindFullPath(std::string* error, std::string* cmp0115Warning);
void CheckExtension();
void CheckLanguage(std::string const& ext);
diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx
new file mode 100644
index 0000000..e1f8753
--- /dev/null
+++ b/Source/cmTransformDepfile.cxx
@@ -0,0 +1,114 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTransformDepfile.h"
+
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include <cm/optional>
+
+#include "cmsys/FStream.hxx"
+
+#include "cmGccDepfileReader.h"
+#include "cmGccDepfileReaderTypes.h"
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+namespace {
+void WriteFilenameGcc(cmsys::ofstream& fout, const std::string& filename)
+{
+ for (auto c : filename) {
+ switch (c) {
+ case ' ':
+ fout << "\\ ";
+ break;
+ case '\\':
+ fout << "\\\\";
+ break;
+ default:
+ fout << c;
+ break;
+ }
+ }
+}
+
+void WriteGccDepfile(cmsys::ofstream& fout, const cmGccDepfileContent& content)
+{
+ for (auto const& dep : content) {
+ bool first = true;
+ for (auto const& rule : dep.rules) {
+ if (!first) {
+ fout << " \\\n ";
+ }
+ first = false;
+ WriteFilenameGcc(fout, rule);
+ }
+ fout << ':';
+ for (auto const& path : dep.paths) {
+ fout << " \\\n " << path;
+ }
+ fout << '\n';
+ }
+}
+
+void WriteVsTlog(cmsys::ofstream& fout, const cmGccDepfileContent& content)
+{
+ for (auto const& dep : content) {
+ fout << '^';
+ bool first = true;
+ for (auto const& rule : dep.rules) {
+ if (!first) {
+ fout << '|';
+ }
+ first = false;
+ fout << cmSystemTools::ConvertToOutputPath(rule);
+ }
+ fout << "\r\n";
+ for (auto const& path : dep.paths) {
+ fout << cmSystemTools::ConvertToOutputPath(path) << "\r\n";
+ }
+ }
+}
+}
+
+bool cmTransformDepfile(cmDepfileFormat format, const std::string& prefix,
+ const std::string& infile, const std::string& outfile)
+{
+ cmGccDepfileContent content;
+ if (cmSystemTools::FileExists(infile)) {
+ auto result = cmReadGccDepfile(infile.c_str());
+ if (!result) {
+ return false;
+ }
+ content = *std::move(result);
+ }
+
+ for (auto& dep : content) {
+ for (auto& rule : dep.rules) {
+ if (!cmSystemTools::FileIsFullPath(rule)) {
+ rule = cmStrCat(prefix, rule);
+ }
+ }
+ for (auto& path : dep.paths) {
+ if (!cmSystemTools::FileIsFullPath(path)) {
+ path = cmStrCat(prefix, path);
+ }
+ }
+ }
+
+ cmsys::ofstream fout(outfile.c_str());
+ if (!fout) {
+ return false;
+ }
+ switch (format) {
+ case cmDepfileFormat::GccDepfile:
+ WriteGccDepfile(fout, content);
+ break;
+ case cmDepfileFormat::VsTlog:
+ WriteVsTlog(fout, content);
+ break;
+ }
+ return true;
+}
diff --git a/Source/cmTransformDepfile.h b/Source/cmTransformDepfile.h
new file mode 100644
index 0000000..792c1aa
--- /dev/null
+++ b/Source/cmTransformDepfile.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+enum class cmDepfileFormat
+{
+ GccDepfile,
+ VsTlog,
+};
+
+bool cmTransformDepfile(cmDepfileFormat format, const std::string& prefix,
+ const std::string& infile, const std::string& outfile);
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 2a14b03..720a567 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -263,7 +263,7 @@ Json::Value cmake::ReportCapabilitiesJson() const
}
obj["generators"] = generators;
obj["fileApi"] = cmFileAPI::ReportCapabilities();
- obj["serverMode"] = true;
+ obj["serverMode"] = false;
return obj;
}
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index e2ff8b7..ea1f968 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -20,6 +20,7 @@
#include "cmStateSnapshot.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
+#include "cmTransformDepfile.h"
#include "cmUVProcessChain.h"
#include "cmUtils.hxx"
#include "cmVersion.h"
@@ -28,8 +29,6 @@
#if !defined(CMAKE_BOOTSTRAP)
# include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback.
# include "cmFileTime.h"
-# include "cmServer.h"
-# include "cmServerConnection.h"
# include "bindexplib.h"
#endif
@@ -61,8 +60,6 @@
#include "cmsys/Process.h"
#include "cmsys/Terminal.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,
@@ -121,7 +118,6 @@ void CMakeCommandUsage(const char* program)
"(on one volume)\n"
<< " rm [-rRf] <file/dir>... - remove files or directories, use -f to "
"force it, r or R to remove directories and their contents recursively\n"
- << " server - start cmake in server mode\n"
<< " sleep <number>... - sleep for given number of seconds\n"
<< " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n"
<< " - create or extract a tar or zip archive\n"
@@ -1359,47 +1355,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
}
if (args[1] == "server") {
- const std::string pipePrefix = "--pipe=";
- bool supportExperimental = false;
- bool isDebug = false;
- std::string pipe;
-
- for (auto const& arg : cmMakeRange(args).advance(2)) {
- if (arg == "--experimental") {
- supportExperimental = true;
- } else if (arg == "--debug") {
- pipe.clear();
- isDebug = true;
- } else if (cmHasPrefix(arg, pipePrefix)) {
- isDebug = false;
- pipe = arg.substr(pipePrefix.size());
- if (pipe.empty()) {
- cmSystemTools::Error("No pipe given after --pipe=");
- return 2;
- }
- } else {
- cmSystemTools::Error("Unknown argument for server mode");
- return 1;
- }
- }
-#if !defined(CMAKE_BOOTSTRAP)
- cmConnection* conn;
- if (isDebug) {
- conn = new cmServerStdIoConnection;
- } else {
- conn = new cmServerPipeConnection(pipe);
- }
- cmServer server(conn, supportExperimental);
- std::string errorMessage;
- if (server.Serve(&errorMessage)) {
- return 0;
- }
- cmSystemTools::Error(errorMessage);
-#else
- static_cast<void>(supportExperimental);
- static_cast<void>(isDebug);
- cmSystemTools::Error("CMake was not built with server mode enabled");
-#endif
+ cmSystemTools::Error(
+ "CMake server mode has been removed in favor of the file-api.");
return 1;
}
@@ -1435,6 +1392,23 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
return cmcmd::WindowsCEEnvironment("9.0", args[2]);
}
#endif
+
+ // Internal depfile transformation
+ if (args[1] == "cmake_transform_depfile" && args.size() == 6) {
+ auto format = cmDepfileFormat::GccDepfile;
+ if (args[2] == "gccdepfile") {
+ format = cmDepfileFormat::GccDepfile;
+ } else if (args[2] == "vstlog") {
+ format = cmDepfileFormat::VsTlog;
+ } else {
+ return 1;
+ }
+ std::string prefix = args[3];
+ if (prefix == "./") {
+ prefix.clear();
+ }
+ return cmTransformDepfile(format, prefix, args[4], args[5]) ? 0 : 1;
+ }
}
::CMakeCommandUsage(args[0].c_str());