diff options
Diffstat (limited to 'Source')
62 files changed, 1283 insertions, 817 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 33ab093..7031d5a 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -348,6 +348,8 @@ set(SRCS cmTestGenerator.cxx cmTestGenerator.h cmUuid.cxx + cmUVHandlePtr.cxx + cmUVHandlePtr.h cmVariableWatch.cxx cmVariableWatch.h cmVersion.cxx @@ -800,7 +802,6 @@ include_directories( # set(CTEST_SRCS cmCTest.cxx CTest/cmProcess.cxx - CTest/cmCTestBatchTestHandler.cxx CTest/cmCTestBuildAndTestHandler.cxx CTest/cmCTestBuildCommand.cxx CTest/cmCTestBuildHandler.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 500a872..a28378a 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 10) -set(CMake_VERSION_PATCH 20171128) +set(CMake_VERSION_PATCH 20171212) #set(CMake_VERSION_RC 1) diff --git a/Source/CMakeVersion.rc.in b/Source/CMakeVersion.rc.in index f4ca3d5..22b4a36 100644 --- a/Source/CMakeVersion.rc.in +++ b/Source/CMakeVersion.rc.in @@ -1,11 +1,14 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -#define VER_FILEVERSION @CMake_VERSION_MAJOR@,@CMake_VERSION_MINOR@,@CMake_VERSION_PATCH@ -#define VER_FILEVERSION_STR "@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@.@CMake_VERSION_PATCH@\0" +#define VER_FILEVERSION @CMake_RCVERSION@ +#define VER_FILEVERSION_STR "@CMake_RCVERSION_STR@\0" -#define VER_PRODUCTVERSION @CMake_VERSION_MAJOR@,@CMake_VERSION_MINOR@,@CMake_VERSION_PATCH@ -#define VER_PRODUCTVERSION_STR "@CMake_VERSION@\0" +#define VER_PRODUCTVERSION @CMake_RCVERSION@ +#define VER_PRODUCTVERSION_STR "@CMake_RCVERSION_STR@\0" + +/* Version-information resource identifier. */ +#define VS_VERSION_INFO 1 VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION diff --git a/Source/CMakeVersionCompute.cmake b/Source/CMakeVersionCompute.cmake index d9218d7..79264ed 100644 --- a/Source/CMakeVersionCompute.cmake +++ b/Source/CMakeVersionCompute.cmake @@ -27,3 +27,13 @@ endif() if(CMake_VERSION_IS_DIRTY) set(CMake_VERSION ${CMake_VERSION}-dirty) endif() + +# Compute the binary version that appears in the RC file. Version +# components in the RC file are 16-bit integers so we may have to +# split the patch component. +if(CMake_VERSION_PATCH MATCHES "^([0-9]+)([0-9][0-9][0-9][0-9])$") + set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMAKE_MATCH_1},${CMAKE_MATCH_2}) +else() + set(CMake_RCVERSION ${CMake_VERSION_MAJOR},${CMake_VERSION_MINOR},${CMake_VERSION_PATCH}) +endif() +set(CMake_RCVERSION_STR ${CMake_VERSION}) diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index be75a9f..ea0e899 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -17,6 +17,7 @@ #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmStateSnapshot.h" +#include "cmVersion.h" #include "cmWorkingDirectory.h" #include "cmXMLSafe.h" #include "cmake.h" @@ -988,10 +989,16 @@ int cmCPackGenerator::DoPackage() */ packageFileNames.push_back(tempPackageFileName ? tempPackageFileName : ""); toplevel = tempDirectory; - if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) { - cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory" - << std::endl); - return 0; + { // scope that enables package generators to run internal scripts with + // latest CMake policies enabled + cmMakefile::ScopePushPop pp{ this->MakefileMap }; + this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion()); + + if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory" + << std::endl); + return 0; + } } /* Prepare checksum algorithm*/ diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx index 4f5b2a0..9ea8540 100644 --- a/Source/CPack/cmCPackPKGGenerator.cxx +++ b/Source/CPack/cmCPackPKGGenerator.cxx @@ -189,7 +189,7 @@ void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component, // This way, selecting C will automatically select everything it depends // on (B and A), while selecting something that depends on C--either D // or E--will automatically cause C to get selected. - std::ostringstream selected("my.choice.selected"); + std::ostringstream selected("my.choice.selected", std::ios_base::ate); std::set<const cmCPackComponent*> visited; AddDependencyAttributes(component, visited, selected); visited.clear(); diff --git a/Source/CTest/cmCTestBatchTestHandler.cxx b/Source/CTest/cmCTestBatchTestHandler.cxx deleted file mode 100644 index 2eed8be..0000000 --- a/Source/CTest/cmCTestBatchTestHandler.cxx +++ /dev/null @@ -1,123 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmCTestBatchTestHandler.h" - -#include "cmCTest.h" -#include "cmCTestMultiProcessHandler.h" -#include "cmCTestTestHandler.h" -#include "cmProcess.h" -#include "cmSystemTools.h" - -#include <map> -#include <utility> -#include <vector> - -cmCTestBatchTestHandler::~cmCTestBatchTestHandler() -{ -} - -void cmCTestBatchTestHandler::RunTests() -{ - this->WriteBatchScript(); - this->SubmitBatchScript(); -} - -void cmCTestBatchTestHandler::WriteBatchScript() -{ - this->Script = this->CTest->GetBinaryDir() + "/Testing/CTestBatch.txt"; - cmsys::ofstream fout; - fout.open(this->Script.c_str()); - fout << "#!/bin/sh\n"; - - for (auto const& t : this->Tests) { - this->WriteSrunArgs(t.first, fout); - this->WriteTestCommand(t.first, fout); - fout << "\n"; - } - fout.flush(); - fout.close(); -} - -void cmCTestBatchTestHandler::WriteSrunArgs(int test, std::ostream& fout) -{ - cmCTestTestHandler::cmCTestTestProperties* properties = - this->Properties[test]; - - fout << "srun "; - // fout << "--jobid=" << test << " "; - fout << "-J=" << properties->Name << " "; - - // Write dependency information - /*if(!this->Tests[test].empty()) - { - fout << "-P=afterany"; - for(TestSet::iterator i = this->Tests[test].begin(); - i != this->Tests[test].end(); ++i) - { - fout << ":" << *i; - } - fout << " "; - }*/ - if (properties->RunSerial) { - fout << "--exclusive "; - } - if (properties->Processors > 1) { - fout << "-n" << properties->Processors << " "; - } -} - -void cmCTestBatchTestHandler::WriteTestCommand(int test, std::ostream& fout) -{ - std::vector<std::string> args = this->Properties[test]->Args; - std::vector<std::string> processArgs; - std::string command; - - command = this->TestHandler->FindTheExecutable(args[1].c_str()); - command = cmSystemTools::ConvertToOutputPath(command.c_str()); - - // Prepends memcheck args to our command string if this is a memcheck - this->TestHandler->GenerateTestCommand(processArgs, test); - processArgs.push_back(command); - - for (std::string const& arg : processArgs) { - fout << arg << " "; - } - - std::vector<std::string>::iterator i = args.begin(); - ++i; // the test name - ++i; // the executable (command) - if (args.size() > 2) { - fout << "'"; - } - while (i != args.end()) { - fout << "\"" << *i << "\""; // args to the test executable - ++i; - - if (i == args.end() && args.size() > 2) { - fout << "'"; - } - fout << " "; - } - // TODO ZACH build TestResult.FullCommandLine - // this->TestResult.FullCommandLine = this->TestCommand; -} - -void cmCTestBatchTestHandler::SubmitBatchScript() -{ - cmProcess sbatch; - std::vector<std::string> args; - args.push_back(this->Script); - args.push_back("-o"); - args.push_back(this->CTest->GetBinaryDir() + "/Testing/CTestBatch.txt"); - - sbatch.SetCommand("sbatch"); - sbatch.SetCommandArguments(args); - /*if(sbatch.StartProcess()) - { - //success condition - } - else - { - //fail condition - }*/ -} diff --git a/Source/CTest/cmCTestBatchTestHandler.h b/Source/CTest/cmCTestBatchTestHandler.h deleted file mode 100644 index 42f87bd..0000000 --- a/Source/CTest/cmCTestBatchTestHandler.h +++ /dev/null @@ -1,33 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#ifndef cmCTestBatchTestHandler_h -#define cmCTestBatchTestHandler_h - -#include "cmConfigure.h" // IWYU pragma: keep - -#include "cmCTestMultiProcessHandler.h" -#include "cmsys/FStream.hxx" -#include <string> - -/** \class cmCTestBatchTestHandler - * \brief run parallel ctest - * - * cmCTestBatchTestHandler - */ -class cmCTestBatchTestHandler : public cmCTestMultiProcessHandler -{ -public: - ~cmCTestBatchTestHandler() override; - void RunTests() override; - -protected: - void WriteBatchScript(); - void WriteSrunArgs(int test, std::ostream& fout); - void WriteTestCommand(int test, std::ostream& fout); - - void SubmitBatchScript(); - - std::string Script; -}; - -#endif diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index dcb17d0..dbdefae 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -438,8 +438,6 @@ bool cmCTestRunTest::StartTest(size_t total) return false; } - this->ComputeArguments(); - std::vector<std::string>& args = this->TestProperties->Args; this->TestResult.Properties = this->TestProperties; this->TestResult.ExecutionTime = std::chrono::duration<double>::zero(); this->TestResult.CompressOutput = false; @@ -450,6 +448,10 @@ bool cmCTestRunTest::StartTest(size_t total) this->TestResult.Name = this->TestProperties->Name; this->TestResult.Path = this->TestProperties->Directory; + // Check for failed fixture dependencies before we even look at the command + // arguments because if we are not going to run the test, the command and + // its arguments are irrelevant. This matters for the case where a fixture + // dependency might be creating the executable we want to run. if (!this->FailedDependencies.empty()) { this->TestProcess = new cmProcess; std::string msg = "Failed test dependencies:"; @@ -465,6 +467,8 @@ bool cmCTestRunTest::StartTest(size_t total) return false; } + this->ComputeArguments(); + std::vector<std::string>& args = this->TestProperties->Args; if (args.size() >= 2 && args[1] == "NOT_AVAILABLE") { this->TestProcess = new cmProcess; std::string msg; diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index e5a0503..4c7cefb 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -19,7 +19,6 @@ #include "cmAlgorithms.h" #include "cmCTest.h" -#include "cmCTestBatchTestHandler.h" #include "cmCTestMultiProcessHandler.h" #include "cmCommand.h" #include "cmGeneratedFileStream.h" @@ -1205,9 +1204,7 @@ void cmCTestTestHandler::ProcessDirectory(std::vector<std::string>& passed, this->StartTestTime = std::chrono::system_clock::now(); auto elapsed_time_start = std::chrono::steady_clock::now(); - cmCTestMultiProcessHandler* parallel = this->CTest->GetBatchJobs() - ? new cmCTestBatchTestHandler - : new cmCTestMultiProcessHandler; + cmCTestMultiProcessHandler* parallel = new cmCTestMultiProcessHandler; parallel->SetCTest(this->CTest); parallel->SetParallelLevel(this->CTest->GetParallelLevel()); parallel->SetTestHandler(this); diff --git a/Source/CTest/cmCTestTestHandler.h b/Source/CTest/cmCTestTestHandler.h index 19b345e..4fb067a 100644 --- a/Source/CTest/cmCTestTestHandler.h +++ b/Source/CTest/cmCTestTestHandler.h @@ -29,7 +29,6 @@ class cmCTestTestHandler : public cmCTestGenericHandler { friend class cmCTestRunTest; friend class cmCTestMultiProcessHandler; - friend class cmCTestBatchTestHandler; public: typedef cmCTestGenericHandler Superclass; diff --git a/Source/Checks/cm_cxx_attribute_fallthrough.cxx b/Source/Checks/cm_cxx_attribute_fallthrough.cxx deleted file mode 100644 index 50605b7..0000000 --- a/Source/Checks/cm_cxx_attribute_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - __attribute__((fallthrough)); - default: - return i; - } -} diff --git a/Source/Checks/cm_cxx_fallthrough.cxx b/Source/Checks/cm_cxx_fallthrough.cxx deleted file mode 100644 index 2825bed..0000000 --- a/Source/Checks/cm_cxx_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - [[fallthrough]]; - default: - return i; - } -} diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake index a30a5e6..2704c40 100644 --- a/Source/Checks/cm_cxx_features.cmake +++ b/Source/Checks/cm_cxx_features.cmake @@ -41,13 +41,6 @@ function(cm_check_cxx_feature name) endif() endfunction() -cm_check_cxx_feature(fallthrough) -if(NOT CMake_HAVE_CXX_FALLTHROUGH) - cm_check_cxx_feature(gnu_fallthrough) - if(NOT CMake_HAVE_CXX_GNU_FALLTHROUGH) - cm_check_cxx_feature(attribute_fallthrough) - endif() -endif() cm_check_cxx_feature(make_unique) if(CMake_HAVE_CXX_MAKE_UNIQUE) set(CMake_HAVE_CXX_UNIQUE_PTR 1) diff --git a/Source/Checks/cm_cxx_gnu_fallthrough.cxx b/Source/Checks/cm_cxx_gnu_fallthrough.cxx deleted file mode 100644 index ebc15f4..0000000 --- a/Source/Checks/cm_cxx_gnu_fallthrough.cxx +++ /dev/null @@ -1,11 +0,0 @@ -int main(int argc, char* []) -{ - int i = 3; - switch (argc) { - case 1: - i = 0; - [[gnu::fallthrough]]; - default: - return i; - } -} diff --git a/Source/Modules/OverrideC.cmake b/Source/Modules/OverrideC.cmake new file mode 100644 index 0000000..f8299ad --- /dev/null +++ b/Source/Modules/OverrideC.cmake @@ -0,0 +1,3 @@ +if("${CMAKE_SYSTEM_NAME};${CMAKE_C_COMPILER_ID}" STREQUAL "AIX;GNU") + string(APPEND CMAKE_C_FLAGS_INIT " -pthread") +endif() diff --git a/Source/Modules/OverrideCXX.cmake b/Source/Modules/OverrideCXX.cmake new file mode 100644 index 0000000..13689e2 --- /dev/null +++ b/Source/Modules/OverrideCXX.cmake @@ -0,0 +1,3 @@ +if("${CMAKE_SYSTEM_NAME};${CMAKE_CXX_COMPILER_ID}" STREQUAL "AIX;GNU") + string(APPEND CMAKE_CXX_FLAGS_INIT " -pthread") +endif() diff --git a/Source/QtDialog/RegexExplorer.cxx b/Source/QtDialog/RegexExplorer.cxx index abed70e..cb67f85 100644 --- a/Source/QtDialog/RegexExplorer.cxx +++ b/Source/QtDialog/RegexExplorer.cxx @@ -8,7 +8,7 @@ RegexExplorer::RegexExplorer(QWidget* p) { this->setupUi(this); - for (int i = 1; i < cmsys::RegularExpression::NSUBEXP; ++i) { + for (int i = 1; i < cmsys::RegularExpressionMatch::NSUBEXP; ++i) { matchNumber->addItem(QString("Match %1").arg(QString::number(i)), QVariant(i)); } @@ -105,7 +105,7 @@ void RegexExplorer::on_matchNumber_currentIndexChanged(int index) QVariant itemData = matchNumber->itemData(index); int idx = itemData.toInt(); - if (idx < 1 || idx >= cmsys::RegularExpression::NSUBEXP) { + if (idx < 1 || idx >= cmsys::RegularExpressionMatch::NSUBEXP) { return; } diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index e48f64a..26e1dcb 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -260,7 +260,6 @@ cmCTest::cmCTest() this->TestLoad = 0; this->SubmitIndex = 0; this->Failover = false; - this->BatchJobs = false; this->ForceNewCTestProcess = false; this->TomorrowTag = false; this->Verbose = false; @@ -1814,9 +1813,6 @@ bool cmCTest::HandleCommandLineArguments(size_t& i, if (this->CheckArgument(arg, "-V", "--verbose")) { this->Verbose = true; } - if (this->CheckArgument(arg, "-B")) { - this->BatchJobs = true; - } if (this->CheckArgument(arg, "-VV", "--extra-verbose")) { this->ExtraVerbose = true; this->Verbose = true; diff --git a/Source/cmCTest.h b/Source/cmCTest.h index 418d576..23d71cb 100644 --- a/Source/cmCTest.h +++ b/Source/cmCTest.h @@ -429,9 +429,6 @@ public: void SetFailover(bool failover) { this->Failover = failover; } bool GetFailover() { return this->Failover; } - void SetBatchJobs(bool batch = true) { this->BatchJobs = batch; } - bool GetBatchJobs() { return this->BatchJobs; } - bool GetVerbose() { return this->Verbose; } bool GetExtraVerbose() { return this->ExtraVerbose; } @@ -477,7 +474,6 @@ private: bool UseHTTP10; bool PrintLabels; bool Failover; - bool BatchJobs; bool ForceNewCTestProcess; diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 9a78aca..c80439b 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -19,22 +19,11 @@ #cmakedefine HAVE_UNSETENV #cmakedefine CMAKE_USE_ELF_PARSER #cmakedefine CMAKE_USE_MACH_PARSER -#cmakedefine CMake_HAVE_CXX_FALLTHROUGH -#cmakedefine CMake_HAVE_CXX_GNU_FALLTHROUGH -#cmakedefine CMake_HAVE_CXX_ATTRIBUTE_FALLTHROUGH #cmakedefine CMake_HAVE_CXX_MAKE_UNIQUE #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@" -#if defined(CMake_HAVE_CXX_FALLTHROUGH) -#define CM_FALLTHROUGH [[fallthrough]] -#elif defined(CMake_HAVE_CXX_GNU_FALLTHROUGH) -#define CM_FALLTHROUGH [[gnu::fallthrough]] -#elif defined(CMake_HAVE_CXX_ATTRIBUTE_FALLTHROUGH) -#define CM_FALLTHROUGH __attribute__((fallthrough)) -#else -#define CM_FALLTHROUGH -#endif +#define CM_FALLTHROUGH cmsys_FALLTHROUGH #define CM_DISABLE_COPY(Class) \ Class(Class const&) = delete; \ diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx index 28ba12c..50e1936 100644 --- a/Source/cmConnection.cxx +++ b/Source/cmConnection.cxx @@ -26,7 +26,7 @@ void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle, void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { - auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data); + auto conn = static_cast<cmEventBasedConnection*>(stream->data); if (conn) { if (nread >= 0) { conn->ReadData(std::string(buf->base, buf->base + nread)); @@ -55,7 +55,7 @@ void cmEventBasedConnection::on_write(uv_write_t* req, int status) void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status) { (void)(status); - auto conn = reinterpret_cast<cmEventBasedConnection*>(stream->data); + auto conn = static_cast<cmEventBasedConnection*>(stream->data); if (conn) { conn->Connect(stream); @@ -76,7 +76,7 @@ void cmEventBasedConnection::WriteData(const std::string& _data) #endif auto data = _data; - assert(this->WriteStream); + assert(this->WriteStream.get()); if (BufferStrategy) { data = BufferStrategy->BufferOutMessage(data); } @@ -87,8 +87,7 @@ void cmEventBasedConnection::WriteData(const std::string& _data) req->req.data = this; req->buf = uv_buf_init(new char[ds], static_cast<unsigned int>(ds)); memcpy(req->buf.base, data.c_str(), ds); - uv_write(reinterpret_cast<uv_write_t*>(req), - static_cast<uv_stream_t*>(this->WriteStream), &req->buf, 1, + uv_write(reinterpret_cast<uv_write_t*>(req), this->WriteStream, &req->buf, 1, on_write); } @@ -156,13 +155,11 @@ bool cmConnection::OnServeStart(std::string* errString) bool cmEventBasedConnection::OnConnectionShuttingDown() { - if (this->WriteStream) { + if (this->WriteStream.get()) { this->WriteStream->data = nullptr; } - if (this->ReadStream) { - this->ReadStream->data = nullptr; - } - this->ReadStream = nullptr; - this->WriteStream = nullptr; + + WriteStream.reset(); + return true; } diff --git a/Source/cmConnection.h b/Source/cmConnection.h index ddb7744..ce2d2dc 100644 --- a/Source/cmConnection.h +++ b/Source/cmConnection.h @@ -5,6 +5,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmUVHandlePtr.h" #include "cm_uv.h" #include <cstddef> @@ -107,8 +108,6 @@ public: bool OnConnectionShuttingDown() override; virtual void OnDisconnect(int errorCode); - uv_stream_t* ReadStream = nullptr; - uv_stream_t* WriteStream = nullptr; static void on_close(uv_handle_t* handle); @@ -119,6 +118,8 @@ public: } protected: + cm::uv_stream_ptr WriteStream; + std::string RawReadBuffer; std::unique_ptr<cmConnectionBufferStrategy> BufferStrategy; diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 76fc8f1..edce330 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -642,6 +642,13 @@ void cmExtraCodeBlocksGenerator::AppendTarget( // Translate the cmake compiler id into the CodeBlocks compiler id std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf) { + // allow the user to overwrite the detected compiler + std::string userCompiler = + mf->GetSafeDefinition("CMAKE_CODEBLOCKS_COMPILER_ID"); + if (!userCompiler.empty()) { + return userCompiler; + } + // figure out which language to use // for now care only for C, C++, and Fortran diff --git a/Source/cmExtraSublimeTextGenerator.cxx b/Source/cmExtraSublimeTextGenerator.cxx index 3d72ae3..bd1b6bb 100644 --- a/Source/cmExtraSublimeTextGenerator.cxx +++ b/Source/cmExtraSublimeTextGenerator.cxx @@ -362,9 +362,8 @@ std::string cmExtraSublimeTextGenerator::ComputeFlagsForObject( // Add source file specific flags. if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - const char* processed = ge.Parse(cflags)->Evaluate(lg, config); - lg->AppendFlags(flags, processed); + cmGeneratorExpressionInterpreter genexInterpreter(lg, gtgt, config); + lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags)); } return flags; @@ -380,6 +379,7 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( cmMakefile* makefile = lg->GetMakefile(); const std::string& language = source->GetLanguage(); const std::string& config = makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); + cmGeneratorExpressionInterpreter genexInterpreter(lg, target, config); // Add the export symbol definition for shared library objects. if (const char* exportMacro = target->GetExportMacro()) { @@ -388,11 +388,14 @@ std::string cmExtraSublimeTextGenerator::ComputeDefines( // Add preprocessor definitions for this target and configuration. lg->AddCompileDefinitions(defines, target, config, language); - lg->AppendDefines(defines, source->GetProperty("COMPILE_DEFINITIONS")); - { - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += cmSystemTools::UpperCase(config); - lg->AppendDefines(defines, source->GetProperty(defPropName)); + if (const char* compile_defs = source->GetProperty("COMPILE_DEFINITIONS")) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(compile_defs)); + } + + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += cmSystemTools::UpperCase(config); + if (const char* config_compile_defs = source->GetProperty(defPropName)) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(config_compile_defs)); } std::string definesString; diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h index cface0d..611fbf8 100644 --- a/Source/cmGeneratorExpression.h +++ b/Source/cmGeneratorExpression.h @@ -153,4 +153,54 @@ private: bool EvaluateForBuildsystem; }; +class cmGeneratorExpressionInterpreter +{ + CM_DISABLE_COPY(cmGeneratorExpressionInterpreter) + +public: + cmGeneratorExpressionInterpreter(cmLocalGenerator* localGenerator, + cmGeneratorTarget* generatorTarget, + const std::string& config) + : LocalGenerator(localGenerator) + , GeneratorTarget(generatorTarget) + , Config(config) + { + } + + const char* Evaluate(const char* expression) + { + this->CompiledGeneratorExpression = + this->GeneratorExpression.Parse(expression); + + return this->CompiledGeneratorExpression->Evaluate( + this->LocalGenerator, this->Config, false, this->GeneratorTarget); + } + const char* Evaluate(const std::string& expression) + { + return this->Evaluate(expression.c_str()); + } + +protected: + cmGeneratorExpression& GetGeneratorExpression() + { + return this->GeneratorExpression; + } + + cmCompiledGeneratorExpression& GetCompiledGeneratorExpression() + { + return *(this->CompiledGeneratorExpression); + } + + cmLocalGenerator* GetLocalGenerator() { return this->LocalGenerator; } + + cmGeneratorTarget* GetGeneratorTarget() { return this->GeneratorTarget; } + +private: + cmGeneratorExpression GeneratorExpression; + std::unique_ptr<cmCompiledGeneratorExpression> CompiledGeneratorExpression; + cmLocalGenerator* LocalGenerator = nullptr; + cmGeneratorTarget* GeneratorTarget = nullptr; + std::string Config; +}; + #endif diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 99f33e5..92e6a29 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -358,6 +358,10 @@ public: virtual bool IsIPOSupported() const { return false; } + /** Return whether the generator can import external visual studio project + using INCLUDE_EXTERNAL_MSPROJECT */ + virtual bool IsIncludeExternalMSProjectSupported() const { return false; } + /** Return whether the generator should use EFFECTIVE_PLATFORM_NAME. This is relevant for mixed macOS and iOS builds. */ virtual bool UseEffectivePlatformName(cmMakefile*) const { return false; } diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 55a6813..f4fc3cf 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -101,6 +101,8 @@ public: /** Return true if building for Windows CE */ virtual bool TargetsWindowsCE() const { return false; } + bool IsIncludeExternalMSProjectSupported() const override { return true; } + class TargetSet : public std::set<cmGeneratorTarget const*> { }; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index c376c8d..bbf4175 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -676,9 +676,51 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath( return buildFile; } +class XCodeGeneratorExpressionInterpreter + : public cmGeneratorExpressionInterpreter +{ + CM_DISABLE_COPY(XCodeGeneratorExpressionInterpreter) + +public: + XCodeGeneratorExpressionInterpreter(cmSourceFile* sourceFile, + cmLocalGenerator* localGenerator, + cmGeneratorTarget* generatorTarget) + : cmGeneratorExpressionInterpreter(localGenerator, generatorTarget, + "NO-PER-CONFIG-SUPPORT-IN-XCODE") + , SourceFile(sourceFile) + { + } + + using cmGeneratorExpressionInterpreter::Evaluate; + + const char* Evaluate(const char* expression, const char* property) + { + const char* processed = this->Evaluate(expression); + if (this->GetCompiledGeneratorExpression() + .GetHadContextSensitiveCondition()) { + std::ostringstream e; + /* clang-format off */ + e << + "Xcode does not support per-config per-source " << property << ":\n" + " " << expression << "\n" + "specified for source:\n" + " " << this->SourceFile->GetFullPath() << "\n"; + /* clang-format on */ + this->GetLocalGenerator()->IssueMessage(cmake::FATAL_ERROR, e.str()); + } + + return processed; + } + +private: + cmSourceFile* SourceFile = nullptr; +}; + cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( cmLocalGenerator* lg, cmSourceFile* sf, cmGeneratorTarget* gtgt) { + XCodeGeneratorExpressionInterpreter genexInterpreter(sf, lg, gtgt); + // Add flags from target and source file properties. std::string flags; const char* srcfmt = sf->GetProperty("Fortran_FORMAT"); @@ -693,30 +735,16 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( break; } if (const char* cflags = sf->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::string configName = "NO-PER-CONFIG-SUPPORT-IN-XCODE"; - std::unique_ptr<cmCompiledGeneratorExpression> compiledExpr = - ge.Parse(cflags); - const char* processed = - compiledExpr->Evaluate(lg, configName, false, gtgt); - if (compiledExpr->GetHadContextSensitiveCondition()) { - std::ostringstream e; - /* clang-format off */ - e << - "Xcode does not support per-config per-source COMPILE_FLAGS:\n" - " " << cflags << "\n" - "specified for source:\n" - " " << sf->GetFullPath() << "\n"; - /* clang-format on */ - lg->IssueMessage(cmake::FATAL_ERROR, e.str()); - } - lg->AppendFlags(flags, processed); + lg->AppendFlags(flags, genexInterpreter.Evaluate(cflags, "COMPILE_FLAGS")); } // Add per-source definitions. BuildObjectListOrString flagsBuild(this, false); - this->AppendDefines(flagsBuild, sf->GetProperty("COMPILE_DEFINITIONS"), - true); + if (const char* compile_defs = sf->GetProperty("COMPILE_DEFINITIONS")) { + this->AppendDefines( + flagsBuild, + genexInterpreter.Evaluate(compile_defs, "COMPILE_DEFINITIONS"), true); + } if (!flagsBuild.IsEmpty()) { if (!flags.empty()) { flags += ' '; diff --git a/Source/cmIncludeExternalMSProjectCommand.cxx b/Source/cmIncludeExternalMSProjectCommand.cxx index bd16b1d..85e8cd3 100644 --- a/Source/cmIncludeExternalMSProjectCommand.cxx +++ b/Source/cmIncludeExternalMSProjectCommand.cxx @@ -3,6 +3,7 @@ #include "cmIncludeExternalMSProjectCommand.h" #ifdef _WIN32 +#include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmStateTypes.h" #include "cmSystemTools.h" @@ -22,7 +23,9 @@ bool cmIncludeExternalMSProjectCommand::InitialPass( } // only compile this for win32 to avoid coverage errors #ifdef _WIN32 - if (this->Makefile->GetDefinition("WIN32")) { + if (this->Makefile->GetDefinition("WIN32") || + this->Makefile->GetGlobalGenerator() + ->IsIncludeExternalMSProjectSupported()) { enum Doing { DoingNone, diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 477ce51..2d969d2 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -207,6 +207,9 @@ void cmLocalNinjaGenerator::WritePools(std::ostream& os) const char* jobpools = this->GetCMakeInstance()->GetState()->GetGlobalProperty("JOB_POOLS"); + if (!jobpools) { + jobpools = this->GetMakefile()->GetDefinition("CMAKE_JOB_POOLS"); + } if (jobpools) { cmGlobalNinjaGenerator::WriteComment( os, "Pools defined by global property JOB_POOLS"); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index f01ed7a..53966cd 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -615,6 +615,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( switch (target->GetType()) { case cmStateEnums::OBJECT_LIBRARY: targetBuilds = false; // no manifest tool for object library + CM_FALLTHROUGH; case cmStateEnums::STATIC_LIBRARY: projectType = "typeStaticLibrary"; configType = "4"; @@ -630,6 +631,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( case cmStateEnums::UTILITY: case cmStateEnums::GLOBAL_TARGET: configType = "10"; + CM_FALLTHROUGH; default: targetBuilds = false; break; @@ -1456,15 +1458,14 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( i != configs.end(); ++i, ++ci) { std::string configUpper = cmSystemTools::UpperCase(*i); cmLVS7GFileConfig fc; + cmGeneratorExpressionInterpreter genexInterpreter(lg, gt, *i); bool needfc = false; if (!objectName.empty()) { fc.ObjectName = objectName; needfc = true; } if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - fc.CompileFlags = cge->Evaluate(lg, *i, false, gt); + fc.CompileFlags = genexInterpreter.Evaluate(cflags); needfc = true; } if (lg->FortranProject) { @@ -1483,13 +1484,13 @@ cmLocalVisualStudio7GeneratorFCInfo::cmLocalVisualStudio7GeneratorFCInfo( } } if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) { - fc.CompileDefs = cdefs; + fc.CompileDefs = genexInterpreter.Evaluate(cdefs); needfc = true; } std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; - if (const char* ccdefs = sf.GetProperty(defPropName.c_str())) { - fc.CompileDefsConfig = ccdefs; + if (const char* ccdefs = sf.GetProperty(defPropName)) { + fc.CompileDefsConfig = genexInterpreter.Evaluate(ccdefs); needfc = true; } diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 7db010c..5e0c582 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -425,6 +425,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( std::string config = this->LocalGenerator->GetConfigName(); std::string configUpper = cmSystemTools::UpperCase(config); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, config); // Add Fortran format flags. if (lang == "Fortran") { @@ -433,10 +435,7 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // Add flags from source file properties. if (const char* cflags = source.GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config, - false, this->GeneratorTarget); + const char* evaluatedFlags = genexInterpreter.Evaluate(cflags); this->LocalGenerator->AppendFlags(flags, evaluatedFlags); *this->FlagFileStream << "# Custom flags: " << relativeObj << "_FLAGS = " << evaluatedFlags << "\n" @@ -448,18 +447,19 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( // Add source-sepcific preprocessor definitions. if (const char* compile_defs = source.GetProperty("COMPILE_DEFINITIONS")) { - this->LocalGenerator->AppendDefines(defines, compile_defs); + const char* evaluatedDefs = genexInterpreter.Evaluate(compile_defs); + this->LocalGenerator->AppendDefines(defines, evaluatedDefs); *this->FlagFileStream << "# Custom defines: " << relativeObj - << "_DEFINES = " << compile_defs << "\n" + << "_DEFINES = " << evaluatedDefs << "\n" << "\n"; } std::string defPropName = "COMPILE_DEFINITIONS_"; defPropName += configUpper; if (const char* config_compile_defs = source.GetProperty(defPropName)) { - this->LocalGenerator->AppendDefines(defines, config_compile_defs); + const char* evaluatedDefs = genexInterpreter.Evaluate(config_compile_defs); + this->LocalGenerator->AppendDefines(defines, evaluatedDefs); *this->FlagFileStream << "# Custom defines: " << relativeObj << "_DEFINES_" - << configUpper << " = " << config_compile_defs - << "\n" + << configUpper << " = " << evaluatedDefs << "\n" << "\n"; } @@ -657,8 +657,8 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } // Maybe insert a compiler launcher like ccache or distcc - if (!compileCommands.empty() && - (lang == "C" || lang == "CXX" || lang == "CUDA")) { + if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || + lang == "Fortran" || lang == "CUDA")) { std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 5805259..1036977 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -136,12 +136,11 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( // Add source file specific flags. if (const char* cflags = source->GetProperty("COMPILE_FLAGS")) { - std::string config = this->LocalGenerator->GetConfigName(); - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(cflags); - const char* evaluatedFlags = cge->Evaluate(this->LocalGenerator, config, - false, this->GeneratorTarget); - this->LocalGenerator->AppendFlags(flags, evaluatedFlags); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, + this->LocalGenerator->GetConfigName()); + this->LocalGenerator->AppendFlags(flags, + genexInterpreter.Evaluate(cflags)); } return flags; @@ -178,13 +177,20 @@ std::string cmNinjaTargetGenerator::ComputeDefines(cmSourceFile const* source, const std::string& language) { std::set<std::string> defines; - this->LocalGenerator->AppendDefines( - defines, source->GetProperty("COMPILE_DEFINITIONS")); - { - std::string defPropName = "COMPILE_DEFINITIONS_"; - defPropName += cmSystemTools::UpperCase(this->GetConfigName()); - this->LocalGenerator->AppendDefines(defines, - source->GetProperty(defPropName)); + const std::string config = this->LocalGenerator->GetConfigName(); + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, config); + + if (const char* compile_defs = source->GetProperty("COMPILE_DEFINITIONS")) { + this->LocalGenerator->AppendDefines( + defines, genexInterpreter.Evaluate(compile_defs)); + } + + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += cmSystemTools::UpperCase(config); + if (const char* config_compile_defs = source->GetProperty(defPropName)) { + this->LocalGenerator->AppendDefines( + defines, genexInterpreter.Evaluate(config_compile_defs)); } std::string definesString = this->GetDefines(language); @@ -647,7 +653,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang) // Maybe insert a compiler launcher like ccache or distcc if (!compileCmds.empty() && - (lang == "C" || lang == "CXX" || lang == "CUDA")) { + (lang == "C" || lang == "CXX" || lang == "Fortran" || lang == "CUDA")) { std::string const clauncher_prop = lang + "_COMPILER_LAUNCHER"; const char* clauncher = this->GeneratorTarget->GetProperty(clauncher_prop); if (clauncher && *clauncher) { diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx index 9e565f6..3dab2f0 100644 --- a/Source/cmPipeConnection.cxx +++ b/Source/cmPipeConnection.cxx @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmPipeConnection.h" +#include <algorithm> + #include "cmServer.h" cmPipeConnection::cmPipeConnection(const std::string& name, @@ -13,39 +15,33 @@ cmPipeConnection::cmPipeConnection(const std::string& name, void cmPipeConnection::Connect(uv_stream_t* server) { - if (this->ClientPipe) { + if (this->WriteStream.get()) { // Accept and close all pipes but the first: - uv_pipe_t* rejectPipe = new uv_pipe_t(); + cm::uv_pipe_ptr rejectPipe; + + rejectPipe.init(*this->Server->GetLoop(), 0); + uv_accept(server, rejectPipe); - uv_pipe_init(this->Server->GetLoop(), rejectPipe, 0); - uv_accept(server, reinterpret_cast<uv_stream_t*>(rejectPipe)); - uv_close(reinterpret_cast<uv_handle_t*>(rejectPipe), - &on_close_delete<uv_pipe_t>); return; } - this->ClientPipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), this->ClientPipe, 0); - this->ClientPipe->data = static_cast<cmEventBasedConnection*>(this); - auto client = reinterpret_cast<uv_stream_t*>(this->ClientPipe); - if (uv_accept(server, client) != 0) { - uv_close(reinterpret_cast<uv_handle_t*>(client), - &on_close_delete<uv_pipe_t>); - this->ClientPipe = nullptr; + cm::uv_pipe_ptr ClientPipe; + ClientPipe.init(*this->Server->GetLoop(), 0, + static_cast<cmEventBasedConnection*>(this)); + + if (uv_accept(server, ClientPipe) != 0) { return; } - this->ReadStream = client; - this->WriteStream = client; - uv_read_start(this->ReadStream, on_alloc_buffer, on_read); + uv_read_start(ClientPipe, on_alloc_buffer, on_read); + WriteStream = std::move(ClientPipe); Server->OnConnected(this); } bool cmPipeConnection::OnServeStart(std::string* errorMessage) { - this->ServerPipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), this->ServerPipe, 0); - this->ServerPipe->data = static_cast<cmEventBasedConnection*>(this); + 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) { @@ -53,8 +49,8 @@ bool cmPipeConnection::OnServeStart(std::string* errorMessage) ": " + uv_err_name(r); return false; } - auto serverStream = reinterpret_cast<uv_stream_t*>(this->ServerPipe); - if ((r = uv_listen(serverStream, 1, on_new_connection)) != 0) { + + 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; @@ -65,18 +61,11 @@ bool cmPipeConnection::OnServeStart(std::string* errorMessage) bool cmPipeConnection::OnConnectionShuttingDown() { - if (this->ClientPipe) { - uv_close(reinterpret_cast<uv_handle_t*>(this->ClientPipe), - &on_close_delete<uv_pipe_t>); + if (this->WriteStream.get()) { this->WriteStream->data = nullptr; } - uv_close(reinterpret_cast<uv_handle_t*>(this->ServerPipe), - &on_close_delete<uv_pipe_t>); - this->ClientPipe = nullptr; - this->ServerPipe = nullptr; - this->WriteStream = nullptr; - this->ReadStream = nullptr; + this->ServerPipe.reset(); return cmEventBasedConnection::OnConnectionShuttingDown(); } diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h index 7b89842..49f9fdf 100644 --- a/Source/cmPipeConnection.h +++ b/Source/cmPipeConnection.h @@ -4,6 +4,7 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmUVHandlePtr.h" #include <string> #include "cmConnection.h" @@ -23,6 +24,5 @@ public: private: const std::string PipeName; - uv_pipe_t* ServerPipe = nullptr; - uv_pipe_t* ClientPipe = nullptr; + cm::uv_pipe_ptr ServerPipe; }; diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index bd692a2..14743de 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -821,40 +821,39 @@ void cmQtAutoGeneratorInitializer::InitCustomTargets() this->Target->Target->AddPreBuildCommand(cc); } else { - // Convert file dependencies std::set to std::vector - std::vector<std::string> autogenDepends(autogenDependFiles.begin(), - autogenDependFiles.end()); - // Add link library target dependencies to the autogen target // dependencies - for (std::string const& config : this->ConfigsList) { - cmLinkImplementationLibraries const* libs = - this->Target->GetLinkImplementationLibraries(config); - if (libs != nullptr) { - for (cmLinkItem const& item : libs->Libraries) { - cmGeneratorTarget const* libTarget = item.Target; - if ((libTarget != nullptr) && - !StaticLibraryCycle(this->Target, libTarget, config)) { - std::string util; - if (this->ConfigsList.size() > 1) { - util += "$<$<CONFIG:"; - util += config; - util += ">:"; - } - util += libTarget->GetName(); - if (this->ConfigsList.size() > 1) { - util += ">"; + { + // add_dependencies/addUtility do not support generator expressions. + // We depend only on the libraries found in all configs therefore. + std::map<cmGeneratorTarget const*, std::size_t> commonTargets; + for (std::string const& config : this->ConfigsList) { + cmLinkImplementationLibraries const* libs = + this->Target->GetLinkImplementationLibraries(config); + if (libs != nullptr) { + for (cmLinkItem const& item : libs->Libraries) { + cmGeneratorTarget const* libTarget = item.Target; + if ((libTarget != nullptr) && + !StaticLibraryCycle(this->Target, libTarget, config)) { + // Increment target config count + commonTargets[libTarget]++; } - autogenDepends.push_back(util); } } } + for (auto const& item : commonTargets) { + if (item.second == this->ConfigsList.size()) { + autogenDependTargets.insert(item.first->Target); + } + } } // Create autogen target cmTarget* autogenTarget = makefile->AddUtilityCommand( this->AutogenTargetName, cmMakefile::TargetOrigin::Generator, true, - this->DirWork.c_str(), /*byproducts=*/autogenProvides, autogenDepends, + this->DirWork.c_str(), /*byproducts=*/autogenProvides, + std::vector<std::string>(autogenDependFiles.begin(), + autogenDependFiles.end()), commandLines, false, autogenComment.c_str()); // Create autogen generator target localGen->AddGeneratorTarget( diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index 9af4c0a..1b04ca2 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -18,17 +18,19 @@ #include <cstdint> #include <iostream> #include <memory> +#include <mutex> #include <utility> void on_signal(uv_signal_t* signal, int signum) { - auto conn = reinterpret_cast<cmServerBase*>(signal->data); + 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); } @@ -58,6 +60,8 @@ cmServer::cmServer(cmConnection* conn, bool supportExperimental) cmServer::~cmServer() { + Close(); + for (cmServerProtocol* p : this->SupportedProtocols) { delete p; } @@ -409,7 +413,7 @@ void cmServer::StartShutDown() static void __start_thread(void* arg) { - auto server = reinterpret_cast<cmServerBase*>(arg); + auto server = static_cast<cmServerBase*>(arg); std::string error; bool success = server->Serve(&error); if (!success || error.empty() == false) { @@ -417,22 +421,19 @@ static void __start_thread(void* arg) } } -static void __shutdownThread(uv_async_t* arg) -{ - auto server = reinterpret_cast<cmServerBase*>(arg->data); - on_walk_to_shutdown(reinterpret_cast<uv_handle_t*>(arg), nullptr); - server->StartShutDown(); -} - bool cmServerBase::StartServeThread() { ServeThreadRunning = true; - uv_async_init(&Loop, &this->ShutdownSignal, __shutdownThread); - this->ShutdownSignal.data = this; 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 @@ -443,14 +444,13 @@ bool cmServerBase::Serve(std::string* errorMessage) errorMessage->clear(); - uv_signal_init(&Loop, &this->SIGINTHandler); - uv_signal_init(&Loop, &this->SIGHUPHandler); + ShutdownSignal.init(Loop, __shutdownThread, this); - this->SIGINTHandler.data = this; - this->SIGHUPHandler.data = this; + SIGINTHandler.init(Loop, this); + SIGHUPHandler.init(Loop, this); - uv_signal_start(&this->SIGINTHandler, &on_signal, SIGINT); - uv_signal_start(&this->SIGHUPHandler, &on_signal, SIGHUP); + SIGINTHandler.start(&on_signal, SIGINT); + SIGHUPHandler.start(&on_signal, SIGHUP); OnServeStart(); @@ -473,7 +473,6 @@ bool cmServerBase::Serve(std::string* errorMessage) return false; } - ServeThreadRunning = false; return true; } @@ -487,18 +486,12 @@ void cmServerBase::OnServeStart() void cmServerBase::StartShutDown() { - if (!uv_is_closing( - reinterpret_cast<const uv_handle_t*>(&this->SIGINTHandler))) { - uv_signal_stop(&this->SIGINTHandler); - } - - if (!uv_is_closing( - reinterpret_cast<const uv_handle_t*>(&this->SIGHUPHandler))) { - uv_signal_stop(&this->SIGHUPHandler); - } + ShutdownSignal.reset(); + SIGINTHandler.reset(); + SIGHUPHandler.reset(); { - cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); for (auto& connection : Connections) { connection->OnConnectionShuttingDown(); } @@ -519,26 +512,33 @@ cmServerBase::cmServerBase(cmConnection* connection) { auto err = uv_loop_init(&Loop); (void)err; + Loop.data = this; assert(err == 0); AddNewConnection(connection); } -cmServerBase::~cmServerBase() +void cmServerBase::Close() { + if (Loop.data) { + if (ServeThreadRunning) { + this->ShutdownSignal.send(); + uv_thread_join(&ServeThread); + } - if (ServeThreadRunning) { - uv_async_send(&this->ShutdownSignal); - uv_thread_join(&ServeThread); + uv_loop_close(&Loop); + Loop.data = nullptr; } - - uv_loop_close(&Loop); +} +cmServerBase::~cmServerBase() +{ + Close(); } void cmServerBase::AddNewConnection(cmConnection* ownedConnection) { { - cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); Connections.emplace_back(ownedConnection); } ownedConnection->SetServer(this); @@ -555,13 +555,13 @@ void cmServerBase::OnDisconnect(cmConnection* pConnection) return m.get() == pConnection; }; { - cm::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); + std::unique_lock<cm::shared_mutex> lock(ConnectionsMutex); Connections.erase( std::remove_if(Connections.begin(), Connections.end(), pred), Connections.end()); } if (Connections.empty()) { - StartShutDown(); + this->ShutdownSignal.send(); } } diff --git a/Source/cmServer.h b/Source/cmServer.h index 6e46f8c..ca37ce2 100644 --- a/Source/cmServer.h +++ b/Source/cmServer.h @@ -8,6 +8,8 @@ #include "cm_thread.hxx" #include "cm_uv.h" +#include "cmUVHandlePtr.h" + #include <memory> // IWYU pragma: keep #include <string> #include <vector> @@ -58,7 +60,7 @@ public: virtual bool OnSignal(int signum); uv_loop_t* GetLoop(); - + void Close(); void OnDisconnect(cmConnection* pConnection); protected: @@ -67,7 +69,7 @@ protected: bool ServeThreadRunning = false; uv_thread_t ServeThread; - uv_async_t ShutdownSignal; + cm::uv_async_ptr ShutdownSignal; #ifndef NDEBUG public: // When the server starts it will mark down it's current thread ID, @@ -80,8 +82,8 @@ protected: uv_loop_t Loop; - uv_signal_t SIGINTHandler; - uv_signal_t SIGHUPHandler; + cm::uv_signal_ptr SIGINTHandler; + cm::uv_signal_ptr SIGHUPHandler; }; class cmServer : public cmServerBase diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx index 44af75f..78c8f06 100644 --- a/Source/cmServerConnection.cxx +++ b/Source/cmServerConnection.cxx @@ -5,6 +5,9 @@ #include "cmConfigure.h" #include "cmServer.h" #include "cmServerDictionary.h" +#include "cm_uv.h" + +#include <algorithm> #ifdef _WIN32 #include "io.h" #else @@ -18,36 +21,34 @@ cmStdIoConnection::cmStdIoConnection( { } -void cmStdIoConnection::SetupStream(uv_stream_t*& stream, int file_id) +cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id) { - assert(stream == nullptr); switch (uv_guess_handle(file_id)) { case UV_TTY: { - auto tty = new uv_tty_t(); - uv_tty_init(this->Server->GetLoop(), tty, file_id, file_id == 0); + 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); - stream = reinterpret_cast<uv_stream_t*>(tty); - break; + return std::move(tty); } case UV_FILE: if (file_id == 0) { - return; + return nullptr; } // Intentional fallthrough; stdin can _not_ be treated as a named // pipe, however stdout can be. CM_FALLTHROUGH; case UV_NAMED_PIPE: { - auto pipe = new uv_pipe_t(); - uv_pipe_init(this->Server->GetLoop(), pipe, 0); + cm::uv_pipe_ptr pipe; + pipe.init(*this->Server->GetLoop(), 0, + static_cast<cmEventBasedConnection*>(this)); uv_pipe_open(pipe, file_id); - stream = reinterpret_cast<uv_stream_t*>(pipe); - break; + return std::move(pipe); } default: assert(false && "Unable to determine stream type"); - return; + return nullptr; } - stream->data = static_cast<cmEventBasedConnection*>(this); } void cmStdIoConnection::SetServer(cmServerBase* s) @@ -57,14 +58,14 @@ void cmStdIoConnection::SetServer(cmServerBase* s) return; } - SetupStream(this->ReadStream, 0); - SetupStream(this->WriteStream, 1); + this->ReadStream = SetupStream(0); + this->WriteStream = SetupStream(1); } void shutdown_connection(uv_prepare_t* prepare) { cmStdIoConnection* connection = - reinterpret_cast<cmStdIoConnection*>(prepare->data); + static_cast<cmStdIoConnection*>(prepare->data); if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(prepare))) { uv_close(reinterpret_cast<uv_handle_t*>(prepare), @@ -76,7 +77,7 @@ void shutdown_connection(uv_prepare_t* prepare) bool cmStdIoConnection::OnServeStart(std::string* pString) { Server->OnConnected(this); - if (this->ReadStream) { + 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]; @@ -94,44 +95,14 @@ bool cmStdIoConnection::OnServeStart(std::string* pString) return cmConnection::OnServeStart(pString); } -void cmStdIoConnection::ShutdownStream(uv_stream_t*& stream) -{ - if (!stream) { - return; - } - switch (stream->type) { - case UV_TTY: { - assert(!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))); - if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))) { - uv_close(reinterpret_cast<uv_handle_t*>(stream), - &on_close_delete<uv_tty_t>); - } - break; - } - case UV_FILE: - case UV_NAMED_PIPE: { - assert(!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))); - if (!uv_is_closing(reinterpret_cast<uv_handle_t*>(stream))) { - uv_close(reinterpret_cast<uv_handle_t*>(stream), - &on_close_delete<uv_pipe_t>); - } - break; - } - default: - assert(false && "Unable to determine stream type"); - } - - stream = nullptr; -} - bool cmStdIoConnection::OnConnectionShuttingDown() { - if (ReadStream) { + if (ReadStream.get()) { uv_read_stop(ReadStream); + ReadStream->data = nullptr; } - ShutdownStream(ReadStream); - ShutdownStream(WriteStream); + this->ReadStream.reset(); cmEventBasedConnection::OnConnectionShuttingDown(); diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h index 4ca908d..a70edb4 100644 --- a/Source/cmServerConnection.h +++ b/Source/cmServerConnection.h @@ -8,7 +8,7 @@ #include "cmConnection.h" #include "cmPipeConnection.h" -#include "cm_uv.h" +#include "cmUVHandlePtr.h" class cmServerBase; @@ -46,8 +46,8 @@ public: bool OnServeStart(std::string* pString) override; private: - void SetupStream(uv_stream_t*& stream, int file_id); - void ShutdownStream(uv_stream_t*& stream); + cm::uv_stream_ptr SetupStream(int file_id); + cm::uv_stream_ptr ReadStream; }; /*** diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h index 62dee11..685542c 100644 --- a/Source/cmServerDictionary.h +++ b/Source/cmServerDictionary.h @@ -97,11 +97,6 @@ static const std::string kCTEST_INFO = "ctestInfo"; static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion"; static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided"; -static const std::string kTARGET_CROSS_REFERENCES_KEY = "crossReferences"; -static const std::string kLINE_NUMBER_KEY = "line"; -static const std::string kBACKTRACE_KEY = "backtrace"; -static const std::string kRELATED_STATEMENTS_KEY = "relatedStatements"; - static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==["; static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index cfac513..ad66467 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -11,7 +11,6 @@ #include "cmInstallGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmLinkLineComputer.h" -#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmProperty.h" @@ -692,6 +691,8 @@ static Json::Value DumpSourceFilesList( std::vector<cmSourceFile*> files; target->GetSourceFiles(files, config); + cmGeneratorExpressionInterpreter genexInterpreter( + target->GetLocalGenerator(), target, config); std::unordered_map<LanguageData, std::vector<std::string>> fileGroups; for (cmSourceFile* file : files) { @@ -703,21 +704,23 @@ static Json::Value DumpSourceFilesList( std::string compileFlags = ld.Flags; if (const char* cflags = file->GetProperty("COMPILE_FLAGS")) { - cmGeneratorExpression ge; - auto cge = ge.Parse(cflags); - const char* processed = - cge->Evaluate(target->GetLocalGenerator(), config); - lg->AppendFlags(compileFlags, processed); + lg->AppendFlags(compileFlags, genexInterpreter.Evaluate(cflags)); } fileData.Flags = compileFlags; fileData.IncludePathList = ld.IncludePathList; std::set<std::string> defines; - lg->AppendDefines(defines, file->GetProperty("COMPILE_DEFINITIONS")); + if (const char* defs = file->GetProperty("COMPILE_DEFINITIONS")) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(defs)); + } + const std::string defPropName = "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - lg->AppendDefines(defines, file->GetProperty(defPropName)); + if (const char* config_defs = file->GetProperty(defPropName)) { + lg->AppendDefines(defines, genexInterpreter.Evaluate(config_defs)); + } + defines.insert(ld.Defines.begin(), ld.Defines.end()); fileData.SetDefines(defines); @@ -740,37 +743,6 @@ static Json::Value DumpSourceFilesList( return result; } -static Json::Value DumpBacktrace(const cmListFileBacktrace& backtrace) -{ - Json::Value result = Json::arrayValue; - - cmListFileBacktrace backtraceCopy = backtrace; - while (!backtraceCopy.Top().FilePath.empty()) { - Json::Value entry = Json::objectValue; - entry[kPATH_KEY] = backtraceCopy.Top().FilePath; - if (backtraceCopy.Top().Line) { - entry[kLINE_NUMBER_KEY] = static_cast<int>(backtraceCopy.Top().Line); - } - if (!backtraceCopy.Top().Name.empty()) { - entry[kNAME_KEY] = backtraceCopy.Top().Name; - } - result.append(entry); - backtraceCopy = backtraceCopy.Pop(); - } - return result; -} - -static void DumpBacktraceRange(Json::Value& result, const std::string& type, - cmBacktraceRange range) -{ - for (auto const& bt : range) { - Json::Value obj = Json::objectValue; - obj[kTYPE_KEY] = type; - obj[kBACKTRACE_KEY] = DumpBacktrace(bt); - result.append(obj); - } -} - static Json::Value DumpCTestInfo(cmTest* testInfo) { Json::Value result = Json::objectValue; @@ -795,9 +767,6 @@ static Json::Value DumpCTestInfo(cmTest* testInfo) } result[kPROPERTIES_KEY] = properties; - // Need backtrace to figure out where this test was originally added - result[kBACKTRACE_KEY] = DumpBacktrace(testInfo->GetBacktrace()); - return result; } @@ -929,22 +898,6 @@ static Json::Value DumpTarget(cmGeneratorTarget* target, result[kINSTALL_PATHS] = installPaths; } - Json::Value crossRefs = Json::objectValue; - crossRefs[kBACKTRACE_KEY] = DumpBacktrace(target->Target->GetBacktrace()); - - Json::Value statements = Json::arrayValue; - DumpBacktraceRange(statements, "target_compile_definitions", - target->Target->GetCompileDefinitionsBacktraces()); - DumpBacktraceRange(statements, "target_include_directories", - target->Target->GetIncludeDirectoriesBacktraces()); - DumpBacktraceRange(statements, "target_compile_options", - target->Target->GetCompileOptionsBacktraces()); - DumpBacktraceRange(statements, "target_link_libraries", - target->Target->GetLinkImplementationBacktraces()); - - crossRefs[kRELATED_STATEMENTS_KEY] = std::move(statements); - result[kTARGET_CROSS_REFERENCES_KEY] = std::move(crossRefs); - if (target->HaveWellDefinedOutputFiles()) { Json::Value artifacts = Json::arrayValue; artifacts.append( diff --git a/Source/cmStandardLexer.h b/Source/cmStandardLexer.h index c9f42e4..b212c7e 100644 --- a/Source/cmStandardLexer.h +++ b/Source/cmStandardLexer.h @@ -3,7 +3,7 @@ #ifndef cmStandardLexer_h #define cmStandardLexer_h -#include "cmConfigure.h" // IWYU pragma: keep +#include "cmsys/Configure.h" // IWYU pragma: keep /* Disable some warnings. */ #if defined(_MSC_VER) diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 693f35f..de23b08 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -239,6 +239,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SetPropertyDefault("COMPILE_PDB_OUTPUT_DIRECTORY", nullptr); this->SetPropertyDefault("Fortran_FORMAT", nullptr); this->SetPropertyDefault("Fortran_MODULE_DIRECTORY", nullptr); + this->SetPropertyDefault("Fortran_COMPILER_LAUNCHER", nullptr); this->SetPropertyDefault("GNUtoMS", nullptr); this->SetPropertyDefault("OSX_ARCHITECTURES", nullptr); this->SetPropertyDefault("IOS_INSTALL_COMBINED", nullptr); diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 37bcb70..97bb0a2 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -25,16 +25,17 @@ const char* cmTargetLinkLibrariesCommand::LinkLibraryTypeNames[3] = { bool cmTargetLinkLibrariesCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - // must have one argument + // Must have at least one argument. if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } - + // Alias targets cannot be on the LHS of this command. if (this->Makefile->IsAlias(args[0])) { this->SetError("can not be used on an ALIAS target."); return false; } + // Lookup the target for which libraries are specified. this->Target = this->Makefile->GetCMakeInstance()->GetGlobalGenerator()->FindTarget( @@ -78,8 +79,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( break; } } - - // now actually print the message + // Now actually print the message. switch (t) { case cmake::AUTHOR_WARNING: this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str()); @@ -94,6 +94,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( return true; } + // OBJECT libraries are not allowed on the LHS of the command. if (this->Target->GetType() == cmStateEnums::OBJECT_LIBRARY) { std::ostringstream e; e << "Object library target \"" << args[0] << "\" " @@ -103,6 +104,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( return true; } + // Having a UTILITY library on the LHS is a bug. if (this->Target->GetType() == cmStateEnums::UTILITY) { std::ostringstream e; const char* modal = nullptr; @@ -129,7 +131,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( } } - // but we might not have any libs after variable expansion + // But we might not have any libs after variable expansion. if (args.size() < 2) { return true; } @@ -142,8 +144,8 @@ bool cmTargetLinkLibrariesCommand::InitialPass( // specification if the keyword is encountered as the first argument. this->CurrentProcessingState = ProcessingLinkLibraries; - // add libraries, note that there is an optional prefix - // of debug and optimized that can be used + // Add libraries, note that there is an optional prefix + // of debug and optimized that can be used. for (unsigned int i = 1; i < args.size(); ++i) { if (args[i] == "LINK_INTERFACE_LIBRARIES") { this->CurrentProcessingState = ProcessingPlainLinkInterface; @@ -160,8 +162,9 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordPublicInterface && this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( - cmake::FATAL_ERROR, "The INTERFACE option must appear as the second " - "argument, just after the target name."); + cmake::FATAL_ERROR, + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " + "argument, just after the target name."); return true; } this->CurrentProcessingState = ProcessingKeywordLinkInterface; @@ -183,7 +186,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, - "The PUBLIC or PRIVATE option must appear as the second " + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " "argument, just after the target name."); return true; } @@ -206,7 +209,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( this->CurrentProcessingState != ProcessingKeywordLinkInterface) { this->Makefile->IssueMessage( cmake::FATAL_ERROR, - "The PUBLIC or PRIVATE option must appear as the second " + "The INTERFACE, PUBLIC or PRIVATE option must appear as the second " "argument, just after the target name."); return true; } @@ -349,12 +352,11 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, // form must be the plain form. const char* existingSig = (sig == cmTarget::KeywordTLLSignature ? "plain" : "keyword"); - e << "The " << existingSig << " signature for target_link_libraries " - "has already been used with the target \"" - << this->Target->GetName() << "\". All uses of " - "target_link_libraries with a target " - << modal << " be either " - "all-keyword or all-plain.\n"; + e << "The " << existingSig << " signature for target_link_libraries has " + "already been used with the target \"" + << this->Target->GetName() + << "\". All uses of target_link_libraries with a target " << modal + << " be either all-keyword or all-plain.\n"; this->Target->GetTllSignatureTraces(e, sig == cmTarget::KeywordTLLSignature ? cmTarget::PlainTLLSignature @@ -366,10 +368,13 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, } } - // Handle normal case first. + // Handle normal case where the command was called with another keyword than + // INTERFACE / LINK_INTERFACE_LIBRARIES or none at all. (The "LINK_LIBRARIES" + // property of the target on the LHS shall be populated.) if (this->CurrentProcessingState != ProcessingKeywordLinkInterface && this->CurrentProcessingState != ProcessingPlainLinkInterface) { + // Assure that the target on the LHS was created in the current directory. cmTarget* t = this->Makefile->FindLocalNonAliasTarget(this->Target->GetName()); if (!t) { @@ -388,92 +393,100 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, << this->Target->GetName() << "\" which is not built in this directory."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - } else { - - cmTarget* tgt = this->Makefile->GetGlobalGenerator()->FindTarget(lib); + return false; + } - if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && - (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && - (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) && - (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) && - !tgt->IsExecutableWithExports()) { - std::ostringstream e; - e << "Target \"" << lib << "\" of type " - << cmState::GetTargetTypeName(tgt->GetType()) - << " may not be linked into another target. " - << "One may link only to STATIC or SHARED libraries, or " - << "to executables with the ENABLE_EXPORTS property set."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - } + cmTarget* tgt = this->Makefile->GetGlobalGenerator()->FindTarget(lib); - this->Target->AddLinkLibrary(*this->Makefile, lib, llt); + if (tgt && (tgt->GetType() != cmStateEnums::STATIC_LIBRARY) && + (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) && + (tgt->GetType() != cmStateEnums::UNKNOWN_LIBRARY) && + (tgt->GetType() != cmStateEnums::INTERFACE_LIBRARY) && + !tgt->IsExecutableWithExports()) { + std::ostringstream e; + e << "Target \"" << lib << "\" of type " + << cmState::GetTargetTypeName(tgt->GetType()) + << " may not be linked into another target. One may link only to " + "INTERFACE, STATIC or SHARED libraries, or to executables with the " + "ENABLE_EXPORTS property set."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } - if (this->CurrentProcessingState == ProcessingLinkLibraries) { - this->Target->AppendProperty( - "INTERFACE_LINK_LIBRARIES", - this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); - return true; - } - if (this->CurrentProcessingState != ProcessingKeywordPublicInterface && - this->CurrentProcessingState != ProcessingPlainPublicInterface) { - if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) { - std::string configLib = - this->Target->GetDebugGeneratorExpressions(lib, llt); - if (cmGeneratorExpression::IsValidTargetName(lib) || - cmGeneratorExpression::Find(lib) != std::string::npos) { - configLib = "$<LINK_ONLY:" + configLib + ">"; - } - this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", - configLib.c_str()); + this->Target->AddLinkLibrary(*this->Makefile, lib, llt); + } + + // Handle (additional) case where the command was called with PRIVATE / + // LINK_PRIVATE and stop its processing. (The "INTERFACE_LINK_LIBRARIES" + // property of the target on the LHS shall only be populated if it is a + // STATIC library.) + if (this->CurrentProcessingState == ProcessingKeywordPrivateInterface || + this->CurrentProcessingState == ProcessingPlainPrivateInterface) { + if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY) { + std::string configLib = + this->Target->GetDebugGeneratorExpressions(lib, llt); + if (cmGeneratorExpression::IsValidTargetName(lib) || + cmGeneratorExpression::Find(lib) != std::string::npos) { + configLib = "$<LINK_ONLY:" + configLib + ">"; } - // Not a 'public' or 'interface' library. Do not add to interface - // property. - return true; + this->Target->AppendProperty("INTERFACE_LINK_LIBRARIES", + configLib.c_str()); } + return true; } + // Handle general case where the command was called with another keyword than + // PRIVATE / LINK_PRIVATE or none at all. (The "INTERFACE_LINK_LIBRARIES" + // property of the target on the LHS shall be populated.) this->Target->AppendProperty( "INTERFACE_LINK_LIBRARIES", this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); + // Stop processing if called without any keyword. + if (this->CurrentProcessingState == ProcessingLinkLibraries) { + return true; + } + // Stop processing if policy CMP0022 is set to NEW. const cmPolicies::PolicyStatus policy22Status = this->Target->GetPolicyStatusCMP0022(); - if (policy22Status != cmPolicies::OLD && policy22Status != cmPolicies::WARN) { return true; } - + // Stop processing if called with an INTERFACE library on the LHS. if (this->Target->GetType() == cmStateEnums::INTERFACE_LIBRARY) { return true; } - // Get the list of configurations considered to be DEBUG. - std::vector<std::string> debugConfigs = - this->Makefile->GetCMakeInstance()->GetDebugConfigs(); - std::string prop; - - // Include this library in the link interface for the target. - if (llt == DEBUG_LibraryType || llt == GENERAL_LibraryType) { - // Put in the DEBUG configuration interfaces. - for (std::string const& dc : debugConfigs) { - prop = "LINK_INTERFACE_LIBRARIES_"; - prop += dc; - this->Target->AppendProperty(prop, lib.c_str()); + // Handle (additional) backward-compatibility case where the command was + // called with PUBLIC / INTERFACE / LINK_PUBLIC / LINK_INTERFACE_LIBRARIES. + // (The policy CMP0022 is not set to NEW.) + { + // Get the list of configurations considered to be DEBUG. + std::vector<std::string> debugConfigs = + this->Makefile->GetCMakeInstance()->GetDebugConfigs(); + std::string prop; + + // Include this library in the link interface for the target. + if (llt == DEBUG_LibraryType || llt == GENERAL_LibraryType) { + // Put in the DEBUG configuration interfaces. + for (std::string const& dc : debugConfigs) { + prop = "LINK_INTERFACE_LIBRARIES_"; + prop += dc; + this->Target->AppendProperty(prop, lib.c_str()); + } } - } - if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) { - // Put in the non-DEBUG configuration interfaces. - this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib.c_str()); - - // Make sure the DEBUG configuration interfaces exist so that the - // general one will not be used as a fall-back. - for (std::string const& dc : debugConfigs) { - prop = "LINK_INTERFACE_LIBRARIES_"; - prop += dc; - if (!this->Target->GetProperty(prop)) { - this->Target->SetProperty(prop, ""); + if (llt == OPTIMIZED_LibraryType || llt == GENERAL_LibraryType) { + // Put in the non-DEBUG configuration interfaces. + this->Target->AppendProperty("LINK_INTERFACE_LIBRARIES", lib.c_str()); + + // Make sure the DEBUG configuration interfaces exist so that the + // general one will not be used as a fall-back. + for (std::string const& dc : debugConfigs) { + prop = "LINK_INTERFACE_LIBRARIES_"; + prop += dc; + if (!this->Target->GetProperty(prop)) { + this->Target->SetProperty(prop, ""); + } } } } diff --git a/Source/cmTargetLinkLibrariesCommand.h b/Source/cmTargetLinkLibrariesCommand.h index f41af49..a2f3ecd 100644 --- a/Source/cmTargetLinkLibrariesCommand.h +++ b/Source/cmTargetLinkLibrariesCommand.h @@ -20,6 +20,9 @@ class cmTarget; * cmTargetLinkLibrariesCommand is used to specify a list of libraries to link * into executable(s) or shared objects. The names of the libraries * should be those defined by the LIBRARY(library) command(s). + * + * Additionally, it allows to propagate usage-requirements (including link + * libraries) from one target into another. */ class cmTargetLinkLibrariesCommand : public cmCommand { diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx index ed9026e..06ce0b1 100644 --- a/Source/cmTargetPropertyComputer.cxx +++ b/Source/cmTargetPropertyComputer.cxx @@ -3,6 +3,7 @@ #include "cmTargetPropertyComputer.h" +#include <cctype> #include <sstream> #include <unordered_set> @@ -49,6 +50,12 @@ bool cmTargetPropertyComputer::WhiteListedInterfaceProperty( if (cmHasLiteralPrefix(prop, "INTERFACE_")) { return true; } + if (cmHasLiteralPrefix(prop, "_")) { + return true; + } + if (std::islower(prop[0])) { + return true; + } static std::unordered_set<std::string> builtIns; if (builtIns.empty()) { builtIns.insert("COMPATIBLE_INTERFACE_BOOL"); diff --git a/Source/cmUVHandlePtr.cxx b/Source/cmUVHandlePtr.cxx new file mode 100644 index 0000000..eb70416 --- /dev/null +++ b/Source/cmUVHandlePtr.cxx @@ -0,0 +1,227 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#define cmUVHandlePtr_cxx +#include "cmUVHandlePtr.h" + +#include <assert.h> +#include <mutex> +#include <stdlib.h> + +#include "cm_uv.h" + +namespace cm { + +static void close_delete(uv_handle_t* h) +{ + free(h); +} + +template <typename T> +static void default_delete(T* type_handle) +{ + auto handle = reinterpret_cast<uv_handle_t*>(type_handle); + if (handle) { + assert(!uv_is_closing(handle)); + if (!uv_is_closing(handle)) { + uv_close(handle, &close_delete); + } + } +} + +/** + * Encapsulates delete logic for a given handle type T + */ +template <typename T> +struct uv_handle_deleter +{ + void operator()(T* type_handle) const { default_delete(type_handle); } +}; + +template <typename T> +void uv_handle_ptr_base_<T>::allocate(void* data) +{ + reset(); + + /* + We use calloc since we know all these types are c structs + and we just want to 0 init them. New would do the same thing; + but casting from uv_handle_t to certain other types -- namely + uv_timer_t -- triggers a cast_align warning on certain systems. + */ + handle.reset(static_cast<T*>(calloc(1, sizeof(T))), uv_handle_deleter<T>()); + handle->data = data; +} + +template <typename T> +void uv_handle_ptr_base_<T>::reset() +{ + handle.reset(); +} + +template <typename T> +uv_handle_ptr_base_<T>::operator uv_handle_t*() +{ + return reinterpret_cast<uv_handle_t*>(handle.get()); +} + +template <typename T> +T* uv_handle_ptr_base_<T>::operator->() const noexcept +{ + return handle.get(); +} + +template <typename T> +T* uv_handle_ptr_base_<T>::get() const +{ + return handle.get(); +} + +template <typename T> +uv_handle_ptr_<T>::operator T*() const +{ + return this->handle.get(); +} + +#ifdef CMAKE_BUILD_WITH_CMAKE +template <> +struct uv_handle_deleter<uv_async_t> +{ + /*** + * Wile uv_async_send is itself thread-safe, there are + * no strong guarantees that close hasn't already been + * called on the handle; and that it might be deleted + * as the send call goes through. This mutex guards + * against that. + * + * The shared_ptr here is to allow for copy construction + * which is mandated by the standard for Deleter on + * shared_ptrs. + */ + std::shared_ptr<std::mutex> handleMutex; + + uv_handle_deleter() + : handleMutex(std::make_shared<std::mutex>()) + { + } + + void operator()(uv_async_t* handle) + { + std::lock_guard<std::mutex> lock(*handleMutex); + default_delete(handle); + } +}; + +void uv_async_ptr::send() +{ + auto deleter = std::get_deleter<uv_handle_deleter<uv_async_t>>(this->handle); + assert(deleter); + + std::lock_guard<std::mutex> lock(*deleter->handleMutex); + if (this->handle) { + uv_async_send(*this); + } +} + +int uv_async_ptr::init(uv_loop_t& loop, uv_async_cb async_cb, void* data) +{ + allocate(data); + return uv_async_init(&loop, handle.get(), async_cb); +} +#endif + +template <> +struct uv_handle_deleter<uv_signal_t> +{ + void operator()(uv_signal_t* handle) const + { + if (handle) { + uv_signal_stop(handle); + default_delete(handle); + } + } +}; + +int uv_signal_ptr::init(uv_loop_t& loop, void* data) +{ + allocate(data); + return uv_signal_init(&loop, handle.get()); +} + +int uv_signal_ptr::start(uv_signal_cb cb, int signum) +{ + assert(handle); + return uv_signal_start(*this, cb, signum); +} + +void uv_signal_ptr::stop() +{ + if (handle) { + uv_signal_stop(*this); + } +} + +int uv_pipe_ptr::init(uv_loop_t& loop, int ipc, void* data) +{ + allocate(data); + return uv_pipe_init(&loop, *this, ipc); +} + +uv_pipe_ptr::operator uv_stream_t*() const +{ + return reinterpret_cast<uv_stream_t*>(handle.get()); +} + +#ifdef CMAKE_BUILD_WITH_CMAKE +int uv_process_ptr::spawn(uv_loop_t& loop, uv_process_options_t const& options, + void* data) +{ + allocate(data); + return uv_spawn(&loop, *this, &options); +} + +int uv_timer_ptr::init(uv_loop_t& loop, void* data) +{ + allocate(data); + return uv_timer_init(&loop, *this); +} + +int uv_timer_ptr::start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat) +{ + assert(handle); + return uv_timer_start(*this, cb, timeout, repeat); +} + +uv_tty_ptr::operator uv_stream_t*() const +{ + return reinterpret_cast<uv_stream_t*>(handle.get()); +} + +int uv_tty_ptr::init(uv_loop_t& loop, int fd, int readable, void* data) +{ + allocate(data); + return uv_tty_init(&loop, *this, fd, readable); +} +#endif + +template class uv_handle_ptr_base_<uv_handle_t>; + +#define UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(NAME) \ + template class uv_handle_ptr_base_<uv_##NAME##_t>; \ + template class uv_handle_ptr_<uv_##NAME##_t>; + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(signal) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(pipe) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(stream) + +#ifdef CMAKE_BUILD_WITH_CMAKE +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(async) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(process) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(timer) + +UV_HANDLE_PTR_INSTANTIATE_EXPLICIT(tty) +#endif +} diff --git a/Source/cmUVHandlePtr.h b/Source/cmUVHandlePtr.h new file mode 100644 index 0000000..a6ce565 --- /dev/null +++ b/Source/cmUVHandlePtr.h @@ -0,0 +1,222 @@ +/* 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 <algorithm> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <type_traits> + +#include "cm_uv.h" + +#define CM_PERFECT_FWD_CTOR(Class, FwdTo) \ + template <typename... Args> \ + Class(Args&&... args) \ + : FwdTo(std::forward<Args>(args)...) \ + { \ + } + +namespace cm { + +/*** +* RAII class to simplify and insure the safe usage of uv_*_t types. This +* includes making sure resources are properly freed and contains casting +* operators which allow for passing into relevant uv_* functions. +* +*@tparam T actual uv_*_t type represented. +*/ +template <typename T> +class uv_handle_ptr_base_ +{ +protected: + template <typename _T> + friend class uv_handle_ptr_base_; + + /** + * This must be a pointer type since the handle can outlive this class. + * When uv_close is eventually called on the handle, the memory the + * handle inhabits must be valid until the close callback is called + * which can be later on in the loop. + */ + std::shared_ptr<T> handle; + + /** + * Allocate memory for the type and optionally set it's 'data' pointer. + * Protected since this should only be called for an appropriate 'init' + * call. + * + * @param data data pointer to set + */ + void allocate(void* data = nullptr); + +public: + CM_DISABLE_COPY(uv_handle_ptr_base_) + uv_handle_ptr_base_(uv_handle_ptr_base_&&) noexcept; + uv_handle_ptr_base_& operator=(uv_handle_ptr_base_&&) noexcept; + + /** + * This move constructor allows us to move out of a more specialized + * uv type into a less specialized one. The only constraint is that + * the right hand side is castable to T. + * + * This allows you to return uv_handle_ptr or uv_stream_ptr from a function + * that initializes something like uv_pipe_ptr or uv_tcp_ptr and interact + * and clean up after it without caring about the exact type. + */ + template <typename S, typename = typename std::enable_if< + std::is_rvalue_reference<S&&>::value>::type> + uv_handle_ptr_base_(S&& rhs) + { + // This will force a compiler error if rhs doesn't have a casting + // operator to get T* + this->handle = std::shared_ptr<T>(rhs.handle, rhs); + rhs.handle.reset(); + } + + // Dtor and ctor need to be inline defined like this for default ctors and + // dtors to work. + uv_handle_ptr_base_() {} + uv_handle_ptr_base_(std::nullptr_t) {} + ~uv_handle_ptr_base_() { reset(); } + + /** + * Properly close the handle if needed and sets the inner handle to nullptr + */ + void reset(); + + /** + * Allow less verbose calling of uv_handle_* functions + * @return reinterpreted handle + */ + operator uv_handle_t*(); + + T* get() const; + T* operator->() const noexcept; +}; + +template <typename T> +inline uv_handle_ptr_base_<T>::uv_handle_ptr_base_( + uv_handle_ptr_base_<T>&&) noexcept = default; +template <typename T> +inline uv_handle_ptr_base_<T>& uv_handle_ptr_base_<T>::operator=( + uv_handle_ptr_base_<T>&&) noexcept = default; + +/** + * While uv_handle_ptr_base_ only exposes uv_handle_t*, this exposes uv_T_t* + * too. It is broken out like this so we can reuse most of the code for the + * uv_handle_ptr class. + */ +template <typename T> +class uv_handle_ptr_ : public uv_handle_ptr_base_<T> +{ + template <typename _T> + friend class uv_handle_ptr_; + +public: + CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<T>); + + /*** + * Allow less verbose calling of uv_<T> functions + * @return reinterpreted handle + */ + operator T*() const; +}; + +/*** + * This specialization is required to avoid duplicate 'operator uv_handle_t*()' + * declarations + */ +template <> +class uv_handle_ptr_<uv_handle_t> : public uv_handle_ptr_base_<uv_handle_t> +{ +public: + CM_PERFECT_FWD_CTOR(uv_handle_ptr_, uv_handle_ptr_base_<uv_handle_t>); +}; + +class uv_async_ptr : public uv_handle_ptr_<uv_async_t> +{ +public: + CM_PERFECT_FWD_CTOR(uv_async_ptr, uv_handle_ptr_<uv_async_t>); + + int init(uv_loop_t& loop, uv_async_cb async_cb, void* data = nullptr); + + void send(); +}; + +struct uv_signal_ptr : public uv_handle_ptr_<uv_signal_t> +{ + CM_PERFECT_FWD_CTOR(uv_signal_ptr, uv_handle_ptr_<uv_signal_t>); + + int init(uv_loop_t& loop, void* data = nullptr); + + int start(uv_signal_cb cb, int signum); + + void stop(); +}; + +struct uv_pipe_ptr : public uv_handle_ptr_<uv_pipe_t> +{ + CM_PERFECT_FWD_CTOR(uv_pipe_ptr, uv_handle_ptr_<uv_pipe_t>); + + operator uv_stream_t*() const; + + int init(uv_loop_t& loop, int ipc, void* data = nullptr); +}; + +struct uv_process_ptr : public uv_handle_ptr_<uv_process_t> +{ + CM_PERFECT_FWD_CTOR(uv_process_ptr, uv_handle_ptr_<uv_process_t>); + + int spawn(uv_loop_t& loop, uv_process_options_t const& options, + void* data = nullptr); +}; + +struct uv_timer_ptr : public uv_handle_ptr_<uv_timer_t> +{ + CM_PERFECT_FWD_CTOR(uv_timer_ptr, uv_handle_ptr_<uv_timer_t>); + + int init(uv_loop_t& loop, void* data = nullptr); + + int start(uv_timer_cb cb, uint64_t timeout, uint64_t repeat); +}; + +struct uv_tty_ptr : public uv_handle_ptr_<uv_tty_t> +{ + CM_PERFECT_FWD_CTOR(uv_tty_ptr, uv_handle_ptr_<uv_tty_t>); + + operator uv_stream_t*() const; + + int init(uv_loop_t& loop, int fd, int readable, void* data = nullptr); +}; + +typedef uv_handle_ptr_<uv_stream_t> uv_stream_ptr; +typedef uv_handle_ptr_<uv_handle_t> uv_handle_ptr; + +#ifndef cmUVHandlePtr_cxx + +extern template class uv_handle_ptr_base_<uv_handle_t>; + +#define UV_HANDLE_PTR_INSTANTIATE_EXTERN(NAME) \ + extern template class uv_handle_ptr_base_<uv_##NAME##_t>; \ + extern template class uv_handle_ptr_<uv_##NAME##_t>; + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(async) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(signal) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(pipe) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(process) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(stream) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(timer) + +UV_HANDLE_PTR_INSTANTIATE_EXTERN(tty) + +#undef UV_HANDLE_PTR_INSTANTIATE_EXTERN + +#endif +} diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index caeeeb9..8589a96 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -52,6 +52,7 @@ static std::string cmVS10EscapeComment(std::string comment) case '>': /* no break */ case '^': echoable += '^'; /* no break */ + CM_FALLTHROUGH; default: echoable += *c; break; @@ -66,11 +67,14 @@ static bool cmVS10IsTargetsFile(std::string const& path) return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0; } -static std::string computeProjectFileExtension(cmGeneratorTarget const* t) +static std::string computeProjectFileExtension(cmGeneratorTarget const* t, + const std::string& config) { std::string res; res = ".vcxproj"; - if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t)) { + std::string lang = t->GetLinkerLanguage(config); + if (cmGlobalVisualStudioGenerator::TargetIsCSharpOnly(t) || + lang == "CSharp") { res = ".csproj"; } return res; @@ -199,8 +203,8 @@ void cmVisualStudio10TargetGenerator::Generate() this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) { return; } - this->ProjectFileExtension = - computeProjectFileExtension(this->GeneratorTarget); + this->ProjectFileExtension = computeProjectFileExtension( + this->GeneratorTarget, *this->Configurations.begin()); if (this->ProjectFileExtension == ".vcxproj") { this->ProjectType = vcxproj; this->Managed = false; @@ -1393,7 +1397,8 @@ void cmVisualStudio10TargetGenerator::WriteGroups() std::string path = this->LocalGenerator->GetCurrentBinaryDirectory(); path += "/"; path += this->Name; - path += computeProjectFileExtension(this->GeneratorTarget); + path += computeProjectFileExtension(this->GeneratorTarget, + *this->Configurations.begin()); path += ".filters"; cmGeneratedFileStream fout(path.c_str()); fout.SetCopyIfDifferent(true); @@ -2061,14 +2066,15 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( std::string flags; bool configDependentFlags = false; std::string defines; + bool configDependentDefines = false; if (const char* cflags = sf.GetProperty("COMPILE_FLAGS")) { - - if (cmGeneratorExpression::Find(cflags) != std::string::npos) { - configDependentFlags = true; - } + configDependentFlags = + cmGeneratorExpression::Find(cflags) != std::string::npos; flags += cflags; } if (const char* cdefs = sf.GetProperty("COMPILE_DEFINITIONS")) { + configDependentDefines = + cmGeneratorExpression::Find(cdefs) != std::string::npos; defines += cdefs; } std::string lang = @@ -2118,12 +2124,13 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( if (!configDefines.empty()) { configDefines += ";"; } + configDependentDefines |= + cmGeneratorExpression::Find(ccdefs) != std::string::npos; configDefines += ccdefs; } // if we have flags or defines for this config then // use them - if (!flags.empty() || configDependentFlags || !configDefines.empty() || - compileAs || noWinRT) { + if (!flags.empty() || !configDefines.empty() || compileAs || noWinRT) { (*this->BuildFileStream) << firstString; firstString = ""; // only do firstString once hasFlags = true; @@ -2144,6 +2151,8 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } else if (srclang == "CSharp") { flagtable = gg->GetCSharpFlagTable(); } + cmGeneratorExpressionInterpreter genexInterpreter( + this->LocalGenerator, this->GeneratorTarget, *config); cmVisualStudioGeneratorOptions clOptions( this->LocalGenerator, cmVisualStudioGeneratorOptions::Compiler, flagtable, 0, this); @@ -2154,11 +2163,7 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( clOptions.AddFlag("CompileAsWinRT", "false"); } if (configDependentFlags) { - cmGeneratorExpression ge; - std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(flags); - std::string evaluatedFlags = cge->Evaluate( - this->LocalGenerator, *config, false, this->GeneratorTarget); - clOptions.Parse(evaluatedFlags.c_str()); + clOptions.Parse(genexInterpreter.Evaluate(flags)); } else { clOptions.Parse(flags.c_str()); } @@ -2170,7 +2175,11 @@ bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( clOptions.AppendFlag("DisableSpecificWarnings", "%(DisableSpecificWarnings)"); } - clOptions.AddDefines(configDefines.c_str()); + if (configDependentDefines) { + clOptions.AddDefines(genexInterpreter.Evaluate(configDefines)); + } else { + clOptions.AddDefines(configDefines.c_str()); + } clOptions.SetConfiguration((*config).c_str()); clOptions.PrependInheritedString("AdditionalOptions"); clOptions.OutputFlagMap(*this->BuildFileStream, " "); @@ -3670,7 +3679,7 @@ void cmVisualStudio10TargetGenerator::WriteProjectReferences() path = lg->GetCurrentBinaryDirectory(); path += "/"; path += dt->GetName(); - path += computeProjectFileExtension(dt); + path += computeProjectFileExtension(dt, *this->Configurations.begin()); } this->ConvertToWindowsSlash(path); (*this->BuildFileStream) << cmVS10EscapeXML(path) << "\">\n"; diff --git a/Source/cm_thread.hxx b/Source/cm_thread.hxx index b8c25c7..84e6a5c 100644 --- a/Source/cm_thread.hxx +++ b/Source/cm_thread.hxx @@ -7,36 +7,11 @@ #include "cm_uv.h" namespace cm { -class mutex -{ - uv_mutex_t _M_; - -public: - mutex() { uv_mutex_init(&_M_); } - ~mutex() { uv_mutex_destroy(&_M_); } - - void lock() { uv_mutex_lock(&_M_); } - - void unlock() { uv_mutex_unlock(&_M_); } -}; - -template <typename T> -class lock_guard -{ - T& _mutex; - -public: - lock_guard(T& m) - : _mutex(m) - { - _mutex.lock(); - } - ~lock_guard() { _mutex.unlock(); } -}; class shared_mutex { uv_rwlock_t _M_; + CM_DISABLE_COPY(shared_mutex) public: shared_mutex() { uv_rwlock_init(&_M_); } @@ -55,6 +30,7 @@ template <typename T> class shared_lock { T& _mutex; + CM_DISABLE_COPY(shared_lock) public: shared_lock(T& m) @@ -64,15 +40,5 @@ public: } ~shared_lock() { _mutex.unlock_shared(); } }; - -template <typename T> -class unique_lock : public lock_guard<T> -{ -public: - unique_lock(T& m) - : lock_guard<T>(m) - { - } -}; } #endif diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 3d9f65a..b78fbe6 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -270,10 +270,12 @@ static int HandleCppLint(const std::string& runCmd, << "\n"; return 1; } - + std::cerr << "Warning: cpplint diagnostics:\n"; // Output the output from cpplint to stderr std::cerr << stdOut; - return ret; + // always return 0 so the build can continue as cpplint returns non-zero + // for any warning + return 0; } static int HandleCppCheck(const std::string& runCmd, diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 51f4088..351e38d 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -705,9 +705,13 @@ ENDIF() # selected components. Initialize with required components. SET(KWSYS_CLASSES) SET(KWSYS_H_FILES Configure SharedForward) -SET(KWSYS_HXX_FILES Configure String - hashtable hash_fun hash_map hash_set - ) +SET(KWSYS_HXX_FILES Configure String) + +IF(NOT CMake_SOURCE_DIR) + SET(KWSYS_HXX_FILES ${KWSYS_HXX_FILES} + hashtable hash_fun hash_map hash_set + ) +ENDIF() # Add selected C++ classes. SET(cppclasses @@ -1027,12 +1031,13 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) ENDFOREACH() # C++ tests - IF(NOT WATCOM) + IF(NOT WATCOM AND NOT CMake_SOURCE_DIR) SET(KWSYS_CXX_TESTS testHashSTL ) ENDIF() SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testConfigure testSystemTools testCommandLineArguments testCommandLineArguments1 diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in index 1c07a4e..1e67874 100644 --- a/Source/kwsys/Configure.hxx.in +++ b/Source/kwsys/Configure.hxx.in @@ -12,6 +12,31 @@ #define @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H \ @KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H@ +#if defined(__SUNPRO_CC) && __SUNPRO_CC > 0x5130 && defined(__has_attribute) +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_attribute(x) +#elif defined(__has_cpp_attribute) +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) __has_cpp_attribute(x) +#else +#define @KWSYS_NAMESPACE@__has_cpp_attribute(x) 0 +#endif + +#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH +#if __cplusplus >= 201703L && @KWSYS_NAMESPACE@__has_cpp_attribute(fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[fallthrough]] +#elif __cplusplus >= 201103L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(gnu::fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[gnu::fallthrough]] +#elif __cplusplus >= 201103L && \ + @KWSYS_NAMESPACE@__has_cpp_attribute(clang::fallthrough) +#define @KWSYS_NAMESPACE@_FALLTHROUGH [[clang::fallthrough]] +#endif +#endif +#ifndef @KWSYS_NAMESPACE@_FALLTHROUGH +#define @KWSYS_NAMESPACE@_FALLTHROUGH static_cast<void>(0) +#endif + +#undef @KWSYS_NAMESPACE@__has_cpp_attribute + /* If building a C++ file in kwsys itself, give the source file access to the macros without a configured namespace. */ #if defined(KWSYS_NAMESPACE) @@ -22,6 +47,7 @@ #define KWSYS_STL_HAS_WSTRING @KWSYS_NAMESPACE@_STL_HAS_WSTRING #define KWSYS_CXX_HAS_EXT_STDIO_FILEBUF_H \ @KWSYS_NAMESPACE@_CXX_HAS_EXT_STDIO_FILEBUF_H +#define KWSYS_FALLTHROUGH @KWSYS_NAMESPACE@_FALLTHROUGH #endif #endif diff --git a/Source/kwsys/ConsoleBuf.hxx.in b/Source/kwsys/ConsoleBuf.hxx.in index 46d65a8..cf68146 100644 --- a/Source/kwsys/ConsoleBuf.hxx.in +++ b/Source/kwsys/ConsoleBuf.hxx.in @@ -264,6 +264,7 @@ private: if (m_isConsoleInput) { break; } + @KWSYS_NAMESPACE@_FALLTHROUGH; case FILE_TYPE_PIPE: m_activeInputCodepage = input_pipe_codepage; break; @@ -290,6 +291,7 @@ private: if (m_isConsoleOutput) { break; } + @KWSYS_NAMESPACE@_FALLTHROUGH; case FILE_TYPE_PIPE: m_activeOutputCodepage = output_pipe_codepage; break; diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx index 26e84e0..fa3551c 100644 --- a/Source/kwsys/RegularExpression.cxx +++ b/Source/kwsys/RegularExpression.cxx @@ -45,9 +45,9 @@ RegularExpression::RegularExpression(const RegularExpression& rxp) this->program = new char[this->progsize]; // Allocate storage for (ind = this->progsize; ind-- != 0;) // Copy regular expresion this->program[ind] = rxp.program[ind]; - this->startp[0] = rxp.startp[0]; // Copy pointers into last - this->endp[0] = rxp.endp[0]; // Successful "find" operation - this->regmust = rxp.regmust; // Copy field + // Copy pointers into last successful "find" operation + this->regmatch = rxp.regmatch; + this->regmust = rxp.regmust; // Copy field if (rxp.regmust != 0) { char* dum = rxp.program; ind = 0; @@ -78,9 +78,9 @@ RegularExpression& RegularExpression::operator=(const RegularExpression& rxp) this->program = new char[this->progsize]; // Allocate storage for (ind = this->progsize; ind-- != 0;) // Copy regular expresion this->program[ind] = rxp.program[ind]; - this->startp[0] = rxp.startp[0]; // Copy pointers into last - this->endp[0] = rxp.endp[0]; // Successful "find" operation - this->regmust = rxp.regmust; // Copy field + // Copy pointers into last successful "find" operation + this->regmatch = rxp.regmatch; + this->regmust = rxp.regmust; // Copy field if (rxp.regmust != 0) { char* dum = rxp.program; ind = 0; @@ -123,8 +123,9 @@ bool RegularExpression::deep_equal(const RegularExpression& rxp) const while (ind-- != 0) // Else while still characters if (this->program[ind] != rxp.program[ind]) // If regexp are different return false; // Return failure - return (this->startp[0] == rxp.startp[0] && // Else if same start/end ptrs, - this->endp[0] == rxp.endp[0]); // Return true + // Else if same start/end ptrs, return true + return (this->regmatch.start() == rxp.regmatch.start() && + this->regmatch.end() == rxp.regmatch.end()); } // The remaining code in this file is derived from the regular expression code @@ -276,31 +277,35 @@ const unsigned char MAGIC = 0234; ///////////////////////////////////////////////////////////////////////// /* - * Global work variables for compile(). + * Read only utility variables. */ -static const char* regparse; // Input-scan pointer. -static int regnpar; // () count. static char regdummy; -static char* regcode; // Code-emit pointer; ®dummy = don't. -static long regsize; // Code size. +static char* const regdummyptr = ®dummy; /* - * Forward declarations for compile()'s friends. + * Utility class for RegularExpression::compile(). */ -// #ifndef static -// #define static static -// #endif -static char* reg(int, int*); -static char* regbranch(int*); -static char* regpiece(int*); -static char* regatom(int*); -static char* regnode(char); +class RegExpCompile +{ +public: + const char* regparse; // Input-scan pointer. + int regnpar; // () count. + char* regcode; // Code-emit pointer; regdummyptr = don't. + long regsize; // Code size. + + char* reg(int, int*); + char* regbranch(int*); + char* regpiece(int*); + char* regatom(int*); + char* regnode(char); + void regc(char); + void reginsert(char, char*); + static void regtail(char*, const char*); + static void regoptail(char*, const char*); +}; + static const char* regnext(const char*); static char* regnext(char*); -static void regc(char); -static void reginsert(char, char*); -static void regtail(char*, const char*); -static void regoptail(char*, const char*); #ifdef STRCSPN static int strcspn(); @@ -337,19 +342,20 @@ bool RegularExpression::compile(const char* exp) } // First pass: determine size, legality. - regparse = exp; - regnpar = 1; - regsize = 0L; - regcode = ®dummy; - regc(static_cast<char>(MAGIC)); - if (!reg(0, &flags)) { + RegExpCompile comp; + comp.regparse = exp; + comp.regnpar = 1; + comp.regsize = 0L; + comp.regcode = regdummyptr; + comp.regc(static_cast<char>(MAGIC)); + if (!comp.reg(0, &flags)) { printf("RegularExpression::compile(): Error in compile.\n"); return false; } - this->startp[0] = this->endp[0] = this->searchstring = 0; + this->regmatch.clear(); // Small enough for pointer-storage convention? - if (regsize >= 32767L) { // Probably could be 65535L. + if (comp.regsize >= 32767L) { // Probably could be 65535L. // RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big), printf("RegularExpression::compile(): Expression too big.\n"); return false; @@ -360,8 +366,8 @@ bool RegularExpression::compile(const char* exp) if (this->program != 0) delete[] this->program; //#endif - this->program = new char[regsize]; - this->progsize = static_cast<int>(regsize); + this->program = new char[comp.regsize]; + this->progsize = static_cast<int>(comp.regsize); if (this->program == 0) { // RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory), @@ -370,11 +376,11 @@ bool RegularExpression::compile(const char* exp) } // Second pass: emit code. - regparse = exp; - regnpar = 1; - regcode = this->program; - regc(static_cast<char>(MAGIC)); - reg(0, &flags); + comp.regparse = exp; + comp.regnpar = 1; + comp.regcode = this->program; + comp.regc(static_cast<char>(MAGIC)); + comp.reg(0, &flags); // Dig out information for optimizations. this->regstart = '\0'; // Worst-case defaults. @@ -423,7 +429,7 @@ bool RegularExpression::compile(const char* exp) * is a trifle forced, but the need to tie the tails of the branches to what * follows makes it hard to avoid. */ -static char* reg(int paren, int* flagp) +char* RegExpCompile::reg(int paren, int* flagp) { char* ret; char* br; @@ -435,7 +441,7 @@ static char* reg(int paren, int* flagp) // Make an OPEN node, if parenthesized. if (paren) { - if (regnpar >= RegularExpression::NSUBEXP) { + if (regnpar >= RegularExpressionMatch::NSUBEXP) { // RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens), printf("RegularExpression::compile(): Too many parentheses.\n"); return 0; @@ -501,7 +507,7 @@ static char* reg(int paren, int* flagp) * * Implements the concatenation operator. */ -static char* regbranch(int* flagp) +char* RegExpCompile::regbranch(int* flagp) { char* ret; char* chain; @@ -538,7 +544,7 @@ static char* regbranch(int* flagp) * It might seem that this node could be dispensed with entirely, but the * endmarker role is not redundant. */ -static char* regpiece(int* flagp) +char* RegExpCompile::regpiece(int* flagp) { char* ret; char op; @@ -605,7 +611,7 @@ static char* regpiece(int* flagp) * faster to run. Backslashed characters are exceptions, each becoming a * separate node; the code is simpler that way and it's not worth fixing. */ -static char* regatom(int* flagp) +char* RegExpCompile::regatom(int* flagp) { char* ret; int flags; @@ -724,13 +730,13 @@ static char* regatom(int* flagp) - regnode - emit a node Location. */ -static char* regnode(char op) +char* RegExpCompile::regnode(char op) { char* ret; char* ptr; ret = regcode; - if (ret == ®dummy) { + if (ret == regdummyptr) { regsize += 3; return (ret); } @@ -747,9 +753,9 @@ static char* regnode(char op) /* - regc - emit (if appropriate) a byte of code */ -static void regc(char b) +void RegExpCompile::regc(char b) { - if (regcode != ®dummy) + if (regcode != regdummyptr) *regcode++ = b; else regsize++; @@ -760,13 +766,13 @@ static void regc(char b) * * Means relocating the operand. */ -static void reginsert(char op, char* opnd) +void RegExpCompile::reginsert(char op, char* opnd) { char* src; char* dst; char* place; - if (regcode == ®dummy) { + if (regcode == regdummyptr) { regsize += 3; return; } @@ -786,13 +792,13 @@ static void reginsert(char op, char* opnd) /* - regtail - set the next-pointer at the end of a node chain */ -static void regtail(char* p, const char* val) +void RegExpCompile::regtail(char* p, const char* val) { char* scan; char* temp; int offset; - if (p == ®dummy) + if (p == regdummyptr) return; // Find last node. @@ -815,10 +821,10 @@ static void regtail(char* p, const char* val) /* - regoptail - regtail on operand of first argument; nop if operandless */ -static void regoptail(char* p, const char* val) +void RegExpCompile::regoptail(char* p, const char* val) { // "Operandless" and "op != BRANCH" are synonymous in practice. - if (p == 0 || p == ®dummy || OP(p) != BRANCH) + if (p == 0 || p == regdummyptr || OP(p) != BRANCH) return; regtail(OPERAND(p), val); } @@ -830,34 +836,30 @@ static void regoptail(char* p, const char* val) //////////////////////////////////////////////////////////////////////// /* - * Global work variables for find(). + * Utility class for RegularExpression::find(). */ -static const char* reginput; // String-input pointer. -static const char* regbol; // Beginning of input, for ^ check. -static const char** regstartp; // Pointer to startp array. -static const char** regendp; // Ditto for endp. +class RegExpFind +{ +public: + const char* reginput; // String-input pointer. + const char* regbol; // Beginning of input, for ^ check. + const char** regstartp; // Pointer to startp array. + const char** regendp; // Ditto for endp. -/* - * Forwards. - */ -static int regtry(const char*, const char**, const char**, const char*); -static int regmatch(const char*); -static int regrepeat(const char*); - -#ifdef DEBUG -int regnarrate = 0; -void regdump(); -static char* regprop(); -#endif + int regtry(const char*, const char**, const char**, const char*); + int regmatch(const char*); + int regrepeat(const char*); +}; // find -- Matches the regular expression to the given string. // Returns true if found, and sets start and end indexes accordingly. - -bool RegularExpression::find(const char* string) +bool RegularExpression::find(char const* string, + RegularExpressionMatch& rmatch) const { const char* s; - this->searchstring = string; + rmatch.clear(); + rmatch.searchstring = string; if (!this->program) { return false; @@ -868,7 +870,7 @@ bool RegularExpression::find(const char* string) // RAISE Error, SYM(RegularExpression), SYM(Internal_Error), printf( "RegularExpression::find(): Compiled regular expression corrupted.\n"); - return 0; + return false; } // If there is a "must appear" string, look for it. @@ -880,42 +882,45 @@ bool RegularExpression::find(const char* string) s++; } if (s == 0) // Not present. - return (0); + return false; } + RegExpFind regFind; + // Mark beginning of line for ^ . - regbol = string; + regFind.regbol = string; // Simplest case: anchored match need be tried only once. if (this->reganch) - return (regtry(string, this->startp, this->endp, this->program) != 0); + return ( + regFind.regtry(string, rmatch.startp, rmatch.endp, this->program) != 0); // Messy cases: unanchored match. s = string; if (this->regstart != '\0') // We know what char it must start with. while ((s = strchr(s, this->regstart)) != 0) { - if (regtry(s, this->startp, this->endp, this->program)) - return (1); + if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) + return true; s++; } else // We don't -- general case. do { - if (regtry(s, this->startp, this->endp, this->program)) - return (1); + if (regFind.regtry(s, rmatch.startp, rmatch.endp, this->program)) + return true; } while (*s++ != '\0'); // Failure. - return (0); + return false; } /* - regtry - try match at specific point 0 failure, 1 success */ -static int regtry(const char* string, const char** start, const char** end, - const char* prog) +int RegExpFind::regtry(const char* string, const char** start, + const char** end, const char* prog) { int i; const char** sp1; @@ -927,7 +932,7 @@ static int regtry(const char* string, const char** start, const char** end, sp1 = start; ep = end; - for (i = RegularExpression::NSUBEXP; i > 0; i--) { + for (i = RegularExpressionMatch::NSUBEXP; i > 0; i--) { *sp1++ = 0; *ep++ = 0; } @@ -950,7 +955,7 @@ static int regtry(const char* string, const char** start, const char** end, * by recursion. * 0 failure, 1 success */ -static int regmatch(const char* prog) +int RegExpFind::regmatch(const char* prog) { const char* scan; // Current node. const char* next; // Next node. @@ -1129,7 +1134,7 @@ static int regmatch(const char* prog) /* - regrepeat - repeatedly match something simple, report how many */ -static int regrepeat(const char* p) +int RegExpFind::regrepeat(const char* p) { int count = 0; const char* scan; @@ -1176,7 +1181,7 @@ static const char* regnext(const char* p) { int offset; - if (p == ®dummy) + if (p == regdummyptr) return (0); offset = NEXT(p); @@ -1193,7 +1198,7 @@ static char* regnext(char* p) { int offset; - if (p == ®dummy) + if (p == regdummyptr) return (0); offset = NEXT(p); diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in index 763fdab..a3fe72d 100644 --- a/Source/kwsys/RegularExpression.hxx.in +++ b/Source/kwsys/RegularExpression.hxx.in @@ -34,6 +34,115 @@ namespace @KWSYS_NAMESPACE@ { +// Forward declaration +class RegularExpression; + +/** \class RegularExpressionMatch + * \brief Stores the pattern matches of a RegularExpression + */ +class @KWSYS_NAMESPACE@_EXPORT RegularExpressionMatch +{ +public: + RegularExpressionMatch(); + + bool isValid() const; + void clear(); + + std::string::size_type start() const; + std::string::size_type end() const; + std::string::size_type start(int n) const; + std::string::size_type end(int n) const; + std::string match(int n) const; + + enum + { + NSUBEXP = 10 + }; + +private: + friend class RegularExpression; + const char* startp[NSUBEXP]; + const char* endp[NSUBEXP]; + const char* searchstring; +}; + +/** + * \brief Creates an invalid match object + */ +inline RegularExpressionMatch::RegularExpressionMatch() +{ + startp[0] = 0; + endp[0] = 0; + searchstring = 0; +} + +/** + * \brief Returns true if the match pointers are valid + */ +inline bool RegularExpressionMatch::isValid() const +{ + return (this->startp[0] != 0); +} + +/** + * \brief Resets to the (invalid) construction state. + */ +inline void RegularExpressionMatch::clear() +{ + startp[0] = 0; + endp[0] = 0; + searchstring = 0; +} + +/** + * \brief Returns the start index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::start() const +{ + return static_cast<std::string::size_type>(this->startp[0] - searchstring); +} + +/** + * \brief Returns the end index of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end() const +{ + return static_cast<std::string::size_type>(this->endp[0] - searchstring); +} + +/** + * \brief Returns the start index of nth submatch. + * start(0) is the start of the full match. + */ +inline std::string::size_type RegularExpressionMatch::start(int n) const +{ + return static_cast<std::string::size_type>(this->startp[n] - + this->searchstring); +} + +/** + * \brief Returns the end index of nth submatch. + * end(0) is the end of the full match. + */ +inline std::string::size_type RegularExpressionMatch::end(int n) const +{ + return static_cast<std::string::size_type>(this->endp[n] - + this->searchstring); +} + +/** + * \brief Returns the nth submatch as a string. + */ +inline std::string RegularExpressionMatch::match(int n) const +{ + if (this->startp[n] == 0) { + return std::string(); + } else { + return std::string(this->startp[n], static_cast<std::string::size_type>( + this->endp[n] - this->startp[n])); + } +} + /** \class RegularExpression * \brief Implements pattern matching with regular expressions. * @@ -170,6 +279,9 @@ namespace @KWSYS_NAMESPACE@ { * the same as the two characters before the first p encounterd in * the line. It would match "drepa qrepb" in "rep drepa qrepb". * + * All methods of RegularExpression can be called simultaneously from + * different threads but only if each invocation uses an own instance of + * RegularExpression. */ class @KWSYS_NAMESPACE@_EXPORT RegularExpression { @@ -213,9 +325,19 @@ public: /** * Matches the regular expression to the given string. + * Returns true if found, and sets start and end indexes + * in the RegularExpressionMatch instance accordingly. + * + * This method is thread safe when called with different + * RegularExpressionMatch instances. + */ + bool find(char const*, RegularExpressionMatch&) const; + + /** + * Matches the regular expression to the given string. * Returns true if found, and sets start and end indexes accordingly. */ - bool find(char const*); + inline bool find(char const*); /** * Matches the regular expression to the given std string. @@ -224,14 +346,18 @@ public: inline bool find(std::string const&); /** - * Index to start of first find. + * Match indices */ + inline RegularExpressionMatch const& regMatch() const; inline std::string::size_type start() const; + inline std::string::size_type end() const; + inline std::string::size_type start(int n) const; + inline std::string::size_type end(int n) const; /** - * Index to end of first find. + * Match strings */ - inline std::string::size_type end() const; + inline std::string match(int n) const; /** * Copy the given regular expression. @@ -266,29 +392,14 @@ public: */ inline void set_invalid(); - /** - * Destructor. - */ - // awf added - std::string::size_type start(int n) const; - std::string::size_type end(int n) const; - std::string match(int n) const; - - enum - { - NSUBEXP = 10 - }; - private: - const char* startp[NSUBEXP]; - const char* endp[NSUBEXP]; + RegularExpressionMatch regmatch; char regstart; // Internal use only char reganch; // Internal use only const char* regmust; // Internal use only std::string::size_type regmlen; // Internal use only char* program; int progsize; - const char* searchstring; }; /** @@ -344,51 +455,42 @@ inline bool RegularExpression::compile(std::string const& s) * Matches the regular expression to the given std string. * Returns true if found, and sets start and end indexes accordingly. */ -inline bool RegularExpression::find(std::string const& s) +inline bool RegularExpression::find(const char* s) { - return this->find(s.c_str()); + return this->find(s, this->regmatch); } /** - * Set the start position for the regular expression. + * Matches the regular expression to the given std string. + * Returns true if found, and sets start and end indexes accordingly. */ -inline std::string::size_type RegularExpression::start() const +inline bool RegularExpression::find(std::string const& s) { - return static_cast<std::string::size_type>(this->startp[0] - searchstring); + return this->find(s.c_str()); } /** - * Returns the start/end index of the last item found. + * Returns the internal match object */ -inline std::string::size_type RegularExpression::end() const +inline RegularExpressionMatch const& RegularExpression::regMatch() const { - return static_cast<std::string::size_type>(this->endp[0] - searchstring); + return this->regmatch; } /** - * Returns true if two regular expressions have different - * compiled program for pattern matching. + * Returns the start index of the full match. */ -inline bool RegularExpression::operator!=(const RegularExpression& r) const +inline std::string::size_type RegularExpression::start() const { - return (!(*this == r)); + return regmatch.start(); } /** - * Returns true if a valid regular expression is compiled - * and ready for pattern matching. + * Returns the end index of the full match. */ -inline bool RegularExpression::is_valid() const -{ - return (this->program != 0); -} - -inline void RegularExpression::set_invalid() +inline std::string::size_type RegularExpression::end() const { - //#ifndef _WIN32 - delete[] this->program; - //#endif - this->program = 0; + return regmatch.end(); } /** @@ -396,7 +498,7 @@ inline void RegularExpression::set_invalid() */ inline std::string::size_type RegularExpression::start(int n) const { - return static_cast<std::string::size_type>(this->startp[n] - searchstring); + return regmatch.start(n); } /** @@ -404,7 +506,7 @@ inline std::string::size_type RegularExpression::start(int n) const */ inline std::string::size_type RegularExpression::end(int n) const { - return static_cast<std::string::size_type>(this->endp[n] - searchstring); + return regmatch.end(n); } /** @@ -412,12 +514,33 @@ inline std::string::size_type RegularExpression::end(int n) const */ inline std::string RegularExpression::match(int n) const { - if (this->startp[n] == 0) { - return std::string(""); - } else { - return std::string(this->startp[n], static_cast<std::string::size_type>( - this->endp[n] - this->startp[n])); - } + return regmatch.match(n); +} + +/** + * Returns true if two regular expressions have different + * compiled program for pattern matching. + */ +inline bool RegularExpression::operator!=(const RegularExpression& r) const +{ + return (!(*this == r)); +} + +/** + * Returns true if a valid regular expression is compiled + * and ready for pattern matching. + */ +inline bool RegularExpression::is_valid() const +{ + return (this->program != 0); +} + +inline void RegularExpression::set_invalid() +{ + //#ifndef _WIN32 + delete[] this->program; + //#endif + this->program = 0; } } // namespace @KWSYS_NAMESPACE@ diff --git a/Source/kwsys/hash_map.hxx.in b/Source/kwsys/hash_map.hxx.in index 3f9174f..8c9b81e 100644 --- a/Source/kwsys/hash_map.hxx.in +++ b/Source/kwsys/hash_map.hxx.in @@ -49,7 +49,7 @@ namespace @KWSYS_NAMESPACE@ { // select1st is an extension: it is not part of the standard. template <class T1, class T2> -struct hash_select1st : public std::unary_function<std::pair<T1, T2>, T1> +struct hash_select1st { const T1& operator()(const std::pair<T1, T2>& __x) const { diff --git a/Source/kwsys/hash_set.hxx.in b/Source/kwsys/hash_set.hxx.in index e3a0c6c..5edd367 100644 --- a/Source/kwsys/hash_set.hxx.in +++ b/Source/kwsys/hash_set.hxx.in @@ -49,7 +49,7 @@ namespace @KWSYS_NAMESPACE@ { // identity is an extension: it is not part of the standard. template <class _Tp> -struct _Identity : public std::unary_function<_Tp, _Tp> +struct _Identity { const _Tp& operator()(const _Tp& __x) const { return __x; } }; diff --git a/Source/kwsys/hashtable.hxx.in b/Source/kwsys/hashtable.hxx.in index dd92cb9..e962f17 100644 --- a/Source/kwsys/hashtable.hxx.in +++ b/Source/kwsys/hashtable.hxx.in @@ -35,13 +35,12 @@ #include <@KWSYS_NAMESPACE@/Configure.hxx> -#include <algorithm> // lower_bound -#include <functional> // unary_function -#include <iterator> // iterator_traits -#include <memory> // allocator -#include <stddef.h> // size_t -#include <utility> // pair -#include <vector> // vector +#include <algorithm> // lower_bound +#include <iterator> // iterator_traits +#include <memory> // allocator +#include <stddef.h> // size_t +#include <utility> // pair +#include <vector> // vector #if defined(_MSC_VER) #pragma warning(push) diff --git a/Source/kwsys/testConfigure.cxx b/Source/kwsys/testConfigure.cxx new file mode 100644 index 0000000..916dcc1 --- /dev/null +++ b/Source/kwsys/testConfigure.cxx @@ -0,0 +1,30 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying +file Copyright.txt or https://cmake.org/licensing#kwsys for details. */ +#include "kwsysPrivate.h" +#include KWSYS_HEADER(Configure.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +#include "Configure.hxx.in" +#endif + +static bool testFallthrough(int n) +{ + int r = 0; + switch (n) { + case 1: + ++r; + KWSYS_FALLTHROUGH; + default: + ++r; + } + return r == 2; +} + +int testConfigure(int, char* []) +{ + bool res = true; + res = testFallthrough(1) && res; + return res ? 0 : 1; +} |