diff options
Diffstat (limited to 'Source')
23 files changed, 636 insertions, 237 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 310ffeb..1be424a 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -336,6 +336,7 @@ set(SRCS cmInstallTargetGenerator.cxx cmInstallDirectoryGenerator.h cmInstallDirectoryGenerator.cxx + cmJSONHelpers.h cmLDConfigLDConfigTool.cxx cmLDConfigLDConfigTool.h cmLDConfigTool.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 24976ad..835b785 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 18) -set(CMake_VERSION_PATCH 20200908) +set(CMake_VERSION_PATCH 20200910) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CTest/cmCTestResourceSpec.cxx b/Source/CTest/cmCTestResourceSpec.cxx index 21c97de..101dc2c 100644 --- a/Source/CTest/cmCTestResourceSpec.cxx +++ b/Source/CTest/cmCTestResourceSpec.cxx @@ -2,19 +2,140 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestResourceSpec.h" +#include <functional> #include <map> #include <string> #include <utility> #include <vector> +#include <cmext/string_view> + #include <cm3p/json/reader.h> #include <cm3p/json/value.h> #include "cmsys/FStream.hxx" #include "cmsys/RegularExpression.hxx" -static const cmsys::RegularExpression IdentifierRegex{ "^[a-z_][a-z0-9_]*$" }; -static const cmsys::RegularExpression IdRegex{ "^[a-z0-9_]+$" }; +#include "cmJSONHelpers.h" + +namespace { +const cmsys::RegularExpression IdentifierRegex{ "^[a-z_][a-z0-9_]*$" }; +const cmsys::RegularExpression IdRegex{ "^[a-z0-9_]+$" }; + +struct Version +{ + int Major = 1; + int Minor = 0; +}; + +struct TopVersion +{ + struct Version Version; +}; + +auto const VersionFieldHelper = + cmJSONIntHelper<cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_VERSION); + +auto const VersionHelper = + cmJSONRequiredHelper<Version, cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::NO_VERSION, + cmJSONObjectHelper<Version, cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_VERSION) + .Bind("major"_s, &Version::Major, VersionFieldHelper) + .Bind("minor"_s, &Version::Minor, VersionFieldHelper)); + +auto const RootVersionHelper = + cmJSONObjectHelper<TopVersion, cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_ROOT) + .Bind("version"_s, &TopVersion::Version, VersionHelper, false); + +cmCTestResourceSpec::ReadFileResult ResourceIdHelper(std::string& out, + const Json::Value* value) +{ + auto result = cmJSONStringHelper( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE)(out, value); + if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) { + return result; + } + cmsys::RegularExpressionMatch match; + if (!IdRegex.find(out.c_str(), match)) { + return cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE; + } + return cmCTestResourceSpec::ReadFileResult::READ_OK; +} + +auto const ResourceHelper = + cmJSONObjectHelper<cmCTestResourceSpec::Resource, + cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE) + .Bind("id"_s, &cmCTestResourceSpec::Resource::Id, ResourceIdHelper) + .Bind("slots"_s, &cmCTestResourceSpec::Resource::Capacity, + cmJSONUIntHelper( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE, 1), + false); + +auto const ResourceListHelper = + cmJSONVectorHelper<cmCTestResourceSpec::Resource, + cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_RESOURCE_TYPE, + ResourceHelper); + +auto const ResourceMapHelper = + cmJSONMapFilterHelper<std::vector<cmCTestResourceSpec::Resource>, + cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC, + ResourceListHelper, [](const std::string& key) -> bool { + cmsys::RegularExpressionMatch match; + return IdentifierRegex.find(key.c_str(), match); + }); + +auto const SocketSetHelper = cmJSONVectorHelper< + std::map<std::string, std::vector<cmCTestResourceSpec::Resource>>>( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC, ResourceMapHelper); + +cmCTestResourceSpec::ReadFileResult SocketHelper( + cmCTestResourceSpec::Socket& out, const Json::Value* value) +{ + std::vector< + std::map<std::string, std::vector<cmCTestResourceSpec::Resource>>> + sockets; + cmCTestResourceSpec::ReadFileResult result = SocketSetHelper(sockets, value); + if (result != cmCTestResourceSpec::ReadFileResult::READ_OK) { + return result; + } + if (sockets.size() > 1) { + return cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC; + } + if (sockets.empty()) { + out.Resources.clear(); + } else { + out.Resources = std::move(sockets[0]); + } + return cmCTestResourceSpec::ReadFileResult::READ_OK; +} + +auto const LocalRequiredHelper = + cmJSONRequiredHelper<cmCTestResourceSpec::Socket, + cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::INVALID_SOCKET_SPEC, SocketHelper); + +auto const RootHelper = + cmJSONObjectHelper<cmCTestResourceSpec, cmCTestResourceSpec::ReadFileResult>( + cmCTestResourceSpec::ReadFileResult::READ_OK, + cmCTestResourceSpec::ReadFileResult::INVALID_ROOT) + .Bind("local", &cmCTestResourceSpec::LocalSocket, LocalRequiredHelper, + false); +} cmCTestResourceSpec::ReadFileResult cmCTestResourceSpec::ReadFromJSONFile( const std::string& filename) @@ -30,99 +151,17 @@ cmCTestResourceSpec::ReadFileResult cmCTestResourceSpec::ReadFromJSONFile( return ReadFileResult::JSON_PARSE_ERROR; } - if (!root.isObject()) { - return ReadFileResult::INVALID_ROOT; - } - - int majorVersion = 1; - int minorVersion = 0; - if (root.isMember("version")) { - auto const& version = root["version"]; - if (version.isObject()) { - if (!version.isMember("major") || !version.isMember("minor")) { - return ReadFileResult::INVALID_VERSION; - } - auto const& major = version["major"]; - auto const& minor = version["minor"]; - if (!major.isInt() || !minor.isInt()) { - return ReadFileResult::INVALID_VERSION; - } - majorVersion = major.asInt(); - minorVersion = minor.asInt(); - } else { - return ReadFileResult::INVALID_VERSION; - } - } else { - return ReadFileResult::NO_VERSION; + TopVersion version; + ReadFileResult result; + if ((result = RootVersionHelper(version, &root)) != + ReadFileResult::READ_OK) { + return result; } - - if (majorVersion != 1 || minorVersion != 0) { + if (version.Version.Major != 1 || version.Version.Minor != 0) { return ReadFileResult::UNSUPPORTED_VERSION; } - auto const& local = root["local"]; - if (!local.isArray()) { - return ReadFileResult::INVALID_SOCKET_SPEC; - } - if (local.size() > 1) { - return ReadFileResult::INVALID_SOCKET_SPEC; - } - - if (local.empty()) { - this->LocalSocket.Resources.clear(); - return ReadFileResult::READ_OK; - } - - auto const& localSocket = local[0]; - if (!localSocket.isObject()) { - return ReadFileResult::INVALID_SOCKET_SPEC; - } - std::map<std::string, std::vector<cmCTestResourceSpec::Resource>> resources; - cmsys::RegularExpressionMatch match; - for (auto const& key : localSocket.getMemberNames()) { - if (IdentifierRegex.find(key.c_str(), match)) { - auto const& value = localSocket[key]; - auto& r = resources[key]; - if (value.isArray()) { - for (auto const& item : value) { - if (item.isObject()) { - cmCTestResourceSpec::Resource resource; - - if (!item.isMember("id")) { - return ReadFileResult::INVALID_RESOURCE; - } - auto const& id = item["id"]; - if (!id.isString()) { - return ReadFileResult::INVALID_RESOURCE; - } - resource.Id = id.asString(); - if (!IdRegex.find(resource.Id.c_str(), match)) { - return ReadFileResult::INVALID_RESOURCE; - } - - if (item.isMember("slots")) { - auto const& capacity = item["slots"]; - if (!capacity.isConvertibleTo(Json::uintValue)) { - return ReadFileResult::INVALID_RESOURCE; - } - resource.Capacity = capacity.asUInt(); - } else { - resource.Capacity = 1; - } - - r.push_back(resource); - } else { - return ReadFileResult::INVALID_RESOURCE; - } - } - } else { - return ReadFileResult::INVALID_RESOURCE_TYPE; - } - } - } - - this->LocalSocket.Resources = std::move(resources); - return ReadFileResult::READ_OK; + return RootHelper(*this, &root); } const char* cmCTestResourceSpec::ResultToString(ReadFileResult result) diff --git a/Source/CTest/cmCTestResourceSpec.h b/Source/CTest/cmCTestResourceSpec.h index 1aa279b..72628a3 100644 --- a/Source/CTest/cmCTestResourceSpec.h +++ b/Source/CTest/cmCTestResourceSpec.h @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include "cmConfigure.h" // IWYU pragma: keep + #include <map> #include <string> #include <vector> diff --git a/Source/LexerParser/cmCommandArgumentLexer.cxx b/Source/LexerParser/cmCommandArgumentLexer.cxx index 5879912..46220ff 100644 --- a/Source/LexerParser/cmCommandArgumentLexer.cxx +++ b/Source/LexerParser/cmCommandArgumentLexer.cxx @@ -653,7 +653,7 @@ This file must be translated to C++ and modified to build everywhere. Run flex >= 2.6 like this: - flex --nounistd -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l + flex --nounistd --never-interactive --batch -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l Modify cmCommandArgumentLexer.cxx: - remove trailing whitespace: sed -i 's/\s*$//' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx @@ -668,10 +668,7 @@ Modify cmCommandArgumentLexer.cxx: #include "cmCommandArgumentParserHelper.h" -/* Replace the lexer input function. */ -#undef YY_INPUT -#define YY_INPUT(buf, result, max_size) \ - do { result = yyextra->LexInput(buf, max_size); } while (0) +#define YY_USER_ACTION yyextra->UpdateInputPosition(yyleng); /* Include the set of tokens from the parser. */ #include "cmCommandArgumentParserTokens.h" @@ -967,16 +964,12 @@ yy_match: yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 41 ); + while ( yy_current_state != 29 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; yy_find_action: yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - yy_act = yy_accept[yy_current_state]; - } YY_DO_BEFORE_ACTION; @@ -1173,7 +1166,8 @@ case YY_STATE_EOF(NOESCAPES): else { - yy_cp = yyg->yy_c_buf_p; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; } } @@ -1661,7 +1655,7 @@ static void yy_load_buffer_state (yyscan_t yyscanner) b->yy_bs_column = 0; } - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + b->yy_is_interactive = 0; errno = oerrno; } diff --git a/Source/LexerParser/cmCommandArgumentLexer.in.l b/Source/LexerParser/cmCommandArgumentLexer.in.l index 010d54b..8ad2335 100644 --- a/Source/LexerParser/cmCommandArgumentLexer.in.l +++ b/Source/LexerParser/cmCommandArgumentLexer.in.l @@ -7,7 +7,7 @@ This file must be translated to C++ and modified to build everywhere. Run flex >= 2.6 like this: - flex --nounistd -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l + flex --nounistd --never-interactive --batch -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l Modify cmCommandArgumentLexer.cxx: - remove trailing whitespace: sed -i 's/\s*$//' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx @@ -22,10 +22,7 @@ Modify cmCommandArgumentLexer.cxx: #include "cmCommandArgumentParserHelper.h" -/* Replace the lexer input function. */ -#undef YY_INPUT -#define YY_INPUT(buf, result, max_size) \ - do { result = yyextra->LexInput(buf, max_size); } while (0) +#define YY_USER_ACTION yyextra->UpdateInputPosition(yyleng); /* Include the set of tokens from the parser. */ #include "cmCommandArgumentParserTokens.h" diff --git a/Source/cmCommandArgumentParserHelper.cxx b/Source/cmCommandArgumentParserHelper.cxx index e07f7f1..e3d014e 100644 --- a/Source/cmCommandArgumentParserHelper.cxx +++ b/Source/cmCommandArgumentParserHelper.cxx @@ -205,23 +205,24 @@ bool cmCommandArgumentParserHelper::HandleEscapeSymbol( void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes); -int cmCommandArgumentParserHelper::ParseString(const char* str, int verb) +int cmCommandArgumentParserHelper::ParseString(std::string const& str, + int verb) { - if (!str) { + if (str.empty()) { return 0; } + this->InputSize = str.size(); this->Verbose = verb; - this->InputBuffer = str; - this->InputBufferPos = 0; - this->CurrentLine = 0; this->Result.clear(); yyscan_t yyscanner; cmCommandArgument_yylex_init(&yyscanner); + auto scanBuf = cmCommandArgument_yy_scan_string(str.c_str(), yyscanner); cmCommandArgument_yyset_extra(this, yyscanner); cmCommandArgument_SetupEscapes(yyscanner, this->NoEscapeMode); int res = cmCommandArgument_yyparse(yyscanner); + cmCommandArgument_yy_delete_buffer(scanBuf, yyscanner); cmCommandArgument_yylex_destroy(yyscanner); if (res != 0) { return 0; @@ -241,25 +242,14 @@ void cmCommandArgumentParserHelper::CleanupParser() this->Variables.clear(); } -int cmCommandArgumentParserHelper::LexInput(char* buf, int maxlen) +void cmCommandArgumentParserHelper::Error(const char* str) { - if (maxlen < 1) { - return 0; + auto pos = this->InputBufferPos; + auto const isEof = (this->InputSize < this->InputBufferPos); + if (!isEof) { + pos -= this->LastTokenLength; } - if (this->InputBufferPos < this->InputBuffer.size()) { - buf[0] = this->InputBuffer[this->InputBufferPos++]; - if (buf[0] == '\n') { - this->CurrentLine++; - } - return (1); - } - buf[0] = '\n'; - return (0); -} -void cmCommandArgumentParserHelper::Error(const char* str) -{ - unsigned long pos = static_cast<unsigned long>(this->InputBufferPos); std::ostringstream ostr; ostr << str << " (" << pos << ")"; this->SetError(ostr.str()); @@ -286,3 +276,9 @@ void cmCommandArgumentParserHelper::SetError(std::string const& msg) this->ErrorString = msg; } } + +void cmCommandArgumentParserHelper::UpdateInputPosition(int const tokenLength) +{ + this->InputBufferPos += tokenLength; + this->LastTokenLength = tokenLength; +} diff --git a/Source/cmCommandArgumentParserHelper.h b/Source/cmCommandArgumentParserHelper.h index 8ff689e..f79ca2c 100644 --- a/Source/cmCommandArgumentParserHelper.h +++ b/Source/cmCommandArgumentParserHelper.h @@ -25,7 +25,7 @@ public: cmCommandArgumentParserHelper& operator=( cmCommandArgumentParserHelper const&) = delete; - int ParseString(const char* str, int verb); + int ParseString(std::string const& str, int verb); // For the lexer: void AllocateParserType(cmCommandArgumentParserHelper::ParserType* pt, @@ -33,7 +33,6 @@ public: bool HandleEscapeSymbol(cmCommandArgumentParserHelper::ParserType* pt, char symbol); - int LexInput(char* buf, int maxlen); void Error(const char* str); // For yacc @@ -46,6 +45,8 @@ public: void SetMakefile(const cmMakefile* mf); + void UpdateInputPosition(int tokenLength); + std::string& GetResult() { return this->Result; } void SetLineFile(long line, const char* file); @@ -57,8 +58,9 @@ public: const char* GetError() { return this->ErrorString.c_str(); } private: - std::string::size_type InputBufferPos; - std::string InputBuffer; + std::string::size_type InputBufferPos{ 1 }; + std::string::size_type LastTokenLength{}; + std::string::size_type InputSize{}; std::vector<char> OutputBuffer; void Print(const char* place, const char* str); @@ -75,7 +77,6 @@ private: std::string ErrorString; const char* FileName; long FileLine; - int CurrentLine; int Verbose; bool EscapeQuotes; bool NoEscapeMode; diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 8021b49..7ada8d8 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -4,7 +4,6 @@ #include <cstdio> #include <cstdlib> -#include <cstring> #include <functional> #include <sstream> #include <utility> @@ -135,7 +134,7 @@ bool cmConditionEvaluator::IsTrue( } //========================================================================= -const char* cmConditionEvaluator::GetDefinitionIfUnquoted( +cmProp cmConditionEvaluator::GetDefinitionIfUnquoted( cmExpandedCommandArgument const& argument) const { if ((this->Policy54Status != cmPolicies::WARN && @@ -162,17 +161,17 @@ const char* cmConditionEvaluator::GetDefinitionIfUnquoted( } } - return cmToCStr(def); + return def; } //========================================================================= -const char* cmConditionEvaluator::GetVariableOrString( +cmProp cmConditionEvaluator::GetVariableOrString( const cmExpandedCommandArgument& argument) const { - const char* def = this->GetDefinitionIfUnquoted(argument); + cmProp def = this->GetDefinitionIfUnquoted(argument); if (!def) { - def = argument.c_str(); + def = &argument.GetValue(); } return def; @@ -232,7 +231,7 @@ bool cmConditionEvaluator::GetBooleanValue( // Check for numbers. if (!arg.empty()) { char* end; - double d = strtod(arg.c_str(), &end); + double d = strtod(arg.GetValue().c_str(), &end); if (*end == '\0') { // The whole string is a number. Use C conversion to bool. return static_cast<bool>(d); @@ -240,7 +239,7 @@ bool cmConditionEvaluator::GetBooleanValue( } // Check definition. - const char* def = this->GetDefinitionIfUnquoted(arg); + cmProp def = this->GetDefinitionIfUnquoted(arg); return !cmIsOff(def); } @@ -257,13 +256,13 @@ bool cmConditionEvaluator::GetBooleanValueOld( if (arg == "1") { return true; } - const char* def = this->GetDefinitionIfUnquoted(arg); + cmProp def = this->GetDefinitionIfUnquoted(arg); return !cmIsOff(def); } // Old GetVariableOrNumber behavior. - const char* def = this->GetDefinitionIfUnquoted(arg); - if (!def && atoi(arg.c_str())) { - def = arg.c_str(); + cmProp def = this->GetDefinitionIfUnquoted(arg); + if (!def && atoi(arg.GetValue().c_str())) { + def = &arg.GetValue(); } return !cmIsOff(def); } @@ -435,36 +434,38 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, this->IncrementArguments(newArgs, argP1, argP2); // does a file exist if (this->IsKeyword(keyEXISTS, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate(cmSystemTools::FileExists(argP1->c_str()), + this->HandlePredicate(cmSystemTools::FileExists(argP1->GetValue()), reducible, arg, newArgs, argP1, argP2); } // does a directory with this name exist if (this->IsKeyword(keyIS_DIRECTORY, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate(cmSystemTools::FileIsDirectory(argP1->c_str()), - reducible, arg, newArgs, argP1, argP2); + this->HandlePredicate( + cmSystemTools::FileIsDirectory(argP1->GetValue()), reducible, arg, + newArgs, argP1, argP2); } // does a symlink with this name exist if (this->IsKeyword(keyIS_SYMLINK, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate(cmSystemTools::FileIsSymlink(argP1->c_str()), + this->HandlePredicate(cmSystemTools::FileIsSymlink(argP1->GetValue()), reducible, arg, newArgs, argP1, argP2); } // is the given path an absolute path ? if (this->IsKeyword(keyIS_ABSOLUTE, *arg) && argP1 != newArgs.end()) { - this->HandlePredicate(cmSystemTools::FileIsFullPath(argP1->c_str()), + this->HandlePredicate(cmSystemTools::FileIsFullPath(argP1->GetValue()), reducible, arg, newArgs, argP1, argP2); } // does a command exist if (this->IsKeyword(keyCOMMAND, *arg) && argP1 != newArgs.end()) { cmState::Command command = - this->Makefile.GetState()->GetCommand(argP1->c_str()); + this->Makefile.GetState()->GetCommand(argP1->GetValue()); this->HandlePredicate(command != nullptr, reducible, arg, newArgs, argP1, argP2); } // does a policy exist if (this->IsKeyword(keyPOLICY, *arg) && argP1 != newArgs.end()) { cmPolicies::PolicyID pid; - this->HandlePredicate(cmPolicies::GetPolicyID(argP1->c_str(), pid), - reducible, arg, newArgs, argP1, argP2); + this->HandlePredicate( + cmPolicies::GetPolicyID(argP1->GetValue().c_str(), pid), reducible, + arg, newArgs, argP1, argP2); } // does a target exist if (this->IsKeyword(keyTARGET, *arg) && argP1 != newArgs.end()) { @@ -476,7 +477,7 @@ bool cmConditionEvaluator::HandleLevel1(cmArgumentList& newArgs, std::string&, if (this->Policy64Status != cmPolicies::OLD && this->Policy64Status != cmPolicies::WARN) { if (this->IsKeyword(keyTEST, *arg) && argP1 != newArgs.end()) { - const cmTest* haveTest = this->Makefile.GetTest(argP1->c_str()); + const cmTest* haveTest = this->Makefile.GetTest(argP1->GetValue()); this->HandlePredicate(haveTest != nullptr, reducible, arg, newArgs, argP1, argP2); } @@ -523,8 +524,8 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, { int reducible; std::string def_buf; - const char* def; - const char* def2; + cmProp def; + cmProp def2; do { reducible = 0; auto arg = newArgs.begin(); @@ -537,14 +538,14 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, IsKeyword(keyMATCHES, *argP1)) { def = this->GetDefinitionIfUnquoted(*arg); if (!def) { - def = arg->c_str(); + def = &arg->GetValue(); } else if (cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_")) { // The string to match is owned by our match result variables. // Move it to our own buffer before clearing them. - def_buf = def; - def = def_buf.c_str(); + def_buf = *def; + def = &def_buf; } - const char* rex = argP2->c_str(); + const std::string& rex = argP2->GetValue(); this->Makefile.ClearMatches(); cmsys::RegularExpression regEntry; if (!regEntry.compile(rex)) { @@ -554,7 +555,7 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, status = MessageType::FATAL_ERROR; return false; } - if (regEntry.find(def)) { + if (regEntry.find(*def)) { this->Makefile.StoreMatches(regEntry); *arg = cmExpandedCommandArgument("1", true); } else { @@ -586,7 +587,8 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, double lhs; double rhs; bool result; - if (sscanf(def, "%lg", &lhs) != 1 || sscanf(def2, "%lg", &rhs) != 1) { + if (sscanf(def->c_str(), "%lg", &lhs) != 1 || + sscanf(def2->c_str(), "%lg", &rhs) != 1) { result = false; } else if (*(argP1) == keyLESS) { result = (lhs < rhs); @@ -610,7 +612,7 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, this->IsKeyword(keySTREQUAL, *argP1))) { def = this->GetVariableOrString(*arg); def2 = this->GetVariableOrString(*argP2); - int val = strcmp(def, def2); + int val = (*def).compare(*def2); bool result; if (*(argP1) == keySTRLESS) { result = (val < 0); @@ -647,7 +649,8 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, } else { // version_equal op = cmSystemTools::OP_EQUAL; } - bool result = cmSystemTools::VersionCompare(op, def, def2); + bool result = + cmSystemTools::VersionCompare(op, def->c_str(), def2->c_str()); this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); } @@ -669,12 +672,11 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList& newArgs, bool result = false; def = this->GetVariableOrString(*arg); - def2 = cmToCStr(this->Makefile.GetDefinition(argP2->GetValue())); + def2 = this->Makefile.GetDefinition(argP2->GetValue()); if (def2) { - std::vector<std::string> list = cmExpandedList(def2, true); - - result = cm::contains(list, def); + std::vector<std::string> list = cmExpandedList(*def2, true); + result = cm::contains(list, *def); } this->HandleBinaryOp(result, reducible, arg, newArgs, argP1, argP2); diff --git a/Source/cmConditionEvaluator.h b/Source/cmConditionEvaluator.h index a1e3829..a4cedff 100644 --- a/Source/cmConditionEvaluator.h +++ b/Source/cmConditionEvaluator.h @@ -12,6 +12,7 @@ #include "cmListFileCache.h" #include "cmMessageType.h" #include "cmPolicies.h" +#include "cmProperty.h" class cmMakefile; @@ -31,11 +32,10 @@ public: private: // Filter the given variable definition based on policy CMP0054. - const char* GetDefinitionIfUnquoted( + cmProp GetDefinitionIfUnquoted( const cmExpandedCommandArgument& argument) const; - const char* GetVariableOrString( - const cmExpandedCommandArgument& argument) const; + cmProp GetVariableOrString(const cmExpandedCommandArgument& argument) const; bool IsKeyword(std::string const& keyword, cmExpandedCommandArgument& argument) const; diff --git a/Source/cmExpandedCommandArgument.cxx b/Source/cmExpandedCommandArgument.cxx index 43f648b..1f14fc4 100644 --- a/Source/cmExpandedCommandArgument.cxx +++ b/Source/cmExpandedCommandArgument.cxx @@ -37,8 +37,3 @@ bool cmExpandedCommandArgument::empty() const { return this->Value.empty(); } - -const char* cmExpandedCommandArgument::c_str() const -{ - return this->Value.c_str(); -} diff --git a/Source/cmExpandedCommandArgument.h b/Source/cmExpandedCommandArgument.h index 50a17a8..1ff6ed1 100644 --- a/Source/cmExpandedCommandArgument.h +++ b/Source/cmExpandedCommandArgument.h @@ -28,8 +28,6 @@ public: bool empty() const; - const char* c_str() const; - private: std::string Value; bool Quoted = false; diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index cdb1492..84639a7 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -28,6 +28,7 @@ #include "cmAlgorithms.h" #include "cmArgumentParser.h" +#include "cmCMakePath.h" #include "cmCryptoHash.h" #include "cmExecutionStatus.h" #include "cmFSPermissions.h" @@ -1234,6 +1235,50 @@ bool HandleInstallCommand(std::vector<std::string> const& args, return installer.Run(args); } +bool HandleRealPathCommand(std::vector<std::string> const& args, + cmExecutionStatus& status) +{ + if (args.size() < 3) { + status.SetError("REAL_PATH requires a path and an output variable"); + return false; + } + + struct Arguments + { + std::string BaseDirectory; + }; + static auto const parser = cmArgumentParser<Arguments>{}.Bind( + "BASE_DIRECTORY"_s, &Arguments::BaseDirectory); + + std::vector<std::string> unparsedArguments; + std::vector<std::string> keywordsMissingValue; + std::vector<std::string> parsedKeywords; + auto arguments = + parser.Parse(cmMakeRange(args).advance(3), &unparsedArguments, + &keywordsMissingValue, &parsedKeywords); + + if (!unparsedArguments.empty()) { + status.SetError("REAL_PATH called with unexpected arguments"); + return false; + } + if (!keywordsMissingValue.empty()) { + status.SetError("BASE_DIRECTORY requires a value"); + return false; + } + + if (parsedKeywords.empty()) { + arguments.BaseDirectory = status.GetMakefile().GetCurrentSourceDirectory(); + } + + cmCMakePath path(args[1]); + path = path.Absolute(arguments.BaseDirectory).Normal(); + auto realPath = cmSystemTools::GetRealPath(path.GenericString()); + + status.GetMakefile().AddDefinition(args[2], realPath); + + return true; +} + bool HandleRelativePathCommand(std::vector<std::string> const& args, cmExecutionStatus& status) { @@ -3360,6 +3405,7 @@ bool cmFileCommand(std::vector<std::string> const& args, { "RPATH_CHECK"_s, HandleRPathCheckCommand }, { "RPATH_REMOVE"_s, HandleRPathRemoveCommand }, { "READ_ELF"_s, HandleReadElfCommand }, + { "REAL_PATH"_s, HandleRealPathCommand }, { "RELATIVE_PATH"_s, HandleRelativePathCommand }, { "TO_CMAKE_PATH"_s, HandleCMakePathCommand }, { "TO_NATIVE_PATH"_s, HandleNativePathCommand }, diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index f8568b3..1bb069f 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -6472,21 +6472,16 @@ bool cmGeneratorTarget::ComputeOutputDir(const std::string& config, // Look for a target property defining the target output directory // based on the target type. std::string targetTypeName = this->GetOutputTargetType(artifact); - const char* propertyName = nullptr; - std::string propertyNameStr = targetTypeName; - if (!propertyNameStr.empty()) { - propertyNameStr += "_OUTPUT_DIRECTORY"; - propertyName = propertyNameStr.c_str(); + std::string propertyName; + if (!targetTypeName.empty()) { + propertyName = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY"); } // Check for a per-configuration output directory target property. std::string configUpper = cmSystemTools::UpperCase(conf); - const char* configProp = nullptr; - std::string configPropStr = targetTypeName; - if (!configPropStr.empty()) { - configPropStr += "_OUTPUT_DIRECTORY_"; - configPropStr += configUpper; - configProp = configPropStr.c_str(); + std::string configProp; + if (!targetTypeName.empty()) { + configProp = cmStrCat(targetTypeName, "_OUTPUT_DIRECTORY_", configUpper); } // Select an output directory. @@ -6547,22 +6542,17 @@ bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind, { // Look for a target property defining the target output directory // based on the target type. - const char* propertyName = nullptr; - std::string propertyNameStr = kind; - if (!propertyNameStr.empty()) { - propertyNameStr += "_OUTPUT_DIRECTORY"; - propertyName = propertyNameStr.c_str(); + std::string propertyName; + if (!kind.empty()) { + propertyName = cmStrCat(kind, "_OUTPUT_DIRECTORY"); } std::string conf = config; // Check for a per-configuration output directory target property. std::string configUpper = cmSystemTools::UpperCase(conf); - const char* configProp = nullptr; - std::string configPropStr = kind; - if (!configPropStr.empty()) { - configPropStr += "_OUTPUT_DIRECTORY_"; - configPropStr += configUpper; - configProp = configPropStr.c_str(); + std::string configProp; + if (!kind.empty()) { + configProp = cmStrCat(kind, "_OUTPUT_DIRECTORY_", configUpper); } // Select an output directory. diff --git a/Source/cmJSONHelpers.h b/Source/cmJSONHelpers.h new file mode 100644 index 0000000..2da2a03 --- /dev/null +++ b/Source/cmJSONHelpers.h @@ -0,0 +1,304 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <algorithm> +#include <cstddef> +#include <functional> +#include <map> +#include <string> +#include <vector> + +#include <cm/optional> +#include <cm/string_view> + +#include <cm3p/json/value.h> + +template <typename T, typename E> +using cmJSONHelper = std::function<E(T& out, const Json::Value* value)>; + +template <typename T, typename E> +class cmJSONObjectHelper +{ +public: + cmJSONObjectHelper(E&& success, E&& fail, bool allowExtra = true); + + template <typename U, typename M, typename F> + cmJSONObjectHelper& Bind(const cm::string_view& name, M U::*member, F func, + bool required = true); + template <typename M, typename F> + cmJSONObjectHelper& Bind(const cm::string_view& name, std::nullptr_t, F func, + bool required = true); + + E operator()(T& out, const Json::Value* value) const; + +private: + // Not a true cmJSONHelper, it just happens to match the signature + using MemberFunction = std::function<E(T& out, const Json::Value* value)>; + struct Member + { + cm::string_view Name; + MemberFunction Function; + bool Required; + }; + std::vector<Member> Members; + bool AnyRequired = false; + E Success; + E Fail; + bool AllowExtra; + + cmJSONObjectHelper& BindPrivate(const cm::string_view& name, + MemberFunction&& func, bool required); +}; + +template <typename T, typename E> +cmJSONObjectHelper<T, E>::cmJSONObjectHelper(E&& success, E&& fail, + bool allowExtra) + : Success(std::move(success)) + , Fail(std::move(fail)) + , AllowExtra(allowExtra) +{ +} + +template <typename T, typename E> +template <typename U, typename M, typename F> +cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind( + const cm::string_view& name, M U::*member, F func, bool required) +{ + return this->BindPrivate( + name, + [func, member](T& out, const Json::Value* value) -> E { + return func(out.*member, value); + }, + required); +} + +template <typename T, typename E> +template <typename M, typename F> +cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::Bind( + const cm::string_view& name, std::nullptr_t, F func, bool required) +{ + return this->BindPrivate(name, + [func](T& /*out*/, const Json::Value* value) -> E { + M dummy; + return func(dummy, value); + }, + required); +} + +template <typename T, typename E> +cmJSONObjectHelper<T, E>& cmJSONObjectHelper<T, E>::BindPrivate( + const cm::string_view& name, MemberFunction&& func, bool required) +{ + Member m; + m.Name = name; + m.Function = std::move(func); + m.Required = required; + this->Members.push_back(std::move(m)); + if (required) { + this->AnyRequired = true; + } + return *this; +} + +template <typename T, typename E> +E cmJSONObjectHelper<T, E>::operator()(T& out, const Json::Value* value) const +{ + if (!value && this->AnyRequired) { + return this->Fail; + } + if (value && !value->isObject()) { + return this->Fail; + } + Json::Value::Members extraFields; + if (value) { + extraFields = value->getMemberNames(); + } + + for (auto const& m : this->Members) { + std::string name(m.Name.data(), m.Name.size()); + if (value && value->isMember(name)) { + E result = m.Function(out, &(*value)[name]); + if (result != this->Success) { + return result; + } + extraFields.erase( + std::find(extraFields.begin(), extraFields.end(), name)); + } else if (!m.Required) { + E result = m.Function(out, nullptr); + if (result != this->Success) { + return result; + } + } else { + return this->Fail; + } + } + + return this->AllowExtra || extraFields.empty() ? this->Success : this->Fail; +} + +template <typename E> +cmJSONHelper<std::string, E> cmJSONStringHelper(E success, E fail, + const std::string& defval = "") +{ + return + [success, fail, defval](std::string& out, const Json::Value* value) -> E { + if (!value) { + out = defval; + return success; + } + if (!value->isString()) { + return fail; + } + out = value->asString(); + return success; + }; +} + +template <typename E> +cmJSONHelper<int, E> cmJSONIntHelper(E success, E fail, int defval = 0) +{ + return [success, fail, defval](int& out, const Json::Value* value) -> E { + if (!value) { + out = defval; + return success; + } + if (!value->isInt()) { + return fail; + } + out = value->asInt(); + return success; + }; +} + +template <typename E> +cmJSONHelper<unsigned int, E> cmJSONUIntHelper(E success, E fail, + unsigned int defval = 0) +{ + return + [success, fail, defval](unsigned int& out, const Json::Value* value) -> E { + if (!value) { + out = defval; + return success; + } + if (!value->isUInt()) { + return fail; + } + out = value->asUInt(); + return success; + }; +} + +template <typename E> +cmJSONHelper<bool, E> cmJSONBoolHelper(E success, E fail, bool defval = false) +{ + return [success, fail, defval](bool& out, const Json::Value* value) -> E { + if (!value) { + out = defval; + return success; + } + if (!value->isBool()) { + return fail; + } + out = value->asBool(); + return success; + }; +} + +template <typename T, typename E, typename F, typename Filter> +cmJSONHelper<std::vector<T>, E> cmJSONVectorFilterHelper(E success, E fail, + F func, Filter filter) +{ + return [success, fail, func, filter](std::vector<T>& out, + const Json::Value* value) -> E { + if (!value) { + out.clear(); + return success; + } + if (!value->isArray()) { + return fail; + } + out.clear(); + for (auto const& item : *value) { + T t; + E result = func(t, &item); + if (result != success) { + return result; + } + if (!filter(t)) { + continue; + } + out.push_back(t); + } + return success; + }; +} + +template <typename T, typename E, typename F> +cmJSONHelper<std::vector<T>, E> cmJSONVectorHelper(E success, E fail, F func) +{ + return cmJSONVectorFilterHelper<T, E, F>(success, fail, func, + [](const T&) { return true; }); +} + +template <typename T, typename E, typename F, typename Filter> +cmJSONHelper<std::map<std::string, T>, E> cmJSONMapFilterHelper(E success, + E fail, F func, + Filter filter) +{ + return [success, fail, func, filter](std::map<std::string, T>& out, + const Json::Value* value) -> E { + if (!value) { + out.clear(); + return success; + } + if (!value->isObject()) { + return fail; + } + out.clear(); + for (auto const& key : value->getMemberNames()) { + if (!filter(key)) { + continue; + } + T t; + E result = func(t, &(*value)[key]); + if (result != success) { + return result; + } + out[key] = std::move(t); + } + return success; + }; +} + +template <typename T, typename E, typename F> +cmJSONHelper<std::map<std::string, T>, E> cmJSONMapHelper(E success, E fail, + F func) +{ + return cmJSONMapFilterHelper<T, E, F>( + success, fail, func, [](const std::string&) { return true; }); +} + +template <typename T, typename E, typename F> +cmJSONHelper<cm::optional<T>, E> cmJSONOptionalHelper(E success, F func) +{ + return [success, func](cm::optional<T>& out, const Json::Value* value) -> E { + if (!value) { + out.reset(); + return success; + } + out.emplace(); + return func(*out, value); + }; +} + +template <typename T, typename E, typename F> +cmJSONHelper<T, E> cmJSONRequiredHelper(E fail, F func) +{ + return [fail, func](T& out, const Json::Value* value) -> E { + if (!value) { + return fail; + } + return func(out, value); + }; +} diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 0ec0757..47931b0 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -2574,17 +2574,29 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) this->Makefile->GetSafeDefinition( cmStrCat("CMAKE_", lang, "_FLAGS_", configUpper)); + bool editAndContinueDebugInfo = + langFlags.find("/ZI") != std::string::npos || + langFlags.find("-ZI") != std::string::npos; + + bool enableDebuggingInformation = + langFlags.find("/Zi") != std::string::npos || + langFlags.find("-Zi") != std::string::npos; + // MSVC 2008 is producing both .pdb and .idb files with /Zi. - if ((langFlags.find("/ZI") != std::string::npos || - langFlags.find("-ZI") != std::string::npos) || - (cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, - compilerVersion.c_str(), - "16.0") && - compilerId == "MSVC")) { + bool msvc2008OrLess = + cmSystemTools::VersionCompare( + cmSystemTools::OP_LESS, compilerVersion.c_str(), "16.0") && + compilerId == "MSVC"; + // but not when used via toolset -Tv90 + if (this->Makefile->GetSafeDefinition( + "CMAKE_VS_PLATFORM_TOOLSET") == "v90") { + msvc2008OrLess = false; + } + + if (editAndContinueDebugInfo || msvc2008OrLess) { CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget, { ".pdb", ".idb" }); - } else if ((langFlags.find("/Zi") != std::string::npos || - langFlags.find("-Zi") != std::string::npos)) { + } else if (enableDebuggingInformation) { CopyPchCompilePdb(config, target, *ReuseFrom, reuseTarget, { ".pdb" }); } diff --git a/Source/cmLocalVisualStudio10Generator.cxx b/Source/cmLocalVisualStudio10Generator.cxx index 98e9db9..3ed49a0 100644 --- a/Source/cmLocalVisualStudio10Generator.cxx +++ b/Source/cmLocalVisualStudio10Generator.cxx @@ -68,13 +68,6 @@ cmLocalVisualStudio10Generator::~cmLocalVisualStudio10Generator() void cmLocalVisualStudio10Generator::GenerateTarget(cmGeneratorTarget* target) { - auto& targetVisited = this->GetSourcesVisited(target); - auto& deps = this->GlobalGenerator->GetTargetDirectDepends(target); - for (auto& d : deps) { - // Take the union of visited source files of custom commands - auto depVisited = this->GetSourcesVisited(d); - targetVisited.insert(depVisited.begin(), depVisited.end()); - } if (static_cast<cmGlobalVisualStudioGenerator*>(this->GlobalGenerator) ->TargetIsFortranOnly(target)) { this->cmLocalVisualStudio7Generator::GenerateTarget(target); diff --git a/Source/cmLocalVisualStudio10Generator.h b/Source/cmLocalVisualStudio10Generator.h index 631132e..45ee082 100644 --- a/Source/cmLocalVisualStudio10Generator.h +++ b/Source/cmLocalVisualStudio10Generator.h @@ -28,19 +28,10 @@ public: void ReadAndStoreExternalGUID(const std::string& name, const char* path) override; - std::set<cmSourceFile const*>& GetSourcesVisited( - cmGeneratorTarget const* target) - { - return SourcesVisited[target]; - }; - protected: const char* ReportErrorLabel() const override; bool CustomCommandUseLocal() const override { return true; } private: void GenerateTarget(cmGeneratorTarget* target) override; - - std::map<cmGeneratorTarget const*, std::set<cmSourceFile const*>> - SourcesVisited; }; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 1ebd5da..7795654 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -86,6 +86,15 @@ void cmLocalVisualStudio7Generator::Generate() if (!gt->IsInBuildSystem() || gt->GetProperty("EXTERNAL_MSPROJECT")) { continue; } + + auto& gtVisited = this->GetSourcesVisited(gt); + auto& deps = this->GlobalGenerator->GetTargetDirectDepends(gt); + for (auto& d : deps) { + // Take the union of visited source files of custom commands + auto depVisited = this->GetSourcesVisited(d); + gtVisited.insert(depVisited.begin(), depVisited.end()); + } + this->GenerateTarget(gt); } @@ -1615,6 +1624,8 @@ bool cmLocalVisualStudio7Generator::WriteGroup( this->WriteVCProjBeginGroup(fout, name.c_str(), ""); } + auto& sourcesVisited = this->GetSourcesVisited(target); + // Loop through each source in the source group. for (const cmSourceFile* sf : sourceFiles) { std::string source = sf->GetFullPath(); @@ -1638,7 +1649,10 @@ bool cmLocalVisualStudio7Generator::WriteGroup( // build it, then it will. fout << "\t\t\t\tRelativePath=\"" << d << "\">\n"; if (cmCustomCommand const* command = sf->GetCustomCommand()) { - this->WriteCustomRule(fout, configs, source.c_str(), *command, fcinfo); + if (sourcesVisited.insert(sf).second) { + this->WriteCustomRule(fout, configs, source.c_str(), *command, + fcinfo); + } } else if (!fcinfo.FileConfigMap.empty()) { const char* aCompilerTool = "VCCLCompilerTool"; std::string ppLang = "CXX"; diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 9ccd1a1..6e06c09 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -83,6 +83,12 @@ public: virtual void ReadAndStoreExternalGUID(const std::string& name, const char* path); + std::set<cmSourceFile const*>& GetSourcesVisited( + cmGeneratorTarget const* target) + { + return this->SourcesVisited[target]; + }; + protected: virtual void GenerateTarget(cmGeneratorTarget* target); @@ -148,4 +154,7 @@ private: bool FortranProject; bool WindowsCEProject; std::unique_ptr<cmLocalVisualStudio7GeneratorInternals> Internal; + + std::map<cmGeneratorTarget const*, std::set<cmSourceFile const*>> + SourcesVisited; }; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index ebbe3e7..d77c4af 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -2898,7 +2898,7 @@ MessageType cmMakefile::ExpandVariablesInStringOld( parser.SetNoEscapeMode(noEscapes); parser.SetReplaceAtSyntax(replaceAt); parser.SetRemoveEmpty(removeEmpty); - int res = parser.ParseString(source.c_str(), 0); + int res = parser.ParseString(source, 0); const char* emsg = parser.GetError(); MessageType mtype = MessageType::LOG; if (res && !emsg[0]) { diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 71c288c..9cb172b 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -192,7 +192,7 @@ public: { public: // -- Parse Cache - bool ParseCacheChanged = false; + std::atomic<bool> ParseCacheChanged = ATOMIC_VAR_INIT(false); cmFileTime ParseCacheTime; ParseCacheT ParseCache; @@ -1777,16 +1777,24 @@ bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping, { // Check dependency timestamps std::string const sourceDir = SubDirPrefix(sourceFile); - for (std::string const& dep : mapping.SourceFile->ParseData->Moc.Depends) { + auto& dependencies = mapping.SourceFile->ParseData->Moc.Depends; + for (auto it = dependencies.begin(); it != dependencies.end(); ++it) { + auto& dep = *it; + // Find dependency file auto const depMatch = FindDependency(sourceDir, dep); if (depMatch.first.empty()) { - Log().Warning(GenT::MOC, - cmStrCat(MessagePath(sourceFile), " depends on ", - MessagePath(dep), - " but the file does not exist.")); - continue; + if (reason != nullptr) { + *reason = + cmStrCat("Generating ", MessagePath(outputFile), " from ", + MessagePath(sourceFile), ", because its dependency ", + MessagePath(dep), " vanished."); + } + dependencies.erase(it); + BaseEval().ParseCacheChanged = true; + return true; } + // Test if dependency file is older if (outputFileTime.Older(depMatch.second)) { if (reason != nullptr) { diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index f3c262b..01e3d94 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -33,6 +33,13 @@ inline bool cmNonempty(std::string const* str) return str && !str->empty(); } +/** Returns length of a literal string. */ +template <size_t N> +constexpr size_t cmStrLen(const char (&/*str*/)[N]) +{ + return N - 1; +} + /** Callable string comparison struct. */ struct cmStrCmp { |