From 0cd84434ace8bc0c26bd6d0d4c9bb04cc53f1c8a Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 8 Oct 2020 11:28:48 -0400 Subject: Begin post-3.19 development --- .gitlab-ci.yml | 6 +++--- Help/release/dev/0-sample-topic.rst | 7 +++++++ Help/release/index.rst | 2 ++ Source/CMakeVersion.cmake | 4 ++-- 4 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 Help/release/dev/0-sample-topic.rst diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index eda96ae..1a94a3d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -52,7 +52,7 @@ prep:doc-package: - .cmake_doc_artifacts - .run_only_for_package -.upload:source-package: +upload:source-package: extends: - .rsync_upload - .run_only_for_package @@ -175,7 +175,7 @@ build:linux-x86_64-package: needs: - prep:doc-package -.upload:linux-x86_64-package: +upload:linux-x86_64-package: extends: - .rsync_upload - .run_only_for_package @@ -250,7 +250,7 @@ build:macos-package: needs: - prep:doc-package -.upload:macos-package: +upload:macos-package: extends: - .rsync_upload - .run_only_for_package diff --git a/Help/release/dev/0-sample-topic.rst b/Help/release/dev/0-sample-topic.rst new file mode 100644 index 0000000..e4cc01e --- /dev/null +++ b/Help/release/dev/0-sample-topic.rst @@ -0,0 +1,7 @@ +0-sample-topic +-------------- + +* This is a sample release note for the change in a topic. + Developers should add similar notes for each topic branch + making a noteworthy change. Each document should be named + and titled to match the topic name to avoid merge conflicts. diff --git a/Help/release/index.rst b/Help/release/index.rst index 6fb0f1a..a8329a6 100644 --- a/Help/release/index.rst +++ b/Help/release/index.rst @@ -7,6 +7,8 @@ CMake Release Notes This file should include the adjacent "dev.txt" file in development versions but not in release versions. +.. include:: dev.txt + Releases ======== diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8c36e7a..de3f450 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,8 +1,8 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 19) -set(CMake_VERSION_PATCH 0) -set(CMake_VERSION_RC 0) +set(CMake_VERSION_PATCH 20201008) +#set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) # Start with the full version number used in tags. It has no dev info. -- cgit v0.12 From 26464da5d3919cf0c5a6fc3e34cf143bd65d9938 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 7 Oct 2020 14:49:30 -0400 Subject: cmMakefile: Drop unnecessary custom command APPEND check Since commit 777ceaea94 (cmMakefile: Delay custom command creation, 2019-10-17, v3.17.0-rc1~352^2) we process custom command declarations at generate time. This includes the append-to-non-existing-command check, so we do not need it at configure time. --- Source/cmAddCustomCommandCommand.cxx | 13 ++---- Source/cmLocalGenerator.cxx | 2 +- Source/cmMakefile.cxx | 51 +--------------------- Source/cmMakefile.h | 12 +---- .../add_custom_command/AppendNotOutput-stderr.txt | 2 +- 5 files changed, 7 insertions(+), 73 deletions(-) diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 231a2d6..bea89c0 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -314,16 +314,9 @@ bool cmAddCustomCommandCommand(std::vector const& args, // Check for an append request. if (append) { - if (mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends, - commandLines)) { - return true; - } - - // No command for this output exists. - status.SetError( - cmStrCat("given APPEND option with output\n ", output[0], - "\nwhich is not already a custom command output.")); - return false; + mf.AppendCustomCommandToOutput(output[0], depends, implicit_depends, + commandLines); + return true; } if (uses_terminal && !job_pool.empty()) { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 4e6010c..a3aaf0b 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -4008,7 +4008,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg, // No existing command found. lg.GetCMakeInstance()->IssueMessage( MessageType::FATAL_ERROR, - cmStrCat("Attempt to append to output\n ", output, + cmStrCat("Attempt to APPEND to custom command with output\n ", output, "\nwhich is not already a custom command output."), lfbt); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 14ec689..cad0ad1 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -939,8 +939,6 @@ void cmMakefile::DoGenerate(cmLocalGenerator& lg) action.Value(lg, action.Backtrace); } this->GeneratorActionsInvoked = true; - this->DelayedOutputFiles.clear(); - this->DelayedOutputFilesHaveGenex = false; // go through all configured files and see which ones still exist. // we don't want cmake to re-run if a configured file is created and deleted @@ -1247,16 +1245,11 @@ void cmMakefile::AddCustomCommandOldStyle( } } -bool cmMakefile::AppendCustomCommandToOutput( +void cmMakefile::AppendCustomCommandToOutput( const std::string& output, const std::vector& depends, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines) { - // Check as good as we can if there will be a command for this output. - if (!this->MightHaveCustomCommand(output)) { - return false; - } - // Validate custom commands. if (this->ValidateCustomCommand(commandLines)) { // Dispatch command creation to allow generator expressions in outputs. @@ -1267,8 +1260,6 @@ bool cmMakefile::AppendCustomCommandToOutput( implicit_depends, commandLines); }); } - - return true; } cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target) @@ -2271,26 +2262,6 @@ cmSourceFile* cmMakefile::GetSourceFileWithOutput( return nullptr; } -bool cmMakefile::MightHaveCustomCommand(const std::string& name) const -{ - if (this->DelayedOutputFilesHaveGenex || - cmGeneratorExpression::Find(name) != std::string::npos) { - // Could be more restrictive, but for now we assume that there could always - // be a match when generator expressions are involved. - return true; - } - // Also see LinearGetSourceFileWithOutput. - if (!cmSystemTools::FileIsFullPath(name)) { - return AnyOutputMatches(name, this->DelayedOutputFiles); - } - // Otherwise we use an efficient lookup map. - auto o = this->OutputToSource.find(name); - if (o != this->OutputToSource.end()) { - return o->second.SourceMightBeOutput; - } - return false; -} - void cmMakefile::AddTargetByproducts( cmTarget* target, const std::vector& byproducts) { @@ -2339,7 +2310,6 @@ void cmMakefile::UpdateOutputToSourceMap(std::string const& output, SourceEntry entry; entry.Sources.Source = source; entry.Sources.SourceIsByproduct = byproduct; - entry.SourceMightBeOutput = !byproduct; auto pr = this->OutputToSource.emplace(output, entry); if (!pr.second) { @@ -2349,7 +2319,6 @@ void cmMakefile::UpdateOutputToSourceMap(std::string const& output, (current.Sources.SourceIsByproduct && !byproduct)) { current.Sources.Source = source; current.Sources.SourceIsByproduct = false; - current.SourceMightBeOutput = true; } else { // Multiple custom commands produce the same output but may // be attached to a different source file (MAIN_DEPENDENCY). @@ -3676,9 +3645,6 @@ void cmMakefile::CreateGeneratedOutputs( for (std::string const& o : outputs) { if (cmGeneratorExpression::Find(o) == std::string::npos) { this->GetOrCreateGeneratedSource(o); - this->AddDelayedOutput(o); - } else { - this->DelayedOutputFilesHaveGenex = true; } } } @@ -3693,21 +3659,6 @@ void cmMakefile::CreateGeneratedByproducts( } } -void cmMakefile::AddDelayedOutput(std::string const& output) -{ - // Note that this vector might contain the output names in a different order - // than in source file iteration order. - this->DelayedOutputFiles.push_back(output); - - SourceEntry entry; - entry.SourceMightBeOutput = true; - - auto pr = this->OutputToSource.emplace(output, entry); - if (!pr.second) { - pr.first->second.SourceMightBeOutput = true; - } -} - void cmMakefile::AddTargetObject(std::string const& tgtName, std::string const& objFile) { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index c7940fb..b4d2336 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -225,7 +225,7 @@ public: const std::string& source, const cmCustomCommandLines& commandLines, const char* comment); - bool AppendCustomCommandToOutput( + void AppendCustomCommandToOutput( const std::string& output, const std::vector& depends, const cmImplicitDependsList& implicit_depends, const cmCustomCommandLines& commandLines); @@ -1133,10 +1133,6 @@ private: std::vector> GeneratorActions; bool GeneratorActionsInvoked = false; - bool DelayedOutputFilesHaveGenex = false; - std::vector DelayedOutputFiles; - - void AddDelayedOutput(std::string const& output); /** * See LinearGetSourceFileWithOutput for background information @@ -1156,7 +1152,6 @@ private: struct SourceEntry { cmSourcesWithOutput Sources; - bool SourceMightBeOutput = false; }; // A map for fast output to input look up. @@ -1167,11 +1162,6 @@ private: void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source, bool byproduct); - /** - * Return if the provided source file might have a custom command. - */ - bool MightHaveCustomCommand(const std::string& name) const; - bool CheckSystemVars; bool CheckCMP0000; std::set WarnedCMP0074; diff --git a/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt b/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt index b7ee23a..9324302 100644 --- a/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt +++ b/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt @@ -1,5 +1,5 @@ CMake Error at AppendNotOutput.cmake:1 \(add_custom_command\): - add_custom_command given APPEND option with output + Attempt to APPEND to custom command with output .*RunCMake/add_custom_command/AppendNotOutput-build/out -- cgit v0.12 From 0090a11a42c83897e05b09d5381967f0200d6eb7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 7 Oct 2020 15:19:58 -0400 Subject: cmLocalGenerator: Migrate custom command output lookup from cmMakefile Since commit 777ceaea94 (cmMakefile: Delay custom command creation, 2019-10-17, v3.17.0-rc1~352^2) we process custom command declarations at generate time. Therefore we do not need to look up what source file holds the custom command producing a given output until generate time. --- Source/cmGeneratorTarget.cxx | 5 +- Source/cmGhsMultiTargetGenerator.cxx | 6 +- Source/cmLocalGenerator.cxx | 198 +++++++++++++++++++++++++++++++++-- Source/cmLocalGenerator.h | 73 +++++++++++++ Source/cmMakefile.cxx | 185 -------------------------------- Source/cmMakefile.h | 80 +------------- 6 files changed, 276 insertions(+), 271 deletions(-) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index bdea9fa..6ebc9e1 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -2986,7 +2986,8 @@ void cmTargetTraceDependencies::FollowName(std::string const& name) auto i = this->NameMap.lower_bound(name); if (i == this->NameMap.end() || i->first != name) { // Check if we know how to generate this file. - cmSourcesWithOutput sources = this->Makefile->GetSourcesWithOutput(name); + cmSourcesWithOutput sources = + this->LocalGenerator->GetSourcesWithOutput(name); // If we failed to find a target or source and we have a relative path, it // might be a valid source if made relative to the current binary // directory. @@ -2996,7 +2997,7 @@ void cmTargetTraceDependencies::FollowName(std::string const& name) cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', name); fullname = cmSystemTools::CollapseFullPath( fullname, this->Makefile->GetHomeOutputDirectory()); - sources = this->Makefile->GetSourcesWithOutput(fullname); + sources = this->LocalGenerator->GetSourcesWithOutput(fullname); } i = this->NameMap.emplace_hint(i, name, sources); } diff --git a/Source/cmGhsMultiTargetGenerator.cxx b/Source/cmGhsMultiTargetGenerator.cxx index a8f8f57..ed50067 100644 --- a/Source/cmGhsMultiTargetGenerator.cxx +++ b/Source/cmGhsMultiTargetGenerator.cxx @@ -763,9 +763,9 @@ bool cmGhsMultiTargetGenerator::VisitCustomCommand( /* set temporary mark; check if revisit*/ if (temp.insert(si).second) { for (auto& di : si->GetCustomCommand()->GetDepends()) { - cmSourceFile const* sf = this->GeneratorTarget->GetLocalGenerator() - ->GetMakefile() - ->GetSourceFileWithOutput(di); + cmSourceFile const* sf = + this->GeneratorTarget->GetLocalGenerator()->GetSourceFileWithOutput( + di); /* if sf exists then visit */ if (sf && this->VisitCustomCommand(temp, perm, order, sf)) { return true; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index a3aaf0b..b7ad78a 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -3918,10 +3918,35 @@ cmSourceFile* AddCustomCommand( cc->SetJobPool(job_pool); file->SetCustomCommand(std::move(cc)); - mf->AddSourceOutputs(file, outputs, byproducts); + lg.AddSourceOutputs(file, outputs, byproducts); } return file; } + +bool AnyOutputMatches(const std::string& name, + const std::vector& outputs) +{ + for (std::string const& output : outputs) { + std::string::size_type pos = output.rfind(name); + // If the output matches exactly + if (pos != std::string::npos && pos == output.size() - name.size() && + (pos == 0 || output[pos - 1] == '/')) { + return true; + } + } + return false; +} + +bool AnyTargetCommandOutputMatches( + const std::string& name, const std::vector& commands) +{ + for (cmCustomCommand const& command : commands) { + if (AnyOutputMatches(name, command.GetByproducts())) { + return true; + } + } + return false; +} } namespace detail { @@ -3937,8 +3962,6 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg, const std::string& job_pool, bool command_expand_lists, bool stdPipesUTF8) { - cmMakefile* mf = lg.GetMakefile(); - // Always create the byproduct sources and mark them generated. CreateGeneratedSources(lg, byproducts, origin, lfbt); @@ -3964,7 +3987,7 @@ void AddCustomCommandToTarget(cmLocalGenerator& lg, break; } - mf->AddTargetByproducts(target, byproducts); + lg.AddTargetByproducts(target, byproducts); } cmSourceFile* AddCustomCommandToOutput( @@ -3996,7 +4019,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg, const cmCustomCommandLines& commandLines) { // Lookup an existing command. - if (cmSourceFile* sf = lg.GetMakefile()->GetSourceFileWithOutput(output)) { + if (cmSourceFile* sf = lg.GetSourceFileWithOutput(output)) { if (cmCustomCommand* cc = sf->GetCustomCommand()) { cc->AppendCommands(commandLines); cc->AppendDepends(depends); @@ -4040,7 +4063,7 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt, /*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists, /*depfile=*/"", job_pool, stdPipesUTF8); if (rule) { - lg.GetMakefile()->AddTargetByproducts(target, byproducts); + lg.AddTargetByproducts(target, byproducts); } if (!force.NameCMP0049.empty()) { @@ -4088,3 +4111,166 @@ std::vector ComputeISPCExtraObjects( return computedObjects; } } + +cmSourcesWithOutput cmLocalGenerator::GetSourcesWithOutput( + const std::string& name) const +{ + // Linear search? Also see GetSourceFileWithOutput for detail. + if (!cmSystemTools::FileIsFullPath(name)) { + cmSourcesWithOutput sources; + sources.Target = this->LinearGetTargetWithOutput(name); + sources.Source = this->LinearGetSourceFileWithOutput( + name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct); + return sources; + } + // Otherwise we use an efficient lookup map. + auto o = this->OutputToSource.find(name); + if (o != this->OutputToSource.end()) { + return o->second.Sources; + } + return {}; +} + +cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput( + const std::string& name, cmSourceOutputKind kind) const +{ + // If the queried path is not absolute we use the backward compatible + // linear-time search for an output with a matching suffix. + if (!cmSystemTools::FileIsFullPath(name)) { + bool byproduct = false; + return this->LinearGetSourceFileWithOutput(name, kind, byproduct); + } + // Otherwise we use an efficient lookup map. + auto o = this->OutputToSource.find(name); + if (o != this->OutputToSource.end() && + (!o->second.Sources.SourceIsByproduct || + kind == cmSourceOutputKind::OutputOrByproduct)) { + // Source file could also be null pointer for example if we found the + // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD + // command of a target, or a not yet created custom command. + return o->second.Sources.Source; + } + return nullptr; +} + +void cmLocalGenerator::AddTargetByproducts( + cmTarget* target, const std::vector& byproducts) +{ + for (std::string const& o : byproducts) { + this->UpdateOutputToSourceMap(o, target); + } +} + +void cmLocalGenerator::AddSourceOutputs( + cmSourceFile* source, const std::vector& outputs, + const std::vector& byproducts) +{ + for (std::string const& o : outputs) { + this->UpdateOutputToSourceMap(o, source, false); + } + for (std::string const& o : byproducts) { + this->UpdateOutputToSourceMap(o, source, true); + } +} + +void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& byproduct, + cmTarget* target) +{ + SourceEntry entry; + entry.Sources.Target = target; + + auto pr = this->OutputToSource.emplace(byproduct, entry); + if (!pr.second) { + SourceEntry& current = pr.first->second; + // Has the target already been set? + if (!current.Sources.Target) { + current.Sources.Target = target; + } else { + // Multiple custom commands/targets produce the same output (source file + // or target). See also comment in other UpdateOutputToSourceMap + // overload. + // + // TODO: Warn the user about this case. + } + } +} + +void cmLocalGenerator::UpdateOutputToSourceMap(std::string const& output, + cmSourceFile* source, + bool byproduct) +{ + SourceEntry entry; + entry.Sources.Source = source; + entry.Sources.SourceIsByproduct = byproduct; + + auto pr = this->OutputToSource.emplace(output, entry); + if (!pr.second) { + SourceEntry& current = pr.first->second; + // Outputs take precedence over byproducts + if (!current.Sources.Source || + (current.Sources.SourceIsByproduct && !byproduct)) { + current.Sources.Source = source; + current.Sources.SourceIsByproduct = false; + } else { + // Multiple custom commands produce the same output but may + // be attached to a different source file (MAIN_DEPENDENCY). + // LinearGetSourceFileWithOutput would return the first one, + // so keep the mapping for the first one. + // + // TODO: Warn the user about this case. However, the VS 8 generator + // triggers it for separate generate.stamp rules in ZERO_CHECK and + // individual targets. + } + } +} + +cmTarget* cmLocalGenerator::LinearGetTargetWithOutput( + const std::string& name) const +{ + // We go through the ordered vector of targets to get reproducible results + // should multiple names match. + for (cmTarget* t : this->Makefile->GetOrderedTargets()) { + // Does the output of any command match the source file name? + if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) { + return t; + } + if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) { + return t; + } + if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) { + return t; + } + } + return nullptr; +} + +cmSourceFile* cmLocalGenerator::LinearGetSourceFileWithOutput( + const std::string& name, cmSourceOutputKind kind, bool& byproduct) const +{ + // Outputs take precedence over byproducts. + byproduct = false; + cmSourceFile* fallback = nullptr; + + // Look through all the source files that have custom commands and see if the + // custom command has the passed source file as an output. + for (const auto& src : this->Makefile->GetSourceFiles()) { + // Does this source file have a custom command? + if (src->GetCustomCommand()) { + // Does the output of the custom command match the source file name? + if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) { + // Return the first matching output. + return src.get(); + } + if (kind == cmSourceOutputKind::OutputOrByproduct) { + if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) { + // Do not return the source yet as there might be a matching output. + fallback = src.get(); + } + } + } + } + + // Did we find a byproduct? + byproduct = fallback != nullptr; + return fallback; +} diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 22d3599..162e70f 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -36,6 +36,24 @@ class cmState; class cmTarget; class cmake; +/** Flag if byproducts shall also be considered. */ +enum class cmSourceOutputKind +{ + OutputOnly, + OutputOrByproduct +}; + +/** Target and source file which have a specific output. */ +struct cmSourcesWithOutput +{ + /** Target with byproduct. */ + cmTarget* Target = nullptr; + + /** Source file with output or byproduct. */ + cmSourceFile* Source = nullptr; + bool SourceIsByproduct = false; +}; + /** \class cmLocalGenerator * \brief Create required build files for a directory. * @@ -337,6 +355,34 @@ public: bool command_expand_lists = false, const std::string& job_pool = "", bool stdPipesUTF8 = false); + /** + * Add target byproducts. + */ + void AddTargetByproducts(cmTarget* target, + const std::vector& byproducts); + + /** + * Add source file outputs. + */ + void AddSourceOutputs(cmSourceFile* source, + const std::vector& outputs, + const std::vector& byproducts); + + /** + * Return the target if the provided source name is a byproduct of a utility + * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command. + * Return the source file which has the provided source name as output. + */ + cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const; + + /** + * Is there a source file that has the provided source name as an output? + * If so then return it. + */ + cmSourceFile* GetSourceFileWithOutput( + const std::string& name, + cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const; + std::string GetProjectName() const; /** Compute the language used to compile the given source file. */ @@ -532,6 +578,33 @@ protected: bool BackwardsCompatibilityFinal; private: + /** + * See LinearGetSourceFileWithOutput for background information + */ + cmTarget* LinearGetTargetWithOutput(const std::string& name) const; + + /** + * Generalized old version of GetSourceFileWithOutput kept for + * backward-compatibility. It implements a linear search and supports + * relative file paths. It is used as a fall back by GetSourceFileWithOutput + * and GetSourcesWithOutput. + */ + cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name, + cmSourceOutputKind kind, + bool& byproduct) const; + struct SourceEntry + { + cmSourcesWithOutput Sources; + }; + + // A map for fast output to input look up. + using OutputToSourceMap = std::unordered_map; + OutputToSourceMap OutputToSource; + + void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target); + void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source, + bool byproduct); + void AddSharedFlags(std::string& flags, const std::string& lang, bool shared); bool GetShouldUseOldFlags(bool shared, const std::string& lang) const; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index cad0ad1..4470193 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -2145,191 +2145,6 @@ cmTarget* cmMakefile::AddNewUtilityTarget(const std::string& utilityName, } namespace { -bool AnyOutputMatches(const std::string& name, - const std::vector& outputs) -{ - for (std::string const& output : outputs) { - std::string::size_type pos = output.rfind(name); - // If the output matches exactly - if (pos != std::string::npos && pos == output.size() - name.size() && - (pos == 0 || output[pos - 1] == '/')) { - return true; - } - } - return false; -} - -bool AnyTargetCommandOutputMatches( - const std::string& name, const std::vector& commands) -{ - for (cmCustomCommand const& command : commands) { - if (AnyOutputMatches(name, command.GetByproducts())) { - return true; - } - } - return false; -} -} - -cmTarget* cmMakefile::LinearGetTargetWithOutput(const std::string& name) const -{ - // We go through the ordered vector of targets to get reproducible results - // should multiple names match. - for (cmTarget* t : this->OrderedTargets) { - // Does the output of any command match the source file name? - if (AnyTargetCommandOutputMatches(name, t->GetPreBuildCommands())) { - return t; - } - if (AnyTargetCommandOutputMatches(name, t->GetPreLinkCommands())) { - return t; - } - if (AnyTargetCommandOutputMatches(name, t->GetPostBuildCommands())) { - return t; - } - } - return nullptr; -} - -cmSourceFile* cmMakefile::LinearGetSourceFileWithOutput( - const std::string& name, cmSourceOutputKind kind, bool& byproduct) const -{ - // Outputs take precedence over byproducts. - byproduct = false; - cmSourceFile* fallback = nullptr; - - // Look through all the source files that have custom commands and see if the - // custom command has the passed source file as an output. - for (const auto& src : this->SourceFiles) { - // Does this source file have a custom command? - if (src->GetCustomCommand()) { - // Does the output of the custom command match the source file name? - if (AnyOutputMatches(name, src->GetCustomCommand()->GetOutputs())) { - // Return the first matching output. - return src.get(); - } - if (kind == cmSourceOutputKind::OutputOrByproduct) { - if (AnyOutputMatches(name, src->GetCustomCommand()->GetByproducts())) { - // Do not return the source yet as there might be a matching output. - fallback = src.get(); - } - } - } - } - - // Did we find a byproduct? - byproduct = fallback != nullptr; - return fallback; -} - -cmSourcesWithOutput cmMakefile::GetSourcesWithOutput( - const std::string& name) const -{ - // Linear search? Also see GetSourceFileWithOutput for detail. - if (!cmSystemTools::FileIsFullPath(name)) { - cmSourcesWithOutput sources; - sources.Target = this->LinearGetTargetWithOutput(name); - sources.Source = this->LinearGetSourceFileWithOutput( - name, cmSourceOutputKind::OutputOrByproduct, sources.SourceIsByproduct); - return sources; - } - // Otherwise we use an efficient lookup map. - auto o = this->OutputToSource.find(name); - if (o != this->OutputToSource.end()) { - return o->second.Sources; - } - return {}; -} - -cmSourceFile* cmMakefile::GetSourceFileWithOutput( - const std::string& name, cmSourceOutputKind kind) const -{ - // If the queried path is not absolute we use the backward compatible - // linear-time search for an output with a matching suffix. - if (!cmSystemTools::FileIsFullPath(name)) { - bool byproduct = false; - return this->LinearGetSourceFileWithOutput(name, kind, byproduct); - } - // Otherwise we use an efficient lookup map. - auto o = this->OutputToSource.find(name); - if (o != this->OutputToSource.end() && - (!o->second.Sources.SourceIsByproduct || - kind == cmSourceOutputKind::OutputOrByproduct)) { - // Source file could also be null pointer for example if we found the - // byproduct of a utility target, a PRE_BUILD, PRE_LINK, or POST_BUILD - // command of a target, or a not yet created custom command. - return o->second.Sources.Source; - } - return nullptr; -} - -void cmMakefile::AddTargetByproducts( - cmTarget* target, const std::vector& byproducts) -{ - for (std::string const& o : byproducts) { - this->UpdateOutputToSourceMap(o, target); - } -} - -void cmMakefile::AddSourceOutputs(cmSourceFile* source, - const std::vector& outputs, - const std::vector& byproducts) -{ - for (std::string const& o : outputs) { - this->UpdateOutputToSourceMap(o, source, false); - } - for (std::string const& o : byproducts) { - this->UpdateOutputToSourceMap(o, source, true); - } -} - -void cmMakefile::UpdateOutputToSourceMap(std::string const& byproduct, - cmTarget* target) -{ - SourceEntry entry; - entry.Sources.Target = target; - - auto pr = this->OutputToSource.emplace(byproduct, entry); - if (!pr.second) { - SourceEntry& current = pr.first->second; - // Has the target already been set? - if (!current.Sources.Target) { - current.Sources.Target = target; - } else { - // Multiple custom commands/targets produce the same output (source file - // or target). See also comment in other UpdateOutputToSourceMap - // overload. - // - // TODO: Warn the user about this case. - } - } -} - -void cmMakefile::UpdateOutputToSourceMap(std::string const& output, - cmSourceFile* source, bool byproduct) -{ - SourceEntry entry; - entry.Sources.Source = source; - entry.Sources.SourceIsByproduct = byproduct; - - auto pr = this->OutputToSource.emplace(output, entry); - if (!pr.second) { - SourceEntry& current = pr.first->second; - // Outputs take precedence over byproducts - if (!current.Sources.Source || - (current.Sources.SourceIsByproduct && !byproduct)) { - current.Sources.Source = source; - current.Sources.SourceIsByproduct = false; - } else { - // Multiple custom commands produce the same output but may - // be attached to a different source file (MAIN_DEPENDENCY). - // LinearGetSourceFileWithOutput would return the first one, - // so keep the mapping for the first one. - // - // TODO: Warn the user about this case. However, the VS 8 generator - // triggers it for separate generate.stamp rules in ZERO_CHECK and - // individual targets. - } - } } #if !defined(CMAKE_BOOTSTRAP) diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index b4d2336..01a9274 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -59,24 +59,6 @@ class cmTestGenerator; class cmVariableWatch; class cmake; -/** Flag if byproducts shall also be considered. */ -enum class cmSourceOutputKind -{ - OutputOnly, - OutputOrByproduct -}; - -/** Target and source file which have a specific output. */ -struct cmSourcesWithOutput -{ - /** Target with byproduct. */ - cmTarget* Target = nullptr; - - /** Source file with output or byproduct. */ - cmSourceFile* Source = nullptr; - bool SourceIsByproduct = false; -}; - /** A type-safe wrapper for a string representing a directory id. */ class cmDirectoryId { @@ -231,19 +213,6 @@ public: const cmCustomCommandLines& commandLines); /** - * Add target byproducts. - */ - void AddTargetByproducts(cmTarget* target, - const std::vector& byproducts); - - /** - * Add source file outputs. - */ - void AddSourceOutputs(cmSourceFile* source, - const std::vector& outputs, - const std::vector& byproducts); - - /** * Add a define flag to the build. */ void AddDefineFlag(std::string const& definition); @@ -753,20 +722,10 @@ public: return this->SourceFiles; } - /** - * Return the target if the provided source name is a byproduct of a utility - * target or a PRE_BUILD, PRE_LINK, or POST_BUILD command. - * Return the source file which has the provided source name as output. - */ - cmSourcesWithOutput GetSourcesWithOutput(const std::string& name) const; - - /** - * Is there a source file that has the provided source name as an output? - * If so then return it. - */ - cmSourceFile* GetSourceFileWithOutput( - const std::string& name, - cmSourceOutputKind kind = cmSourceOutputKind::OutputOnly) const; + std::vector const& GetOrderedTargets() const + { + return this->OrderedTargets; + } //! Add a new cmTest to the list of tests for this makefile. cmTest* CreateTest(const std::string& testName); @@ -983,8 +942,7 @@ protected: mutable cmTargetMap Targets; std::map AliasTargets; - using TargetsVec = std::vector; - TargetsVec OrderedTargets; + std::vector OrderedTargets; std::vector> SourceFiles; @@ -1134,34 +1092,6 @@ private: std::vector> GeneratorActions; bool GeneratorActionsInvoked = false; - /** - * See LinearGetSourceFileWithOutput for background information - */ - cmTarget* LinearGetTargetWithOutput(const std::string& name) const; - - /** - * Generalized old version of GetSourceFileWithOutput kept for - * backward-compatibility. It implements a linear search and supports - * relative file paths. It is used as a fall back by GetSourceFileWithOutput - * and GetSourcesWithOutput. - */ - cmSourceFile* LinearGetSourceFileWithOutput(const std::string& name, - cmSourceOutputKind kind, - bool& byproduct) const; - - struct SourceEntry - { - cmSourcesWithOutput Sources; - }; - - // A map for fast output to input look up. - using OutputToSourceMap = std::unordered_map; - OutputToSourceMap OutputToSource; - - void UpdateOutputToSourceMap(std::string const& byproduct, cmTarget* target); - void UpdateOutputToSourceMap(std::string const& output, cmSourceFile* source, - bool byproduct); - bool CheckSystemVars; bool CheckCMP0000; std::set WarnedCMP0074; -- cgit v0.12 From 953f4d503d0fce45de3f8b4f2087b1739a3a94a3 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 7 Oct 2020 15:27:27 -0400 Subject: cmMakefile: Consolidate CreateGenerated{Outputs,Byproducts} The implementations of these two methods are now identical, so combine them. --- Source/cmMakefile.cxx | 16 +++------------- Source/cmMakefile.h | 1 - 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 4470193..9286e93 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -1102,7 +1102,7 @@ cmTarget* cmMakefile::AddCustomCommandToTarget( } // Always create the byproduct sources and mark them generated. - this->CreateGeneratedByproducts(byproducts); + this->CreateGeneratedOutputs(byproducts); // Strings could be moved into the callback function with C++14. cm::optional commentStr = MakeOptionalString(comment); @@ -1161,7 +1161,7 @@ void cmMakefile::AddCustomCommandToOutput( // Always create the output sources and mark them generated. this->CreateGeneratedOutputs(outputs); - this->CreateGeneratedByproducts(byproducts); + this->CreateGeneratedOutputs(byproducts); // Strings could be moved into the callback function with C++14. cm::optional commentStr = MakeOptionalString(comment); @@ -1304,7 +1304,7 @@ cmTarget* cmMakefile::AddUtilityCommand( this->GetOrCreateGeneratedSource(force.Name); // Always create the byproduct sources and mark them generated. - this->CreateGeneratedByproducts(byproducts); + this->CreateGeneratedOutputs(byproducts); // Strings could be moved into the callback function with C++14. cm::optional commentStr = MakeOptionalString(comment); @@ -3464,16 +3464,6 @@ void cmMakefile::CreateGeneratedOutputs( } } -void cmMakefile::CreateGeneratedByproducts( - const std::vector& byproducts) -{ - for (std::string const& o : byproducts) { - if (cmGeneratorExpression::Find(o) == std::string::npos) { - this->GetOrCreateGeneratedSource(o); - } - } -} - void cmMakefile::AddTargetObject(std::string const& tgtName, std::string const& objFile) { diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 01a9274..ecc6aab 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -1087,7 +1087,6 @@ private: bool ValidateCustomCommand(const cmCustomCommandLines& commandLines) const; void CreateGeneratedOutputs(const std::vector& outputs); - void CreateGeneratedByproducts(const std::vector& byproducts); std::vector> GeneratorActions; bool GeneratorActionsInvoked = false; -- cgit v0.12 From dabce5dcee8e5169d591a554b16d3143aa00a945 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Fri, 9 Oct 2020 00:01:18 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index de3f450..a0462a4 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 19) -set(CMake_VERSION_PATCH 20201008) +set(CMake_VERSION_PATCH 20201009) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 544ee0edc0bd9b747058b42b0f44d36b7d4ee461 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Fri, 9 Oct 2020 11:50:35 -0400 Subject: CI: Add a long filename to a build Nightly testing occasionally uncovers problems around long filenames that were not found during gitlab-ci testing. Give a GitLab runner a long filename to detect such problems. --- .gitlab/os-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml index 8e7a854..217442f 100644 --- a/.gitlab/os-linux.yml +++ b/.gitlab/os-linux.yml @@ -52,7 +52,7 @@ image: "kitware/cmake:ci-fedora31-x86_64-2020-10-03" variables: - GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci" + GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes" #### Lint builds -- cgit v0.12 From a4958a6f28a0048196778cb1b8277b9c324bcad3 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Sat, 10 Oct 2020 00:01:15 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index a0462a4..aaa211c 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 19) -set(CMake_VERSION_PATCH 20201009) +set(CMake_VERSION_PATCH 20201010) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From dda897234b8e8f48f515074bdf0a2d9ce67067f9 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Sun, 11 Oct 2020 00:01:07 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index aaa211c..23e80d7 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 19) -set(CMake_VERSION_PATCH 20201010) +set(CMake_VERSION_PATCH 20201011) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 586cce897b0db400cfd39b1dee3482d1a2a80e28 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Mon, 12 Oct 2020 00:01:19 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 23e80d7..d1cc7e4 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 19) -set(CMake_VERSION_PATCH 20201011) +set(CMake_VERSION_PATCH 20201012) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 2713a4fb373a45ec7c6eff0c936a75a425c886a4 Mon Sep 17 00:00:00 2001 From: Asit Dhal Date: Fri, 2 Oct 2020 18:40:57 +0200 Subject: file(GENERATE): Refactor options handling --- Source/cmFileCommand.cxx | 102 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 29 deletions(-) diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index be91846..4fe5901 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -2314,49 +2315,92 @@ bool HandleGenerateCommand(std::vector const& args, status.SetError("Incorrect arguments to GENERATE subcommand."); return false; } - if (args[1] != "OUTPUT") { + + struct Arguments + { + std::string Output; + std::string Input; + std::string Content; + std::string Condition; + std::string Target; + }; + + static auto const parser = cmArgumentParser{} + .Bind("OUTPUT"_s, &Arguments::Output) + .Bind("INPUT"_s, &Arguments::Input) + .Bind("CONTENT"_s, &Arguments::Content) + .Bind("CONDITION"_s, &Arguments::Condition) + .Bind("TARGET"_s, &Arguments::Target); + + std::vector unparsedArguments; + std::vector keywordsMissingValues; + std::vector parsedKeywords; + Arguments const arguments = + parser.Parse(cmMakeRange(args).advance(1), &unparsedArguments, + &keywordsMissingValues, &parsedKeywords); + + if (!keywordsMissingValues.empty()) { status.SetError("Incorrect arguments to GENERATE subcommand."); return false; } - std::string condition; - std::string target; - - for (std::size_t i = 5; i < args.size();) { - const std::string& arg = args[i++]; + if (!unparsedArguments.empty()) { + status.SetError("Unknown argument to GENERATE subcommand."); + return false; + } - if (args.size() - i == 0) { - status.SetError("Incorrect arguments to GENERATE subcommand."); - return false; + bool mandatoryOptionsSpecified = false; + if (parsedKeywords.size() > 1) { + const bool outputOprionSpecified = parsedKeywords[0] == "OUTPUT"_s; + const bool inputOrContentSpecified = + parsedKeywords[1] == "INPUT"_s || parsedKeywords[1] == "CONTENT"_s; + if (outputOprionSpecified && inputOrContentSpecified) { + mandatoryOptionsSpecified = true; } + } + if (!mandatoryOptionsSpecified) { + status.SetError("Incorrect arguments to GENERATE subcommand."); + return false; + } - const std::string& value = args[i++]; - - if (value.empty()) { - status.SetError( - arg + " of sub-command GENERATE must not be empty if specified."); - return false; - } + const bool conditionOptionSpecified = + std::find(parsedKeywords.begin(), parsedKeywords.end(), "CONDITION"_s) != + parsedKeywords.end(); + if (conditionOptionSpecified && arguments.Condition.empty()) { + status.SetError("CONDITION of sub-command GENERATE must not be empty " + "if specified."); + return false; + } - if (arg == "CONDITION") { - condition = value; - } else if (arg == "TARGET") { - target = value; - } else { - status.SetError("Unknown argument to GENERATE subcommand."); - return false; - } + const bool targetOptionSpecified = + std::find(parsedKeywords.begin(), parsedKeywords.end(), "TARGET"_s) != + parsedKeywords.end(); + if (targetOptionSpecified && arguments.Target.empty()) { + status.SetError("TARGET of sub-command GENERATE must not be empty " + "if specified."); + return false; } - std::string output = args[2]; - const bool inputIsContent = args[3] != "INPUT"; - if (inputIsContent && args[3] != "CONTENT") { + const bool outputOptionSpecified = + std::find(parsedKeywords.begin(), parsedKeywords.end(), "OUTPUT"_s) != + parsedKeywords.end(); + if (outputOptionSpecified && parsedKeywords[0] != "OUTPUT"_s) { status.SetError("Incorrect arguments to GENERATE subcommand."); return false; } - std::string input = args[4]; - AddEvaluationFile(input, target, output, condition, inputIsContent, status); + const bool inputIsContent = parsedKeywords[1] != "INPUT"_s; + if (inputIsContent && parsedKeywords[1] != "CONTENT") { + status.SetError("Unknown argument to GENERATE subcommand."); + } + + std::string input = arguments.Input; + if (inputIsContent) { + input = arguments.Content; + } + + AddEvaluationFile(input, arguments.Target, arguments.Output, + arguments.Condition, inputIsContent, status); return true; } -- cgit v0.12 From 5e4f3ceef73f8c664808b1cafb69ab4a4cd9ad1a Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Tue, 13 Oct 2020 00:01:16 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index d1cc7e4..1057aea 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 19) -set(CMake_VERSION_PATCH 20201012) +set(CMake_VERSION_PATCH 20201013) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From fd50a75fa01b4727a58350b494dbb23f6b0f103f Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Wed, 7 Oct 2020 14:05:34 -0400 Subject: CMP0115: Require source file extensions to be explicit --- Help/manual/cmake-policies.7.rst | 8 ++++ Help/policy/CMP0115.rst | 34 ++++++++++++++ Help/release/dev/explicit-source-extensions.rst | 5 ++ Source/cmGeneratorTarget.cxx | 8 +++- Source/cmPolicies.h | 4 +- Source/cmSourceFile.cxx | 61 ++++++++++++++++++------- Source/cmSourceFile.h | 5 +- Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt | 1 + Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt | 17 +++++++ Tests/RunCMake/CMP0115/CMP0115-NEW.cmake | 1 + Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt | 1 + Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt | 22 +++++++++ Tests/RunCMake/CMP0115/CMP0115-OLD.cmake | 1 + Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt | 1 + Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt | 36 +++++++++++++++ Tests/RunCMake/CMP0115/CMP0115-WARN.cmake | 1 + Tests/RunCMake/CMP0115/CMP0115.cmake | 3 ++ Tests/RunCMake/CMP0115/CMakeLists.txt | 3 ++ Tests/RunCMake/CMP0115/RunCMakeTest.cmake | 12 +++++ Tests/RunCMake/CMP0115/main.c | 4 ++ Tests/RunCMake/CMakeLists.txt | 1 + 21 files changed, 208 insertions(+), 21 deletions(-) create mode 100644 Help/policy/CMP0115.rst create mode 100644 Help/release/dev/explicit-source-extensions.rst create mode 100644 Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt create mode 100644 Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt create mode 100644 Tests/RunCMake/CMP0115/CMP0115-NEW.cmake create mode 100644 Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt create mode 100644 Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt create mode 100644 Tests/RunCMake/CMP0115/CMP0115-OLD.cmake create mode 100644 Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt create mode 100644 Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt create mode 100644 Tests/RunCMake/CMP0115/CMP0115-WARN.cmake create mode 100644 Tests/RunCMake/CMP0115/CMP0115.cmake create mode 100644 Tests/RunCMake/CMP0115/CMakeLists.txt create mode 100644 Tests/RunCMake/CMP0115/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/CMP0115/main.c diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 0392325..0836883 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -51,6 +51,14 @@ The :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` variable may also be used to determine whether to report an error on use of deprecated macros or functions. +Policies Introduced by CMake 3.20 +================================= + +.. toctree:: + :maxdepth: 1 + + CMP0115: Source file extensions must be explicit. + Policies Introduced by CMake 3.19 ================================= diff --git a/Help/policy/CMP0115.rst b/Help/policy/CMP0115.rst new file mode 100644 index 0000000..7f82c43 --- /dev/null +++ b/Help/policy/CMP0115.rst @@ -0,0 +1,34 @@ +CMP0115 +------- + +.. versionadded:: 3.20 + +Source file extensions must be explicit. + +In CMake 3.19 and below, if a source file could not be found by the name +specified, it would append a list of known extensions to the name to see if +the file with the extension could be found. For example, this would allow the +user to run: + +.. code-block:: cmake + + add_executable(exe main) + +and put ``main.c`` in the executable without specifying the extension. + +Starting in CMake 3.20, CMake prefers all source files to have their extensions +explicitly listed: + +.. code-block:: cmake + + add_executable(exe main.c) + +The ``OLD`` behavior for this policy is to implicitly append known extensions +to source files if they can't be found. The ``NEW`` behavior of this policy is +to not append known extensions and require them to be explicit. + +This policy was introduced in CMake version 3.20. CMake version |release| +warns when the policy is not set and uses ``OLD`` behavior. Use the +:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly. + +.. include:: DEPRECATED.txt diff --git a/Help/release/dev/explicit-source-extensions.rst b/Help/release/dev/explicit-source-extensions.rst new file mode 100644 index 0000000..ccd9339 --- /dev/null +++ b/Help/release/dev/explicit-source-extensions.rst @@ -0,0 +1,5 @@ +explicit-source-extensions +-------------------------- + +* Source file extensions must now be explicit. See policy :policy:`CMP0115` for + details. diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 6ebc9e1..3b47550 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1539,10 +1539,14 @@ bool processSources(cmGeneratorTarget const* tgt, for (std::string& src : entry.Values) { cmSourceFile* sf = mf->GetOrCreateSource(src); std::string e; - std::string fullPath = sf->ResolveFullPath(&e); + std::string w; + std::string fullPath = sf->ResolveFullPath(&e, &w); + cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance(); + if (!w.empty()) { + cm->IssueMessage(MessageType::AUTHOR_WARNING, w, tgt->GetBacktrace()); + } if (fullPath.empty()) { if (!e.empty()) { - cmake* cm = tgt->GetLocalGenerator()->GetCMakeInstance(); cm->IssueMessage(MessageType::FATAL_ERROR, e, tgt->GetBacktrace()); } return contextDependent; diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 958d061..f9f7d0e 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -340,7 +340,9 @@ class cmMakefile; 3, 19, 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0114, \ "ExternalProject step targets fully adopt their steps.", 3, 19, 0, \ - cmPolicies::WARN) + cmPolicies::WARN) \ + SELECT(POLICY, CMP0115, "Source file extensions must be explicit.", 3, 20, \ + 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx index ef44a57..61f48e9 100644 --- a/Source/cmSourceFile.cxx +++ b/Source/cmSourceFile.cxx @@ -8,6 +8,7 @@ #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmMessageType.h" +#include "cmPolicies.h" #include "cmProperty.h" #include "cmState.h" #include "cmStringAlgorithms.h" @@ -93,10 +94,11 @@ cmSourceFileLocation const& cmSourceFile::GetLocation() const return this->Location; } -std::string const& cmSourceFile::ResolveFullPath(std::string* error) +std::string const& cmSourceFile::ResolveFullPath(std::string* error, + std::string* cmp0115Warning) { if (this->FullPath.empty()) { - if (this->FindFullPath(error)) { + if (this->FindFullPath(error, cmp0115Warning)) { this->CheckExtension(); } } @@ -108,7 +110,8 @@ std::string const& cmSourceFile::GetFullPath() const return this->FullPath; } -bool cmSourceFile::FindFullPath(std::string* error) +bool cmSourceFile::FindFullPath(std::string* error, + std::string* cmp0115Warning) { // If the file is generated compute the location without checking on disk. if (this->GetIsGenerated()) { @@ -131,9 +134,11 @@ bool cmSourceFile::FindFullPath(std::string* error) // List of extension lists std::vector exts = makefile->GetCMakeInstance()->GetAllExtensions(); + auto cmp0115 = makefile->GetPolicyStatus(cmPolicies::CMP0115); // Tries to find the file in a given directory - auto findInDir = [this, &exts, &lPath](std::string const& dir) -> bool { + auto findInDir = [this, &exts, &lPath, cmp0115, cmp0115Warning, + makefile](std::string const& dir) -> bool { // Compute full path std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir); // Try full path @@ -141,13 +146,29 @@ bool cmSourceFile::FindFullPath(std::string* error) this->FullPath = fullPath; return true; } - // Try full path with extension - for (std::string const& ext : exts) { - if (!ext.empty()) { - std::string extPath = cmStrCat(fullPath, '.', ext); - if (cmSystemTools::FileExists(extPath)) { - this->FullPath = extPath; - return true; + // This has to be an if statement due to a bug in Oracle Developer Studio. + // See https://community.oracle.com/tech/developers/discussion/4476246/ + // for details. + if (cmp0115 == cmPolicies::OLD || cmp0115 == cmPolicies::WARN) { + // Try full path with extension + for (std::string const& ext : exts) { + if (!ext.empty()) { + std::string extPath = cmStrCat(fullPath, '.', ext); + if (cmSystemTools::FileExists(extPath)) { + this->FullPath = extPath; + if (cmp0115 == cmPolicies::WARN) { + std::string warning = + cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0115), + "\nFile:\n ", extPath); + if (cmp0115Warning) { + *cmp0115Warning = std::move(warning); + } else { + makefile->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, warning); + } + } + return true; + } } } } @@ -168,11 +189,19 @@ bool cmSourceFile::FindFullPath(std::string* error) } // Compose error - std::string err = - cmStrCat("Cannot find source file:\n ", lPath, "\nTried extensions"); - for (std::string const& ext : exts) { - err += " ."; - err += ext; + std::string err = cmStrCat("Cannot find source file:\n ", lPath); + switch (cmp0115) { + case cmPolicies::OLD: + case cmPolicies::WARN: + err = cmStrCat(err, "\nTried extensions"); + for (auto const& ext : exts) { + err = cmStrCat(err, " .", ext); + } + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + break; } if (error != nullptr) { *error = std::move(err); diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index 39ea8e3..3196b3f 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -77,7 +77,8 @@ public: * Resolves the full path to the file. Attempts to locate the file on disk * and finalizes its location. */ - std::string const& ResolveFullPath(std::string* error = nullptr); + std::string const& ResolveFullPath(std::string* error = nullptr, + std::string* cmp0115Warning = nullptr); /** * The resolved full path to the file. The returned file name might be empty @@ -138,7 +139,7 @@ private: bool FindFullPathFailed = false; bool IsGenerated = false; - bool FindFullPath(std::string* error); + bool FindFullPath(std::string* error, std::string* cmp0115Warning); void CheckExtension(); void CheckLanguage(std::string const& ext); diff --git a/Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt b/Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt new file mode 100644 index 0000000..b63c53d --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-NEW-stderr.txt @@ -0,0 +1,17 @@ +^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\): + Cannot find source file: + + main +Call Stack \(most recent call first\): + CMP0115-NEW\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\): + No SOURCES given to target: exe +Call Stack \(most recent call first\): + CMP0115-NEW\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/CMP0115/CMP0115-NEW.cmake b/Tests/RunCMake/CMP0115/CMP0115-NEW.cmake new file mode 100644 index 0000000..ddf5071 --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-NEW.cmake @@ -0,0 +1 @@ +include(CMP0115.cmake) diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt b/Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-OLD-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt new file mode 100644 index 0000000..8b90311 --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt @@ -0,0 +1,22 @@ +^CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\): + Cannot find source file: + + noexist + + Tried extensions [^ +]* + [^ +]* +Call Stack \(most recent call first\): + CMP0115-OLD\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\): + No SOURCES given to target: exe +Call Stack \(most recent call first\): + CMP0115-OLD\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD.cmake b/Tests/RunCMake/CMP0115/CMP0115-OLD.cmake new file mode 100644 index 0000000..ddf5071 --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-OLD.cmake @@ -0,0 +1 @@ +include(CMP0115.cmake) diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt b/Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-WARN-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt new file mode 100644 index 0000000..7b100b6 --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt @@ -0,0 +1,36 @@ +^CMake Warning \(dev\) at CMP0115\.cmake:[0-9]+ \(add_executable\): + Policy CMP0115 is not set: Source file extensions must be explicit\. Run + "cmake --help-policy CMP0115" for policy details\. Use the cmake_policy + command to set the policy and suppress this warning\. + + File: + + [^ +]*/Tests/RunCMake/CMP0115/main\.c +Call Stack \(most recent call first\): + CMP0115-WARN\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. + +CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\): + Cannot find source file: + + noexist + + Tried extensions [^ +]* + [^ +]* +Call Stack \(most recent call first\): + CMP0115-WARN\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\): + No SOURCES given to target: exe +Call Stack \(most recent call first\): + CMP0115-WARN\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Generate step failed\. Build files cannot be regenerated correctly\.$ diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN.cmake b/Tests/RunCMake/CMP0115/CMP0115-WARN.cmake new file mode 100644 index 0000000..ddf5071 --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115-WARN.cmake @@ -0,0 +1 @@ +include(CMP0115.cmake) diff --git a/Tests/RunCMake/CMP0115/CMP0115.cmake b/Tests/RunCMake/CMP0115/CMP0115.cmake new file mode 100644 index 0000000..be910a4 --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMP0115.cmake @@ -0,0 +1,3 @@ +enable_language(C) + +add_executable(exe main noexist) diff --git a/Tests/RunCMake/CMP0115/CMakeLists.txt b/Tests/RunCMake/CMP0115/CMakeLists.txt new file mode 100644 index 0000000..b646c4a --- /dev/null +++ b/Tests/RunCMake/CMP0115/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.18) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CMP0115/RunCMakeTest.cmake b/Tests/RunCMake/CMP0115/RunCMakeTest.cmake new file mode 100644 index 0000000..58182ac --- /dev/null +++ b/Tests/RunCMake/CMP0115/RunCMakeTest.cmake @@ -0,0 +1,12 @@ +include(RunCMake) + +function(run_cmp0115 status) + if(NOT status STREQUAL "WARN") + set(RunCMake_TEST_OPTIONS -DCMAKE_POLICY_DEFAULT_CMP0115=${status}) + endif() + run_cmake(CMP0115-${status}) +endfunction() + +run_cmp0115(OLD) +run_cmp0115(WARN) +run_cmp0115(NEW) diff --git a/Tests/RunCMake/CMP0115/main.c b/Tests/RunCMake/CMP0115/main.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/CMP0115/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 63738d7..a8261c6 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -125,6 +125,7 @@ if(CMake_TEST_CUDA) endif() add_RunCMake_test(CMP0106) add_RunCMake_test(CMP0111) +add_RunCMake_test(CMP0115) # The test for Policy 65 requires the use of the # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode -- cgit v0.12 From 946adadd404a160b708e96e668be9b84c949de69 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Fri, 2 Oct 2020 12:11:19 -0400 Subject: cmGccDepfileReader: Rework helper code Fix some of the semantics of the depfile, add error handling, and refactor cmGccDepfileLexerHelper. --- Source/LexerParser/cmGccDepfileLexer.cxx | 2 +- Source/LexerParser/cmGccDepfileLexer.in.l | 2 +- Source/cmGccDepfileLexerHelper.cxx | 33 ++++++++++++++-------- Source/cmGccDepfileLexerHelper.h | 3 +- Source/cmGccDepfileReader.cxx | 9 +++--- Source/cmGccDepfileReader.h | 4 ++- Source/cmQtAutoMocUic.cxx | 8 +++--- Tests/CMakeLib/testGccDepfileReader.cxx | 21 ++++++++++---- Tests/CMakeLib/testGccDepfileReader_data/deps4.d | 1 + Tests/CMakeLib/testGccDepfileReader_data/deps5.d | 0 Tests/CMakeLib/testGccDepfileReader_data/deps5.txt | 2 ++ Tests/CMakeLib/testGccDepfileReader_data/deps7.d | 6 ++++ Tests/CMakeLib/testGccDepfileReader_data/deps7.txt | 10 +++++++ 13 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 Tests/CMakeLib/testGccDepfileReader_data/deps4.d create mode 100644 Tests/CMakeLib/testGccDepfileReader_data/deps5.d create mode 100644 Tests/CMakeLib/testGccDepfileReader_data/deps5.txt create mode 100644 Tests/CMakeLib/testGccDepfileReader_data/deps7.d create mode 100644 Tests/CMakeLib/testGccDepfileReader_data/deps7.txt diff --git a/Source/LexerParser/cmGccDepfileLexer.cxx b/Source/LexerParser/cmGccDepfileLexer.cxx index a98969d..3630f4e 100644 --- a/Source/LexerParser/cmGccDepfileLexer.cxx +++ b/Source/LexerParser/cmGccDepfileLexer.cxx @@ -994,7 +994,7 @@ case 5: YY_RULE_SETUP { // A line continuation ends the current file name. - yyextra->newDependency(); + yyextra->newRuleOrDependency(); } YY_BREAK case 6: diff --git a/Source/LexerParser/cmGccDepfileLexer.in.l b/Source/LexerParser/cmGccDepfileLexer.in.l index 08f8577..c83cb75 100644 --- a/Source/LexerParser/cmGccDepfileLexer.in.l +++ b/Source/LexerParser/cmGccDepfileLexer.in.l @@ -42,7 +42,7 @@ NEWLINE \r?\n } {WSPACE}*\\{NEWLINE} { // A line continuation ends the current file name. - yyextra->newDependency(); + yyextra->newRuleOrDependency(); } {NEWLINE} { // A newline ends the current file name and the current rule. diff --git a/Source/cmGccDepfileLexerHelper.cxx b/Source/cmGccDepfileLexerHelper.cxx index 957896f..c782bcd 100644 --- a/Source/cmGccDepfileLexerHelper.cxx +++ b/Source/cmGccDepfileLexerHelper.cxx @@ -27,23 +27,30 @@ bool cmGccDepfileLexerHelper::readFile(const char* filePath) if (!file) { return false; } - newEntry(); + this->newEntry(); yyscan_t scanner; cmGccDepfile_yylex_init(&scanner); cmGccDepfile_yyset_extra(this, scanner); cmGccDepfile_yyrestart(file, scanner); cmGccDepfile_yylex(scanner); cmGccDepfile_yylex_destroy(scanner); - sanitizeContent(); + this->sanitizeContent(); fclose(file); - return true; + return this->HelperState != State::Failed; } void cmGccDepfileLexerHelper::newEntry() { + if (this->HelperState == State::Rule && !this->Content.empty()) { + if (!this->Content.back().rules.empty() && + !this->Content.back().rules.back().empty()) { + this->HelperState = State::Failed; + } + return; + } this->HelperState = State::Rule; this->Content.emplace_back(); - newRule(); + this->newRule(); } void cmGccDepfileLexerHelper::newRule() @@ -56,20 +63,22 @@ void cmGccDepfileLexerHelper::newRule() void cmGccDepfileLexerHelper::newDependency() { - // printf("NEW DEP\n"); + if (this->HelperState == State::Failed) { + return; + } this->HelperState = State::Dependency; - if (this->Content.back().paths.empty() || - !this->Content.back().paths.back().empty()) { - this->Content.back().paths.emplace_back(); + auto& entry = this->Content.back(); + if (entry.paths.empty() || !entry.paths.back().empty()) { + entry.paths.emplace_back(); } } void cmGccDepfileLexerHelper::newRuleOrDependency() { if (this->HelperState == State::Rule) { - newRule(); - } else { - newDependency(); + this->newRule(); + } else if (this->HelperState == State::Dependency) { + this->newDependency(); } } @@ -93,6 +102,8 @@ void cmGccDepfileLexerHelper::addToCurrentPath(const char* s) } dst = &dep->paths.back(); } break; + case State::Failed: + return; } dst->append(s); } diff --git a/Source/cmGccDepfileLexerHelper.h b/Source/cmGccDepfileLexerHelper.h index 07ca61d..91132f5 100644 --- a/Source/cmGccDepfileLexerHelper.h +++ b/Source/cmGccDepfileLexerHelper.h @@ -29,7 +29,8 @@ private: enum class State { Rule, - Dependency + Dependency, + Failed, }; State HelperState = State::Rule; }; diff --git a/Source/cmGccDepfileReader.cxx b/Source/cmGccDepfileReader.cxx index 9d70ede..eb3511a 100644 --- a/Source/cmGccDepfileReader.cxx +++ b/Source/cmGccDepfileReader.cxx @@ -5,14 +5,15 @@ #include #include +#include + #include "cmGccDepfileLexerHelper.h" -cmGccDepfileContent cmReadGccDepfile(const char* filePath) +cm::optional cmReadGccDepfile(const char* filePath) { - cmGccDepfileContent result; cmGccDepfileLexerHelper helper; if (helper.readFile(filePath)) { - result = std::move(helper).extractContent(); + return cm::make_optional(std::move(helper).extractContent()); } - return result; + return cm::nullopt; } diff --git a/Source/cmGccDepfileReader.h b/Source/cmGccDepfileReader.h index 395dd77..59ed7fd 100644 --- a/Source/cmGccDepfileReader.h +++ b/Source/cmGccDepfileReader.h @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include + #include "cmGccDepfileReaderTypes.h" -cmGccDepfileContent cmReadGccDepfile(const char* filePath); +cm::optional cmReadGccDepfile(const char* filePath); diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 9cb172b..b27bb88 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -26,7 +27,6 @@ #include "cmCryptoHash.h" #include "cmFileTime.h" #include "cmGccDepfileReader.h" -#include "cmGccDepfileReaderTypes.h" #include "cmGeneratedFileStream.h" #include "cmQtAutoGen.h" #include "cmQtAutoGenerator.h" @@ -2841,14 +2841,14 @@ bool cmQtAutoMocUicT::CreateDirectories() std::vector cmQtAutoMocUicT::dependenciesFromDepFile( const char* filePath) { - cmGccDepfileContent content = cmReadGccDepfile(filePath); - if (content.empty()) { + auto const content = cmReadGccDepfile(filePath); + if (!content || content->empty()) { return {}; } // Moc outputs a depfile with exactly one rule. // Discard the rule and return the dependencies. - return content.front().paths; + return content->front().paths; } void cmQtAutoMocUicT::Abort(bool error) diff --git a/Tests/CMakeLib/testGccDepfileReader.cxx b/Tests/CMakeLib/testGccDepfileReader.cxx index e79f047..d46e8f3 100644 --- a/Tests/CMakeLib/testGccDepfileReader.cxx +++ b/Tests/CMakeLib/testGccDepfileReader.cxx @@ -5,6 +5,8 @@ #include #include +#include + #include "cmsys/FStream.hxx" #include "cmGccDepfileReader.h" @@ -112,17 +114,26 @@ int testGccDepfileReader(int argc, char* argv[]) std::string dataDirPath = argv[1]; dataDirPath += "/testGccDepfileReader_data"; - const int numberOfTestFiles = 3; + const int numberOfTestFiles = 7; // 6th file doesn't exist for (int i = 1; i <= numberOfTestFiles; ++i) { const std::string base = dataDirPath + "/deps" + std::to_string(i); const std::string depfile = base + ".d"; const std::string plainDepfile = base + ".txt"; std::cout << "Comparing " << base << " with " << plainDepfile << std::endl; const auto actual = cmReadGccDepfile(depfile.c_str()); - const auto expected = readPlainDepfile(plainDepfile.c_str()); - if (!compare(actual, expected)) { - dump("actual", actual); - dump("expected", expected); + if (cmSystemTools::FileExists(plainDepfile)) { + if (!actual) { + std::cerr << "Reading " << depfile << " should have succeeded\n"; + return 1; + } + const auto expected = readPlainDepfile(plainDepfile.c_str()); + if (!compare(*actual, expected)) { + dump("actual", *actual); + dump("expected", expected); + return 1; + } + } else if (actual) { + std::cerr << "Reading " << depfile << " should have failed\n"; return 1; } } diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps4.d b/Tests/CMakeLib/testGccDepfileReader_data/deps4.d new file mode 100644 index 0000000..9977a28 --- /dev/null +++ b/Tests/CMakeLib/testGccDepfileReader_data/deps4.d @@ -0,0 +1 @@ +invalid diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps5.d b/Tests/CMakeLib/testGccDepfileReader_data/deps5.d new file mode 100644 index 0000000..e69de29 diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps5.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps5.txt new file mode 100644 index 0000000..6c4a75b --- /dev/null +++ b/Tests/CMakeLib/testGccDepfileReader_data/deps5.txt @@ -0,0 +1,2 @@ +--RULES-- +--DEPENDENCIES-- diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps7.d b/Tests/CMakeLib/testGccDepfileReader_data/deps7.d new file mode 100644 index 0000000..92280cf --- /dev/null +++ b/Tests/CMakeLib/testGccDepfileReader_data/deps7.d @@ -0,0 +1,6 @@ +out1 \ + out2: \ + in1 \ + in2 + +out3: in3 diff --git a/Tests/CMakeLib/testGccDepfileReader_data/deps7.txt b/Tests/CMakeLib/testGccDepfileReader_data/deps7.txt new file mode 100644 index 0000000..86b6600 --- /dev/null +++ b/Tests/CMakeLib/testGccDepfileReader_data/deps7.txt @@ -0,0 +1,10 @@ +--RULES-- +out1 +out2 +--DEPENDENCIES-- +in1 +in2 +--RULES-- +out3 +--DEPENDENCIES-- +in3 -- cgit v0.12 From b2c14bc7749c21b8a994ce1d9f4e736f712481b9 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Fri, 2 Oct 2020 14:25:30 -0400 Subject: cmake -E: Add cmake_transform_depfile internal command --- Source/CMakeLists.txt | 2 + Source/cmTransformDepfile.cxx | 114 +++++++++++++++++++++ Source/cmTransformDepfile.h | 14 +++ Source/cmcmd.cxx | 18 ++++ Tests/RunCMake/CMakeLists.txt | 1 + Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake | 21 ++++ Tests/RunCMake/TransformDepfile/deps-unix.d | 6 ++ Tests/RunCMake/TransformDepfile/deps-unix.d.txt | 8 ++ Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt | 6 ++ Tests/RunCMake/TransformDepfile/deps-windows.d | 6 ++ Tests/RunCMake/TransformDepfile/deps-windows.d.txt | 8 ++ .../TransformDepfile/deps-windows.tlog.txt | 6 ++ Tests/RunCMake/TransformDepfile/empty.d | 0 Tests/RunCMake/TransformDepfile/empty.d.txt | 0 Tests/RunCMake/TransformDepfile/empty.tlog.txt | 0 Tests/RunCMake/TransformDepfile/gccdepfile.cmake | 16 +++ .../TransformDepfile/invalid-gcc-result.txt | 1 + .../TransformDepfile/invalid-tlog-result.txt | 1 + Tests/RunCMake/TransformDepfile/invalid.d | 1 + Tests/RunCMake/TransformDepfile/noexist.d.txt | 0 Tests/RunCMake/TransformDepfile/noexist.tlog.txt | 0 Tests/RunCMake/TransformDepfile/vstlog.cmake | 16 +++ bootstrap | 4 + 23 files changed, 249 insertions(+) create mode 100644 Source/cmTransformDepfile.cxx create mode 100644 Source/cmTransformDepfile.h create mode 100644 Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/TransformDepfile/deps-unix.d create mode 100644 Tests/RunCMake/TransformDepfile/deps-unix.d.txt create mode 100644 Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt create mode 100644 Tests/RunCMake/TransformDepfile/deps-windows.d create mode 100644 Tests/RunCMake/TransformDepfile/deps-windows.d.txt create mode 100644 Tests/RunCMake/TransformDepfile/deps-windows.tlog.txt create mode 100644 Tests/RunCMake/TransformDepfile/empty.d create mode 100644 Tests/RunCMake/TransformDepfile/empty.d.txt create mode 100644 Tests/RunCMake/TransformDepfile/empty.tlog.txt create mode 100644 Tests/RunCMake/TransformDepfile/gccdepfile.cmake create mode 100644 Tests/RunCMake/TransformDepfile/invalid-gcc-result.txt create mode 100644 Tests/RunCMake/TransformDepfile/invalid-tlog-result.txt create mode 100644 Tests/RunCMake/TransformDepfile/invalid.d create mode 100644 Tests/RunCMake/TransformDepfile/noexist.d.txt create mode 100644 Tests/RunCMake/TransformDepfile/noexist.tlog.txt create mode 100644 Tests/RunCMake/TransformDepfile/vstlog.cmake diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1e16e17..2946022 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -439,6 +439,8 @@ set(SRCS cmTest.h cmTestGenerator.cxx cmTestGenerator.h + cmTransformDepfile.cxx + cmTransformDepfile.h cmUuid.cxx cmUVHandlePtr.cxx cmUVHandlePtr.h diff --git a/Source/cmTransformDepfile.cxx b/Source/cmTransformDepfile.cxx new file mode 100644 index 0000000..e1f8753 --- /dev/null +++ b/Source/cmTransformDepfile.cxx @@ -0,0 +1,114 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmTransformDepfile.h" + +#include +#include +#include +#include + +#include + +#include "cmsys/FStream.hxx" + +#include "cmGccDepfileReader.h" +#include "cmGccDepfileReaderTypes.h" +#include "cmStringAlgorithms.h" +#include "cmSystemTools.h" + +namespace { +void WriteFilenameGcc(cmsys::ofstream& fout, const std::string& filename) +{ + for (auto c : filename) { + switch (c) { + case ' ': + fout << "\\ "; + break; + case '\\': + fout << "\\\\"; + break; + default: + fout << c; + break; + } + } +} + +void WriteGccDepfile(cmsys::ofstream& fout, const cmGccDepfileContent& content) +{ + for (auto const& dep : content) { + bool first = true; + for (auto const& rule : dep.rules) { + if (!first) { + fout << " \\\n "; + } + first = false; + WriteFilenameGcc(fout, rule); + } + fout << ':'; + for (auto const& path : dep.paths) { + fout << " \\\n " << path; + } + fout << '\n'; + } +} + +void WriteVsTlog(cmsys::ofstream& fout, const cmGccDepfileContent& content) +{ + for (auto const& dep : content) { + fout << '^'; + bool first = true; + for (auto const& rule : dep.rules) { + if (!first) { + fout << '|'; + } + first = false; + fout << cmSystemTools::ConvertToOutputPath(rule); + } + fout << "\r\n"; + for (auto const& path : dep.paths) { + fout << cmSystemTools::ConvertToOutputPath(path) << "\r\n"; + } + } +} +} + +bool cmTransformDepfile(cmDepfileFormat format, const std::string& prefix, + const std::string& infile, const std::string& outfile) +{ + cmGccDepfileContent content; + if (cmSystemTools::FileExists(infile)) { + auto result = cmReadGccDepfile(infile.c_str()); + if (!result) { + return false; + } + content = *std::move(result); + } + + for (auto& dep : content) { + for (auto& rule : dep.rules) { + if (!cmSystemTools::FileIsFullPath(rule)) { + rule = cmStrCat(prefix, rule); + } + } + for (auto& path : dep.paths) { + if (!cmSystemTools::FileIsFullPath(path)) { + path = cmStrCat(prefix, path); + } + } + } + + cmsys::ofstream fout(outfile.c_str()); + if (!fout) { + return false; + } + switch (format) { + case cmDepfileFormat::GccDepfile: + WriteGccDepfile(fout, content); + break; + case cmDepfileFormat::VsTlog: + WriteVsTlog(fout, content); + break; + } + return true; +} diff --git a/Source/cmTransformDepfile.h b/Source/cmTransformDepfile.h new file mode 100644 index 0000000..792c1aa --- /dev/null +++ b/Source/cmTransformDepfile.h @@ -0,0 +1,14 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include + +enum class cmDepfileFormat +{ + GccDepfile, + VsTlog, +}; + +bool cmTransformDepfile(cmDepfileFormat format, const std::string& prefix, + const std::string& infile, const std::string& outfile); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 15d2fd1..0bdc6fa 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -19,6 +19,7 @@ #include "cmStateSnapshot.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTransformDepfile.h" #include "cmUVProcessChain.h" #include "cmUtils.hxx" #include "cmVersion.h" @@ -1426,6 +1427,23 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args) return cmcmd::WindowsCEEnvironment("9.0", args[2]); } #endif + + // Internal depfile transformation + if (args[1] == "cmake_transform_depfile" && args.size() == 6) { + auto format = cmDepfileFormat::GccDepfile; + if (args[2] == "gccdepfile") { + format = cmDepfileFormat::GccDepfile; + } else if (args[2] == "vstlog") { + format = cmDepfileFormat::VsTlog; + } else { + return 1; + } + std::string prefix = args[3]; + if (prefix == "./") { + prefix.clear(); + } + return cmTransformDepfile(format, prefix, args[4], args[5]) ? 0 : 1; + } } ::CMakeCommandUsage(args[0].c_str()); diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index a8261c6..59ca3b1 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -771,6 +771,7 @@ add_RunCMake_test(PrecompileHeaders -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} add_RunCMake_test("UnityBuild") add_RunCMake_test(CMakePresets) +add_RunCMake_test(TransformDepfile) if(WIN32) add_RunCMake_test(Win32GenEx) diff --git a/Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake b/Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake new file mode 100644 index 0000000..cb75eb0 --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/RunCMakeTest.cmake @@ -0,0 +1,21 @@ +include(RunCMake) + +function(run_transform_depfile name) + set(RunCMake-check-file gccdepfile.cmake) + run_cmake_command(${name}-gcc + ${CMAKE_COMMAND} -E cmake_transform_depfile gccdepfile ../ ${CMAKE_CURRENT_LIST_DIR}/${name}.d out.d + ) + set(RunCMake-check-file vstlog.cmake) + run_cmake_command(${name}-tlog + ${CMAKE_COMMAND} -E cmake_transform_depfile vstlog ../ ${CMAKE_CURRENT_LIST_DIR}/${name}.d out.tlog + ) +endfunction() + +if(WIN32) + run_transform_depfile(deps-windows) +else() + run_transform_depfile(deps-unix) +endif() +run_transform_depfile(noexist) +run_transform_depfile(empty) +run_transform_depfile(invalid) diff --git a/Tests/RunCMake/TransformDepfile/deps-unix.d b/Tests/RunCMake/TransformDepfile/deps-unix.d new file mode 100644 index 0000000..5da5be8 --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/deps-unix.d @@ -0,0 +1,6 @@ +out1 /home/build/out2: in1 /home/build/in2 + +out3 \ + /home/build/out4: \ + in3 \ + /home/build/in4 diff --git a/Tests/RunCMake/TransformDepfile/deps-unix.d.txt b/Tests/RunCMake/TransformDepfile/deps-unix.d.txt new file mode 100644 index 0000000..58770f2 --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/deps-unix.d.txt @@ -0,0 +1,8 @@ +../out1 \ + /home/build/out2: \ + ../in1 \ + /home/build/in2 +../out3 \ + /home/build/out4: \ + ../in3 \ + /home/build/in4 diff --git a/Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt b/Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt new file mode 100644 index 0000000..2a26edf --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/deps-unix.tlog.txt @@ -0,0 +1,6 @@ +^../out1|/home/build/out2 +../in1 +/home/build/in2 +^../out3|/home/build/out4 +../in3 +/home/build/in4 diff --git a/Tests/RunCMake/TransformDepfile/deps-windows.d b/Tests/RunCMake/TransformDepfile/deps-windows.d new file mode 100644 index 0000000..c926670 --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/deps-windows.d @@ -0,0 +1,6 @@ +out1 C:/build/out2: in1 C:/build/in2 + +out3 \ + C:/build/out4: \ + in3 \ + C:/build/in4 diff --git a/Tests/RunCMake/TransformDepfile/deps-windows.d.txt b/Tests/RunCMake/TransformDepfile/deps-windows.d.txt new file mode 100644 index 0000000..47b3ebf --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/deps-windows.d.txt @@ -0,0 +1,8 @@ +../out1 \ + C:/build/out2: \ + ../in1 \ + C:/build/in2 +../out3 \ + C:/build/out4: \ + ../in3 \ + C:/build/in4 diff --git a/Tests/RunCMake/TransformDepfile/deps-windows.tlog.txt b/Tests/RunCMake/TransformDepfile/deps-windows.tlog.txt new file mode 100644 index 0000000..1e6024d --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/deps-windows.tlog.txt @@ -0,0 +1,6 @@ +^..\out1|C:\build\out2 +..\in1 +C:\build\in2 +^..\out3|C:\build\out4 +..\in3 +C:\build\in4 diff --git a/Tests/RunCMake/TransformDepfile/empty.d b/Tests/RunCMake/TransformDepfile/empty.d new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/TransformDepfile/empty.d.txt b/Tests/RunCMake/TransformDepfile/empty.d.txt new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/TransformDepfile/empty.tlog.txt b/Tests/RunCMake/TransformDepfile/empty.tlog.txt new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/TransformDepfile/gccdepfile.cmake b/Tests/RunCMake/TransformDepfile/gccdepfile.cmake new file mode 100644 index 0000000..be1e210 --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/gccdepfile.cmake @@ -0,0 +1,16 @@ +if(EXISTS "${RunCMake_SOURCE_DIR}/${name}.d.txt") + file(READ "${RunCMake_SOURCE_DIR}/${name}.d.txt" expected_contents) + + if(EXISTS "${RunCMake_TEST_BINARY_DIR}/out.d") + file(READ "${RunCMake_TEST_BINARY_DIR}/out.d" actual_contents) + if(NOT actual_contents STREQUAL expected_contents) + string(REPLACE "\n" "\n " p_expected_contents "${expected_contents}") + string(REPLACE "\n" "\n " p_actual_contents "${actual_contents}") + string(APPEND RunCMake_TEST_FAILED "Expected contents of ${RunCMake_TEST_BINARY_DIR}/out.d:\n ${p_expected_contents}\nActual contents:\n ${p_actual_contents}") + endif() + else() + string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/out.d should exist\n") + endif() +elseif(EXISTS "${RunCMake_TEST_BINARY_DIR}/out.d") + string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/out.d should not exist\n") +endif() diff --git a/Tests/RunCMake/TransformDepfile/invalid-gcc-result.txt b/Tests/RunCMake/TransformDepfile/invalid-gcc-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/invalid-gcc-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/TransformDepfile/invalid-tlog-result.txt b/Tests/RunCMake/TransformDepfile/invalid-tlog-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/invalid-tlog-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/TransformDepfile/invalid.d b/Tests/RunCMake/TransformDepfile/invalid.d new file mode 100644 index 0000000..9977a28 --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/invalid.d @@ -0,0 +1 @@ +invalid diff --git a/Tests/RunCMake/TransformDepfile/noexist.d.txt b/Tests/RunCMake/TransformDepfile/noexist.d.txt new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/TransformDepfile/noexist.tlog.txt b/Tests/RunCMake/TransformDepfile/noexist.tlog.txt new file mode 100644 index 0000000..e69de29 diff --git a/Tests/RunCMake/TransformDepfile/vstlog.cmake b/Tests/RunCMake/TransformDepfile/vstlog.cmake new file mode 100644 index 0000000..afa78d0 --- /dev/null +++ b/Tests/RunCMake/TransformDepfile/vstlog.cmake @@ -0,0 +1,16 @@ +if(EXISTS "${RunCMake_SOURCE_DIR}/${name}.tlog.txt") + file(READ "${RunCMake_SOURCE_DIR}/${name}.tlog.txt" expected_contents) + + if(EXISTS "${RunCMake_TEST_BINARY_DIR}/out.tlog") + file(READ "${RunCMake_TEST_BINARY_DIR}/out.tlog" actual_contents) + if(NOT actual_contents STREQUAL expected_contents) + string(REPLACE "\n" "\n " p_expected_contents "${expected_contents}") + string(REPLACE "\n" "\n " p_actual_contents "${actual_contents}") + string(APPEND RunCMake_TEST_FAILED "Expected contents of ${RunCMake_TEST_BINARY_DIR}/out.tlog:\n ${p_expected_contents}\nActual contents:\n ${p_actual_contents}") + endif() + else() + string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/out.tlog should exist\n") + endif() +elseif(EXISTS "${RunCMake_TEST_BINARY_DIR}/out.tlog") + string(APPEND RunCMake_TEST_FAILED "${RunCMake_TEST_BINARY_DIR}/out.tlog should not exist\n") +endif() diff --git a/bootstrap b/bootstrap index feccde9..9126ae6 100755 --- a/bootstrap +++ b/bootstrap @@ -412,6 +412,8 @@ CMAKE_CXX_SOURCES="\ cmProjectCommand \ cmPropertyDefinition \ cmPropertyMap \ + cmGccDepfileLexerHelper \ + cmGccDepfileReader \ cmReturnCommand \ cmRulePlaceholderExpander \ cmRuntimeDependencyArchive \ @@ -452,6 +454,7 @@ CMAKE_CXX_SOURCES="\ cmTest \ cmTestGenerator \ cmTimestamp \ + cmTransformDepfile \ cmTryCompileCommand \ cmTryRunCommand \ cmUnsetCommand \ @@ -491,6 +494,7 @@ LexerParser_CXX_SOURCES="\ cmCommandArgumentParser \ cmExprLexer \ cmExprParser \ + cmGccDepfileLexer \ " LexerParser_C_SOURCES="\ -- cgit v0.12 From 596439b1bbac44b4218f65615d93e9fe9bd43922 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Mon, 5 Oct 2020 12:15:17 -0400 Subject: cmCustomCommandGenerator: Add option to transform depfile --- Source/cmCustomCommandGenerator.cxx | 73 ++++++++++++++++++++++++++++++++++++- Source/cmCustomCommandGenerator.h | 4 +- Source/cmGlobalGenerator.h | 6 +++ bootstrap | 67 +++++++++++++++++----------------- 4 files changed, 113 insertions(+), 37 deletions(-) diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 60504ba..d8307f6 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -6,18 +6,22 @@ #include #include +#include #include +#include "cmCryptoHash.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmGeneratorExpression.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmProperty.h" #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmTransformDepfile.h" namespace { void AppendPaths(const std::vector& inputs, @@ -42,7 +46,8 @@ void AppendPaths(const std::vector& inputs, cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config, - cmLocalGenerator* lg) + cmLocalGenerator* lg, + bool transformDepfile) : CC(cc) , Config(std::move(config)) , LG(lg) @@ -75,6 +80,36 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, this->CommandLines.push_back(std::move(argv)); } + if (transformDepfile && !this->CommandLines.empty() && + !cc.GetDepfile().empty() && + this->LG->GetGlobalGenerator()->DepfileFormat()) { + cmCustomCommandLine argv; + argv.push_back(cmSystemTools::GetCMakeCommand()); + argv.emplace_back("-E"); + argv.emplace_back("cmake_transform_depfile"); + switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) { + case cmDepfileFormat::GccDepfile: + argv.emplace_back("gccdepfile"); + break; + case cmDepfileFormat::VsTlog: + argv.emplace_back("vstlog"); + break; + } + if (this->LG->GetCurrentBinaryDirectory() == + this->LG->GetBinaryDirectory()) { + argv.emplace_back("./"); + } else { + argv.push_back(cmStrCat(this->LG->MaybeConvertToRelativePath( + this->LG->GetBinaryDirectory(), + this->LG->GetCurrentBinaryDirectory()), + '/')); + } + argv.push_back(this->GetFullDepfile()); + argv.push_back(this->GetInternalDepfile()); + + this->CommandLines.push_back(std::move(argv)); + } + AppendPaths(cc.GetByproducts(), ge, this->LG, this->Config, this->Byproducts); AppendPaths(cc.GetDepends(), ge, this->LG, this->Config, this->Depends); @@ -97,7 +132,7 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const { - return static_cast(this->CC.GetCommandLines().size()); + return static_cast(this->CommandLines.size()); } void cmCustomCommandGenerator::FillEmulatorsWithArguments() @@ -234,6 +269,40 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c, } } +std::string cmCustomCommandGenerator::GetFullDepfile() const +{ + std::string depfile = this->CC.GetDepfile(); + if (depfile.empty()) { + return ""; + } + + if (!cmSystemTools::FileIsFullPath(depfile)) { + depfile = cmStrCat(this->LG->GetCurrentBinaryDirectory(), '/', depfile); + } + return cmSystemTools::CollapseFullPath(depfile); +} + +std::string cmCustomCommandGenerator::GetInternalDepfile() const +{ + std::string depfile = this->GetFullDepfile(); + if (depfile.empty()) { + return ""; + } + + cmCryptoHash hash(cmCryptoHash::AlgoSHA256); + std::string extension; + switch (*this->LG->GetGlobalGenerator()->DepfileFormat()) { + case cmDepfileFormat::GccDepfile: + extension = ".d"; + break; + case cmDepfileFormat::VsTlog: + extension = ".tlog"; + break; + } + return cmStrCat(this->LG->GetBinaryDirectory(), "/CMakeFiles/d/", + hash.HashString(depfile), extension); +} + const char* cmCustomCommandGenerator::GetComment() const { return this->CC.GetComment(); diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h index 412eba8..8b5259d 100644 --- a/Source/cmCustomCommandGenerator.h +++ b/Source/cmCustomCommandGenerator.h @@ -31,7 +31,7 @@ class cmCustomCommandGenerator public: cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config, - cmLocalGenerator* lg); + cmLocalGenerator* lg, bool transformDepfile = true); cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete; cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) = delete; @@ -45,4 +45,6 @@ public: std::vector const& GetByproducts() const; std::vector const& GetDepends() const; bool HasOnlyEmptyCommandLines() const; + std::string GetFullDepfile() const; + std::string GetInternalDepfile() const; }; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index b532a43..de5eba7 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -14,6 +14,7 @@ #include #include +#include #include #include "cm_codecvt.hxx" @@ -26,6 +27,7 @@ #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetDepend.h" +#include "cmTransformDepfile.h" #if !defined(CMAKE_BOOTSTRAP) # include @@ -452,6 +454,10 @@ public: virtual bool ShouldStripResourcePath(cmMakefile*) const; virtual bool SupportsCustomCommandDepfile() const { return false; } + virtual cm::optional DepfileFormat() const + { + return cm::nullopt; + } std::string GetSharedLibFlagsForLanguage(std::string const& lang) const; diff --git a/bootstrap b/bootstrap index 9126ae6..b36c162 100755 --- a/bootstrap +++ b/bootstrap @@ -307,6 +307,7 @@ CMAKE_CXX_SOURCES="\ cmContinueCommand \ cmCoreTryCompile \ cmCreateTestSourceList \ + cmCryptoHash \ cmCustomCommand \ cmCustomCommandGenerator \ cmCustomCommandLines \ @@ -539,6 +540,18 @@ KWSYS_FILES="\ SystemTools.hxx \ Terminal.h" +LIBRHASH_C_SOURCES="\ + librhash/algorithms.c \ + librhash/byte_order.c \ + librhash/hex.c \ + librhash/md5.c \ + librhash/rhash.c \ + librhash/sha1.c \ + librhash/sha256.c \ + librhash/sha3.c \ + librhash/sha512.c \ + " + if ${cmake_system_mingw}; then LIBUV_C_SOURCES="\ src/fs-poll.c \ @@ -1016,7 +1029,6 @@ cmake_ld_flags=${LDFLAGS} # Add generator-specific files if test "${cmake_bootstrap_generator}" = "Ninja"; then CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES} \ - cmCryptoHash \ cmFortranParserImpl \ cmGlobalNinjaGenerator \ cmLocalNinjaGenerator \ @@ -1037,18 +1049,6 @@ if test "${cmake_bootstrap_generator}" = "Ninja"; then src/lib_json/json_value.cpp \ src/lib_json/json_writer.cpp \ " - - LIBRHASH_C_SOURCES="\ - librhash/algorithms.c \ - librhash/byte_order.c \ - librhash/hex.c \ - librhash/md5.c \ - librhash/rhash.c \ - librhash/sha1.c \ - librhash/sha256.c \ - librhash/sha3.c \ - librhash/sha512.c \ - " else CMAKE_CXX_SOURCES="${CMAKE_CXX_SOURCES} \ cmDepends \ @@ -1062,7 +1062,6 @@ else " JSONCPP_CXX_SOURCES= - LIBRHASH_C_SOURCES= fi # Add Cygwin-specific flags @@ -1632,17 +1631,17 @@ if test "x${bootstrap_system_libuv}" = "x"; then objs="${objs} uv-`cmake_obj ${a}`" done fi +if test "x${bootstrap_system_librhash}" = "x"; then + for a in ${LIBRHASH_C_SOURCES}; do + objs="${objs} rhash-`cmake_obj ${a}`" + done +fi if test "${cmake_bootstrap_generator}" = "Ninja"; then if test "x${bootstrap_system_jsoncpp}" = "x"; then for a in ${JSONCPP_CXX_SOURCES}; do objs="${objs} jsoncpp-`cmake_obj ${a}`" done fi - if test "x${bootstrap_system_librhash}" = "x"; then - for a in ${LIBRHASH_C_SOURCES}; do - objs="${objs} rhash-`cmake_obj ${a}`" - done - fi fi libs="" @@ -1702,6 +1701,15 @@ else libs="${libs} -luv" fi +if test "x${bootstrap_system_librhash}" != "x"; then + if test `which pkg-config`; then + use_librhash_flags="`pkg-config --cflags librhash`" + cmake_c_flags="${cmake_c_flags} ${use_librhash_flags}" + cmake_cxx_flags="${cmake_cxx_flags} ${use_librhash_flags}" + fi + libs="${libs} -lrhash" +fi + if test "${cmake_bootstrap_generator}" = "Ninja"; then jsoncpp_cxx_flags= if test "x${bootstrap_system_jsoncpp}" = "x"; then @@ -1713,15 +1721,6 @@ if test "${cmake_bootstrap_generator}" = "Ninja"; then fi libs="${libs} -ljsoncpp" fi - - if test "x${bootstrap_system_librhash}" != "x"; then - if test `which pkg-config`; then - use_librhash_flags="`pkg-config --cflags librhash`" - cmake_c_flags="${cmake_c_flags} ${use_librhash_flags}" - cmake_cxx_flags="${cmake_cxx_flags} ${use_librhash_flags}" - fi - libs="${libs} -lrhash" - fi fi if test "x${cmake_ansi_cxx_flags}" != "x"; then @@ -1845,6 +1844,12 @@ if test "x${bootstrap_system_libuv}" = "x"; then write_source_rule "c" "uv-`cmake_obj ${a}`" "${src}" "${uv_c_flags}" done fi +if test "x${bootstrap_system_librhash}" = "x"; then + for a in ${LIBRHASH_C_SOURCES}; do + src=`cmake_escape_artifact "${cmake_source_dir}/Utilities/cmlibrhash/${a}"` + write_source_rule "c" "rhash-`cmake_obj ${a}`" "${src}" "" + done +fi if test "${cmake_bootstrap_generator}" = "Ninja"; then if test "x${bootstrap_system_jsoncpp}" = "x"; then for a in ${JSONCPP_CXX_SOURCES}; do @@ -1852,12 +1857,6 @@ if test "${cmake_bootstrap_generator}" = "Ninja"; then write_source_rule "cxx" "jsoncpp-`cmake_obj ${a}`" "${src}" "${jsoncpp_cxx_flags}" done fi - if test "x${bootstrap_system_librhash}" = "x"; then - for a in ${LIBRHASH_C_SOURCES}; do - src=`cmake_escape_artifact "${cmake_source_dir}/Utilities/cmlibrhash/${a}"` - write_source_rule "c" "rhash-`cmake_obj ${a}`" "${src}" "" - done - fi fi if test "${cmake_bootstrap_generator}" = "Ninja"; then echo " -- cgit v0.12 From 146e1e6ba14d964bf120635aca953cc76e5b2282 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Fri, 2 Oct 2020 17:35:40 -0400 Subject: Ninja: Transform DEPFILEs with policy CMP0116 Fixes: #21267 --- Help/command/add_custom_command.rst | 5 +++ Help/manual/cmake-policies.7.rst | 1 + Help/policy/CMP0116.rst | 38 +++++++++++++++++ Help/release/dev/ninja-depfile-transformation.rst | 5 +++ Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst | 2 + Source/cmGlobalNinjaGenerator.h | 5 +++ Source/cmLocalNinjaGenerator.cxx | 45 +++++++++++++++++++- Source/cmPolicies.h | 5 ++- Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake | 3 ++ Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake | 3 ++ Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake | 3 ++ Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake | 3 ++ .../CMP0116/CMP0116-WARN-NOWARN-stderr.txt | 7 ++++ Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake | 3 ++ .../RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt | 16 +++++++ Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake | 3 ++ Tests/RunCMake/CMP0116/CMakeLists.txt | 3 ++ Tests/RunCMake/CMP0116/Common.cmake | 8 ++++ Tests/RunCMake/CMP0116/RunCMakeTest.cmake | 49 ++++++++++++++++++++++ Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt | 6 +++ Tests/RunCMake/CMP0116/WriteDepfile.cmake | 3 ++ Tests/RunCMake/CMP0116/check.cmake | 18 ++++++++ Tests/RunCMake/CMakeLists.txt | 3 ++ 23 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 Help/policy/CMP0116.rst create mode 100644 Help/release/dev/ninja-depfile-transformation.rst create mode 100644 Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake create mode 100644 Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake create mode 100644 Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake create mode 100644 Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake create mode 100644 Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt create mode 100644 Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake create mode 100644 Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt create mode 100644 Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake create mode 100644 Tests/RunCMake/CMP0116/CMakeLists.txt create mode 100644 Tests/RunCMake/CMP0116/Common.cmake create mode 100644 Tests/RunCMake/CMP0116/RunCMakeTest.cmake create mode 100644 Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt create mode 100644 Tests/RunCMake/CMP0116/WriteDepfile.cmake create mode 100644 Tests/RunCMake/CMP0116/check.cmake diff --git a/Help/command/add_custom_command.rst b/Help/command/add_custom_command.rst index 231f9da..a28b0b1 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -239,6 +239,11 @@ The options are: command itself. Using ``DEPFILE`` with other generators than Ninja is an error. + If the ``DEPFILE`` argument is relative, it should be relative to + :variable:`CMAKE_CURRENT_BINARY_DIR`, and any relative paths inside the + ``DEPFILE`` should also be relative to :variable:`CMAKE_CURRENT_BINARY_DIR` + (see policy :policy:`CMP0116`.) + Build Events ^^^^^^^^^^^^ diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 0836883..886fe80 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -57,6 +57,7 @@ Policies Introduced by CMake 3.20 .. toctree:: :maxdepth: 1 + CMP0116: Ninja generators transform DEPFILEs from add_custom_command(). CMP0115: Source file extensions must be explicit. Policies Introduced by CMake 3.19 diff --git a/Help/policy/CMP0116.rst b/Help/policy/CMP0116.rst new file mode 100644 index 0000000..25a14c4 --- /dev/null +++ b/Help/policy/CMP0116.rst @@ -0,0 +1,38 @@ +CMP0116 +------- + +.. versionadded:: 3.20 + +Ninja generators transform ``DEPFILE`` s from :command:`add_custom_command`. + +In CMake 3.19 and below, files given to the ``DEPFILE`` argument of +:command:`add_custom_command` were passed directly to Ninja's ``depfile`` +variable without any path resolution. This meant that if +:command:`add_custom_command` was called from a subdirectory (created by +:command:`add_subdirectory`), the ``DEPFILE`` argument would have to be either +an absolute path or a path relative to :variable:`CMAKE_BINARY_DIR`, rather +than :variable:`CMAKE_CURRENT_BINARY_DIR`. In addition, no transformation was +done on the file listed in ``DEPFILE``, which meant that the paths within the +``DEPFILE`` had the same restrictions. + +Starting with CMake 3.20, the ``DEPFILE`` argument is relative to +:variable:`CMAKE_CURRENT_BINARY_DIR` (unless it is absolute), and the paths in +the ``DEPFILE`` are also relative to :variable:`CMAKE_CURRENT_BINARY_DIR`. +CMake automatically transforms the paths in the ``DEPFILE`` (unless they are +absolute) after the custom command is run. The file listed in ``DEPFILE`` is +not modified in any way. Instead, CMake writes the transformation to its own +internal file, and passes this internal file to Ninja's ``depfile`` variable. +This transformation happens regardless of whether or not ``DEPFILE`` is +relative, and regardless of whether or not :command:`add_custom_command` is +called from a subdirectory. + +The ``OLD`` behavior for this policy is to pass the ``DEPFILE`` to Ninja +unaltered. The ``NEW`` behavior for this policy is to transform the ``DEPFILE`` +after running the custom command. + +This policy was introduced in CMake version 3.20. Unlike most policies, +CMake version |release| does *not* warn by default when this policy is not set +(unless ``DEPFILE`` is used in a subdirectory) and simply uses ``OLD`` +behavior. See documentation of the +:variable:`CMAKE_POLICY_WARNING_CMP0116 >` +variable to control the warning. diff --git a/Help/release/dev/ninja-depfile-transformation.rst b/Help/release/dev/ninja-depfile-transformation.rst new file mode 100644 index 0000000..edf7f58 --- /dev/null +++ b/Help/release/dev/ninja-depfile-transformation.rst @@ -0,0 +1,5 @@ +ninja-depfile-transformation +---------------------------- + +* Ninja generators now transform ``DEPFILE`` s from + :command:`add_custom_command`. See policy :policy:`CMP0116` for details. diff --git a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst index d35595a..9f68741 100644 --- a/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst +++ b/Help/variable/CMAKE_POLICY_WARNING_CMPNNNN.rst @@ -27,6 +27,8 @@ warn by default: policy :policy:`CMP0102`. * ``CMAKE_POLICY_WARNING_CMP0112`` controls the warning for policy :policy:`CMP0112`. +* ``CMAKE_POLICY_WARNING_CMP0116`` controls the warning for + policy :policy:`CMP0116`. This variable should not be set by a project in CMake code. Project developers running CMake may set this variable in their cache to diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 884a711..ec001d3 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -24,6 +24,7 @@ #include "cmNinjaTypes.h" #include "cmPolicies.h" #include "cmStringAlgorithms.h" +#include "cmTransformDepfile.h" class cmCustomCommand; class cmGeneratorTarget; @@ -211,6 +212,10 @@ public: const char* GetCleanTargetName() const override { return "clean"; } bool SupportsCustomCommandDepfile() const override { return true; } + cm::optional DepfileFormat() const override + { + return cmDepfileFormat::GccDepfile; + } virtual cmGeneratedFileStream* GetImplFileStream( const std::string& /*config*/) const diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index ad782ee..ce85320 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -22,7 +22,9 @@ #include "cmGlobalNinjaGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" +#include "cmMessageType.h" #include "cmNinjaTargetGenerator.h" +#include "cmPolicies.h" #include "cmProperty.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" @@ -573,7 +575,20 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( return; } - cmCustomCommandGenerator ccg(*cc, config, this); + bool transformDepfile = false; + auto cmp0116 = this->GetPolicyStatus(cmPolicies::CMP0116); + switch (cmp0116) { + case cmPolicies::OLD: + case cmPolicies::WARN: + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + transformDepfile = true; + break; + } + + cmCustomCommandGenerator ccg(*cc, config, this, transformDepfile); const std::vector& outputs = ccg.GetOutputs(); const std::vector& byproducts = ccg.GetByproducts(); @@ -623,10 +638,36 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( cmCryptoHash hash(cmCryptoHash::AlgoSHA256); customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7); + std::string depfile = cc->GetDepfile(); + if (!depfile.empty()) { + switch (cmp0116) { + case cmPolicies::WARN: + if (this->GetCurrentBinaryDirectory() != + this->GetBinaryDirectory() || + this->Makefile->PolicyOptionalWarningEnabled( + "CMAKE_POLICY_WARNING_CMP0116")) { + this->GetCMakeInstance()->IssueMessage( + MessageType::AUTHOR_WARNING, + cmPolicies::GetPolicyWarning(cmPolicies::CMP0116), + cc->GetBacktrace()); + } + CM_FALLTHROUGH; + case cmPolicies::OLD: + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + cmSystemTools::MakeDirectory( + cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles/d")); + depfile = ccg.GetInternalDepfile(); + break; + } + } + gg->WriteCustomCommandBuild( this->BuildCommandLine(cmdLines, customStep), this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0], - cc->GetDepfile(), cc->GetJobPool(), cc->GetUsesTerminal(), + depfile, cc->GetJobPool(), cc->GetUsesTerminal(), /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, config, ninjaDeps, orderOnlyDeps); } diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index f9f7d0e..99bac98 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -342,7 +342,10 @@ class cmMakefile; "ExternalProject step targets fully adopt their steps.", 3, 19, 0, \ cmPolicies::WARN) \ SELECT(POLICY, CMP0115, "Source file extensions must be explicit.", 3, 20, \ - 0, cmPolicies::WARN) + 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0116, \ + "Ninja generators transform DEPFILEs from add_custom_command().", 3, \ + 20, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake new file mode 100644 index 0000000..f92fac6 --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMP0116-NEW-NOWARN.cmake @@ -0,0 +1,3 @@ +set(depdir) + +include(Common.cmake) diff --git a/Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake new file mode 100644 index 0000000..f92fac6 --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMP0116-NEW-WARN.cmake @@ -0,0 +1,3 @@ +set(depdir) + +include(Common.cmake) diff --git a/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake new file mode 100644 index 0000000..665f485 --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMP0116-OLD-NOWARN.cmake @@ -0,0 +1,3 @@ +set(depdir Subdirectory/) + +include(Common.cmake) diff --git a/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake new file mode 100644 index 0000000..665f485 --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMP0116-OLD-WARN.cmake @@ -0,0 +1,3 @@ +set(depdir Subdirectory/) + +include(Common.cmake) diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt new file mode 100644 index 0000000..843ff1c --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN-stderr.txt @@ -0,0 +1,7 @@ +^(CMake Warning \(dev\) at Subdirectory/CMakeLists\.txt:[0-9]+ \(add_custom_command\): + Policy CMP0116 is not set: Ninja generators transform DEPFILEs from + add_custom_command\(\)\. Run "cmake --help-policy CMP0116" for policy + details\. Use the cmake_policy command to set the policy and suppress this + warning\. +This warning is for project developers\. Use -Wno-dev to suppress it\. +*)+$ diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake new file mode 100644 index 0000000..665f485 --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMP0116-WARN-NOWARN.cmake @@ -0,0 +1,3 @@ +set(depdir Subdirectory/) + +include(Common.cmake) diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt new file mode 100644 index 0000000..e29af91 --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN-stderr.txt @@ -0,0 +1,16 @@ +^(CMake Warning \(dev\) at Common\.cmake:[0-9]+ \(add_custom_command\): + Policy CMP0116 is not set: Ninja generators transform DEPFILEs from + add_custom_command\(\)\. Run "cmake --help-policy CMP0116" for policy + details\. Use the cmake_policy command to set the policy and suppress this + warning\. +Call Stack \(most recent call first\): + CMP0116-WARN-WARN\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\. ++)+(CMake Warning \(dev\) at Subdirectory/CMakeLists\.txt:[0-9]+ \(add_custom_command\): + Policy CMP0116 is not set: Ninja generators transform DEPFILEs from + add_custom_command\(\)\. Run "cmake --help-policy CMP0116" for policy + details\. Use the cmake_policy command to set the policy and suppress this + warning\. +This warning is for project developers\. Use -Wno-dev to suppress it\. +*)+$ diff --git a/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake new file mode 100644 index 0000000..665f485 --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMP0116-WARN-WARN.cmake @@ -0,0 +1,3 @@ +set(depdir Subdirectory/) + +include(Common.cmake) diff --git a/Tests/RunCMake/CMP0116/CMakeLists.txt b/Tests/RunCMake/CMP0116/CMakeLists.txt new file mode 100644 index 0000000..b646c4a --- /dev/null +++ b/Tests/RunCMake/CMP0116/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.18) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/CMP0116/Common.cmake b/Tests/RunCMake/CMP0116/Common.cmake new file mode 100644 index 0000000..472b162 --- /dev/null +++ b/Tests/RunCMake/CMP0116/Common.cmake @@ -0,0 +1,8 @@ +add_custom_command( + OUTPUT top.txt + COMMAND ${CMAKE_COMMAND} -DOUTFILE=top.txt -DINFILE=topdep.txt -DDEPFILE=top.txt.d -DSTAMPFILE=topstamp.txt -DDEPDIR= -P ${CMAKE_SOURCE_DIR}/WriteDepfile.cmake + DEPFILE top.txt.d + ) +add_custom_target(top ALL DEPENDS top.txt) + +add_subdirectory(Subdirectory) diff --git a/Tests/RunCMake/CMP0116/RunCMakeTest.cmake b/Tests/RunCMake/CMP0116/RunCMakeTest.cmake new file mode 100644 index 0000000..8a83cc1 --- /dev/null +++ b/Tests/RunCMake/CMP0116/RunCMakeTest.cmake @@ -0,0 +1,49 @@ +include(RunCMake) + +function(run_cmp0116 status warn) + if(warn) + set(name CMP0116-${status}-WARN) + else() + set(name CMP0116-${status}-NOWARN) + endif() + set(RunCMake_TEST_OPTIONS + -DCMAKE_POLICY_WARNING_CMP0116:BOOL=${warn} + ) + if(NOT status STREQUAL "WARN") + list(APPEND RunCMake_TEST_OPTIONS + -DCMAKE_POLICY_DEFAULT_CMP0116:STRING=${status} + ) + endif() + + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-build) + run_cmake(${name}) + unset(RunCMake_TEST_OPTIONS) + set(RunCMake_TEST_NO_CLEAN 1) + set(RunCMake-check-file check.cmake) + + file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topdep.txt") + file(TOUCH "${RunCMake_TEST_BINARY_DIR}/Subdirectory/subdep.txt") + set(cmp0116_step 1) + run_cmake_command(${name}-build1 ${CMAKE_COMMAND} --build . --config Debug) + file(REMOVE "${RunCMake_TEST_BINARY_DIR}/topstamp.txt") + file(REMOVE "${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt") + execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.25) + + file(TOUCH "${RunCMake_TEST_BINARY_DIR}/topdep.txt") + file(TOUCH "${RunCMake_TEST_BINARY_DIR}/Subdirectory/subdep.txt") + set(cmp0116_step 2) + run_cmake_command(${name}-build2 ${CMAKE_COMMAND} --build . --config Debug) + file(REMOVE "${RunCMake_TEST_BINARY_DIR}/topstamp.txt") + file(REMOVE "${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt") + execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1.25) + + set(cmp0116_step 3) + run_cmake_command(${name}-build3 ${CMAKE_COMMAND} --build . --config Debug) +endfunction() + +run_cmp0116(WARN OFF) +run_cmp0116(OLD OFF) +run_cmp0116(NEW OFF) +run_cmp0116(WARN ON) +run_cmp0116(OLD ON) +run_cmp0116(NEW ON) diff --git a/Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt b/Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt new file mode 100644 index 0000000..f0f60b2 --- /dev/null +++ b/Tests/RunCMake/CMP0116/Subdirectory/CMakeLists.txt @@ -0,0 +1,6 @@ +add_custom_command( + OUTPUT sub.txt + COMMAND ${CMAKE_COMMAND} -DOUTFILE=sub.txt -DINFILE=subdep.txt -DDEPFILE=sub.txt.d -DSTAMPFILE=substamp.txt -DDEPDIR=${depdir} -P ${CMAKE_SOURCE_DIR}/WriteDepfile.cmake + DEPFILE ${depdir}sub.txt.d + ) +add_custom_target(sub ALL DEPENDS sub.txt) diff --git a/Tests/RunCMake/CMP0116/WriteDepfile.cmake b/Tests/RunCMake/CMP0116/WriteDepfile.cmake new file mode 100644 index 0000000..1a74d2a --- /dev/null +++ b/Tests/RunCMake/CMP0116/WriteDepfile.cmake @@ -0,0 +1,3 @@ +file(TOUCH "${OUTFILE}") +file(TOUCH "${STAMPFILE}") +file(WRITE "${DEPFILE}" "${DEPDIR}${OUTFILE}: ${DEPDIR}${INFILE}\n") diff --git a/Tests/RunCMake/CMP0116/check.cmake b/Tests/RunCMake/CMP0116/check.cmake new file mode 100644 index 0000000..1b16748 --- /dev/null +++ b/Tests/RunCMake/CMP0116/check.cmake @@ -0,0 +1,18 @@ +function(check_exists file) + if(NOT EXISTS "${file}") + string(APPEND RunCMake_TEST_FAILED "${file} does not exist\n") + endif() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) +endfunction() + +function(check_not_exists file) + if(EXISTS "${file}") + string(APPEND RunCMake_TEST_FAILED "${file} exists\n") + endif() + set(RunCMake_TEST_FAILED "${RunCMake_TEST_FAILED}" PARENT_SCOPE) +endfunction() + +if(cmp0116_step EQUAL 3) + check_not_exists("${RunCMake_TEST_BINARY_DIR}/topstamp.txt") + check_not_exists("${RunCMake_TEST_BINARY_DIR}/Subdirectory/substamp.txt") +endif() diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 59ca3b1..6072711 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -126,6 +126,9 @@ endif() add_RunCMake_test(CMP0106) add_RunCMake_test(CMP0111) add_RunCMake_test(CMP0115) +if(CMAKE_GENERATOR MATCHES "Ninja") + add_RunCMake_test(CMP0116) +endif() # The test for Policy 65 requires the use of the # CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode -- cgit v0.12 From 297ab15bf6cbc75f30c83238977b4b83524e7107 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Tue, 13 Oct 2020 10:37:30 -0400 Subject: Ninja Multi-Config: Read configuration variables as normal variables Early versions of the Ninja Multi-Config generator required CMAKE_CONFIGURATION_TYPES and friends to be cache variables in order to support selecting the default config in cmake(1) --build. The behavior of cmake(1) --build has since been updated to no longer require this, and requiring these variables to be cache variables is inconsistent with the other generators. Read the variables as normal CMake variables like the other generators. This does not require a policy, since the only scenario where this would cause a breakage is one where the cache variable and the CMake variable are explicitly set to different values, which doesn't make sense to do anyway. --- Source/cmGlobalNinjaGenerator.cxx | 33 +++++++++++++-------------------- Source/cmGlobalNinjaGenerator.h | 3 --- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 985f430..9e25a54 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -2650,30 +2650,17 @@ void cmGlobalNinjaMultiGenerator::GetQtAutoGenConfigs( bool cmGlobalNinjaMultiGenerator::InspectConfigTypeVariables() { - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_BUILD_TYPE"); - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_CROSS_CONFIGS"); - this->GetCMakeInstance()->MarkCliAsUsed("CMAKE_DEFAULT_CONFIGS"); - return this->ReadCacheEntriesForBuild(*this->Makefiles.front()->GetState()); -} - -std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const -{ - return ""; -} - -bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( - const cmState& state) -{ std::vector configsVec; - cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CONFIGURATION_TYPES"), - configsVec); + cmExpandList( + this->Makefiles.front()->GetSafeDefinition("CMAKE_CONFIGURATION_TYPES"), + configsVec); if (configsVec.empty()) { configsVec.emplace_back(); } std::set configs(configsVec.cbegin(), configsVec.cend()); this->DefaultFileConfig = - state.GetSafeCacheEntryValue("CMAKE_DEFAULT_BUILD_TYPE"); + this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_BUILD_TYPE"); if (this->DefaultFileConfig.empty()) { this->DefaultFileConfig = configsVec.front(); } @@ -2688,8 +2675,9 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( } std::vector crossConfigsVec; - cmExpandList(state.GetSafeCacheEntryValue("CMAKE_CROSS_CONFIGS"), - crossConfigsVec); + cmExpandList( + this->Makefiles.front()->GetSafeDefinition("CMAKE_CROSS_CONFIGS"), + crossConfigsVec); auto crossConfigs = ListSubsetWithAll(configs, configs, crossConfigsVec); if (!crossConfigs) { std::ostringstream msg; @@ -2702,7 +2690,7 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( this->CrossConfigs = *crossConfigs; auto defaultConfigsString = - state.GetSafeCacheEntryValue("CMAKE_DEFAULT_CONFIGS"); + this->Makefiles.front()->GetSafeDefinition("CMAKE_DEFAULT_CONFIGS"); if (defaultConfigsString.empty()) { defaultConfigsString = this->DefaultFileConfig; } @@ -2736,6 +2724,11 @@ bool cmGlobalNinjaMultiGenerator::ReadCacheEntriesForBuild( return true; } +std::string cmGlobalNinjaMultiGenerator::GetDefaultBuildConfig() const +{ + return ""; +} + std::string cmGlobalNinjaMultiGenerator::OrderDependsTargetForTarget( cmGeneratorTarget const* target, const std::string& config) const { diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 884a711..f6e7633 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -31,7 +31,6 @@ class cmLinkLineComputer; class cmLocalGenerator; class cmMakefile; class cmOutputConverter; -class cmState; class cmStateDirectory; class cmake; struct cmDocumentationEntry; @@ -647,8 +646,6 @@ public: std::string GetDefaultBuildConfig() const override; - bool ReadCacheEntriesForBuild(const cmState& state) override; - bool SupportsDefaultBuildType() const override { return true; } bool SupportsCrossConfigs() const override { return true; } bool SupportsDefaultConfigs() const override { return true; } -- cgit v0.12 From 2b218883cda6b16d38eb2372ab080aa5f5326e0c Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 13 Oct 2020 14:01:54 -0400 Subject: Add deprecation warnings for policies CMP0075 and below The OLD behaviors of all policies are deprecated, but only by documentation. Add an explicit deprecation diagnostic for policies introduced in CMake 3.12 and below to encourage projects to port away from setting policies to OLD. --- Source/cmMakefile.cxx | 2 +- Tests/RunCMake/CheckModules/CMP0075-stderr.txt | 13 ++++++++++++- Tests/RunCMake/add_library/CMP0073-stderr.txt | 10 ++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 Tests/RunCMake/add_library/CMP0073-stderr.txt diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 9286e93..c366b48 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -4427,7 +4427,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, // Deprecate old policies, especially those that require a lot // of code to maintain the old behavior. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0072 && + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0075 && !(this->GetCMakeInstance()->GetIsInTryCompile() && ( // Policies set by cmCoreTryCompile::TryCompileCode. diff --git a/Tests/RunCMake/CheckModules/CMP0075-stderr.txt b/Tests/RunCMake/CheckModules/CMP0075-stderr.txt index 960fe94..97833f5 100644 --- a/Tests/RunCMake/CheckModules/CMP0075-stderr.txt +++ b/Tests/RunCMake/CheckModules/CMP0075-stderr.txt @@ -47,4 +47,15 @@ CMake Warning \(dev\) at [^ Call Stack \(most recent call first\): CMP0075.cmake:41 \(check_include_files\) CMakeLists.txt:[0-9]+ \(include\) -This warning is for project developers. Use -Wno-dev to suppress it.$ +This warning is for project developers. Use -Wno-dev to suppress it. ++ +CMake Deprecation Warning at CMP0075.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0075 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/add_library/CMP0073-stderr.txt b/Tests/RunCMake/add_library/CMP0073-stderr.txt new file mode 100644 index 0000000..7f43fd7 --- /dev/null +++ b/Tests/RunCMake/add_library/CMP0073-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0073.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0073 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ -- cgit v0.12 From 3eaf053940682a0ca69cc9118ac7237b4b3e006f Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 13 Oct 2020 14:37:47 -0400 Subject: export: Increase maximum policy version in exported files to 3.18 The files generatd by `install(EXPORT)` and `export()` commands are known to work with policies as of CMake 3.18, so enable them in sufficiently new CMake versions. --- Source/cmExportFileGenerator.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index cbae4e5..a853bb1 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -924,13 +924,13 @@ void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) // Isolate the file policy level. // Support CMake versions as far back as 2.6 but also support using NEW - // policy settings for up to CMake 3.17 (this upper limit may be reviewed + // policy settings for up to CMake 3.18 (this upper limit may be reviewed // and increased from time to time). This reduces the opportunity for CMake // warnings when an older export file is later used with newer CMake // versions. /* clang-format off */ os << "cmake_policy(PUSH)\n" - << "cmake_policy(VERSION 2.6...3.17)\n"; + << "cmake_policy(VERSION 2.6...3.18)\n"; /* clang-format on */ } -- cgit v0.12 From a0e474aaf25f5554750eb72cc1cff1f73effa30a Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 13 Oct 2020 14:42:08 -0400 Subject: Configure CMake itself with policies through CMake 3.18 --- CMakeLists.txt | 2 +- Utilities/Doxygen/CMakeLists.txt | 2 +- Utilities/Sphinx/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d860d4..a2fcf2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. -cmake_minimum_required(VERSION 3.1...3.15 FATAL_ERROR) +cmake_minimum_required(VERSION 3.1...3.18 FATAL_ERROR) set(CMAKE_USER_MAKE_RULES_OVERRIDE_C ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideC.cmake) set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX ${CMAKE_CURRENT_SOURCE_DIR}/Source/Modules/OverrideCXX.cmake) project(CMake) diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt index 5bf13f3..a880f7a 100644 --- a/Utilities/Doxygen/CMakeLists.txt +++ b/Utilities/Doxygen/CMakeLists.txt @@ -3,7 +3,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeDeveloperReference_STANDALONE 1) - cmake_minimum_required(VERSION 3.1...3.15 FATAL_ERROR) + cmake_minimum_required(VERSION 3.1...3.18 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt index e5be43a..f989907 100644 --- a/Utilities/Sphinx/CMakeLists.txt +++ b/Utilities/Sphinx/CMakeLists.txt @@ -3,7 +3,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeHelp_STANDALONE 1) - cmake_minimum_required(VERSION 3.1...3.15 FATAL_ERROR) + cmake_minimum_required(VERSION 3.1...3.18 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) -- cgit v0.12 From 8b13f1a5272696250494e7e9692d4447ce4a20bc Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 13 Oct 2020 14:44:09 -0400 Subject: Help/dev: Add maintainer guide step for post-release policy updates --- Help/dev/maint.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Help/dev/maint.rst b/Help/dev/maint.rst index 75d685c..664b7a4 100644 --- a/Help/dev/maint.rst +++ b/Help/dev/maint.rst @@ -357,3 +357,13 @@ policies added for that version. Commit with a message such as:: The files generatd by `install(EXPORT)` and `export()` commands are known to work with policies as of CMake $prev, so enable them in sufficiently new CMake versions. + +Update the ``cmake_minimum_required`` version range in CMake itself: + +* ``CMakeLists.txt`` +* ``Utilities/Doxygen/CMakeLists.txt`` +* ``Utilities/Sphinx/CMakeLists.txt`` + +to end in the previous release. Commit with a message such as:: + + Configure CMake itself with policies through CMake $prev -- cgit v0.12 From c30d06b7e66c9bfe52f91f472a38cefdfc527601 Mon Sep 17 00:00:00 2001 From: Sibi Siddharthan Date: Tue, 6 Oct 2020 09:37:40 +0530 Subject: FindIntl: Add imported target Fixes: #21271 Signed-off-by: Sibi Siddharthan --- .gitlab/ci/configure_debian10_ninja.cmake | 1 + .gitlab/ci/configure_fedora31_makefiles.cmake | 1 + Help/release/dev/FindIntl-imported-target.rst | 4 +++ Modules/FindIntl.cmake | 44 ++++++++++++++++++++++----- Tests/CMakeLists.txt | 1 + Tests/FindIntl/CMakeLists.txt | 10 ++++++ Tests/FindIntl/Test/CMakeLists.txt | 14 +++++++++ Tests/FindIntl/Test/main.cxx | 11 +++++++ 8 files changed, 78 insertions(+), 8 deletions(-) create mode 100644 Help/release/dev/FindIntl-imported-target.rst create mode 100644 Tests/FindIntl/CMakeLists.txt create mode 100644 Tests/FindIntl/Test/CMakeLists.txt create mode 100644 Tests/FindIntl/Test/main.cxx diff --git a/.gitlab/ci/configure_debian10_ninja.cmake b/.gitlab/ci/configure_debian10_ninja.cmake index 2340543..90556bf 100644 --- a/.gitlab/ci/configure_debian10_ninja.cmake +++ b/.gitlab/ci/configure_debian10_ninja.cmake @@ -19,6 +19,7 @@ set(CMake_TEST_FindGSL "ON" CACHE BOOL "") set(CMake_TEST_FindGTest "ON" CACHE BOOL "") set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "") set(CMake_TEST_FindIconv "ON" CACHE BOOL "") +set(CMake_TEST_FindIntl "ON" CACHE BOOL "") set(CMake_TEST_FindJPEG "ON" CACHE BOOL "") set(CMake_TEST_FindJsonCpp "ON" CACHE BOOL "") set(CMake_TEST_FindLAPACK "ON" CACHE BOOL "") diff --git a/.gitlab/ci/configure_fedora31_makefiles.cmake b/.gitlab/ci/configure_fedora31_makefiles.cmake index 8d2454f..db2d005 100644 --- a/.gitlab/ci/configure_fedora31_makefiles.cmake +++ b/.gitlab/ci/configure_fedora31_makefiles.cmake @@ -19,6 +19,7 @@ set(CMake_TEST_FindGSL "ON" CACHE BOOL "") set(CMake_TEST_FindGTest "ON" CACHE BOOL "") set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "") set(CMake_TEST_FindIconv "ON" CACHE BOOL "") +set(CMake_TEST_FindIntl "ON" CACHE BOOL "") set(CMake_TEST_FindJPEG "ON" CACHE BOOL "") set(CMake_TEST_FindJsonCpp "ON" CACHE BOOL "") set(CMake_TEST_FindLAPACK "ON" CACHE BOOL "") diff --git a/Help/release/dev/FindIntl-imported-target.rst b/Help/release/dev/FindIntl-imported-target.rst new file mode 100644 index 0000000..5770f21 --- /dev/null +++ b/Help/release/dev/FindIntl-imported-target.rst @@ -0,0 +1,4 @@ +FindIntl-imported-target +------------------------ + +* The :module:`FindIntl` module now provides an imported target. diff --git a/Modules/FindIntl.cmake b/Modules/FindIntl.cmake index 1a09a60..d29f554 100644 --- a/Modules/FindIntl.cmake +++ b/Modules/FindIntl.cmake @@ -15,11 +15,16 @@ installation in several variables. General variables:: Intl_FOUND - true if the libintl headers and libraries were found Intl_INCLUDE_DIRS - the directory containing the libintl headers Intl_LIBRARIES - libintl libraries to be linked + Intl::Intl - imported target for Intl The following cache variables may also be set:: Intl_INCLUDE_DIR - the directory containing the libintl headers Intl_LIBRARY - the libintl library (if any) + Intl_HAVE_GETTEXT_BUILTIN - check if gettext is in the C library + Intl_HAVE_DCGETTEXT_BUILTIN - check if dcgettext is in the C library + Intl_IS_BUILTIN - whether intl is a part of the C library determined + from the result of Intl_HAVE_GETTEXT_BUILTIN and Intl_HAVE_DCGETTEXT_BUILTIN .. note:: On some platforms, such as Linux with GNU libc, the gettext @@ -35,6 +40,22 @@ The following cache variables may also be set:: # Written by Roger Leigh +include(${CMAKE_CURRENT_LIST_DIR}/CMakePushCheckState.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CheckSymbolExists.cmake) + +# Check if we have libintl is a part of libc +cmake_push_check_state(RESET) +set(CMAKE_REQUIRED_QUIET TRUE) +check_symbol_exists(gettext libintl.h Intl_HAVE_GETTEXT_BUILTIN) +check_symbol_exists(dcgettext libintl.h Intl_HAVE_DCGETTEXT_BUILTIN) # redundant check +cmake_pop_check_state() + +if(Intl_HAVE_GETTEXT_BUILTIN AND Intl_HAVE_DCGETTEXT_BUILTIN) + set(Intl_IS_BUILTIN TRUE) +else() + set(Intl_IS_BUILTIN FALSE) +endif() + # Find include directory find_path(Intl_INCLUDE_DIR NAMES "libintl.h" @@ -42,21 +63,28 @@ find_path(Intl_INCLUDE_DIR mark_as_advanced(Intl_INCLUDE_DIR) # Find all Intl libraries -find_library(Intl_LIBRARY "intl" NAMES_PER_DIR - DOC "libintl libraries (if not in the C library)") -mark_as_advanced(Intl_LIBRARY) +set(Intl_REQUIRED_VARS) +if(NOT Intl_IS_BUILTIN) + find_library(Intl_LIBRARY "intl" "libintl" NAMES_PER_DIR + DOC "libintl libraries (if not in the C library)") + mark_as_advanced(Intl_LIBRARY) + list(APPEND Intl_REQUIRED_VARS Intl_LIBRARY) +endif() include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Intl FOUND_VAR Intl_FOUND - REQUIRED_VARS Intl_INCLUDE_DIR + REQUIRED_VARS Intl_INCLUDE_DIR ${Intl_REQUIRED_VARS} FAIL_MESSAGE "Failed to find Gettext libintl") +unset(Intl_REQUIRED_VARS) if(Intl_FOUND) set(Intl_INCLUDE_DIRS "${Intl_INCLUDE_DIR}") - if(Intl_LIBRARY) - set(Intl_LIBRARIES "${Intl_LIBRARY}") - else() - unset(Intl_LIBRARIES) + set(Intl_LIBRARIES "${Intl_LIBRARY}") + if(NOT TARGET Intl::Intl) + add_library(Intl::Intl INTERFACE IMPORTED) + set_target_properties(Intl::Intl PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Intl_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${Intl_LIBRARIES}") endif() endif() diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 9aa401d..f4be4b6 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1422,6 +1422,7 @@ if(BUILD_TESTING) GTK2 Iconv ICU + Intl JPEG JsonCpp LAPACK diff --git a/Tests/FindIntl/CMakeLists.txt b/Tests/FindIntl/CMakeLists.txt new file mode 100644 index 0000000..0906ede --- /dev/null +++ b/Tests/FindIntl/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindIntl.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $ + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindIntl/Test" + "${CMake_BINARY_DIR}/Tests/FindIntl/Test" + ${build_generator_args} + --build-project TestFindIntl + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $ + ) diff --git a/Tests/FindIntl/Test/CMakeLists.txt b/Tests/FindIntl/Test/CMakeLists.txt new file mode 100644 index 0000000..5140406 --- /dev/null +++ b/Tests/FindIntl/Test/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.10) +project(TestFindIntl CXX) +include(CTest) + +find_package(Intl REQUIRED) + +add_executable(test_intl_tgt main.cxx) +target_link_libraries(test_intl_tgt Intl::Intl) +add_test(NAME test_intl_tgt COMMAND test_intl_tgt) + +add_executable(test_intl_var main.cxx) +target_include_directories(test_intl_var PRIVATE ${Intl_INCLUDE_DIRS}) +target_link_libraries(test_intl_var PRIVATE ${Intl_LIBRARIES}) +add_test(NAME test_intl_var COMMAND test_intl_var) diff --git a/Tests/FindIntl/Test/main.cxx b/Tests/FindIntl/Test/main.cxx new file mode 100644 index 0000000..d90c095 --- /dev/null +++ b/Tests/FindIntl/Test/main.cxx @@ -0,0 +1,11 @@ +extern "C" { +#include +} + +int main() +{ + // Check if we include the directory correctly and have no link errors + bindtextdomain("", ""); + gettext(""); + return 0; +} -- cgit v0.12 From 652b096872adcdecd2c7ed6fdfe39c767a57e0c3 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Wed, 14 Oct 2020 00:01:11 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 1057aea..46f6226 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 19) -set(CMake_VERSION_PATCH 20201013) +set(CMake_VERSION_PATCH 20201014) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 9952ee063a1a2b31c784733b0cf676b4a6efc36e Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 14 Oct 2020 12:46:55 -0400 Subject: server: remove deprecated 'cmake -E server' mode The server mode has been deprecated since commit 996e1885c4 (server: deprecate in favor of the file-api, 2019-04-19, v3.15.0-rc1~198^2). Clients should now be using the file-api. Remove the server mode. --- Help/guide/ide-integration/index.rst | 4 +- Help/manual/cmake-server.7.rst | 741 +------------------- Help/manual/cmake.1.rst | 1 + Help/release/dev/remove-server-mode.rst | 5 + Source/CMakeLists.txt | 14 - Source/cmConnection.cxx | 173 ----- Source/cmConnection.h | 137 ---- Source/cmFileMonitor.cxx | 383 ----------- Source/cmFileMonitor.h | 35 - Source/cmJsonObjectDictionary.h | 45 -- Source/cmJsonObjects.cxx | 692 ------------------- Source/cmJsonObjects.h | 24 - Source/cmPipeConnection.cxx | 71 -- Source/cmPipeConnection.h | 29 - Source/cmServer.cxx | 570 ---------------- Source/cmServer.h | 162 ----- Source/cmServerConnection.cxx | 165 ----- Source/cmServerConnection.h | 67 -- Source/cmServerDictionary.h | 67 -- Source/cmServerProtocol.cxx | 760 --------------------- Source/cmServerProtocol.h | 162 ----- Source/cmake.cxx | 2 +- Source/cmcmd.cxx | 48 +- Tests/CMakeLists.txt | 9 - Tests/CMakeServerLib/CMakeLists.txt | 21 - Tests/CMakeServerLib/testServerBuffering.cpp | 87 --- .../RunCMake/CommandLine/E_capabilities-stdout.txt | 2 +- Tests/RunCMake/CommandLine/E_server-arg-result.txt | 1 - Tests/RunCMake/CommandLine/E_server-arg-stderr.txt | 1 - .../RunCMake/CommandLine/E_server-pipe-result.txt | 1 - .../RunCMake/CommandLine/E_server-pipe-stderr.txt | 1 - Tests/RunCMake/CommandLine/E_server-result.txt | 1 + Tests/RunCMake/CommandLine/E_server-stderr.txt | 1 + Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 3 +- Tests/Server/CMakeLists.txt | 28 - Tests/Server/buildsystem1/CMakeLists.txt | 22 - Tests/Server/buildsystem1/foo.cpp | 5 - Tests/Server/buildsystem1/main.cpp | 5 - Tests/Server/buildsystem1/subdir/CMakeLists.txt | 5 - Tests/Server/buildsystem1/subdir/empty.cpp | 5 - Tests/Server/cmakelib.py | 380 ----------- Tests/Server/empty.cpp | 5 - Tests/Server/server-test.py | 105 --- Tests/Server/tc_buildsystem1.json | 27 - Tests/Server/tc_cache.json | 24 - Tests/Server/tc_globalSettings.json | 140 ---- Tests/Server/tc_handshake.json | 75 -- 47 files changed, 17 insertions(+), 5294 deletions(-) create mode 100644 Help/release/dev/remove-server-mode.rst delete mode 100644 Source/cmConnection.cxx delete mode 100644 Source/cmConnection.h delete mode 100644 Source/cmFileMonitor.cxx delete mode 100644 Source/cmFileMonitor.h delete mode 100644 Source/cmJsonObjectDictionary.h delete mode 100644 Source/cmJsonObjects.cxx delete mode 100644 Source/cmJsonObjects.h delete mode 100644 Source/cmPipeConnection.cxx delete mode 100644 Source/cmPipeConnection.h delete mode 100644 Source/cmServer.cxx delete mode 100644 Source/cmServer.h delete mode 100644 Source/cmServerConnection.cxx delete mode 100644 Source/cmServerConnection.h delete mode 100644 Source/cmServerDictionary.h delete mode 100644 Source/cmServerProtocol.cxx delete mode 100644 Source/cmServerProtocol.h delete mode 100644 Tests/CMakeServerLib/CMakeLists.txt delete mode 100644 Tests/CMakeServerLib/testServerBuffering.cpp delete mode 100644 Tests/RunCMake/CommandLine/E_server-arg-result.txt delete mode 100644 Tests/RunCMake/CommandLine/E_server-arg-stderr.txt delete mode 100644 Tests/RunCMake/CommandLine/E_server-pipe-result.txt delete mode 100644 Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt create mode 100644 Tests/RunCMake/CommandLine/E_server-result.txt create mode 100644 Tests/RunCMake/CommandLine/E_server-stderr.txt delete mode 100644 Tests/Server/CMakeLists.txt delete mode 100644 Tests/Server/buildsystem1/CMakeLists.txt delete mode 100644 Tests/Server/buildsystem1/foo.cpp delete mode 100644 Tests/Server/buildsystem1/main.cpp delete mode 100644 Tests/Server/buildsystem1/subdir/CMakeLists.txt delete mode 100644 Tests/Server/buildsystem1/subdir/empty.cpp delete mode 100644 Tests/Server/cmakelib.py delete mode 100644 Tests/Server/empty.cpp delete mode 100644 Tests/Server/server-test.py delete mode 100644 Tests/Server/tc_buildsystem1.json delete mode 100644 Tests/Server/tc_cache.json delete mode 100644 Tests/Server/tc_globalSettings.json delete mode 100644 Tests/Server/tc_handshake.json diff --git a/Help/guide/ide-integration/index.rst b/Help/guide/ide-integration/index.rst index b1b9fc4..46ad4ef 100644 --- a/Help/guide/ide-integration/index.rst +++ b/Help/guide/ide-integration/index.rst @@ -79,8 +79,8 @@ as the include directories, compile definitions, etc. used to build the artifacts. Such information can be obtained by using the :manual:`File API `. The manual page for the File API contains more information about the API and how to invoke it. -:manual:`Server mode ` is deprecated and should not be -used on CMake 3.14 or later. +:manual:`Server mode ` was removed as of CMake 3.20 and +should not be used on CMake 3.14 or later. IDEs should avoid creating more build trees than necessary, and only create multiple build trees if the user wishes to switch to a different compiler, diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst index 8f10b9f..6c8d0f4 100644 --- a/Help/manual/cmake-server.7.rst +++ b/Help/manual/cmake-server.7.rst @@ -3,742 +3,5 @@ cmake-server(7) *************** -.. only:: html - - .. contents:: - -.. deprecated:: 3.15 - - This will be removed from a future version of CMake. - Clients should use the :manual:`cmake-file-api(7)` instead. - -Introduction -============ - -:manual:`cmake(1)` is capable of providing semantic information about -CMake code it executes to generate a buildsystem. If executed with -the ``-E server`` command line options, it starts in a long running mode -and allows a client to request the available information via a JSON protocol. - -The protocol is designed to be useful to IDEs, refactoring tools, and -other tools which have a need to understand the buildsystem in entirety. - -A single :manual:`cmake-buildsystem(7)` may describe buildsystem contents -and build properties which differ based on -:manual:`generation-time context ` -including: - -* The Platform (eg, Windows, APPLE, Linux). -* The build configuration (eg, Debug, Release, Coverage). -* The Compiler (eg, MSVC, GCC, Clang) and compiler version. -* The language of the source files compiled. -* Available compile features (eg CXX variadic templates). -* CMake policies. - -The protocol aims to provide information to tooling to satisfy several -needs: - -#. Provide a complete and easily parsed source of all information relevant - to the tooling as it relates to the source code. There should be no need - for tooling to parse generated buildsystems to access include directories - or compile definitions for example. -#. Semantic information about the CMake buildsystem itself. -#. Provide a stable interface for reading the information in the CMake cache. -#. Information for determining when cmake needs to be re-run as a result of - file changes. - - -Operation -========= - -Start :manual:`cmake(1)` in the server command mode, supplying the path to -the build directory to process:: - - cmake -E server (--debug|--pipe=) - -The server will communicate using stdin/stdout (with the ``--debug`` parameter) -or using a named pipe (with the ``--pipe=`` parameter). Note -that "named pipe" refers to a local domain socket on Unix and to a named pipe -on Windows. - -When connecting to the server (via named pipe or by starting it in ``--debug`` -mode), the server will reply with a hello message:: - - [== "CMake Server" ==[ - {"supportedProtocolVersions":[{"major":1,"minor":0}],"type":"hello"} - ]== "CMake Server" ==] - -Messages sent to and from the process are wrapped in magic strings:: - - [== "CMake Server" ==[ - { - ... some JSON message ... - } - ]== "CMake Server" ==] - -The server is now ready to accept further requests via the named pipe -or stdin. - - -Debugging -========= - -CMake server mode can be asked to provide statistics on execution times, etc. -or to dump a copy of the response into a file. This is done passing a "debug" -JSON object as a child of the request. - -The debug object supports the "showStats" key, which takes a boolean and makes -the server mode return a "zzzDebug" object with stats as part of its response. -"dumpToFile" takes a string value and will cause the cmake server to copy -the response into the given filename. - -This is a response from the cmake server with "showStats" set to true:: - - [== "CMake Server" ==[ - { - "cookie":"", - "errorMessage":"Waiting for type \"handshake\".", - "inReplyTo":"unknown", - "type":"error", - "zzzDebug": { - "dumpFile":"/tmp/error.txt", - "jsonSerialization":0.011016, - "size":111, - "totalTime":0.025995 - } - } - ]== "CMake Server" ==] - -The server has made a copy of this response into the file /tmp/error.txt and -took 0.011 seconds to turn the JSON response into a string, and it took 0.025 -seconds to process the request in total. The reply has a size of 111 bytes. - - -Protocol API -============ - - -General Message Layout ----------------------- - -All messages need to have a "type" value, which identifies the type of -message that is passed back or forth. E.g. the initial message sent by the -server is of type "hello". Messages without a type will generate an response -of type "error". - -All requests sent to the server may contain a "cookie" value. This value -will he handed back unchanged in all responses triggered by the request. - -All responses will contain a value "inReplyTo", which may be empty in -case of parse errors, but will contain the type of the request message -in all other cases. - - -Type "reply" -^^^^^^^^^^^^ - -This type is used by the server to reply to requests. - -The message may -- depending on the type of the original request -- -contain values. - -Example:: - - [== "CMake Server" ==[ - {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"} - ]== "CMake Server" ==] - - -Type "error" -^^^^^^^^^^^^ - -This type is used to return an error condition to the client. It will -contain an "errorMessage". - -Example:: - - [== "CMake Server" ==[ - {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"} - ]== "CMake Server" ==] - - -Type "progress" -^^^^^^^^^^^^^^^ - -When the server is busy for a long time, it is polite to send back replies of -type "progress" to the client. These will contain a "progressMessage" with a -string describing the action currently taking place as well as -"progressMinimum", "progressMaximum" and "progressCurrent" with integer values -describing the range of progress. - -Messages of type "progress" will be followed by more "progress" messages or with -a message of type "reply" or "error" that complete the request. - -"progress" messages may not be emitted after the "reply" or "error" message for -the request that triggered the responses was delivered. - - -Type "message" -^^^^^^^^^^^^^^ - -A message is triggered when the server processes a request and produces some -form of output that should be displayed to the user. A Message has a "message" -with the actual text to display as well as a "title" with a suggested dialog -box title. - -Example:: - - [== "CMake Server" ==[ - {"cookie":"","message":"Something happened.","title":"Title Text","inReplyTo":"handshake","type":"message"} - ]== "CMake Server" ==] - - -Type "signal" -^^^^^^^^^^^^^ - -The server can send signals when it detects changes in the system state. Signals -are of type "signal", have an empty "cookie" and "inReplyTo" field and always -have a "name" set to show which signal was sent. - - -Specific Signals ----------------- - -The cmake server may sent signals with the following names: - -"dirty" Signal -^^^^^^^^^^^^^^ - -The "dirty" signal is sent whenever the server determines that the configuration -of the project is no longer up-to-date. This happens when any of the files that have -an influence on the build system is changed. - -The "dirty" signal may look like this:: - - [== "CMake Server" ==[ - { - "cookie":"", - "inReplyTo":"", - "name":"dirty", - "type":"signal"} - ]== "CMake Server" ==] - - -"fileChange" Signal -^^^^^^^^^^^^^^^^^^^ - -The "fileChange" signal is sent whenever a watched file is changed. It contains -the "path" that has changed and a list of "properties" with the kind of change -that was detected. Possible changes are "change" and "rename". - -The "fileChange" signal looks like this:: - - [== "CMake Server" ==[ - { - "cookie":"", - "inReplyTo":"", - "name":"fileChange", - "path":"/absolute/CMakeLists.txt", - "properties":["change"], - "type":"signal"} - ]== "CMake Server" ==] - - -Specific Message Types ----------------------- - - -Type "hello" -^^^^^^^^^^^^ - -The initial message send by the cmake server on startup is of type "hello". -This is the only message ever sent by the server that is not of type "reply", -"progress" or "error". - -It will contain "supportedProtocolVersions" with an array of server protocol -versions supported by the cmake server. These are JSON objects with "major" and -"minor" keys containing non-negative integer values. Some versions may be marked -as experimental. These will contain the "isExperimental" key set to true. Enabling -these requires a special command line argument when starting the cmake server mode. - -Within a "major" version all "minor" versions are fully backwards compatible. -New "minor" versions may introduce functionality in such a way that existing -clients of the same "major" version will continue to work, provided they -ignore keys in the output that they do not know about. - -Example:: - - [== "CMake Server" ==[ - {"supportedProtocolVersions":[{"major":0,"minor":1}],"type":"hello"} - ]== "CMake Server" ==] - - -Type "handshake" -^^^^^^^^^^^^^^^^ - -The first request that the client may send to the server is of type "handshake". - -This request needs to pass one of the "supportedProtocolVersions" of the "hello" -type response received earlier back to the server in the "protocolVersion" field. -Giving the "major" version of the requested protocol version will make the server -use the latest minor version of that protocol. Use this if you do not explicitly -need to depend on a specific minor version. - -Protocol version 1.0 requires the following attributes to be set: - - * "sourceDirectory" with a path to the sources - * "buildDirectory" with a path to the build directory - * "generator" with the generator name - * "extraGenerator" (optional!) with the extra generator to be used - * "platform" with the generator platform (if supported by the generator) - * "toolset" with the generator toolset (if supported by the generator) - -Protocol version 1.2 makes all but the build directory optional, provided -there is a valid cache in the build directory that contains all the other -information already. - -Example:: - - [== "CMake Server" ==[ - {"cookie":"zimtstern","type":"handshake","protocolVersion":{"major":0}, - "sourceDirectory":"/home/code/cmake", "buildDirectory":"/tmp/testbuild", - "generator":"Ninja"} - ]== "CMake Server" ==] - -which will result in a response type "reply":: - - [== "CMake Server" ==[ - {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"} - ]== "CMake Server" ==] - -indicating that the server is ready for action. - - -Type "globalSettings" -^^^^^^^^^^^^^^^^^^^^^ - -This request can be sent after the initial handshake. It will return a -JSON structure with information on cmake state. - -Example:: - - [== "CMake Server" ==[ - {"type":"globalSettings"} - ]== "CMake Server" ==] - -which will result in a response type "reply":: - - [== "CMake Server" ==[ - { - "buildDirectory": "/tmp/test-build", - "capabilities": { - "generators": [ - { - "extraGenerators": [], - "name": "Watcom WMake", - "platformSupport": false, - "toolsetSupport": false - }, - <...> - ], - "serverMode": false, - "version": { - "isDirty": false, - "major": 3, - "minor": 6, - "patch": 20160830, - "string": "3.6.20160830-gd6abad", - "suffix": "gd6abad" - } - }, - "checkSystemVars": false, - "cookie": "", - "extraGenerator": "", - "generator": "Ninja", - "debugOutput": false, - "inReplyTo": "globalSettings", - "sourceDirectory": "/home/code/cmake", - "trace": false, - "traceExpand": false, - "type": "reply", - "warnUninitialized": false, - "warnUnused": false, - "warnUnusedCli": true - } - ]== "CMake Server" ==] - - -Type "setGlobalSettings" -^^^^^^^^^^^^^^^^^^^^^^^^ - -This request can be sent to change the global settings attributes. Unknown -attributes are going to be ignored. Read-only attributes reported by -"globalSettings" are all capabilities, buildDirectory, generator, -extraGenerator and sourceDirectory. Any attempt to set these will be ignored, -too. - -All other settings will be changed. - -The server will respond with an empty reply message or an error. - -Example:: - - [== "CMake Server" ==[ - {"type":"setGlobalSettings","debugOutput":true} - ]== "CMake Server" ==] - -CMake will reply to this with:: - - [== "CMake Server" ==[ - {"inReplyTo":"setGlobalSettings","type":"reply"} - ]== "CMake Server" ==] - - -Type "configure" -^^^^^^^^^^^^^^^^ - -This request will configure a project for build. - -To configure a build directory already containing cmake files, it is enough to -set "buildDirectory" via "setGlobalSettings". To create a fresh build directory -you also need to set "currentGenerator" and "sourceDirectory" via "setGlobalSettings" -in addition to "buildDirectory". - -You may a list of strings to "configure" via the "cacheArguments" key. These -strings will be interpreted similar to command line arguments related to -cache handling that are passed to the cmake command line client. - -Example:: - - [== "CMake Server" ==[ - {"type":"configure", "cacheArguments":["-Dsomething=else"]} - ]== "CMake Server" ==] - -CMake will reply like this (after reporting progress for some time):: - - [== "CMake Server" ==[ - {"cookie":"","inReplyTo":"configure","type":"reply"} - ]== "CMake Server" ==] - - -Type "compute" -^^^^^^^^^^^^^^ - -This request will generate build system files in the build directory and -is only available after a project was successfully "configure"d. - -Example:: - - [== "CMake Server" ==[ - {"type":"compute"} - ]== "CMake Server" ==] - -CMake will reply (after reporting progress information):: - - [== "CMake Server" ==[ - {"cookie":"","inReplyTo":"compute","type":"reply"} - ]== "CMake Server" ==] - - -Type "codemodel" -^^^^^^^^^^^^^^^^ - -The "codemodel" request can be used after a project was "compute"d successfully. - -It will list the complete project structure as it is known to cmake. - -The reply will contain a key "configurations", which will contain a list of -configuration objects. Configuration objects are used to destinquish between -different configurations the build directory might have enabled. While most -generators only support one configuration, others might support several. - -Each configuration object can have the following keys: - -"name" - contains the name of the configuration. The name may be empty. -"projects" - contains a list of project objects, one for each build project. - -Project objects define one (sub-)project defined in the cmake build system. - -Each project object can have the following keys: - -"name" - contains the (sub-)projects name. -"minimumCMakeVersion" - contains the minimum cmake version allowed for this project, null if the - project doesn't specify one. -"hasInstallRule" - true if the project contains any install rules, false otherwise. -"sourceDirectory" - contains the current source directory -"buildDirectory" - contains the current build directory. -"targets" - contains a list of build system target objects. - -Target objects define individual build targets for a certain configuration. - -Each target object can have the following keys: - -"name" - contains the name of the target. -"type" - defines the type of build of the target. Possible values are - "STATIC_LIBRARY", "MODULE_LIBRARY", "SHARED_LIBRARY", "OBJECT_LIBRARY", - "EXECUTABLE", "UTILITY" and "INTERFACE_LIBRARY". -"fullName" - contains the full name of the build result (incl. extensions, etc.). -"sourceDirectory" - contains the current source directory. -"buildDirectory" - contains the current build directory. -"isGeneratorProvided" - true if the target is auto-created by a generator, false otherwise -"hasInstallRule" - true if the target contains any install rules, false otherwise. -"installPaths" - full path to the destination directories defined by target install rules. -"artifacts" - with a list of build artifacts. The list is sorted with the most - important artifacts first (e.g. a .DLL file is listed before a - .PDB file on windows). -"linkerLanguage" - contains the language of the linker used to produce the artifact. -"linkLibraries" - with a list of libraries to link to. This value is encoded in the - system's native shell format. -"linkFlags" - with a list of flags to pass to the linker. This value is encoded in - the system's native shell format. -"linkLanguageFlags" - with the flags for a compiler using the linkerLanguage. This value is - encoded in the system's native shell format. -"frameworkPath" - with the framework path (on Apple computers). This value is encoded - in the system's native shell format. -"linkPath" - with the link path. This value is encoded in the system's native shell - format. -"sysroot" - with the sysroot path. -"fileGroups" - contains the source files making up the target. - -FileGroups are used to group sources using similar settings together. - -Each fileGroup object may contain the following keys: - -"language" - contains the programming language used by all files in the group. -"compileFlags" - with a string containing all the flags passed to the compiler - when building any of the files in this group. This value is encoded in - the system's native shell format. -"includePath" - with a list of include paths. Each include path is an object - containing a "path" with the actual include path and "isSystem" with a bool - value informing whether this is a normal include or a system include. This - value is encoded in the system's native shell format. -"defines" - with a list of defines in the form "SOMEVALUE" or "SOMEVALUE=42". This - value is encoded in the system's native shell format. -"sources" - with a list of source files. - -All file paths in the fileGroup are either absolute or relative to the -sourceDirectory of the target. - -Example:: - - [== "CMake Server" ==[ - {"type":"codemodel"} - ]== "CMake Server" ==] - -CMake will reply:: - - [== "CMake Server" ==[ - { - "configurations": [ - { - "name": "", - "projects": [ - { - "buildDirectory": "/tmp/build/Source/CursesDialog/form", - "name": "CMAKE_FORM", - "sourceDirectory": "/home/code/src/cmake/Source/CursesDialog/form", - "targets": [ - { - "artifacts": [ "/tmp/build/Source/CursesDialog/form/libcmForm.a" ], - "buildDirectory": "/tmp/build/Source/CursesDialog/form", - "fileGroups": [ - { - "compileFlags": " -std=gnu11", - "defines": [ "CURL_STATICLIB", "LIBARCHIVE_STATIC" ], - "includePath": [ { "path": "/tmp/build/Utilities" }, <...> ], - "isGenerated": false, - "language": "C", - "sources": [ "fld_arg.c", <...> ] - } - ], - "fullName": "libcmForm.a", - "linkerLanguage": "C", - "name": "cmForm", - "sourceDirectory": "/home/code/src/cmake/Source/CursesDialog/form", - "type": "STATIC_LIBRARY" - } - ] - }, - <...> - ] - } - ], - "cookie": "", - "inReplyTo": "codemodel", - "type": "reply" - } - ]== "CMake Server" ==] - - -Type "ctestInfo" -^^^^^^^^^^^^^^^^ - -The "ctestInfo" request can be used after a project was "compute"d successfully. - -It will list the complete project test structure as it is known to cmake. - -The reply will contain a key "configurations", which will contain a list of -configuration objects. Configuration objects are used to destinquish between -different configurations the build directory might have enabled. While most -generators only support one configuration, others might support several. - -Each configuration object can have the following keys: - -"name" - contains the name of the configuration. The name may be empty. -"projects" - contains a list of project objects, one for each build project. - -Project objects define one (sub-)project defined in the cmake build system. - -Each project object can have the following keys: - -"name" - contains the (sub-)projects name. -"ctestInfo" - contains a list of test objects. - -Each test object can have the following keys: - -"ctestName" - contains the name of the test. -"ctestCommand" - contains the test command. -"properties" - contains a list of test property objects. - -Each test property object can have the following keys: - -"key" - contains the test property key. -"value" - contains the test property value. - - -Type "cmakeInputs" -^^^^^^^^^^^^^^^^^^ - -The "cmakeInputs" requests will report files used by CMake as part -of the build system itself. - -This request is only available after a project was successfully -"configure"d. - -Example:: - - [== "CMake Server" ==[ - {"type":"cmakeInputs"} - ]== "CMake Server" ==] - -CMake will reply with the following information:: - - [== "CMake Server" ==[ - {"buildFiles": - [ - {"isCMake":true,"isTemporary":false,"sources":["/usr/lib/cmake/...", ... ]}, - {"isCMake":false,"isTemporary":false,"sources":["CMakeLists.txt", ...]}, - {"isCMake":false,"isTemporary":true,"sources":["/tmp/build/CMakeFiles/...", ...]} - ], - "cmakeRootDirectory":"/usr/lib/cmake", - "sourceDirectory":"/home/code/src/cmake", - "cookie":"", - "inReplyTo":"cmakeInputs", - "type":"reply" - } - ]== "CMake Server" ==] - -All file names are either relative to the top level source directory or -absolute. - -The list of files which "isCMake" set to true are part of the cmake installation. - -The list of files witch "isTemporary" set to true are part of the build directory -and will not survive the build directory getting cleaned out. - - -Type "cache" -^^^^^^^^^^^^ - -The "cache" request will list the cached configuration values. - -Example:: - - [== "CMake Server" ==[ - {"type":"cache"} - ]== "CMake Server" ==] - -CMake will respond with the following output:: - - [== "CMake Server" ==[ - { - "cookie":"","inReplyTo":"cache","type":"reply", - "cache": - [ - { - "key":"SOMEVALUE", - "properties": - { - "ADVANCED":"1", - "HELPSTRING":"This is not helpful" - } - "type":"STRING", - "value":"TEST"} - ] - } - ]== "CMake Server" ==] - -The output can be limited to a list of keys by passing an array of key names -to the "keys" optional field of the "cache" request. - - -Type "fileSystemWatchers" -^^^^^^^^^^^^^^^^^^^^^^^^^ - -The server can watch the filesystem for changes. The "fileSystemWatchers" -command will report on the files and directories watched. - -Example:: - - [== "CMake Server" ==[ - {"type":"fileSystemWatchers"} - ]== "CMake Server" ==] - -CMake will respond with the following output:: - - [== "CMake Server" ==[ - { - "cookie":"","inReplyTo":"fileSystemWatchers","type":"reply", - "watchedFiles": [ "/absolute/path" ], - "watchedDirectories": [ "/absolute" ] - } - ]== "CMake Server" ==] +The :manual:`cmake(1)` server mode has been removed since CMake 3.20. +Clients should use the :manual:`cmake-file-api(7)` instead. diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index b8a1b42..356ca38 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -906,6 +906,7 @@ Available commands are: ``serverMode`` ``true`` if cmake supports server-mode and ``false`` otherwise. + Always false since CMake 3.20. ``cat ...`` Concatenate files and print on the standard output. diff --git a/Help/release/dev/remove-server-mode.rst b/Help/release/dev/remove-server-mode.rst new file mode 100644 index 0000000..7c986b1 --- /dev/null +++ b/Help/release/dev/remove-server-mode.rst @@ -0,0 +1,5 @@ +remove-server-mode +------------------ + +* The :manual:`cmake-server(7)` mode has been removed. + Clients should use the :manual:`cmake-file-api(7)` instead. diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 2946022..91dd4f1 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1156,20 +1156,6 @@ add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE}) list(APPEND _tools cmake) target_link_libraries(cmake CMakeLib) -add_library(CMakeServerLib - cmConnection.h cmConnection.cxx - cmFileMonitor.cxx cmFileMonitor.h - cmJsonObjectDictionary.h - cmJsonObjects.h - cmJsonObjects.cxx - cmPipeConnection.cxx cmPipeConnection.h - cmServer.cxx cmServer.h - cmServerConnection.cxx cmServerConnection.h - cmServerProtocol.cxx cmServerProtocol.h - ) -target_link_libraries(CMakeServerLib CMakeLib) -target_link_libraries(cmake CMakeServerLib) - # Build CTest executable add_executable(ctest ctest.cxx ${MANIFEST_FILE}) list(APPEND _tools ctest) diff --git a/Source/cmConnection.cxx b/Source/cmConnection.cxx deleted file mode 100644 index e4d0cf1..0000000 --- a/Source/cmConnection.cxx +++ /dev/null @@ -1,173 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmConnection.h" - -#include -#include - -#include - -#include "cmServer.h" - -struct write_req_t -{ - uv_write_t req; - uv_buf_t buf; -}; - -void cmEventBasedConnection::on_alloc_buffer(uv_handle_t* handle, - size_t suggested_size, - uv_buf_t* buf) -{ - (void)(handle); -#ifndef __clang_analyzer__ - char* rawBuffer = new char[suggested_size]; - *buf = uv_buf_init(rawBuffer, static_cast(suggested_size)); -#else - (void)(suggested_size); - (void)(buf); -#endif /* __clang_analyzer__ */ -} - -void cmEventBasedConnection::on_read(uv_stream_t* stream, ssize_t nread, - const uv_buf_t* buf) -{ - auto conn = static_cast(stream->data); - if (conn) { - if (nread >= 0) { - conn->ReadData(std::string(buf->base, buf->base + nread)); - } else { - conn->OnDisconnect(static_cast(nread)); - } - } - - delete[](buf->base); -} - -void cmEventBasedConnection::on_close(uv_handle_t* /*handle*/) -{ -} - -void cmEventBasedConnection::on_write(uv_write_t* req, int status) -{ - (void)(status); - - // Free req and buffer - write_req_t* wr = reinterpret_cast(req); - delete[](wr->buf.base); - delete wr; -} - -void cmEventBasedConnection::on_new_connection(uv_stream_t* stream, int status) -{ - (void)(status); - auto conn = static_cast(stream->data); - - if (conn) { - conn->Connect(stream); - } -} - -bool cmEventBasedConnection::IsOpen() const -{ - return this->WriteStream != nullptr; -} - -void cmEventBasedConnection::WriteData(const std::string& _data) -{ -#ifndef NDEBUG - auto curr_thread_id = uv_thread_self(); - assert(this->Server); - assert(uv_thread_equal(&curr_thread_id, &this->Server->ServeThreadId)); -#endif - -#ifndef __clang_analyzer__ - auto data = _data; - assert(this->WriteStream.get()); - if (BufferStrategy) { - data = BufferStrategy->BufferOutMessage(data); - } - - auto ds = data.size(); - - write_req_t* req = new write_req_t; - req->req.data = this; - req->buf = uv_buf_init(new char[ds], static_cast(ds)); - memcpy(req->buf.base, data.c_str(), ds); - uv_write(reinterpret_cast(req), this->WriteStream, &req->buf, 1, - on_write); -#else - (void)(_data); -#endif /* __clang_analyzer__ */ -} - -void cmEventBasedConnection::ReadData(const std::string& data) -{ - this->RawReadBuffer += data; - if (BufferStrategy) { - std::string packet = BufferStrategy->BufferMessage(this->RawReadBuffer); - while (!packet.empty()) { - ProcessRequest(packet); - packet = BufferStrategy->BufferMessage(this->RawReadBuffer); - } - } else { - ProcessRequest(this->RawReadBuffer); - this->RawReadBuffer.clear(); - } -} - -cmEventBasedConnection::cmEventBasedConnection( - cmConnectionBufferStrategy* bufferStrategy) - : BufferStrategy(bufferStrategy) -{ -} - -void cmEventBasedConnection::Connect(uv_stream_t* server) -{ - (void)server; - Server->OnConnected(nullptr); -} - -void cmEventBasedConnection::OnDisconnect(int onerror) -{ - (void)onerror; - this->OnConnectionShuttingDown(); - if (this->Server) { - this->Server->OnDisconnect(this); - } -} - -cmConnection::~cmConnection() = default; - -bool cmConnection::OnConnectionShuttingDown() -{ - this->Server = nullptr; - return true; -} - -void cmConnection::SetServer(cmServerBase* s) -{ - Server = s; -} - -void cmConnection::ProcessRequest(const std::string& request) -{ - Server->ProcessRequest(this, request); -} - -bool cmConnection::OnServeStart(std::string* errString) -{ - (void)errString; - return true; -} - -bool cmEventBasedConnection::OnConnectionShuttingDown() -{ - if (this->WriteStream.get()) { - this->WriteStream->data = nullptr; - } - - WriteStream.reset(); - - return true; -} diff --git a/Source/cmConnection.h b/Source/cmConnection.h deleted file mode 100644 index 5335a7f..0000000 --- a/Source/cmConnection.h +++ /dev/null @@ -1,137 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ - -#pragma once - -#include "cmConfigure.h" // IWYU pragma: keep - -#include -#include -#include - -#include - -#include "cmUVHandlePtr.h" - -class cmServerBase; - -/*** - * Given a sequence of bytes with any kind of buffering, instances of this - * class arrange logical chunks according to whatever the use case is for - * the connection. - */ -class cmConnectionBufferStrategy -{ -public: - virtual ~cmConnectionBufferStrategy(); - - /*** - * Called whenever with an active raw buffer. If a logical chunk - * becomes available, that chunk is returned and that portion is - * removed from the rawBuffer - * - * @param rawBuffer in/out parameter. Receive buffer; the buffer strategy is - * free to manipulate this buffer anyway it needs to. - * - * @return Next chunk from the stream. Returns the empty string if a chunk - * isn't ready yet. Users of this interface should repeatedly call this - * function until an empty string is returned since its entirely possible - * multiple chunks come in a single raw buffer. - */ - virtual std::string BufferMessage(std::string& rawBuffer) = 0; - - /*** - * Called to properly buffer an outgoing message. - * - * @param rawBuffer Message to format in the correct way - * - * @return Formatted message - */ - virtual std::string BufferOutMessage(const std::string& rawBuffer) const - { - return rawBuffer; - }; - /*** - * Resets the internal state of the buffering - */ - virtual void clear(); - - // TODO: There should be a callback / flag set for errors -}; - -class cmConnection -{ -public: - cmConnection() = default; - - cmConnection(cmConnection const&) = delete; - cmConnection& operator=(cmConnection const&) = delete; - - virtual void WriteData(const std::string& data) = 0; - - virtual ~cmConnection(); - - virtual bool OnConnectionShuttingDown(); - - virtual bool IsOpen() const = 0; - - virtual void SetServer(cmServerBase* s); - - virtual void ProcessRequest(const std::string& request); - - virtual bool OnServeStart(std::string* pString); - -protected: - cmServerBase* Server = nullptr; -}; - -/*** - * Abstraction of a connection; ties in event callbacks from libuv and notifies - * the server when appropriate - */ -class cmEventBasedConnection : public cmConnection -{ - -public: - /*** - * @param bufferStrategy If no strategy is given, it will process the raw - * chunks as they come in. The connection - * owns the pointer given. - */ - cmEventBasedConnection(cmConnectionBufferStrategy* bufferStrategy = nullptr); - - virtual void Connect(uv_stream_t* server); - - virtual void ReadData(const std::string& data); - - bool IsOpen() const override; - - void WriteData(const std::string& data) override; - bool OnConnectionShuttingDown() override; - - virtual void OnDisconnect(int errorCode); - - static void on_close(uv_handle_t* handle); - - template - static void on_close_delete(uv_handle_t* handle) - { - delete reinterpret_cast(handle); - } - -protected: - cm::uv_stream_ptr WriteStream; - - std::string RawReadBuffer; - - std::unique_ptr BufferStrategy; - - static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf); - - static void on_write(uv_write_t* req, int status); - - static void on_new_connection(uv_stream_t* stream, int status); - - static void on_alloc_buffer(uv_handle_t* handle, size_t suggested_size, - uv_buf_t* buf); -}; diff --git a/Source/cmFileMonitor.cxx b/Source/cmFileMonitor.cxx deleted file mode 100644 index 8cfdb2d..0000000 --- a/Source/cmFileMonitor.cxx +++ /dev/null @@ -1,383 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmFileMonitor.h" - -#include -#include -#include -#include - -#include - -#include "cmsys/SystemTools.hxx" - -namespace { -void on_directory_change(uv_fs_event_t* handle, const char* filename, - int events, int status); -void on_fs_close(uv_handle_t* handle); -} // namespace - -class cmIBaseWatcher -{ -public: - virtual ~cmIBaseWatcher() = default; - - virtual void Trigger(const std::string& pathSegment, int events, - int status) const = 0; - virtual std::string Path() const = 0; - virtual uv_loop_t* Loop() const = 0; - - virtual void StartWatching() = 0; - virtual void StopWatching() = 0; - - virtual std::vector WatchedFiles() const = 0; - virtual std::vector WatchedDirectories() const = 0; -}; - -class cmVirtualDirectoryWatcher : public cmIBaseWatcher -{ -public: - ~cmVirtualDirectoryWatcher() override = default; - - cmIBaseWatcher* Find(const std::string& ps) - { - const auto i = this->Children.find(ps); - return (i == this->Children.end()) ? nullptr : i->second.get(); - } - - void Trigger(const std::string& pathSegment, int events, - int status) const final - { - if (pathSegment.empty()) { - for (auto const& child : this->Children) { - child.second->Trigger(std::string(), events, status); - } - } else { - const auto i = this->Children.find(pathSegment); - if (i != this->Children.end()) { - i->second->Trigger(std::string(), events, status); - } - } - } - - void StartWatching() override - { - for (auto const& child : this->Children) { - child.second->StartWatching(); - } - } - - void StopWatching() override - { - for (auto const& child : this->Children) { - child.second->StopWatching(); - } - } - - std::vector WatchedFiles() const final - { - std::vector result; - for (auto const& child : this->Children) { - for (std::string const& f : child.second->WatchedFiles()) { - result.push_back(f); - } - } - return result; - } - - std::vector WatchedDirectories() const override - { - std::vector result; - for (auto const& child : this->Children) { - for (std::string const& dir : child.second->WatchedDirectories()) { - result.push_back(dir); - } - } - return result; - } - - void Reset() { this->Children.clear(); } - - void AddChildWatcher(const std::string& ps, cmIBaseWatcher* watcher) - { - assert(!ps.empty()); - assert(this->Children.find(ps) == this->Children.end()); - assert(watcher); - - this->Children.emplace(ps, std::unique_ptr(watcher)); - } - -private: - std::unordered_map> - Children; // owned! -}; - -// Root of all the different (on windows!) root directories: -class cmRootWatcher : public cmVirtualDirectoryWatcher -{ -public: - cmRootWatcher(uv_loop_t* loop) - : mLoop(loop) - { - assert(loop); - } - - std::string Path() const final - { - assert(false); - return std::string(); - } - uv_loop_t* Loop() const final { return this->mLoop; } - -private: - uv_loop_t* const mLoop; // no ownership! -}; - -// Real directories: -class cmRealDirectoryWatcher : public cmVirtualDirectoryWatcher -{ -public: - cmRealDirectoryWatcher(cmVirtualDirectoryWatcher* p, const std::string& ps) - : Parent(p) - , PathSegment(ps) - { - assert(p); - assert(!ps.empty()); - - p->AddChildWatcher(ps, this); - } - - void StartWatching() final - { - if (!this->Handle) { - this->Handle = new uv_fs_event_t; - - uv_fs_event_init(this->Loop(), this->Handle); - this->Handle->data = this; - uv_fs_event_start(this->Handle, &on_directory_change, Path().c_str(), 0); - } - cmVirtualDirectoryWatcher::StartWatching(); - } - - void StopWatching() final - { - if (this->Handle) { - uv_fs_event_stop(this->Handle); - if (!uv_is_closing(reinterpret_cast(this->Handle))) { - uv_close(reinterpret_cast(this->Handle), &on_fs_close); - } - this->Handle = nullptr; - } - cmVirtualDirectoryWatcher::StopWatching(); - } - - uv_loop_t* Loop() const final { return this->Parent->Loop(); } - - std::vector WatchedDirectories() const override - { - std::vector result = { Path() }; - for (std::string const& dir : - cmVirtualDirectoryWatcher::WatchedDirectories()) { - result.push_back(dir); - } - return result; - } - -protected: - cmVirtualDirectoryWatcher* const Parent; - const std::string PathSegment; - -private: - uv_fs_event_t* Handle = nullptr; // owner! -}; - -// Root directories: -class cmRootDirectoryWatcher : public cmRealDirectoryWatcher -{ -public: - cmRootDirectoryWatcher(cmRootWatcher* p, const std::string& ps) - : cmRealDirectoryWatcher(p, ps) - { - } - - std::string Path() const final { return this->PathSegment; } -}; - -// Normal directories below root: -class cmDirectoryWatcher : public cmRealDirectoryWatcher -{ -public: - cmDirectoryWatcher(cmRealDirectoryWatcher* p, const std::string& ps) - : cmRealDirectoryWatcher(p, ps) - { - } - - std::string Path() const final - { - return this->Parent->Path() + this->PathSegment + "/"; - } -}; - -class cmFileWatcher : public cmIBaseWatcher -{ -public: - cmFileWatcher(cmRealDirectoryWatcher* p, const std::string& ps, - cmFileMonitor::Callback cb) - : Parent(p) - , PathSegment(ps) - , CbList({ std::move(cb) }) - { - assert(p); - assert(!ps.empty()); - p->AddChildWatcher(ps, this); - } - - void StartWatching() final {} - - void StopWatching() final {} - - void AppendCallback(cmFileMonitor::Callback const& cb) - { - this->CbList.push_back(cb); - } - - std::string Path() const final - { - return this->Parent->Path() + this->PathSegment; - } - - std::vector WatchedDirectories() const final { return {}; } - - std::vector WatchedFiles() const final - { - return { this->Path() }; - } - - void Trigger(const std::string& ps, int events, int status) const final - { - assert(ps.empty()); - assert(status == 0); - static_cast(ps); - - const std::string path = this->Path(); - for (cmFileMonitor::Callback const& cb : this->CbList) { - cb(path, events, status); - } - } - - uv_loop_t* Loop() const final { return this->Parent->Loop(); } - -private: - cmRealDirectoryWatcher* Parent; - const std::string PathSegment; - std::vector CbList; -}; - -namespace { - -void on_directory_change(uv_fs_event_t* handle, const char* filename, - int events, int status) -{ - const cmIBaseWatcher* const watcher = - static_cast(handle->data); - const std::string pathSegment(filename ? filename : ""); - watcher->Trigger(pathSegment, events, status); -} - -void on_fs_close(uv_handle_t* handle) -{ - delete reinterpret_cast(handle); -} - -} // namespace - -cmFileMonitor::cmFileMonitor(uv_loop_t* l) - : Root(cm::make_unique(l)) -{ -} - -cmFileMonitor::~cmFileMonitor() = default; - -void cmFileMonitor::MonitorPaths(const std::vector& paths, - Callback const& cb) -{ - for (std::string const& p : paths) { - std::vector pathSegments; - cmsys::SystemTools::SplitPath(p, pathSegments, true); - const bool pathIsFile = !cmsys::SystemTools::FileIsDirectory(p); - - const size_t segmentCount = pathSegments.size(); - if (segmentCount < 2) { // Expect at least rootdir and filename - continue; - } - cmVirtualDirectoryWatcher* currentWatcher = this->Root.get(); - for (size_t i = 0; i < segmentCount; ++i) { - assert(currentWatcher); - - const bool fileSegment = (i == segmentCount - 1 && pathIsFile); - const bool rootSegment = (i == 0); - assert( - !(fileSegment && - rootSegment)); // Can not be both filename and root part of the path! - - const std::string& currentSegment = pathSegments[i]; - if (currentSegment.empty()) { - continue; - } - - cmIBaseWatcher* nextWatcher = currentWatcher->Find(currentSegment); - if (!nextWatcher) { - if (rootSegment) { // Root part - assert(currentWatcher == this->Root.get()); - nextWatcher = - new cmRootDirectoryWatcher(this->Root.get(), currentSegment); - assert(currentWatcher->Find(currentSegment) == nextWatcher); - } else if (fileSegment) { // File part - assert(currentWatcher != this->Root.get()); - nextWatcher = new cmFileWatcher( - dynamic_cast(currentWatcher), - currentSegment, cb); - assert(currentWatcher->Find(currentSegment) == nextWatcher); - } else { // Any normal directory in between - nextWatcher = new cmDirectoryWatcher( - dynamic_cast(currentWatcher), - currentSegment); - assert(currentWatcher->Find(currentSegment) == nextWatcher); - } - } else { - if (fileSegment) { - auto filePtr = dynamic_cast(nextWatcher); - assert(filePtr); - filePtr->AppendCallback(cb); - continue; - } - } - currentWatcher = dynamic_cast(nextWatcher); - } - } - this->Root->StartWatching(); -} - -void cmFileMonitor::StopMonitoring() -{ - this->Root->StopWatching(); - this->Root->Reset(); -} - -std::vector cmFileMonitor::WatchedFiles() const -{ - std::vector result; - if (this->Root) { - result = this->Root->WatchedFiles(); - } - return result; -} - -std::vector cmFileMonitor::WatchedDirectories() const -{ - std::vector result; - if (this->Root) { - result = this->Root->WatchedDirectories(); - } - return result; -} diff --git a/Source/cmFileMonitor.h b/Source/cmFileMonitor.h deleted file mode 100644 index fc75b0c..0000000 --- a/Source/cmFileMonitor.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include "cmConfigure.h" // IWYU pragma: keep - -#include -#include -#include -#include - -#include - -class cmRootWatcher; - -class cmFileMonitor -{ - -public: - cmFileMonitor(uv_loop_t* l); - ~cmFileMonitor(); - - cmFileMonitor(cmFileMonitor const&) = delete; - cmFileMonitor& operator=(cmFileMonitor const&) = delete; - - using Callback = std::function; - void MonitorPaths(const std::vector& paths, Callback const& cb); - void StopMonitoring(); - - std::vector WatchedFiles() const; - std::vector WatchedDirectories() const; - -private: - std::unique_ptr Root; -}; diff --git a/Source/cmJsonObjectDictionary.h b/Source/cmJsonObjectDictionary.h deleted file mode 100644 index 8a2b529..0000000 --- a/Source/cmJsonObjectDictionary.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include - -// Vocabulary: - -static const std::string kARTIFACTS_KEY = "artifacts"; -static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; -static const std::string kCOMPILE_FLAGS_KEY = "compileFlags"; -static const std::string kCONFIGURATIONS_KEY = "configurations"; -static const std::string kDEFINES_KEY = "defines"; -static const std::string kFILE_GROUPS_KEY = "fileGroups"; -static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath"; -static const std::string kFULL_NAME_KEY = "fullName"; -static const std::string kINCLUDE_PATH_KEY = "includePath"; -static const std::string kIS_CMAKE_KEY = "isCMake"; -static const std::string kIS_GENERATED_KEY = "isGenerated"; -static const std::string kIS_SYSTEM_KEY = "isSystem"; -static const std::string kIS_TEMPORARY_KEY = "isTemporary"; -static const std::string kKEY_KEY = "key"; -static const std::string kLANGUAGE_KEY = "language"; -static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage"; -static const std::string kLINK_FLAGS_KEY = "linkFlags"; -static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags"; -static const std::string kLINK_LIBRARIES_KEY = "linkLibraries"; -static const std::string kLINK_PATH_KEY = "linkPath"; -static const std::string kNAME_KEY = "name"; -static const std::string kPATH_KEY = "path"; -static const std::string kPROJECTS_KEY = "projects"; -static const std::string kPROPERTIES_KEY = "properties"; -static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; -static const std::string kSOURCES_KEY = "sources"; -static const std::string kSYSROOT_KEY = "sysroot"; -static const std::string kTARGETS_KEY = "targets"; -static const std::string kTYPE_KEY = "type"; -static const std::string kVALUE_KEY = "value"; -static const std::string kHAS_INSTALL_RULE = "hasInstallRule"; -static const std::string kINSTALL_PATHS = "installPaths"; -static const std::string kCTEST_NAME = "ctestName"; -static const std::string kCTEST_COMMAND = "ctestCommand"; -static const std::string kCTEST_INFO = "ctestInfo"; -static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion"; -static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided"; diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx deleted file mode 100644 index 3a7ae0c..0000000 --- a/Source/cmJsonObjects.cxx +++ /dev/null @@ -1,692 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmJsonObjects.h" // IWYU pragma: keep - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "cmGeneratorExpression.h" -#include "cmGeneratorTarget.h" -#include "cmGlobalGenerator.h" -#include "cmInstallGenerator.h" -#include "cmInstallSubdirectoryGenerator.h" -#include "cmInstallTargetGenerator.h" -#include "cmJsonObjectDictionary.h" -#include "cmJsonObjects.h" -#include "cmLinkLineComputer.h" -#include "cmLocalGenerator.h" -#include "cmMakefile.h" -#include "cmProperty.h" -#include "cmPropertyMap.h" -#include "cmSourceFile.h" -#include "cmState.h" -#include "cmStateDirectory.h" -#include "cmStateSnapshot.h" -#include "cmStateTypes.h" -#include "cmStringAlgorithms.h" -#include "cmSystemTools.h" -#include "cmTarget.h" -#include "cmTest.h" -#include "cmake.h" - -namespace { - -std::vector getConfigurations(const cmake* cm) -{ - std::vector configurations; - const auto& makefiles = cm->GetGlobalGenerator()->GetMakefiles(); - if (makefiles.empty()) { - return configurations; - } - - return makefiles[0]->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); -} - -bool hasString(const Json::Value& v, const std::string& s) -{ - return !v.isNull() && - std::any_of(v.begin(), v.end(), - [s](const Json::Value& i) { return i.asString() == s; }); -} - -template -Json::Value fromStringList(const T& in) -{ - Json::Value result = Json::arrayValue; - for (std::string const& i : in) { - result.append(i); - } - return result; -} - -} // namespace - -void cmGetCMakeInputs(const cmGlobalGenerator* gg, - const std::string& sourceDir, - const std::string& buildDir, - std::vector* internalFiles, - std::vector* explicitFiles, - std::vector* tmpFiles) -{ - const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/'; - auto const& makefiles = gg->GetMakefiles(); - for (const auto& mf : makefiles) { - for (std::string const& lf : mf->GetListFiles()) { - - const std::string startOfFile = lf.substr(0, cmakeRootDir.size()); - const bool isInternal = (startOfFile == cmakeRootDir); - const bool isTemporary = - !isInternal && (cmHasPrefix(lf, buildDir + '/')); - - std::string toAdd = lf; - if (!sourceDir.empty()) { - const std::string& relative = - cmSystemTools::RelativePath(sourceDir, lf); - if (toAdd.size() > relative.size()) { - toAdd = relative; - } - } - - if (isInternal) { - if (internalFiles) { - internalFiles->push_back(std::move(toAdd)); - } - } else { - if (isTemporary) { - if (tmpFiles) { - tmpFiles->push_back(std::move(toAdd)); - } - } else { - if (explicitFiles) { - explicitFiles->push_back(std::move(toAdd)); - } - } - } - } - } -} - -Json::Value cmDumpCMakeInputs(const cmake* cm) -{ - const cmGlobalGenerator* gg = cm->GetGlobalGenerator(); - const std::string& buildDir = cm->GetHomeOutputDirectory(); - const std::string& sourceDir = cm->GetHomeDirectory(); - - std::vector internalFiles; - std::vector explicitFiles; - std::vector tmpFiles; - cmGetCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles, - &tmpFiles); - - Json::Value array = Json::arrayValue; - - Json::Value tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = true; - tmp[kIS_TEMPORARY_KEY] = false; - tmp[kSOURCES_KEY] = fromStringList(internalFiles); - array.append(tmp); - - tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = false; - tmp[kIS_TEMPORARY_KEY] = false; - tmp[kSOURCES_KEY] = fromStringList(explicitFiles); - array.append(tmp); - - tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = false; - tmp[kIS_TEMPORARY_KEY] = true; - tmp[kSOURCES_KEY] = fromStringList(tmpFiles); - array.append(tmp); - - return array; -} - -class LanguageData -{ -public: - bool operator==(const LanguageData& other) const; - - void SetDefines(const std::set& defines); - - bool IsGenerated = false; - std::string Language; - std::string Flags; - std::vector Defines; - std::vector> IncludePathList; -}; - -bool LanguageData::operator==(const LanguageData& other) const -{ - return Language == other.Language && Defines == other.Defines && - Flags == other.Flags && IncludePathList == other.IncludePathList && - IsGenerated == other.IsGenerated; -} - -void LanguageData::SetDefines(const std::set& defines) -{ - std::vector result; - result.reserve(defines.size()); - for (std::string const& i : defines) { - result.push_back(i); - } - std::sort(result.begin(), result.end()); - Defines = std::move(result); -} - -namespace std { - -template <> -struct hash -{ - std::size_t operator()(const LanguageData& in) const - { - using std::hash; - size_t result = - hash()(in.Language) ^ hash()(in.Flags); - for (auto const& i : in.IncludePathList) { - result = result ^ - (hash()(i.first) ^ - (i.second ? std::numeric_limits::max() : 0)); - } - for (auto const& i : in.Defines) { - result = result ^ hash()(i); - } - result = - result ^ (in.IsGenerated ? std::numeric_limits::max() : 0); - return result; - } -}; - -} // namespace std - -static Json::Value DumpSourceFileGroup(const LanguageData& data, - const std::vector& files, - const std::string& baseDir) -{ - Json::Value result = Json::objectValue; - - if (!data.Language.empty()) { - result[kLANGUAGE_KEY] = data.Language; - if (!data.Flags.empty()) { - result[kCOMPILE_FLAGS_KEY] = data.Flags; - } - if (!data.IncludePathList.empty()) { - Json::Value includes = Json::arrayValue; - for (auto const& i : data.IncludePathList) { - Json::Value tmp = Json::objectValue; - tmp[kPATH_KEY] = i.first; - if (i.second) { - tmp[kIS_SYSTEM_KEY] = i.second; - } - includes.append(tmp); - } - result[kINCLUDE_PATH_KEY] = includes; - } - if (!data.Defines.empty()) { - result[kDEFINES_KEY] = fromStringList(data.Defines); - } - } - - result[kIS_GENERATED_KEY] = data.IsGenerated; - - Json::Value sourcesValue = Json::arrayValue; - for (auto const& i : files) { - const std::string relPath = cmSystemTools::RelativePath(baseDir, i); - sourcesValue.append(relPath.size() < i.size() ? relPath : i); - } - - result[kSOURCES_KEY] = sourcesValue; - return result; -} - -static Json::Value DumpSourceFilesList( - cmGeneratorTarget* target, const std::string& config, - const std::map& languageDataMap) -{ - // Collect sourcefile groups: - - std::vector files; - target->GetSourceFiles(files, config); - - std::unordered_map> fileGroups; - for (cmSourceFile* file : files) { - LanguageData fileData; - fileData.Language = file->GetOrDetermineLanguage(); - if (!fileData.Language.empty()) { - const LanguageData& ld = languageDataMap.at(fileData.Language); - cmLocalGenerator* lg = target->GetLocalGenerator(); - cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target, - fileData.Language); - - std::string compileFlags = ld.Flags; - const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (cmProp cflags = file->GetProperty(COMPILE_FLAGS)) { - lg->AppendFlags(compileFlags, - genexInterpreter.Evaluate(*cflags, COMPILE_FLAGS)); - } - const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (cmProp coptions = file->GetProperty(COMPILE_OPTIONS)) { - lg->AppendCompileOptions( - compileFlags, genexInterpreter.Evaluate(*coptions, COMPILE_OPTIONS)); - } - fileData.Flags = compileFlags; - - // Add include directories from source file properties. - std::vector includes; - - const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (cmProp cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) { - const std::string& evaluatedIncludes = - genexInterpreter.Evaluate(*cincludes, INCLUDE_DIRECTORIES); - lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file); - - for (const auto& include : includes) { - fileData.IncludePathList.emplace_back( - include, - target->IsSystemIncludeDirectory(include, config, - fileData.Language)); - } - } - - fileData.IncludePathList.insert(fileData.IncludePathList.end(), - ld.IncludePathList.begin(), - ld.IncludePathList.end()); - - const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); - std::set defines; - if (cmProp defs = file->GetProperty(COMPILE_DEFINITIONS)) { - lg->AppendDefines( - defines, genexInterpreter.Evaluate(*defs, COMPILE_DEFINITIONS)); - } - - const std::string defPropName = - "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - if (cmProp config_defs = file->GetProperty(defPropName)) { - lg->AppendDefines( - defines, - genexInterpreter.Evaluate(*config_defs, COMPILE_DEFINITIONS)); - } - - defines.insert(ld.Defines.begin(), ld.Defines.end()); - - fileData.SetDefines(defines); - } - - fileData.IsGenerated = file->GetIsGenerated(); - std::vector& groupFileList = fileGroups[fileData]; - groupFileList.push_back(file->ResolveFullPath()); - } - - const std::string& baseDir = target->Makefile->GetCurrentSourceDirectory(); - Json::Value result = Json::arrayValue; - for (auto const& it : fileGroups) { - Json::Value group = DumpSourceFileGroup(it.first, it.second, baseDir); - if (!group.isNull()) { - result.append(group); - } - } - - return result; -} - -static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kCTEST_NAME] = testInfo->GetName(); - - // Concat command entries together. After the first should be the arguments - // for the command - std::string command; - for (auto const& cmd : testInfo->GetCommand()) { - command.append(cmd); - command.append(" "); - } - - // Remove any config specific variables from the output. - result[kCTEST_COMMAND] = - cmGeneratorExpression::Evaluate(command, lg, config); - - // Build up the list of properties that may have been specified - Json::Value properties = Json::arrayValue; - for (auto& prop : testInfo->GetProperties().GetList()) { - Json::Value entry = Json::objectValue; - entry[kKEY_KEY] = prop.first; - - // Remove config variables from the value too. - entry[kVALUE_KEY] = - cmGeneratorExpression::Evaluate(prop.second, lg, config); - properties.append(entry); - } - result[kPROPERTIES_KEY] = properties; - - return result; -} - -static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config, - Json::Value* result) -{ - auto mf = lg->GetMakefile(); - std::vector tests; - mf->GetTests(config, tests); - for (auto test : tests) { - Json::Value tmp = DumpCTestInfo(lg, test, config); - if (!tmp.isNull()) { - result->append(tmp); - } - } -} - -static Json::Value DumpCTestProjectList(const cmake* cm, - std::string const& config) -{ - Json::Value result = Json::arrayValue; - - auto globalGen = cm->GetGlobalGenerator(); - - for (const auto& projectIt : globalGen->GetProjectMap()) { - Json::Value pObj = Json::objectValue; - pObj[kNAME_KEY] = projectIt.first; - - Json::Value tests = Json::arrayValue; - - // Gather tests for every generator - for (const auto& lg : projectIt.second) { - // Make sure they're generated. - lg->GenerateTestFiles(); - DumpMakefileTests(lg, config, &tests); - } - - pObj[kCTEST_INFO] = tests; - - result.append(pObj); - } - - return result; -} - -static Json::Value DumpCTestConfiguration(const cmake* cm, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kNAME_KEY] = config; - - result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config); - - return result; -} - -static Json::Value DumpCTestConfigurationsList(const cmake* cm) -{ - Json::Value result = Json::arrayValue; - - for (const std::string& c : getConfigurations(cm)) { - result.append(DumpCTestConfiguration(cm, c)); - } - - return result; -} - -Json::Value cmDumpCTestInfo(const cmake* cm) -{ - Json::Value result = Json::objectValue; - result[kCONFIGURATIONS_KEY] = DumpCTestConfigurationsList(cm); - return result; -} - -static Json::Value DumpTarget(cmGeneratorTarget* target, - const std::string& config) -{ - cmLocalGenerator* lg = target->GetLocalGenerator(); - - const cmStateEnums::TargetType type = target->GetType(); - const std::string typeName = cmState::GetTargetTypeName(type); - - Json::Value ttl = Json::arrayValue; - ttl.append("EXECUTABLE"); - ttl.append("STATIC_LIBRARY"); - ttl.append("SHARED_LIBRARY"); - ttl.append("MODULE_LIBRARY"); - ttl.append("OBJECT_LIBRARY"); - ttl.append("UTILITY"); - ttl.append("INTERFACE_LIBRARY"); - - if (!hasString(ttl, typeName) || target->IsImported()) { - return Json::Value(); - } - - Json::Value result = Json::objectValue; - result[kNAME_KEY] = target->GetName(); - result[kIS_GENERATOR_PROVIDED_KEY] = - target->Target->GetIsGeneratorProvided(); - result[kTYPE_KEY] = typeName; - result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory(); - result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory(); - - if (type == cmStateEnums::INTERFACE_LIBRARY) { - return result; - } - - result[kFULL_NAME_KEY] = target->GetFullName(config); - - if (target->Target->GetHaveInstallRule()) { - result[kHAS_INSTALL_RULE] = true; - - Json::Value installPaths = Json::arrayValue; - for (const auto& installGenerator : - target->Makefile->GetInstallGenerators()) { - auto installTargetGenerator = - dynamic_cast(installGenerator.get()); - if (installTargetGenerator != nullptr && - installTargetGenerator->GetTarget()->Target == target->Target) { - auto dest = installTargetGenerator->GetDestination(config); - - std::string installPath; - if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) { - installPath = dest; - } else { - installPath = cmStrCat( - target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"), '/', - dest); - } - - installPaths.append(installPath); - } - } - - result[kINSTALL_PATHS] = installPaths; - } - - if (target->HaveWellDefinedOutputFiles()) { - Json::Value artifacts = Json::arrayValue; - artifacts.append( - target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact)); - if (target->HasImportLibrary(config)) { - artifacts.append( - target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact)); - } - if (target->IsDLLPlatform()) { - const cmGeneratorTarget::OutputInfo* output = - target->GetOutputInfo(config); - if (output && !output->PdbDir.empty()) { - artifacts.append(output->PdbDir + '/' + target->GetPDBName(config)); - } - } - result[kARTIFACTS_KEY] = artifacts; - - result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config); - - std::string linkLibs; - std::string linkFlags; - std::string linkLanguageFlags; - std::string frameworkPath; - std::string linkPath; - cmLinkLineComputer linkLineComputer(lg, - lg->GetStateSnapshot().GetDirectory()); - lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags, - linkFlags, frameworkPath, linkPath, target); - - linkLibs = cmTrimWhitespace(linkLibs); - linkFlags = cmTrimWhitespace(linkFlags); - linkLanguageFlags = cmTrimWhitespace(linkLanguageFlags); - frameworkPath = cmTrimWhitespace(frameworkPath); - linkPath = cmTrimWhitespace(linkPath); - - if (!cmTrimWhitespace(linkLibs).empty()) { - result[kLINK_LIBRARIES_KEY] = linkLibs; - } - if (!cmTrimWhitespace(linkFlags).empty()) { - result[kLINK_FLAGS_KEY] = linkFlags; - } - if (!cmTrimWhitespace(linkLanguageFlags).empty()) { - result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags; - } - if (!frameworkPath.empty()) { - result[kFRAMEWORK_PATH_KEY] = frameworkPath; - } - if (!linkPath.empty()) { - result[kLINK_PATH_KEY] = linkPath; - } - const std::string sysroot = - lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT"); - if (!sysroot.empty()) { - result[kSYSROOT_KEY] = sysroot; - } - } - - std::set languages; - target->GetLanguages(languages, config); - std::map languageDataMap; - - for (std::string const& lang : languages) { - LanguageData& ld = languageDataMap[lang]; - ld.Language = lang; - lg->GetTargetCompileFlags(target, config, lang, ld.Flags); - std::set defines; - lg->GetTargetDefines(target, config, lang, defines); - ld.SetDefines(defines); - std::vector includePathList; - lg->GetIncludeDirectories(includePathList, target, lang, config); - for (std::string const& i : includePathList) { - ld.IncludePathList.emplace_back( - i, target->IsSystemIncludeDirectory(i, config, lang)); - } - } - - Json::Value sourceGroupsValue = - DumpSourceFilesList(target, config, languageDataMap); - if (!sourceGroupsValue.empty()) { - result[kFILE_GROUPS_KEY] = sourceGroupsValue; - } - - return result; -} - -static Json::Value DumpTargetsList( - const std::vector& generators, const std::string& config) -{ - Json::Value result = Json::arrayValue; - - std::vector targetList; - for (auto const& lgIt : generators) { - cm::append(targetList, lgIt->GetGeneratorTargets()); - } - std::sort(targetList.begin(), targetList.end()); - - for (cmGeneratorTarget* target : targetList) { - Json::Value tmp = DumpTarget(target, config); - if (!tmp.isNull()) { - result.append(tmp); - } - } - - return result; -} - -static Json::Value DumpProjectList(const cmake* cm, std::string const& config) -{ - Json::Value result = Json::arrayValue; - - auto globalGen = cm->GetGlobalGenerator(); - - for (auto const& projectIt : globalGen->GetProjectMap()) { - Json::Value pObj = Json::objectValue; - pObj[kNAME_KEY] = projectIt.first; - - // All Projects must have at least one local generator - assert(!projectIt.second.empty()); - const cmLocalGenerator* lg = projectIt.second.at(0); - - // Project structure information: - const cmMakefile* mf = lg->GetMakefile(); - auto minVersion = mf->GetSafeDefinition("CMAKE_MINIMUM_REQUIRED_VERSION"); - pObj[kMINIMUM_CMAKE_VERSION] = minVersion; - pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory(); - pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory(); - pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config); - - // For a project-level install rule it might be defined in any of its - // associated generators. - bool hasInstallRule = false; - for (const auto generator : projectIt.second) { - for (const auto& installGen : - generator->GetMakefile()->GetInstallGenerators()) { - if (!dynamic_cast(installGen.get())) { - hasInstallRule = true; - break; - } - } - - if (hasInstallRule) { - break; - } - } - - pObj[kHAS_INSTALL_RULE] = hasInstallRule; - - result.append(pObj); - } - - return result; -} - -static Json::Value DumpConfiguration(const cmake* cm, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kNAME_KEY] = config; - - result[kPROJECTS_KEY] = DumpProjectList(cm, config); - - return result; -} - -static Json::Value DumpConfigurationsList(const cmake* cm) -{ - Json::Value result = Json::arrayValue; - - for (std::string const& c : getConfigurations(cm)) { - result.append(DumpConfiguration(cm, c)); - } - - return result; -} - -Json::Value cmDumpCodeModel(const cmake* cm) -{ - Json::Value result = Json::objectValue; - result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(cm); - return result; -} diff --git a/Source/cmJsonObjects.h b/Source/cmJsonObjects.h deleted file mode 100644 index 80a4834..0000000 --- a/Source/cmJsonObjects.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include "cmConfigure.h" // IWYU pragma: keep - -#include -#include - -#include - -class cmake; -class cmGlobalGenerator; - -extern void cmGetCMakeInputs(const cmGlobalGenerator* gg, - const std::string& sourceDir, - const std::string& buildDir, - std::vector* internalFiles, - std::vector* explicitFiles, - std::vector* tmpFiles); - -extern Json::Value cmDumpCodeModel(const cmake* cm); -extern Json::Value cmDumpCTestInfo(const cmake* cm); -extern Json::Value cmDumpCMakeInputs(const cmake* cm); diff --git a/Source/cmPipeConnection.cxx b/Source/cmPipeConnection.cxx deleted file mode 100644 index 1eede13..0000000 --- a/Source/cmPipeConnection.cxx +++ /dev/null @@ -1,71 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmPipeConnection.h" - -#include - -#include "cmServer.h" - -cmPipeConnection::cmPipeConnection(std::string name, - cmConnectionBufferStrategy* bufferStrategy) - : cmEventBasedConnection(bufferStrategy) - , PipeName(std::move(name)) -{ -} - -void cmPipeConnection::Connect(uv_stream_t* server) -{ - if (this->WriteStream.get()) { - // Accept and close all pipes but the first: - cm::uv_pipe_ptr rejectPipe; - - rejectPipe.init(*this->Server->GetLoop(), 0); - uv_accept(server, rejectPipe); - - return; - } - - cm::uv_pipe_ptr ClientPipe; - ClientPipe.init(*this->Server->GetLoop(), 0, - static_cast(this)); - - if (uv_accept(server, ClientPipe) != 0) { - return; - } - - uv_read_start(ClientPipe, on_alloc_buffer, on_read); - WriteStream = std::move(ClientPipe); - Server->OnConnected(this); -} - -bool cmPipeConnection::OnServeStart(std::string* errorMessage) -{ - this->ServerPipe.init(*this->Server->GetLoop(), 0, - static_cast(this)); - - int r; - if ((r = uv_pipe_bind(this->ServerPipe, this->PipeName.c_str())) != 0) { - *errorMessage = std::string("Internal Error with ") + this->PipeName + - ": " + uv_err_name(r); - return false; - } - - if ((r = uv_listen(this->ServerPipe, 1, on_new_connection)) != 0) { - *errorMessage = std::string("Internal Error listening on ") + - this->PipeName + ": " + uv_err_name(r); - return false; - } - - return cmConnection::OnServeStart(errorMessage); -} - -bool cmPipeConnection::OnConnectionShuttingDown() -{ - if (this->WriteStream.get()) { - this->WriteStream->data = nullptr; - } - - this->ServerPipe.reset(); - - return cmEventBasedConnection::OnConnectionShuttingDown(); -} diff --git a/Source/cmPipeConnection.h b/Source/cmPipeConnection.h deleted file mode 100644 index 1215716..0000000 --- a/Source/cmPipeConnection.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include "cmConfigure.h" // IWYU pragma: keep - -#include - -#include - -#include "cmConnection.h" -#include "cmUVHandlePtr.h" - -class cmPipeConnection : public cmEventBasedConnection -{ -public: - cmPipeConnection(std::string name, - cmConnectionBufferStrategy* bufferStrategy = nullptr); - - bool OnServeStart(std::string* pString) override; - - bool OnConnectionShuttingDown() override; - - void Connect(uv_stream_t* server) override; - -private: - const std::string PipeName; - cm::uv_pipe_ptr ServerPipe; -}; diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx deleted file mode 100644 index 7f97406..0000000 --- a/Source/cmServer.cxx +++ /dev/null @@ -1,570 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmServer.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "cmsys/FStream.hxx" - -#include "cmConnection.h" -#include "cmFileMonitor.h" -#include "cmJsonObjectDictionary.h" -#include "cmServerDictionary.h" -#include "cmServerProtocol.h" -#include "cmSystemTools.h" -#include "cmake.h" - -void on_signal(uv_signal_t* signal, int signum) -{ - auto conn = static_cast(signal->data); - conn->OnSignal(signum); -} - -static void on_walk_to_shutdown(uv_handle_t* handle, void* arg) -{ - (void)arg; - assert(uv_is_closing(handle)); - if (!uv_is_closing(handle)) { - uv_close(handle, &cmEventBasedConnection::on_close); - } -} - -class cmServer::DebugInfo -{ -public: - DebugInfo() - : StartTime(uv_hrtime()) - { - } - - bool PrintStatistics = false; - - std::string OutputFile; - uint64_t StartTime; -}; - -cmServer::cmServer(cmConnection* conn, bool supportExperimental) - : cmServerBase(conn) - , SupportExperimental(supportExperimental) -{ - // Register supported protocols: - this->RegisterProtocol(cm::make_unique()); -} - -cmServer::~cmServer() -{ - Close(); -} - -void cmServer::ProcessRequest(cmConnection* connection, - const std::string& input) -{ - Json::Reader reader; - Json::Value value; - if (!reader.parse(input, value)) { - this->WriteParseError(connection, "Failed to parse JSON input."); - return; - } - - std::unique_ptr debug; - Json::Value debugValue = value["debug"]; - if (!debugValue.isNull()) { - debug = cm::make_unique(); - debug->OutputFile = debugValue["dumpToFile"].asString(); - debug->PrintStatistics = debugValue["showStats"].asBool(); - } - - const cmServerRequest request(this, connection, value[kTYPE_KEY].asString(), - value[kCOOKIE_KEY].asString(), value); - - if (request.Type.empty()) { - cmServerResponse response(request); - response.SetError("No type given in request."); - this->WriteResponse(connection, response, nullptr); - return; - } - - cmSystemTools::SetMessageCallback( - [&request](const std::string& msg, const char* title) { - reportMessage(msg, title, request); - }); - - if (this->Protocol) { - this->Protocol->CMakeInstance()->SetProgressCallback( - [&request](const std::string& msg, float prog) { - reportProgress(msg, prog, request); - }); - this->WriteResponse(connection, this->Protocol->Process(request), - debug.get()); - } else { - this->WriteResponse(connection, this->SetProtocolVersion(request), - debug.get()); - } -} - -void cmServer::RegisterProtocol(std::unique_ptr protocol) -{ - if (protocol->IsExperimental() && !this->SupportExperimental) { - protocol.reset(); - return; - } - auto version = protocol->ProtocolVersion(); - assert(version.first >= 0); - assert(version.second >= 0); - auto it = std::find_if( - this->SupportedProtocols.begin(), this->SupportedProtocols.end(), - [version](const std::unique_ptr& p) { - return p->ProtocolVersion() == version; - }); - if (it == this->SupportedProtocols.end()) { - this->SupportedProtocols.push_back(std::move(protocol)); - } -} - -void cmServer::PrintHello(cmConnection* connection) const -{ - Json::Value hello = Json::objectValue; - hello[kTYPE_KEY] = "hello"; - - Json::Value& protocolVersions = hello[kSUPPORTED_PROTOCOL_VERSIONS] = - Json::arrayValue; - - for (auto const& proto : this->SupportedProtocols) { - auto version = proto->ProtocolVersion(); - Json::Value tmp = Json::objectValue; - tmp[kMAJOR_KEY] = version.first; - tmp[kMINOR_KEY] = version.second; - if (proto->IsExperimental()) { - tmp[kIS_EXPERIMENTAL_KEY] = true; - } - protocolVersions.append(tmp); - } - - this->WriteJsonObject(connection, hello, nullptr); -} - -void cmServer::reportProgress(const std::string& msg, float progress, - const cmServerRequest& request) -{ - if (progress < 0.0f || progress > 1.0f) { - request.ReportMessage(msg, ""); - } else { - request.ReportProgress(0, static_cast(progress * 1000), 1000, msg); - } -} - -void cmServer::reportMessage(const std::string& msg, const char* title, - const cmServerRequest& request) -{ - std::string titleString; - if (title) { - titleString = title; - } - request.ReportMessage(msg, titleString); -} - -cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request) -{ - if (request.Type != kHANDSHAKE_TYPE) { - return request.ReportError("Waiting for type \"" + kHANDSHAKE_TYPE + - "\"."); - } - - Json::Value requestedProtocolVersion = request.Data[kPROTOCOL_VERSION_KEY]; - if (requestedProtocolVersion.isNull()) { - return request.ReportError("\"" + kPROTOCOL_VERSION_KEY + - "\" is required for \"" + kHANDSHAKE_TYPE + - "\"."); - } - - if (!requestedProtocolVersion.isObject()) { - return request.ReportError("\"" + kPROTOCOL_VERSION_KEY + - "\" must be a JSON object."); - } - - Json::Value majorValue = requestedProtocolVersion[kMAJOR_KEY]; - if (!majorValue.isInt()) { - return request.ReportError("\"" + kMAJOR_KEY + - "\" must be set and an integer."); - } - - Json::Value minorValue = requestedProtocolVersion[kMINOR_KEY]; - if (!minorValue.isNull() && !minorValue.isInt()) { - return request.ReportError("\"" + kMINOR_KEY + - "\" must be unset or an integer."); - } - - const int major = majorValue.asInt(); - const int minor = minorValue.isNull() ? -1 : minorValue.asInt(); - if (major < 0) { - return request.ReportError("\"" + kMAJOR_KEY + "\" must be >= 0."); - } - if (!minorValue.isNull() && minor < 0) { - return request.ReportError("\"" + kMINOR_KEY + - "\" must be >= 0 when set."); - } - - this->Protocol = - cmServer::FindMatchingProtocol(this->SupportedProtocols, major, minor); - if (!this->Protocol) { - return request.ReportError("Protocol version not supported."); - } - - std::string errorMessage; - if (!this->Protocol->Activate(this, request, &errorMessage)) { - this->Protocol = nullptr; - return request.ReportError("Failed to activate protocol version: " + - errorMessage); - } - return request.Reply(Json::objectValue); -} - -bool cmServer::Serve(std::string* errorMessage) -{ - if (this->SupportedProtocols.empty()) { - *errorMessage = - "No protocol versions defined. Maybe you need --experimental?"; - return false; - } - assert(!this->Protocol); - - return cmServerBase::Serve(errorMessage); -} - -cmFileMonitor* cmServer::FileMonitor() const -{ - return fileMonitor.get(); -} - -void cmServer::WriteJsonObject(const Json::Value& jsonValue, - const DebugInfo* debug) const -{ - cm::shared_lock lock(ConnectionsMutex); - for (auto& connection : this->Connections) { - WriteJsonObject(connection.get(), jsonValue, debug); - } -} - -void cmServer::WriteJsonObject(cmConnection* connection, - const Json::Value& jsonValue, - const DebugInfo* debug) const -{ - Json::FastWriter writer; - - auto beforeJson = uv_hrtime(); - std::string result = writer.write(jsonValue); - - if (debug) { - Json::Value copy = jsonValue; - if (debug->PrintStatistics) { - Json::Value stats = Json::objectValue; - auto endTime = uv_hrtime(); - - stats["jsonSerialization"] = double(endTime - beforeJson) / 1000000.0; - stats["totalTime"] = double(endTime - debug->StartTime) / 1000000.0; - stats["size"] = static_cast(result.size()); - if (!debug->OutputFile.empty()) { - stats["dumpFile"] = debug->OutputFile; - } - - copy["zzzDebug"] = stats; - - result = writer.write(copy); // Update result to include debug info - } - - if (!debug->OutputFile.empty()) { - cmsys::ofstream myfile(debug->OutputFile.c_str()); - myfile << result; - } - } - - connection->WriteData(result); -} - -cmServerProtocol* cmServer::FindMatchingProtocol( - const std::vector>& protocols, int major, - int minor) -{ - cmServerProtocol* bestMatch = nullptr; - for (const auto& protocol : protocols) { - auto version = protocol->ProtocolVersion(); - if (major != version.first) { - continue; - } - if (minor == version.second) { - return protocol.get(); - } - if (!bestMatch || bestMatch->ProtocolVersion().second < version.second) { - bestMatch = protocol.get(); - } - } - return minor < 0 ? bestMatch : nullptr; -} - -void cmServer::WriteProgress(const cmServerRequest& request, int min, - int current, int max, - const std::string& message) const -{ - assert(min <= current && current <= max); - assert(message.length() != 0); - - Json::Value obj = Json::objectValue; - obj[kTYPE_KEY] = kPROGRESS_TYPE; - obj[kREPLY_TO_KEY] = request.Type; - obj[kCOOKIE_KEY] = request.Cookie; - obj[kPROGRESS_MESSAGE_KEY] = message; - obj[kPROGRESS_MINIMUM_KEY] = min; - obj[kPROGRESS_MAXIMUM_KEY] = max; - obj[kPROGRESS_CURRENT_KEY] = current; - - this->WriteJsonObject(request.Connection, obj, nullptr); -} - -void cmServer::WriteMessage(const cmServerRequest& request, - const std::string& message, - const std::string& title) const -{ - if (message.empty()) { - return; - } - - Json::Value obj = Json::objectValue; - obj[kTYPE_KEY] = kMESSAGE_TYPE; - obj[kREPLY_TO_KEY] = request.Type; - obj[kCOOKIE_KEY] = request.Cookie; - obj[kMESSAGE_KEY] = message; - if (!title.empty()) { - obj[kTITLE_KEY] = title; - } - - WriteJsonObject(request.Connection, obj, nullptr); -} - -void cmServer::WriteParseError(cmConnection* connection, - const std::string& message) const -{ - Json::Value obj = Json::objectValue; - obj[kTYPE_KEY] = kERROR_TYPE; - obj[kERROR_MESSAGE_KEY] = message; - obj[kREPLY_TO_KEY] = ""; - obj[kCOOKIE_KEY] = ""; - - this->WriteJsonObject(connection, obj, nullptr); -} - -void cmServer::WriteSignal(const std::string& name, - const Json::Value& data) const -{ - assert(data.isObject()); - Json::Value obj = data; - obj[kTYPE_KEY] = kSIGNAL_TYPE; - obj[kREPLY_TO_KEY] = ""; - obj[kCOOKIE_KEY] = ""; - obj[kNAME_KEY] = name; - - WriteJsonObject(obj, nullptr); -} - -void cmServer::WriteResponse(cmConnection* connection, - const cmServerResponse& response, - const DebugInfo* debug) const -{ - assert(response.IsComplete()); - - Json::Value obj = response.Data(); - obj[kCOOKIE_KEY] = response.Cookie; - obj[kTYPE_KEY] = response.IsError() ? kERROR_TYPE : kREPLY_TYPE; - obj[kREPLY_TO_KEY] = response.Type; - if (response.IsError()) { - obj[kERROR_MESSAGE_KEY] = response.ErrorMessage(); - } - - this->WriteJsonObject(connection, obj, debug); -} - -void cmServer::OnConnected(cmConnection* connection) -{ - PrintHello(connection); -} - -void cmServer::OnServeStart() -{ - cmServerBase::OnServeStart(); - fileMonitor = std::make_shared(GetLoop()); -} - -void cmServer::StartShutDown() -{ - if (fileMonitor) { - fileMonitor->StopMonitoring(); - fileMonitor.reset(); - } - cmServerBase::StartShutDown(); -} - -static void __start_thread(void* arg) -{ - auto server = static_cast(arg); - std::string error; - bool success = server->Serve(&error); - if (!success || !error.empty()) { - std::cerr << "Error during serve: " << error << std::endl; - } -} - -bool cmServerBase::StartServeThread() -{ - ServeThreadRunning = true; - uv_thread_create(&ServeThread, __start_thread, this); - return true; -} - -static void __shutdownThread(uv_async_t* arg) -{ - auto server = static_cast(arg->data); - server->StartShutDown(); -} - -bool cmServerBase::Serve(std::string* errorMessage) -{ -#ifndef NDEBUG - uv_thread_t blank_thread_t = {}; - assert(uv_thread_equal(&blank_thread_t, &ServeThreadId)); - ServeThreadId = uv_thread_self(); -#endif - - errorMessage->clear(); - - ShutdownSignal.init(Loop, __shutdownThread, this); - - SIGINTHandler.init(Loop, this); - SIGHUPHandler.init(Loop, this); - - SIGINTHandler.start(&on_signal, SIGINT); - SIGHUPHandler.start(&on_signal, SIGHUP); - - OnServeStart(); - - { - cm::shared_lock lock(ConnectionsMutex); - for (auto& connection : Connections) { - if (!connection->OnServeStart(errorMessage)) { - return false; - } - } - } - - if (uv_run(&Loop, UV_RUN_DEFAULT) != 0) { - // It is important we don't ever let the event loop exit with open handles - // at best this is a memory leak, but it can also introduce race conditions - // which can hang the program. - assert(false && "Event loop stopped in unclean state."); - - *errorMessage = "Internal Error: Event loop stopped in unclean state."; - return false; - } - - return true; -} - -void cmServerBase::OnConnected(cmConnection*) -{ -} - -void cmServerBase::OnServeStart() -{ -} - -void cmServerBase::StartShutDown() -{ - ShutdownSignal.reset(); - SIGINTHandler.reset(); - SIGHUPHandler.reset(); - - { - std::unique_lock lock(ConnectionsMutex); - for (auto& connection : Connections) { - connection->OnConnectionShuttingDown(); - } - Connections.clear(); - } - - uv_walk(&Loop, on_walk_to_shutdown, nullptr); -} - -bool cmServerBase::OnSignal(int signum) -{ - (void)signum; - StartShutDown(); - return true; -} - -cmServerBase::cmServerBase(cmConnection* connection) -{ - auto err = uv_loop_init(&Loop); - (void)err; - Loop.data = this; - assert(err == 0); - - AddNewConnection(connection); -} - -void cmServerBase::Close() -{ - if (Loop.data) { - if (ServeThreadRunning) { - this->ShutdownSignal.send(); - uv_thread_join(&ServeThread); - } - - uv_loop_close(&Loop); - Loop.data = nullptr; - } -} -cmServerBase::~cmServerBase() -{ - Close(); -} - -void cmServerBase::AddNewConnection(cmConnection* ownedConnection) -{ - { - std::unique_lock lock(ConnectionsMutex); - Connections.emplace_back(ownedConnection); - } - ownedConnection->SetServer(this); -} - -uv_loop_t* cmServerBase::GetLoop() -{ - return &Loop; -} - -void cmServerBase::OnDisconnect(cmConnection* pConnection) -{ - auto pred = [pConnection](const std::unique_ptr& m) { - return m.get() == pConnection; - }; - { - std::unique_lock lock(ConnectionsMutex); - Connections.erase( - std::remove_if(Connections.begin(), Connections.end(), pred), - Connections.end()); - } - - if (Connections.empty()) { - this->ShutdownSignal.send(); - } -} diff --git a/Source/cmServer.h b/Source/cmServer.h deleted file mode 100644 index 9543329..0000000 --- a/Source/cmServer.h +++ /dev/null @@ -1,162 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include "cmConfigure.h" // IWYU pragma: keep - -#include -#include -#include - -#include - -#include -#include - -#include "cmUVHandlePtr.h" - -class cmConnection; -class cmFileMonitor; -class cmServerProtocol; -class cmServerRequest; -class cmServerResponse; - -/*** - * This essentially hold and manages a libuv event queue and responds to - * messages - * on any of its connections. - */ -class cmServerBase -{ -public: - cmServerBase(cmConnection* connection); - virtual ~cmServerBase(); - - virtual void AddNewConnection(cmConnection* ownedConnection); - - /*** - * The main override responsible for tailoring behavior towards - * whatever the given server is supposed to do - * - * This should almost always be called by the given connections - * directly. - * - * @param connection The connection the request was received on - * @param request The actual request - */ - virtual void ProcessRequest(cmConnection* connection, - const std::string& request) = 0; - virtual void OnConnected(cmConnection* connection); - - /*** - * Start a dedicated thread. If this is used to start the server, it will - * join on the - * servers dtor. - */ - virtual bool StartServeThread(); - virtual bool Serve(std::string* errorMessage); - - virtual void OnServeStart(); - virtual void StartShutDown(); - - virtual bool OnSignal(int signum); - uv_loop_t* GetLoop(); - void Close(); - void OnDisconnect(cmConnection* pConnection); - -protected: - mutable cm::shared_mutex ConnectionsMutex; - std::vector> Connections; - - bool ServeThreadRunning = false; - uv_thread_t ServeThread; - cm::uv_async_ptr ShutdownSignal; -#ifndef NDEBUG -public: - // When the server starts it will mark down it's current thread ID, - // which is useful in other contexts to just assert that operations - // are performed on that same thread. - uv_thread_t ServeThreadId = {}; - -protected: -#endif - - uv_loop_t Loop; - - cm::uv_signal_ptr SIGINTHandler; - cm::uv_signal_ptr SIGHUPHandler; -}; - -class cmServer : public cmServerBase -{ -public: - class DebugInfo; - - cmServer(cmConnection* conn, bool supportExperimental); - ~cmServer() override; - - cmServer(cmServer const&) = delete; - cmServer& operator=(cmServer const&) = delete; - - bool Serve(std::string* errorMessage) override; - - cmFileMonitor* FileMonitor() const; - -private: - void RegisterProtocol(std::unique_ptr protocol); - - // Callbacks from cmServerConnection: - - void ProcessRequest(cmConnection* connection, - const std::string& request) override; - std::shared_ptr fileMonitor; - -public: - void OnServeStart() override; - - void StartShutDown() override; - -public: - void OnConnected(cmConnection* connection) override; - -private: - static void reportProgress(const std::string& msg, float progress, - const cmServerRequest& request); - static void reportMessage(const std::string& msg, const char* title, - const cmServerRequest& request); - - // Handle requests: - cmServerResponse SetProtocolVersion(const cmServerRequest& request); - - void PrintHello(cmConnection* connection) const; - - // Write responses: - void WriteProgress(const cmServerRequest& request, int min, int current, - int max, const std::string& message) const; - void WriteMessage(const cmServerRequest& request, const std::string& message, - const std::string& title) const; - void WriteResponse(cmConnection* connection, - const cmServerResponse& response, - const DebugInfo* debug) const; - void WriteParseError(cmConnection* connection, - const std::string& message) const; - void WriteSignal(const std::string& name, const Json::Value& obj) const; - - void WriteJsonObject(Json::Value const& jsonValue, - const DebugInfo* debug) const; - - void WriteJsonObject(cmConnection* connection, Json::Value const& jsonValue, - const DebugInfo* debug) const; - - static cmServerProtocol* FindMatchingProtocol( - const std::vector>& protocols, int major, - int minor); - - const bool SupportExperimental; - - cmServerProtocol* Protocol = nullptr; - std::vector> SupportedProtocols; - - friend class cmServerProtocol; - friend class cmServerRequest; -}; diff --git a/Source/cmServerConnection.cxx b/Source/cmServerConnection.cxx deleted file mode 100644 index b4f41a0..0000000 --- a/Source/cmServerConnection.cxx +++ /dev/null @@ -1,165 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmConfigure.h" - -#include "cmServerConnection.h" - -#include - -#include "cmServer.h" -#include "cmServerDictionary.h" - -#ifdef _WIN32 -# include "io.h" -#else -# include -#endif -#include -#include - -cmStdIoConnection::cmStdIoConnection( - cmConnectionBufferStrategy* bufferStrategy) - : cmEventBasedConnection(bufferStrategy) -{ -} - -cm::uv_stream_ptr cmStdIoConnection::SetupStream(int file_id) -{ - switch (uv_guess_handle(file_id)) { - case UV_TTY: { - cm::uv_tty_ptr tty; - tty.init(*this->Server->GetLoop(), file_id, file_id == 0, - static_cast(this)); - uv_tty_set_mode(tty, UV_TTY_MODE_NORMAL); - return { std::move(tty) }; - } - case UV_FILE: - if (file_id == 0) { - return nullptr; - } - // Intentional fallthrough; stdin can _not_ be treated as a named - // pipe, however stdout can be. - CM_FALLTHROUGH; - case UV_NAMED_PIPE: { - cm::uv_pipe_ptr pipe; - pipe.init(*this->Server->GetLoop(), 0, - static_cast(this)); - uv_pipe_open(pipe, file_id); - return { std::move(pipe) }; - } - default: - assert(false && "Unable to determine stream type"); - return nullptr; - } -} - -void cmStdIoConnection::SetServer(cmServerBase* s) -{ - cmConnection::SetServer(s); - if (!s) { - return; - } - - this->ReadStream = SetupStream(0); - this->WriteStream = SetupStream(1); -} - -void shutdown_connection(uv_prepare_t* prepare) -{ - cmStdIoConnection* connection = - static_cast(prepare->data); - - if (!uv_is_closing(reinterpret_cast(prepare))) { - uv_close(reinterpret_cast(prepare), - &cmEventBasedConnection::on_close_delete); - } - connection->OnDisconnect(0); -} - -bool cmStdIoConnection::OnServeStart(std::string* pString) -{ - Server->OnConnected(this); - if (this->ReadStream.get()) { - uv_read_start(this->ReadStream, on_alloc_buffer, on_read); - } else if (uv_guess_handle(0) == UV_FILE) { - char buffer[1024]; - while (auto len = read(0, buffer, sizeof(buffer))) { - ReadData(std::string(buffer, buffer + len)); - } - - // We can't start the disconnect from here, add a prepare hook to do that - // for us - auto prepare = new uv_prepare_t(); - prepare->data = this; - uv_prepare_init(Server->GetLoop(), prepare); - uv_prepare_start(prepare, shutdown_connection); - } - return cmConnection::OnServeStart(pString); -} - -bool cmStdIoConnection::OnConnectionShuttingDown() -{ - if (ReadStream.get()) { - uv_read_stop(ReadStream); - ReadStream->data = nullptr; - } - - this->ReadStream.reset(); - - cmEventBasedConnection::OnConnectionShuttingDown(); - - return true; -} - -cmServerPipeConnection::cmServerPipeConnection(const std::string& name) - : cmPipeConnection(name, new cmServerBufferStrategy) -{ -} - -cmServerStdIoConnection::cmServerStdIoConnection() - : cmStdIoConnection(new cmServerBufferStrategy) -{ -} - -cmConnectionBufferStrategy::~cmConnectionBufferStrategy() = default; - -void cmConnectionBufferStrategy::clear() -{ -} - -std::string cmServerBufferStrategy::BufferOutMessage( - const std::string& rawBuffer) const -{ - return std::string("\n") + kSTART_MAGIC + std::string("\n") + rawBuffer + - kEND_MAGIC + std::string("\n"); -} - -std::string cmServerBufferStrategy::BufferMessage(std::string& RawReadBuffer) -{ - for (;;) { - auto needle = RawReadBuffer.find('\n'); - - if (needle == std::string::npos) { - return ""; - } - std::string line = RawReadBuffer.substr(0, needle); - const auto ls = line.size(); - if (ls > 1 && line.at(ls - 1) == '\r') { - line.erase(ls - 1, 1); - } - RawReadBuffer.erase(RawReadBuffer.begin(), - RawReadBuffer.begin() + static_cast(needle) + 1); - if (line == kSTART_MAGIC) { - RequestBuffer.clear(); - continue; - } - if (line == kEND_MAGIC) { - std::string rtn; - rtn.swap(this->RequestBuffer); - return rtn; - } - - this->RequestBuffer += line; - this->RequestBuffer += "\n"; - } -} diff --git a/Source/cmServerConnection.h b/Source/cmServerConnection.h deleted file mode 100644 index a70edb4..0000000 --- a/Source/cmServerConnection.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include "cmConfigure.h" // IWYU pragma: keep - -#include - -#include "cmConnection.h" -#include "cmPipeConnection.h" -#include "cmUVHandlePtr.h" - -class cmServerBase; - -/*** - * This connection buffer strategy accepts messages in the form of - * [== "CMake Server" ==[ -{ - ... some JSON message ... -} -]== "CMake Server" ==] - * and only passes on the core json; it discards the envelope. - */ -class cmServerBufferStrategy : public cmConnectionBufferStrategy -{ -public: - std::string BufferMessage(std::string& rawBuffer) override; - std::string BufferOutMessage(const std::string& rawBuffer) const override; - -private: - std::string RequestBuffer; -}; - -/*** - * Generic connection over std io interfaces -- tty - */ -class cmStdIoConnection : public cmEventBasedConnection -{ -public: - cmStdIoConnection(cmConnectionBufferStrategy* bufferStrategy); - - void SetServer(cmServerBase* s) override; - - bool OnConnectionShuttingDown() override; - - bool OnServeStart(std::string* pString) override; - -private: - cm::uv_stream_ptr SetupStream(int file_id); - cm::uv_stream_ptr ReadStream; -}; - -/*** - * These specific connections use the cmake server - * buffering strategy. - */ -class cmServerStdIoConnection : public cmStdIoConnection -{ -public: - cmServerStdIoConnection(); -}; - -class cmServerPipeConnection : public cmPipeConnection -{ -public: - cmServerPipeConnection(const std::string& name); -}; diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h deleted file mode 100644 index 961e4b7..0000000 --- a/Source/cmServerDictionary.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include - -// Vocabulary: - -static const std::string kDIRTY_SIGNAL = "dirty"; -static const std::string kFILE_CHANGE_SIGNAL = "fileChange"; - -static const std::string kCACHE_TYPE = "cache"; -static const std::string kCMAKE_INPUTS_TYPE = "cmakeInputs"; -static const std::string kCODE_MODEL_TYPE = "codemodel"; -static const std::string kCOMPUTE_TYPE = "compute"; -static const std::string kCONFIGURE_TYPE = "configure"; -static const std::string kERROR_TYPE = "error"; -static const std::string kFILESYSTEM_WATCHERS_TYPE = "fileSystemWatchers"; -static const std::string kGLOBAL_SETTINGS_TYPE = "globalSettings"; -static const std::string kHANDSHAKE_TYPE = "handshake"; -static const std::string kMESSAGE_TYPE = "message"; -static const std::string kPROGRESS_TYPE = "progress"; -static const std::string kREPLY_TYPE = "reply"; -static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings"; -static const std::string kSIGNAL_TYPE = "signal"; -static const std::string kCTEST_INFO_TYPE = "ctestInfo"; - -static const std::string kBUILD_FILES_KEY = "buildFiles"; -static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments"; -static const std::string kCACHE_KEY = "cache"; -static const std::string kCAPABILITIES_KEY = "capabilities"; -static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars"; -static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory"; -static const std::string kCOOKIE_KEY = "cookie"; -static const std::string kDEBUG_OUTPUT_KEY = "debugOutput"; -static const std::string kERROR_MESSAGE_KEY = "errorMessage"; -static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator"; -static const std::string kGENERATOR_KEY = "generator"; -static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental"; -static const std::string kKEYS_KEY = "keys"; -static const std::string kMAJOR_KEY = "major"; -static const std::string kMESSAGE_KEY = "message"; -static const std::string kMINOR_KEY = "minor"; -static const std::string kPLATFORM_KEY = "platform"; -static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent"; -static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum"; -static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage"; -static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum"; -static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion"; -static const std::string kREPLY_TO_KEY = "inReplyTo"; -static const std::string kSUPPORTED_PROTOCOL_VERSIONS = - "supportedProtocolVersions"; -static const std::string kTITLE_KEY = "title"; -static const std::string kTOOLSET_KEY = "toolset"; -static const std::string kTRACE_EXPAND_KEY = "traceExpand"; -static const std::string kTRACE_KEY = "trace"; -static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized"; -static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli"; -static const std::string kWARN_UNUSED_KEY = "warnUnused"; -static const std::string kWATCHED_DIRECTORIES_KEY = "watchedDirectories"; -static const std::string kWATCHED_FILES_KEY = "watchedFiles"; - -static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==["; -static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]"; - -static const std::string kRENAME_PROPERTY_VALUE = "rename"; -static const std::string kCHANGE_PROPERTY_VALUE = "change"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx deleted file mode 100644 index e586fd9..0000000 --- a/Source/cmServerProtocol.cxx +++ /dev/null @@ -1,760 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#include "cmServerProtocol.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "cmExternalMakefileProjectGenerator.h" -#include "cmFileMonitor.h" -#include "cmGlobalGenerator.h" -#include "cmJsonObjectDictionary.h" -#include "cmJsonObjects.h" -#include "cmMessageType.h" -#include "cmProperty.h" -#include "cmServer.h" -#include "cmServerDictionary.h" -#include "cmState.h" -#include "cmSystemTools.h" -#include "cmake.h" - -// Get rid of some windows macros: -#undef max - -namespace { - -std::vector toStringList(const Json::Value& in) -{ - std::vector result; - for (auto const& it : in) { - result.push_back(it.asString()); - } - return result; -} - -} // namespace - -cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection, - std::string t, std::string c, Json::Value d) - : Type(std::move(t)) - , Cookie(std::move(c)) - , Data(std::move(d)) - , Connection(connection) - , m_Server(server) -{ -} - -void cmServerRequest::ReportProgress(int min, int current, int max, - const std::string& message) const -{ - this->m_Server->WriteProgress(*this, min, current, max, message); -} - -void cmServerRequest::ReportMessage(const std::string& message, - const std::string& title) const -{ - m_Server->WriteMessage(*this, message, title); -} - -cmServerResponse cmServerRequest::Reply(const Json::Value& data) const -{ - cmServerResponse response(*this); - response.SetData(data); - return response; -} - -cmServerResponse cmServerRequest::ReportError(const std::string& message) const -{ - cmServerResponse response(*this); - response.SetError(message); - return response; -} - -cmServerResponse::cmServerResponse(const cmServerRequest& request) - : Type(request.Type) - , Cookie(request.Cookie) -{ -} - -void cmServerResponse::SetData(const Json::Value& data) -{ - assert(this->m_Payload == PAYLOAD_UNKNOWN); - if (!data[kCOOKIE_KEY].isNull() || !data[kTYPE_KEY].isNull()) { - this->SetError("Response contains cookie or type field."); - return; - } - this->m_Payload = PAYLOAD_DATA; - this->m_Data = data; -} - -void cmServerResponse::SetError(const std::string& message) -{ - assert(this->m_Payload == PAYLOAD_UNKNOWN); - this->m_Payload = PAYLOAD_ERROR; - this->m_ErrorMessage = message; -} - -bool cmServerResponse::IsComplete() const -{ - return this->m_Payload != PAYLOAD_UNKNOWN; -} - -bool cmServerResponse::IsError() const -{ - assert(this->m_Payload != PAYLOAD_UNKNOWN); - return this->m_Payload == PAYLOAD_ERROR; -} - -std::string cmServerResponse::ErrorMessage() const -{ - if (this->m_Payload == PAYLOAD_ERROR) { - return this->m_ErrorMessage; - } - return std::string(); -} - -Json::Value cmServerResponse::Data() const -{ - assert(this->m_Payload != PAYLOAD_UNKNOWN); - return this->m_Data; -} - -bool cmServerProtocol::Activate(cmServer* server, - const cmServerRequest& request, - std::string* errorMessage) -{ - assert(server); - this->m_Server = server; - this->m_CMakeInstance = - cm::make_unique(cmake::RoleProject, cmState::Project); - this->m_WarnUnused = false; - const bool result = this->DoActivate(request, errorMessage); - if (!result) { - this->m_CMakeInstance = nullptr; - } - return result; -} - -cmFileMonitor* cmServerProtocol::FileMonitor() const -{ - return this->m_Server ? this->m_Server->FileMonitor() : nullptr; -} - -void cmServerProtocol::SendSignal(const std::string& name, - const Json::Value& data) const -{ - if (this->m_Server) { - this->m_Server->WriteSignal(name, data); - } -} - -cmake* cmServerProtocol::CMakeInstance() const -{ - return this->m_CMakeInstance.get(); -} - -bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/, - std::string* /*errorMessage*/) -{ - return true; -} - -std::pair cmServerProtocol1::ProtocolVersion() const -{ - return { 1, 2 }; -} - -static void setErrorMessage(std::string* errorMessage, const std::string& text) -{ - if (errorMessage) { - *errorMessage = text; - } -} - -static bool getOrTestHomeDirectory(cmState* state, std::string& value, - std::string* errorMessage) -{ - const std::string cachedValue = - *state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY"); - if (value.empty()) { - value = cachedValue; - return true; - } - const std::string suffix = "/CMakeLists.txt"; - const std::string cachedValueCML = cachedValue + suffix; - const std::string valueCML = value + suffix; - if (!cmSystemTools::SameFile(valueCML, cachedValueCML)) { - setErrorMessage(errorMessage, - std::string("\"CMAKE_HOME_DIRECTORY\" is set but " - "incompatible with configured " - "source directory value.")); - return false; - } - return true; -} - -static bool getOrTestValue(cmState* state, const std::string& key, - std::string& value, - const std::string& keyDescription, - std::string* errorMessage) -{ - const std::string cachedValue = state->GetSafeCacheEntryValue(key); - if (value.empty()) { - value = cachedValue; - } - if (!cachedValue.empty() && cachedValue != value) { - setErrorMessage(errorMessage, - std::string("\"") + key + - "\" is set but incompatible with configured " + - keyDescription + " value."); - return false; - } - return true; -} - -bool cmServerProtocol1::DoActivate(const cmServerRequest& request, - std::string* errorMessage) -{ - std::string sourceDirectory = request.Data[kSOURCE_DIRECTORY_KEY].asString(); - std::string buildDirectory = request.Data[kBUILD_DIRECTORY_KEY].asString(); - std::string generator = request.Data[kGENERATOR_KEY].asString(); - std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString(); - std::string toolset = request.Data[kTOOLSET_KEY].asString(); - std::string platform = request.Data[kPLATFORM_KEY].asString(); - - // normalize source and build directory - if (!sourceDirectory.empty()) { - sourceDirectory = cmSystemTools::CollapseFullPath(sourceDirectory); - cmSystemTools::ConvertToUnixSlashes(sourceDirectory); - } - if (!buildDirectory.empty()) { - buildDirectory = cmSystemTools::CollapseFullPath(buildDirectory); - cmSystemTools::ConvertToUnixSlashes(buildDirectory); - } - - if (buildDirectory.empty()) { - setErrorMessage(errorMessage, - std::string("\"") + kBUILD_DIRECTORY_KEY + - "\" is missing."); - return false; - } - - cmake* cm = CMakeInstance(); - if (cmSystemTools::PathExists(buildDirectory)) { - if (!cmSystemTools::FileIsDirectory(buildDirectory)) { - setErrorMessage(errorMessage, - std::string("\"") + kBUILD_DIRECTORY_KEY + - "\" exists but is not a directory."); - return false; - } - - const std::string cachePath = cmake::FindCacheFile(buildDirectory); - if (cm->LoadCache(cachePath)) { - cmState* state = cm->GetState(); - - // Check generator: - if (!getOrTestValue(state, "CMAKE_GENERATOR", generator, "generator", - errorMessage)) { - return false; - } - - // check extra generator: - if (!getOrTestValue(state, "CMAKE_EXTRA_GENERATOR", extraGenerator, - "extra generator", errorMessage)) { - return false; - } - - // check sourcedir: - if (!getOrTestHomeDirectory(state, sourceDirectory, errorMessage)) { - return false; - } - - // check toolset: - if (!getOrTestValue(state, "CMAKE_GENERATOR_TOOLSET", toolset, "toolset", - errorMessage)) { - return false; - } - - // check platform: - if (!getOrTestValue(state, "CMAKE_GENERATOR_PLATFORM", platform, - "platform", errorMessage)) { - return false; - } - } - } - - if (sourceDirectory.empty()) { - setErrorMessage(errorMessage, - std::string("\"") + kSOURCE_DIRECTORY_KEY + - "\" is unset but required."); - return false; - } - if (!cmSystemTools::FileIsDirectory(sourceDirectory)) { - setErrorMessage(errorMessage, - std::string("\"") + kSOURCE_DIRECTORY_KEY + - "\" is not a directory."); - return false; - } - if (generator.empty()) { - setErrorMessage(errorMessage, - std::string("\"") + kGENERATOR_KEY + - "\" is unset but required."); - return false; - } - - std::vector generators; - cm->GetRegisteredGenerators(generators); - auto baseIt = std::find_if(generators.begin(), generators.end(), - [&generator](const cmake::GeneratorInfo& info) { - return info.name == generator; - }); - if (baseIt == generators.end()) { - setErrorMessage(errorMessage, - std::string("Generator \"") + generator + - "\" not supported."); - return false; - } - auto extraIt = std::find_if( - generators.begin(), generators.end(), - [&generator, &extraGenerator](const cmake::GeneratorInfo& info) { - return info.baseName == generator && info.extraName == extraGenerator; - }); - if (extraIt == generators.end()) { - setErrorMessage(errorMessage, - std::string("The combination of generator \"" + generator + - "\" and extra generator \"" + extraGenerator + - "\" is not supported.")); - return false; - } - if (!extraIt->supportsToolset && !toolset.empty()) { - setErrorMessage(errorMessage, - std::string("Toolset was provided but is not supported by " - "the requested generator.")); - return false; - } - if (!extraIt->supportsPlatform && !platform.empty()) { - setErrorMessage(errorMessage, - std::string("Platform was provided but is not supported " - "by the requested generator.")); - return false; - } - - this->GeneratorInfo = - GeneratorInformation(generator, extraGenerator, toolset, platform, - sourceDirectory, buildDirectory); - - this->m_State = STATE_ACTIVE; - return true; -} - -void cmServerProtocol1::HandleCMakeFileChanges(const std::string& path, - int event, int status) -{ - assert(status == 0); - static_cast(status); - - if (!m_isDirty) { - m_isDirty = true; - SendSignal(kDIRTY_SIGNAL, Json::objectValue); - } - Json::Value obj = Json::objectValue; - obj[kPATH_KEY] = path; - Json::Value properties = Json::arrayValue; - if (event & UV_RENAME) { - properties.append(kRENAME_PROPERTY_VALUE); - } - if (event & UV_CHANGE) { - properties.append(kCHANGE_PROPERTY_VALUE); - } - - obj[kPROPERTIES_KEY] = properties; - SendSignal(kFILE_CHANGE_SIGNAL, obj); -} - -cmServerResponse cmServerProtocol1::Process(const cmServerRequest& request) -{ - assert(this->m_State >= STATE_ACTIVE); - - if (request.Type == kCACHE_TYPE) { - return this->ProcessCache(request); - } - if (request.Type == kCMAKE_INPUTS_TYPE) { - return this->ProcessCMakeInputs(request); - } - if (request.Type == kCODE_MODEL_TYPE) { - return this->ProcessCodeModel(request); - } - if (request.Type == kCOMPUTE_TYPE) { - return this->ProcessCompute(request); - } - if (request.Type == kCONFIGURE_TYPE) { - return this->ProcessConfigure(request); - } - if (request.Type == kFILESYSTEM_WATCHERS_TYPE) { - return this->ProcessFileSystemWatchers(request); - } - if (request.Type == kGLOBAL_SETTINGS_TYPE) { - return this->ProcessGlobalSettings(request); - } - if (request.Type == kSET_GLOBAL_SETTINGS_TYPE) { - return this->ProcessSetGlobalSettings(request); - } - if (request.Type == kCTEST_INFO_TYPE) { - return this->ProcessCTests(request); - } - - return request.ReportError("Unknown command!"); -} - -bool cmServerProtocol1::IsExperimental() const -{ - return true; -} - -cmServerResponse cmServerProtocol1::ProcessCache( - const cmServerRequest& request) -{ - cmState* state = this->CMakeInstance()->GetState(); - - Json::Value result = Json::objectValue; - - std::vector allKeys = state->GetCacheEntryKeys(); - - Json::Value list = Json::arrayValue; - std::vector keys = toStringList(request.Data[kKEYS_KEY]); - if (keys.empty()) { - keys = allKeys; - } else { - for (auto const& i : keys) { - if (!cm::contains(allKeys, i)) { - return request.ReportError("Key \"" + i + "\" not found in cache."); - } - } - } - std::sort(keys.begin(), keys.end()); - for (auto const& key : keys) { - Json::Value entry = Json::objectValue; - entry[kKEY_KEY] = key; - entry[kTYPE_KEY] = - cmState::CacheEntryTypeToString(state->GetCacheEntryType(key)); - entry[kVALUE_KEY] = *state->GetCacheEntryValue(key); - - Json::Value props = Json::objectValue; - bool haveProperties = false; - for (auto const& prop : state->GetCacheEntryPropertyList(key)) { - haveProperties = true; - props[prop] = *state->GetCacheEntryProperty(key, prop); - } - if (haveProperties) { - entry[kPROPERTIES_KEY] = props; - } - - list.append(entry); - } - - result[kCACHE_KEY] = list; - return request.Reply(result); -} - -cmServerResponse cmServerProtocol1::ProcessCMakeInputs( - const cmServerRequest& request) -{ - if (this->m_State < STATE_CONFIGURED) { - return request.ReportError("This instance was not yet configured."); - } - - const cmake* cm = this->CMakeInstance(); - const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot(); - const std::string& sourceDir = cm->GetHomeDirectory(); - - Json::Value result = Json::objectValue; - result[kSOURCE_DIRECTORY_KEY] = sourceDir; - result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir; - result[kBUILD_FILES_KEY] = cmDumpCMakeInputs(cm); - return request.Reply(result); -} - -cmServerResponse cmServerProtocol1::ProcessCodeModel( - const cmServerRequest& request) -{ - if (this->m_State != STATE_COMPUTED) { - return request.ReportError("No build system was generated yet."); - } - - return request.Reply(cmDumpCodeModel(this->CMakeInstance())); -} - -cmServerResponse cmServerProtocol1::ProcessCompute( - const cmServerRequest& request) -{ - if (this->m_State > STATE_CONFIGURED) { - return request.ReportError("This build system was already generated."); - } - if (this->m_State < STATE_CONFIGURED) { - return request.ReportError("This project was not configured yet."); - } - - cmake* cm = this->CMakeInstance(); - int ret = cm->Generate(); - - if (ret < 0) { - return request.ReportError("Failed to compute build system."); - } - m_State = STATE_COMPUTED; - return request.Reply(Json::Value()); -} - -cmServerResponse cmServerProtocol1::ProcessConfigure( - const cmServerRequest& request) -{ - if (this->m_State == STATE_INACTIVE) { - return request.ReportError("This instance is inactive."); - } - - FileMonitor()->StopMonitoring(); - - std::string errorMessage; - cmake* cm = this->CMakeInstance(); - this->GeneratorInfo.SetupGenerator(cm, &errorMessage); - if (!errorMessage.empty()) { - return request.ReportError(errorMessage); - } - - // Make sure the types of cacheArguments matches (if given): - std::vector cacheArgs = { "unused" }; - bool cacheArgumentsError = false; - const Json::Value passedArgs = request.Data[kCACHE_ARGUMENTS_KEY]; - if (!passedArgs.isNull()) { - if (passedArgs.isString()) { - cacheArgs.push_back(passedArgs.asString()); - } else if (passedArgs.isArray()) { - for (auto const& arg : passedArgs) { - if (!arg.isString()) { - cacheArgumentsError = true; - break; - } - cacheArgs.push_back(arg.asString()); - } - } else { - cacheArgumentsError = true; - } - } - if (cacheArgumentsError) { - request.ReportError( - "cacheArguments must be unset, a string or an array of strings."); - } - - std::string sourceDir = cm->GetHomeDirectory(); - const std::string buildDir = cm->GetHomeOutputDirectory(); - - cmGlobalGenerator* gg = cm->GetGlobalGenerator(); - - if (buildDir.empty()) { - return request.ReportError("No build directory set via Handshake."); - } - - if (cm->LoadCache(buildDir)) { - // build directory has been set up before - cmProp cachedSourceDir = - cm->GetState()->GetInitializedCacheValue("CMAKE_HOME_DIRECTORY"); - if (!cachedSourceDir) { - return request.ReportError("No CMAKE_HOME_DIRECTORY found in cache."); - } - if (sourceDir.empty()) { - sourceDir = *cachedSourceDir; - cm->SetHomeDirectory(sourceDir); - } - - cmProp cachedGenerator = - cm->GetState()->GetInitializedCacheValue("CMAKE_GENERATOR"); - if (cachedGenerator) { - if (gg && gg->GetName() != *cachedGenerator) { - return request.ReportError("Configured generator does not match with " - "CMAKE_GENERATOR found in cache."); - } - } - } else { - // build directory has not been set up before - if (sourceDir.empty()) { - return request.ReportError("No sourceDirectory set via " - "setGlobalSettings and no cache found in " - "buildDirectory."); - } - } - - cmSystemTools::ResetErrorOccuredFlag(); // Reset error state - - if (cm->AddCMakePaths() != 1) { - return request.ReportError("Failed to set CMake paths."); - } - - if (!cm->SetCacheArgs(cacheArgs)) { - return request.ReportError("cacheArguments could not be set."); - } - - int ret = cm->Configure(); - cm->IssueMessage( - MessageType::DEPRECATION_WARNING, - "The 'cmake-server(7)' is deprecated. " - "Please port clients to use the 'cmake-file-api(7)' instead."); - if (ret < 0) { - return request.ReportError("Configuration failed."); - } - - std::vector toWatchList; - cmGetCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList, - nullptr); - - FileMonitor()->MonitorPaths(toWatchList, - [this](const std::string& p, int e, int s) { - this->HandleCMakeFileChanges(p, e, s); - }); - - m_State = STATE_CONFIGURED; - m_isDirty = false; - return request.Reply(Json::Value()); -} - -cmServerResponse cmServerProtocol1::ProcessGlobalSettings( - const cmServerRequest& request) -{ - cmake* cm = this->CMakeInstance(); - Json::Value obj = Json::objectValue; - - // Capabilities information: - obj[kCAPABILITIES_KEY] = cm->ReportCapabilitiesJson(); - - obj[kDEBUG_OUTPUT_KEY] = cm->GetDebugOutput(); - obj[kTRACE_KEY] = cm->GetTrace(); - obj[kTRACE_EXPAND_KEY] = cm->GetTraceExpand(); - obj[kWARN_UNINITIALIZED_KEY] = cm->GetWarnUninitialized(); - obj[kWARN_UNUSED_KEY] = m_WarnUnused; - obj[kWARN_UNUSED_CLI_KEY] = cm->GetWarnUnusedCli(); - obj[kCHECK_SYSTEM_VARS_KEY] = cm->GetCheckSystemVars(); - - obj[kSOURCE_DIRECTORY_KEY] = this->GeneratorInfo.SourceDirectory; - obj[kBUILD_DIRECTORY_KEY] = this->GeneratorInfo.BuildDirectory; - - // Currently used generator: - obj[kGENERATOR_KEY] = this->GeneratorInfo.GeneratorName; - obj[kEXTRA_GENERATOR_KEY] = this->GeneratorInfo.ExtraGeneratorName; - - return request.Reply(obj); -} - -static void setBool(const cmServerRequest& request, const std::string& key, - std::function const& setter) -{ - if (request.Data[key].isNull()) { - return; - } - setter(request.Data[key].asBool()); -} - -cmServerResponse cmServerProtocol1::ProcessSetGlobalSettings( - const cmServerRequest& request) -{ - const std::vector boolValues = { - kDEBUG_OUTPUT_KEY, kTRACE_KEY, kTRACE_EXPAND_KEY, - kWARN_UNINITIALIZED_KEY, kWARN_UNUSED_KEY, kWARN_UNUSED_CLI_KEY, - kCHECK_SYSTEM_VARS_KEY - }; - for (std::string const& i : boolValues) { - if (!request.Data[i].isNull() && !request.Data[i].isBool()) { - return request.ReportError("\"" + i + - "\" must be unset or a bool value."); - } - } - - cmake* cm = this->CMakeInstance(); - - setBool(request, kDEBUG_OUTPUT_KEY, - [cm](bool e) { cm->SetDebugOutputOn(e); }); - setBool(request, kTRACE_KEY, [cm](bool e) { cm->SetTrace(e); }); - setBool(request, kTRACE_EXPAND_KEY, [cm](bool e) { cm->SetTraceExpand(e); }); - setBool(request, kWARN_UNINITIALIZED_KEY, - [cm](bool e) { cm->SetWarnUninitialized(e); }); - setBool(request, kWARN_UNUSED_KEY, [this](bool e) { m_WarnUnused = e; }); - setBool(request, kWARN_UNUSED_CLI_KEY, - [cm](bool e) { cm->SetWarnUnusedCli(e); }); - setBool(request, kCHECK_SYSTEM_VARS_KEY, - [cm](bool e) { cm->SetCheckSystemVars(e); }); - - return request.Reply(Json::Value()); -} - -cmServerResponse cmServerProtocol1::ProcessFileSystemWatchers( - const cmServerRequest& request) -{ - const cmFileMonitor* const fm = FileMonitor(); - Json::Value result = Json::objectValue; - Json::Value files = Json::arrayValue; - for (auto const& f : fm->WatchedFiles()) { - files.append(f); - } - Json::Value directories = Json::arrayValue; - for (auto const& d : fm->WatchedDirectories()) { - directories.append(d); - } - result[kWATCHED_FILES_KEY] = files; - result[kWATCHED_DIRECTORIES_KEY] = directories; - - return request.Reply(result); -} - -cmServerResponse cmServerProtocol1::ProcessCTests( - const cmServerRequest& request) -{ - if (this->m_State < STATE_COMPUTED) { - return request.ReportError("This instance was not yet computed."); - } - - return request.Reply(cmDumpCTestInfo(this->CMakeInstance())); -} - -cmServerProtocol1::GeneratorInformation::GeneratorInformation( - std::string generatorName, std::string extraGeneratorName, - std::string toolset, std::string platform, std::string sourceDirectory, - std::string buildDirectory) - : GeneratorName(std::move(generatorName)) - , ExtraGeneratorName(std::move(extraGeneratorName)) - , Toolset(std::move(toolset)) - , Platform(std::move(platform)) - , SourceDirectory(std::move(sourceDirectory)) - , BuildDirectory(std::move(buildDirectory)) -{ -} - -void cmServerProtocol1::GeneratorInformation::SetupGenerator( - cmake* cm, std::string* errorMessage) -{ - const std::string fullGeneratorName = - cmExternalMakefileProjectGenerator::CreateFullGeneratorName( - GeneratorName, ExtraGeneratorName); - - cm->SetHomeDirectory(SourceDirectory); - cm->SetHomeOutputDirectory(BuildDirectory); - - auto gg = cm->CreateGlobalGenerator(fullGeneratorName); - if (!gg) { - setErrorMessage( - errorMessage, - std::string("Could not set up the requested combination of \"") + - kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\""); - return; - } - - cm->SetGlobalGenerator(std::move(gg)); - - cm->SetGeneratorToolset(Toolset); - cm->SetGeneratorPlatform(Platform); -} diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h deleted file mode 100644 index 6009e23..0000000 --- a/Source/cmServerProtocol.h +++ /dev/null @@ -1,162 +0,0 @@ -/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying - file Copyright.txt or https://cmake.org/licensing for details. */ -#pragma once - -#include "cmConfigure.h" // IWYU pragma: keep - -#include -#include -#include - -#include - -#include "cmake.h" - -class cmConnection; -class cmFileMonitor; -class cmServer; -class cmServerRequest; - -class cmServerResponse -{ -public: - explicit cmServerResponse(const cmServerRequest& request); - - void SetData(const Json::Value& data); - void SetError(const std::string& message); - - bool IsComplete() const; - bool IsError() const; - std::string ErrorMessage() const; - Json::Value Data() const; - - const std::string Type; - const std::string Cookie; - -private: - enum PayLoad - { - PAYLOAD_UNKNOWN, - PAYLOAD_ERROR, - PAYLOAD_DATA - }; - PayLoad m_Payload = PAYLOAD_UNKNOWN; - std::string m_ErrorMessage; - Json::Value m_Data; -}; - -class cmServerRequest -{ -public: - cmServerResponse Reply(const Json::Value& data) const; - cmServerResponse ReportError(const std::string& message) const; - - const std::string Type; - const std::string Cookie; - const Json::Value Data; - cmConnection* Connection; - -private: - cmServerRequest(cmServer* server, cmConnection* connection, std::string t, - std::string c, Json::Value d); - - void ReportProgress(int min, int current, int max, - const std::string& message) const; - void ReportMessage(const std::string& message, - const std::string& title) const; - - cmServer* m_Server; - - friend class cmServer; -}; - -class cmServerProtocol -{ -public: - cmServerProtocol() = default; - virtual ~cmServerProtocol() = default; - - cmServerProtocol(cmServerProtocol const&) = delete; - cmServerProtocol& operator=(cmServerProtocol const&) = delete; - - virtual std::pair ProtocolVersion() const = 0; - virtual bool IsExperimental() const = 0; - virtual cmServerResponse Process(const cmServerRequest& request) = 0; - - bool Activate(cmServer* server, const cmServerRequest& request, - std::string* errorMessage); - - cmFileMonitor* FileMonitor() const; - void SendSignal(const std::string& name, const Json::Value& data) const; - -protected: - cmake* CMakeInstance() const; - // Implement protocol specific activation tasks here. Called from Activate(). - virtual bool DoActivate(const cmServerRequest& request, - std::string* errorMessage); - bool m_WarnUnused = false; // storage for legacy option - -private: - std::unique_ptr m_CMakeInstance; - cmServer* m_Server = nullptr; // not owned! - - friend class cmServer; -}; - -class cmServerProtocol1 : public cmServerProtocol -{ -public: - std::pair ProtocolVersion() const override; - bool IsExperimental() const override; - cmServerResponse Process(const cmServerRequest& request) override; - -private: - bool DoActivate(const cmServerRequest& request, - std::string* errorMessage) override; - - void HandleCMakeFileChanges(const std::string& path, int event, int status); - - // Handle requests: - cmServerResponse ProcessCache(const cmServerRequest& request); - cmServerResponse ProcessCMakeInputs(const cmServerRequest& request); - cmServerResponse ProcessCodeModel(const cmServerRequest& request); - cmServerResponse ProcessCompute(const cmServerRequest& request); - cmServerResponse ProcessConfigure(const cmServerRequest& request); - cmServerResponse ProcessGlobalSettings(const cmServerRequest& request); - cmServerResponse ProcessSetGlobalSettings(const cmServerRequest& request); - cmServerResponse ProcessFileSystemWatchers(const cmServerRequest& request); - cmServerResponse ProcessCTests(const cmServerRequest& request); - - enum State - { - STATE_INACTIVE, - STATE_ACTIVE, - STATE_CONFIGURED, - STATE_COMPUTED - }; - State m_State = STATE_INACTIVE; - - bool m_isDirty = false; - - struct GeneratorInformation - { - public: - GeneratorInformation() = default; - GeneratorInformation(std::string generatorName, - std::string extraGeneratorName, std::string toolset, - std::string platform, std::string sourceDirectory, - std::string buildDirectory); - - void SetupGenerator(cmake* cm, std::string* errorMessage); - - std::string GeneratorName; - std::string ExtraGeneratorName; - std::string Toolset; - std::string Platform; - - std::string SourceDirectory; - std::string BuildDirectory; - }; - - GeneratorInformation GeneratorInfo; -}; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 2a14b03..720a567 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -263,7 +263,7 @@ Json::Value cmake::ReportCapabilitiesJson() const } obj["generators"] = generators; obj["fileApi"] = cmFileAPI::ReportCapabilities(); - obj["serverMode"] = true; + obj["serverMode"] = false; return obj; } diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 0bdc6fa..61ff470 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -28,8 +28,6 @@ #if !defined(CMAKE_BOOTSTRAP) # include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback. # include "cmFileTime.h" -# include "cmServer.h" -# include "cmServerConnection.h" # include "bindexplib.h" #endif @@ -59,8 +57,6 @@ #include "cmsys/Process.h" #include "cmsys/Terminal.h" -class cmConnection; - int cmcmd_cmake_ninja_depends(std::vector::const_iterator argBeg, std::vector::const_iterator argEnd); int cmcmd_cmake_ninja_dyndep(std::vector::const_iterator argBeg, @@ -119,7 +115,6 @@ void CMakeCommandUsage(const char* program) "(on one volume)\n" << " rm [-rRf] ... - remove files or directories, use -f to " "force it, r or R to remove directories and their contents recursively\n" - << " server - start cmake in server mode\n" << " sleep ... - sleep for given number of seconds\n" << " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n" << " - create or extract a tar or zip archive\n" @@ -1351,47 +1346,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args) } if (args[1] == "server") { - const std::string pipePrefix = "--pipe="; - bool supportExperimental = false; - bool isDebug = false; - std::string pipe; - - for (auto const& arg : cmMakeRange(args).advance(2)) { - if (arg == "--experimental") { - supportExperimental = true; - } else if (arg == "--debug") { - pipe.clear(); - isDebug = true; - } else if (cmHasPrefix(arg, pipePrefix)) { - isDebug = false; - pipe = arg.substr(pipePrefix.size()); - if (pipe.empty()) { - cmSystemTools::Error("No pipe given after --pipe="); - return 2; - } - } else { - cmSystemTools::Error("Unknown argument for server mode"); - return 1; - } - } -#if !defined(CMAKE_BOOTSTRAP) - cmConnection* conn; - if (isDebug) { - conn = new cmServerStdIoConnection; - } else { - conn = new cmServerPipeConnection(pipe); - } - cmServer server(conn, supportExperimental); - std::string errorMessage; - if (server.Serve(&errorMessage)) { - return 0; - } - cmSystemTools::Error(errorMessage); -#else - static_cast(supportExperimental); - static_cast(isDebug); - cmSystemTools::Error("CMake was not built with server mode enabled"); -#endif + cmSystemTools::Error( + "CMake server mode has been removed in favor of the file-api."); return 1; } diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index f4be4b6..328ab7f 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -240,8 +240,6 @@ if(BUILD_TESTING) if(NOT CMake_TEST_EXTERNAL_CMAKE) add_subdirectory(CMakeLib) - - add_subdirectory(CMakeServerLib) endif() add_subdirectory(CMakeOnly) add_subdirectory(RunCMake) @@ -2911,13 +2909,6 @@ if(BUILD_TESTING) ADD_TEST_MACRO(CMakeCommands.link_directories) ADD_TEST_MACRO(CMakeCommands.target_link_directories) - # The cmake server-mode test requires python for a simple client. - find_package(PythonInterp QUIET) - if(PYTHON_EXECUTABLE) - set(Server_BUILD_OPTIONS -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}) - ADD_TEST_MACRO(Server Server) - endif() - configure_file( "${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in" "${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake" diff --git a/Tests/CMakeServerLib/CMakeLists.txt b/Tests/CMakeServerLib/CMakeLists.txt deleted file mode 100644 index 2c23c2d..0000000 --- a/Tests/CMakeServerLib/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMake_BINARY_DIR}/Source - ${CMake_SOURCE_DIR}/Source - ) - -set(CMakeServerLib_TESTS - testServerBuffering.cpp - ) - -create_test_sourcelist(CMakeLib_TEST_SRCS CMakeServerLibTests.cxx ${CMakeServerLib_TESTS}) -add_executable(CMakeServerLibTests ${CMakeLib_TEST_SRCS}) -target_link_libraries(CMakeServerLibTests CMakeLib CMakeServerLib) - -SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY C_CLANG_TIDY "") -SET_PROPERTY(TARGET CMakeServerLibTests PROPERTY CXX_CLANG_TIDY "") - -foreach(testfile ${CMakeServerLib_TESTS}) - get_filename_component(test "${testfile}" NAME_WE) - add_test(CMakeServerLib.${test} CMakeServerLibTests ${test} ${${test}_ARGS}) -endforeach() diff --git a/Tests/CMakeServerLib/testServerBuffering.cpp b/Tests/CMakeServerLib/testServerBuffering.cpp deleted file mode 100644 index 6f22940..0000000 --- a/Tests/CMakeServerLib/testServerBuffering.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include -#include - -#include "cmConnection.h" -#include "cmServerConnection.h" - -void print_error(const std::vector& input, - const std::vector& output) -{ - std::cerr << "Responses don't equal input messages input." << std::endl; - std::cerr << "Responses: " << std::endl; - - for (auto& msg : output) { - std::cerr << "'" << msg << "'" << std::endl; - } - - std::cerr << "Input messages" << std::endl; - for (auto& msg : input) { - std::cerr << "'" << msg << "'" << std::endl; - } -} - -std::string trim_newline(const std::string& _buffer) -{ - auto buffer = _buffer; - while (!buffer.empty() && (buffer.back() == '\n' || buffer.back() == '\r')) { - buffer.pop_back(); - } - return buffer; -} - -int testServerBuffering(int, char** const) -{ - std::vector messages = { - "{ \"test\": 10}", "{ \"test\": { \"test2\": false} }", - "{ \"test\": [1, 2, 3] }", - "{ \"a\": { \"1\": {}, \n\n\n \"2\":[] \t\t\t\t}}" - }; - - std::string fullMessage; - for (auto& msg : messages) { - fullMessage += "[== \"CMake Server\" ==[\n"; - fullMessage += msg; - fullMessage += "\n]== \"CMake Server\" ==]\n"; - } - - // The buffering strategy should cope with any fragmentation, including - // just getting the characters one at a time. - auto bufferingStrategy = - std::unique_ptr(new cmServerBufferStrategy); - std::vector response; - std::string rawBuffer; - for (auto& messageChar : fullMessage) { - rawBuffer += messageChar; - std::string packet = bufferingStrategy->BufferMessage(rawBuffer); - do { - if (!packet.empty() && packet != "\r\n") { - response.push_back(trim_newline(packet)); - } - packet = bufferingStrategy->BufferMessage(rawBuffer); - } while (!packet.empty()); - } - - if (response != messages) { - print_error(messages, response); - return 1; - } - - // We should also be able to deal with getting a bunch at once - response.clear(); - std::string packet = bufferingStrategy->BufferMessage(fullMessage); - do { - if (!packet.empty() && packet != "\r\n") { - response.push_back(trim_newline(packet)); - } - packet = bufferingStrategy->BufferMessage(fullMessage); - } while (!packet.empty()); - - if (response != messages) { - print_error(messages, response); - return 1; - } - - return 0; -} diff --git a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt index e24e131..a8b6584 100644 --- a/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt +++ b/Tests/RunCMake/CommandLine/E_capabilities-stdout.txt @@ -1 +1 @@ -^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":true,"version":{.*}}$ +^{"fileApi":{"requests":\[{"kind":"codemodel","version":\[{"major":2,"minor":2}]},{"kind":"cache","version":\[{"major":2,"minor":0}]},{"kind":"cmakeFiles","version":\[{"major":1,"minor":0}]}]},"generators":\[.*\],"serverMode":false,"version":{.*}}$ diff --git a/Tests/RunCMake/CommandLine/E_server-arg-result.txt b/Tests/RunCMake/CommandLine/E_server-arg-result.txt deleted file mode 100644 index d00491f..0000000 --- a/Tests/RunCMake/CommandLine/E_server-arg-result.txt +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/Tests/RunCMake/CommandLine/E_server-arg-stderr.txt b/Tests/RunCMake/CommandLine/E_server-arg-stderr.txt deleted file mode 100644 index 4dcbab9..0000000 --- a/Tests/RunCMake/CommandLine/E_server-arg-stderr.txt +++ /dev/null @@ -1 +0,0 @@ -^CMake Error: Unknown argument for server mode$ diff --git a/Tests/RunCMake/CommandLine/E_server-pipe-result.txt b/Tests/RunCMake/CommandLine/E_server-pipe-result.txt deleted file mode 100644 index 0cfbf08..0000000 --- a/Tests/RunCMake/CommandLine/E_server-pipe-result.txt +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt b/Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt deleted file mode 100644 index 7193ba6..0000000 --- a/Tests/RunCMake/CommandLine/E_server-pipe-stderr.txt +++ /dev/null @@ -1 +0,0 @@ -^CMake Error: No pipe given after --pipe=$ diff --git a/Tests/RunCMake/CommandLine/E_server-result.txt b/Tests/RunCMake/CommandLine/E_server-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_server-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_server-stderr.txt b/Tests/RunCMake/CommandLine/E_server-stderr.txt new file mode 100644 index 0000000..0cd0e56 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_server-stderr.txt @@ -0,0 +1 @@ +^CMake Error: CMake server mode has been removed in favor of the file-api\.$ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 2a5d5d3..49a10c1 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -25,8 +25,7 @@ run_cmake_command(E_compare_files-ignore-eol-nonexistent ${CMAKE_COMMAND} -E com run_cmake_command(E_compare_files-invalid-arguments ${CMAKE_COMMAND} -E compare_files file1.txt file2.txt file3.txt) run_cmake_command(E_echo_append ${CMAKE_COMMAND} -E echo_append) run_cmake_command(E_rename-no-arg ${CMAKE_COMMAND} -E rename) -run_cmake_command(E_server-arg ${CMAKE_COMMAND} -E server --extra-arg) -run_cmake_command(E_server-pipe ${CMAKE_COMMAND} -E server --pipe=) +run_cmake_command(E_server ${CMAKE_COMMAND} -E server) run_cmake_command(E_true ${CMAKE_COMMAND} -E true) run_cmake_command(E_true-extraargs ${CMAKE_COMMAND} -E true ignored) run_cmake_command(E_false ${CMAKE_COMMAND} -E false) diff --git a/Tests/Server/CMakeLists.txt b/Tests/Server/CMakeLists.txt deleted file mode 100644 index 8321edb..0000000 --- a/Tests/Server/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -cmake_minimum_required(VERSION 3.4) -project(Server CXX) - -find_package(Python REQUIRED) - -macro(do_test bsname file type) - execute_process(COMMAND ${Python_EXECUTABLE} - -B # no .pyc files - "${CMAKE_SOURCE_DIR}/${type}-test.py" - "${CMAKE_COMMAND}" - "${CMAKE_SOURCE_DIR}/${file}" - "${CMAKE_SOURCE_DIR}" - "${CMAKE_BINARY_DIR}" - "${CMAKE_GENERATOR}" - RESULT_VARIABLE test_result - ) - - if (NOT test_result EQUAL 0) - message(SEND_ERROR "TEST FAILED: ${test_result}") - endif() -endmacro() - -do_test("test_cache" "tc_cache.json" "server") -do_test("test_handshake" "tc_handshake.json" "server") -do_test("test_globalSettings" "tc_globalSettings.json" "server") -do_test("test_buildsystem1" "tc_buildsystem1.json" "server") - -add_executable(Server empty.cpp) diff --git a/Tests/Server/buildsystem1/CMakeLists.txt b/Tests/Server/buildsystem1/CMakeLists.txt deleted file mode 100644 index d690472..0000000 --- a/Tests/Server/buildsystem1/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -cmake_minimum_required(VERSION 3.4) - -project(buildsystem2) - -set(var1 123) - -set(var2 345) - -add_executable(main main.cpp) - -add_executable(m_other main.cpp) - -add_library(foo foo.cpp) - -function(f1) -endfunction() - -set(var3 345) - -add_library(someImportedLib UNKNOWN IMPORTED) - -add_subdirectory(subdir) diff --git a/Tests/Server/buildsystem1/foo.cpp b/Tests/Server/buildsystem1/foo.cpp deleted file mode 100644 index 7f39d71..0000000 --- a/Tests/Server/buildsystem1/foo.cpp +++ /dev/null @@ -1,5 +0,0 @@ - -int foo() -{ - return 0; -} diff --git a/Tests/Server/buildsystem1/main.cpp b/Tests/Server/buildsystem1/main.cpp deleted file mode 100644 index 766b775..0000000 --- a/Tests/Server/buildsystem1/main.cpp +++ /dev/null @@ -1,5 +0,0 @@ - -int main() -{ - return 0; -} diff --git a/Tests/Server/buildsystem1/subdir/CMakeLists.txt b/Tests/Server/buildsystem1/subdir/CMakeLists.txt deleted file mode 100644 index 9157312..0000000 --- a/Tests/Server/buildsystem1/subdir/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(bar4 something) - -set(bar5 more) - -add_executable(ooo empty.cpp) diff --git a/Tests/Server/buildsystem1/subdir/empty.cpp b/Tests/Server/buildsystem1/subdir/empty.cpp deleted file mode 100644 index 7f39d71..0000000 --- a/Tests/Server/buildsystem1/subdir/empty.cpp +++ /dev/null @@ -1,5 +0,0 @@ - -int foo() -{ - return 0; -} diff --git a/Tests/Server/cmakelib.py b/Tests/Server/cmakelib.py deleted file mode 100644 index 546ae4c..0000000 --- a/Tests/Server/cmakelib.py +++ /dev/null @@ -1,380 +0,0 @@ -from __future__ import print_function -import sys, subprocess, json, os, select, shutil, time, socket - -termwidth = 150 - -print_communication = True - -def ordered(obj): - if isinstance(obj, dict): - return sorted((k, ordered(v)) for k, v in obj.items()) - if isinstance(obj, list): - return sorted(ordered(x) for x in obj) - else: - return obj - -def col_print(title, array): - print() - print() - print(title) - - indentwidth = 4 - indent = " " * indentwidth - - if not array: - print(indent + "") - return - - padwidth = 2 - - maxitemwidth = len(max(array, key=len)) - - numCols = max(1, int((termwidth - indentwidth + padwidth) / (maxitemwidth + padwidth))) - - numRows = len(array) // numCols + 1 - - pad = " " * padwidth - - for index in range(numRows): - print(indent + pad.join(item.ljust(maxitemwidth) for item in array[index::numRows])) - -filterPacket = lambda x: x - -STDIN = 0 -PIPE = 1 - -communicationMethods = [STDIN] - -if hasattr(socket, 'AF_UNIX'): - communicationMethods.append(PIPE) - -def defaultExitWithError(proc): - data = "" - try: - while select.select([proc.outPipe], [], [], 3.)[0]: - data = data + proc.outPipe.read(1) - if len(data): - print("Rest of raw buffer from server:") - printServer(data) - except: - pass - proc.outPipe.close() - proc.inPipe.close() - proc.kill() - sys.exit(1) - -exitWithError = lambda proc: defaultExitWithError(proc) - -serverTag = "SERVER" - -def printServer(*args): - print(serverTag + ">", *args) - print() - sys.stdout.flush() - -def printClient(*args): - print("CLIENT>", *args) - print() - sys.stdout.flush() - -def waitForRawMessage(cmakeCommand): - stdoutdata = "" - payload = "" - while not cmakeCommand.poll(): - stdoutdataLine = cmakeCommand.outPipe.readline() - if stdoutdataLine: - stdoutdata += stdoutdataLine.decode('utf-8') - else: - break - begin = stdoutdata.find('[== "CMake Server" ==[\n') - end = stdoutdata.find(']== "CMake Server" ==]') - - if begin != -1 and end != -1: - begin += len('[== "CMake Server" ==[\n') - payload = stdoutdata[begin:end] - jsonPayload = json.loads(payload) - filteredPayload = filterPacket(jsonPayload) - if print_communication and filteredPayload: - printServer(filteredPayload) - if filteredPayload is not None or jsonPayload is None: - return jsonPayload - stdoutdata = stdoutdata[(end+len(']== "CMake Server" ==]')):] - -# Python2 has no problem writing the output of encodes directly, -# but Python3 returns only 'int's for encode and so must be turned -# into bytes. We use the existence of 'to_bytes' on an int to -# determine which behavior is appropriate. It might be more clear -# to do this in the code which uses the flag, but introducing -# this lookup cost at every byte sent isn't ideal. -has_to_bytes = "to_bytes" in dir(10) - -def writeRawData(cmakeCommand, content): - writeRawData.counter += 1 - payload = """ -[== "CMake Server" ==[ -%s -]== "CMake Server" ==] -""" % content - - rn = ( writeRawData.counter % 2 ) == 0 - - if rn: - payload = payload.replace('\n', '\r\n') - - if print_communication: - printClient(content, "(Use \\r\\n:", rn, ")") - - # To stress test how cmake deals with fragmentation in the - # communication channel, we send only one byte at a time. - # Certain communication methods / platforms might still buffer - # it all into one message since its so close together, but in - # general this will catch places where we assume full buffers - # come in all at once. - encoded_payload = payload.encode('utf-8') - - # Python version 3+ can't write ints directly; but 'to_bytes' - # for int was only added in python 3.2. If this is a 3+ version - # of python without that conversion function; just write the whole - # thing out at once. - if sys.version_info[0] > 2 and not has_to_bytes: - cmakeCommand.write(encoded_payload) - else: - for c in encoded_payload: - if has_to_bytes: - c = c.to_bytes(1, byteorder='big') - cmakeCommand.write(c) - -writeRawData.counter = 0 - -def writePayload(cmakeCommand, obj): - writeRawData(cmakeCommand, json.dumps(obj)) - -def getPipeName(): - return "/tmp/server-test-socket" - -def attachPipe(cmakeCommand, pipeName): - time.sleep(1) - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - sock.connect(pipeName) - global serverTag - serverTag = "SERVER(PIPE)" - cmakeCommand.outPipe = sock.makefile() - cmakeCommand.inPipe = sock - cmakeCommand.write = cmakeCommand.inPipe.sendall - -def writeAndFlush(pipe, val): - pipe.write(val) - pipe.flush() - -def initServerProc(cmakeCommand, comm): - if comm == PIPE: - pipeName = getPipeName() - cmakeCommand = subprocess.Popen([cmakeCommand, "-E", "server", "--experimental", "--pipe=" + pipeName]) - attachPipe(cmakeCommand, pipeName) - else: - cmakeCommand = subprocess.Popen([cmakeCommand, "-E", "server", "--experimental", "--debug"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - cmakeCommand.outPipe = cmakeCommand.stdout - cmakeCommand.inPipe = cmakeCommand.stdin - cmakeCommand.write = lambda val: writeAndFlush(cmakeCommand.inPipe, val) - - packet = waitForRawMessage(cmakeCommand) - if packet == None: - print("Not in server mode") - sys.exit(2) - - if packet['type'] != 'hello': - print("No hello message") - sys.exit(3) - - return cmakeCommand - -def exitProc(cmakeCommand): - # Tell the server to exit. - cmakeCommand.stdin.close() - cmakeCommand.stdout.close() - - # Wait for the server to exit. - # If this version of python supports it, terminate the server after a timeout. - try: - cmakeCommand.wait(timeout=5) - except TypeError: - cmakeCommand.wait() - except: - cmakeCommand.terminate() - raise - -def waitForMessage(cmakeCommand, expected): - data = ordered(expected) - packet = ordered(waitForRawMessage(cmakeCommand)) - - if packet != data: - print ("Received unexpected message; test failed") - exitWithError(cmakeCommand) - return packet - -def waitForReply(cmakeCommand, originalType, cookie, skipProgress): - gotResult = False - while True: - packet = waitForRawMessage(cmakeCommand) - t = packet['type'] - if packet['cookie'] != cookie or packet['inReplyTo'] != originalType: - print("cookie or inReplyTo mismatch") - sys.exit(4) - if t == 'message' or t == 'progress': - if skipProgress: - continue - if t == 'reply': - break - print("Unrecognized message", packet) - sys.exit(5) - - return packet - -def waitForError(cmakeCommand, originalType, cookie, message): - packet = waitForRawMessage(cmakeCommand) - if packet['cookie'] != cookie or packet['type'] != 'error' or packet['inReplyTo'] != originalType or packet['errorMessage'] != message: - sys.exit(6) - -def waitForProgress(cmakeCommand, originalType, cookie, current, message): - packet = waitForRawMessage(cmakeCommand) - if packet['cookie'] != cookie or packet['type'] != 'progress' or packet['inReplyTo'] != originalType or packet['progressCurrent'] != current or packet['progressMessage'] != message: - sys.exit(7) - -def handshake(cmakeCommand, major, minor, source, build, generator, extraGenerator): - version = { 'major': major } - if minor >= 0: - version['minor'] = minor - - writePayload(cmakeCommand, { 'type': 'handshake', 'protocolVersion': version, - 'cookie': 'TEST_HANDSHAKE', 'sourceDirectory': source, 'buildDirectory': build, - 'generator': generator, 'extraGenerator': extraGenerator }) - waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE', False) - -def validateGlobalSettings(cmakeCommand, cmakeCommandPath, data): - packet = waitForReply(cmakeCommand, 'globalSettings', '', False) - - capabilities = packet['capabilities'] - - # validate version: - cmakeoutput = subprocess.check_output([ cmakeCommandPath, "--version" ], universal_newlines=True) - cmakeVersion = cmakeoutput.splitlines()[0][14:] - - version = capabilities['version'] - versionString = version['string'] - vs = str(version['major']) + '.' + str(version['minor']) + '.' + str(version['patch']) - if (versionString != vs and not versionString.startswith(vs + '-')): - sys.exit(8) - if (versionString != cmakeVersion): - sys.exit(9) - - # validate generators: - generatorObjects = capabilities['generators'] - - cmakeoutput = subprocess.check_output([ cmakeCommandPath, "--help" ], universal_newlines=True) - index = cmakeoutput.index('\nGenerators\n\n') - cmakeGenerators = [] - for line in cmakeoutput[index + 12:].splitlines(): - if not line: - continue - if line[0] == '*': # default generator marker - line = ' ' + line[1:] - if not line.startswith(' '): - continue - if line.startswith(' '): - continue - equalPos = line.find('=') - tmp = '' - if (equalPos > 0): - tmp = line[2:equalPos].strip() - else: - tmp = line.strip() - if tmp.endswith(" [arch]"): - tmp = tmp[0:len(tmp) - 7] - if (len(tmp) > 0) and (" - " not in tmp): - cmakeGenerators.append(tmp) - - generators = [] - for genObj in generatorObjects: - generators.append(genObj['name']) - - generators.sort() - cmakeGenerators.sort() - - for gen in cmakeGenerators: - if (not gen in generators): - sys.exit(10) - - gen = packet['generator'] - if (gen != '' and not (gen in generators)): - sys.exit(11) - - for i in data: - print("Validating", i) - if (packet[i] != data[i]): - sys.exit(12) - -def validateCache(cmakeCommand, data): - packet = waitForReply(cmakeCommand, 'cache', '', False) - - cache = packet['cache'] - - if (data['isEmpty']): - if (cache != []): - print('Expected empty cache, but got data.\n') - sys.exit(1) - return; - - if (cache == []): - print('Expected cache contents, but got none.\n') - sys.exit(1) - - hadHomeDir = False - for value in cache: - if (value['key'] == 'CMAKE_HOME_DIRECTORY'): - hadHomeDir = True - - if (not hadHomeDir): - print('No CMAKE_HOME_DIRECTORY found in cache.') - sys.exit(1) - -def handleBasicMessage(proc, obj, debug): - if 'sendRaw' in obj: - data = obj['sendRaw'] - if debug: print("Sending raw:", data) - writeRawData(proc, data) - return True - elif 'send' in obj: - data = obj['send'] - if debug: print("Sending:", json.dumps(data)) - writePayload(proc, data) - return True - elif 'recv' in obj: - data = obj['recv'] - if debug: print("Waiting for:", json.dumps(data)) - waitForMessage(proc, data) - return True - elif 'message' in obj: - print("MESSAGE:", obj["message"]) - sys.stdout.flush() - return True - return False - -def shutdownProc(proc): - # Tell the server to exit. - proc.inPipe.close() - proc.outPipe.close() - - # Wait for the server to exit. - # If this version of python supports it, terminate the server after a timeout. - try: - proc.wait(timeout=5) - except TypeError: - proc.wait() - except: - proc.terminate() - raise - - print('cmake-server exited: %d' % proc.returncode) - sys.exit(proc.returncode) diff --git a/Tests/Server/empty.cpp b/Tests/Server/empty.cpp deleted file mode 100644 index 766b775..0000000 --- a/Tests/Server/empty.cpp +++ /dev/null @@ -1,5 +0,0 @@ - -int main() -{ - return 0; -} diff --git a/Tests/Server/server-test.py b/Tests/Server/server-test.py deleted file mode 100644 index 701c6e9..0000000 --- a/Tests/Server/server-test.py +++ /dev/null @@ -1,105 +0,0 @@ -from __future__ import print_function -import sys, cmakelib, json, os, shutil - -debug = True - -cmakeCommand = sys.argv[1] -testFile = sys.argv[2] -sourceDir = sys.argv[3] -buildDir = sys.argv[4] + "/" + os.path.splitext(os.path.basename(testFile))[0] -cmakeGenerator = sys.argv[5] - -print("Server Test:", testFile, - "\n-- SourceDir:", sourceDir, - "\n-- BuildDir:", buildDir, - "\n-- Generator:", cmakeGenerator) - -if os.path.exists(buildDir): - shutil.rmtree(buildDir) - -cmakelib.filterBase = sourceDir - -with open(testFile) as f: - testData = json.loads(f.read()) - -for communicationMethod in cmakelib.communicationMethods: - proc = cmakelib.initServerProc(cmakeCommand, communicationMethod) - if proc is None: - continue - - for obj in testData: - if cmakelib.handleBasicMessage(proc, obj, debug): - pass - elif 'reply' in obj: - data = obj['reply'] - if debug: print("Waiting for reply:", json.dumps(data)) - originalType = "" - cookie = "" - skipProgress = False; - if 'cookie' in data: cookie = data['cookie'] - if 'type' in data: originalType = data['type'] - if 'skipProgress' in data: skipProgress = data['skipProgress'] - cmakelib.waitForReply(proc, originalType, cookie, skipProgress) - elif 'error' in obj: - data = obj['error'] - if debug: print("Waiting for error:", json.dumps(data)) - originalType = "" - cookie = "" - message = "" - if 'cookie' in data: cookie = data['cookie'] - if 'type' in data: originalType = data['type'] - if 'message' in data: message = data['message'] - cmakelib.waitForError(proc, originalType, cookie, message) - elif 'progress' in obj: - data = obj['progress'] - if debug: print("Waiting for progress:", json.dumps(data)) - originalType = '' - cookie = "" - current = 0 - message = "" - if 'cookie' in data: cookie = data['cookie'] - if 'type' in data: originalType = data['type'] - if 'current' in data: current = data['current'] - if 'message' in data: message = data['message'] - cmakelib.waitForProgress(proc, originalType, cookie, current, message) - elif 'handshake' in obj: - data = obj['handshake'] - if debug: print("Doing handshake:", json.dumps(data)) - major = -1 - minor = -1 - generator = cmakeGenerator - extraGenerator = '' - sourceDirectory = sourceDir - buildDirectory = buildDir - if 'major' in data: major = data['major'] - if 'minor' in data: minor = data['minor'] - if 'buildDirectory' in data: buildDirectory = data['buildDirectory'] - if 'sourceDirectory' in data: sourceDirectory = data['sourceDirectory'] - if 'generator' in data: generator = data['generator'] - if 'extraGenerator' in data: extraGenerator = data['extraGenerator'] - - if not os.path.isabs(buildDirectory): - buildDirectory = buildDir + "/" + buildDirectory - if sourceDirectory != '' and not os.path.isabs(sourceDirectory): - sourceDirectory = sourceDir + "/" + sourceDirectory - cmakelib.handshake(proc, major, minor, sourceDirectory, buildDirectory, - generator, extraGenerator) - elif 'validateGlobalSettings' in obj: - data = obj['validateGlobalSettings'] - if not 'buildDirectory' in data: data['buildDirectory'] = buildDir - if not 'sourceDirectory' in data: data['sourceDirectory'] = sourceDir - if not 'generator' in data: data['generator'] = cmakeGenerator - if not 'extraGenerator' in data: data['extraGenerator'] = '' - cmakelib.validateGlobalSettings(proc, cmakeCommand, data) - elif 'validateCache' in obj: - data = obj['validateCache'] - if not 'isEmpty' in data: data['isEmpty'] = false - cmakelib.validateCache(proc, data) - elif 'reconnect' in obj: - cmakelib.exitProc(proc) - proc = cmakelib.initServerProc(cmakeCommand, communicationMethod) - else: - print("Unknown command:", json.dumps(obj)) - sys.exit(2) - cmakelib.shutdownProc(proc) - print("Completed") diff --git a/Tests/Server/tc_buildsystem1.json b/Tests/Server/tc_buildsystem1.json deleted file mode 100644 index 08831b7..0000000 --- a/Tests/Server/tc_buildsystem1.json +++ /dev/null @@ -1,27 +0,0 @@ -[ -{ "message": "Testing globalSettings" }, - -{ "handshake": {"major": 1, "sourceDirectory":"buildsystem1","buildDirectory":"buildsystem1"} }, - -{ "message": "Configure:" }, -{ "send": { "type": "configure", "cookie":"CONFIG" } }, -{ "reply": { "type": "configure", "cookie":"CONFIG", "skipProgress":true } }, - -{ "message": "Compute:" }, -{ "send": { "type": "compute", "cookie":"COMPUTE" } }, -{ "reply": { "type": "compute", "cookie":"COMPUTE", "skipProgress":true } }, - -{ "message": "Codemodel:" }, -{ "send": { "type": "codemodel", "cookie":"CODEMODEL" } }, -{ "reply": { "type": "codemodel", "cookie":"CODEMODEL" } }, - -{ "message": "CMake Inputs:"}, -{ "send": { "type": "cmakeInputs", "cookie":"INPUTS" } }, -{ "reply": { "type": "cmakeInputs", "cookie":"INPUTS" } }, - -{ "message": "Cache:"}, -{ "send": { "type": "cache", "cookie":"CACHE" } }, -{ "reply": { "type": "cache", "cookie":"CACHE" } }, - -{ "message": "Everything ok." } -] diff --git a/Tests/Server/tc_cache.json b/Tests/Server/tc_cache.json deleted file mode 100644 index 74af6d9..0000000 --- a/Tests/Server/tc_cache.json +++ /dev/null @@ -1,24 +0,0 @@ -[ -{ "message": "Testing cache" }, - -{ "message": "Cache after first handshake is empty:" }, -{ "handshake": {"major": 1, "sourceDirectory": "buildsystem1", "buildDirectory": "buildsystem1"} }, -{ "send": { "type": "cache" } }, -{ "validateCache": { "isEmpty": true } }, - -{ "message": "Cache after configure is populated:" }, -{ "send": { "type": "configure" } }, -{ "reply": { "type": "configure", "skipProgress":true } }, -{ "send": { "type": "cache" } }, -{ "validateCache": { "isEmpty": false } }, - -{ "message": "Handshake for existing cache requires buildDirectory only:" }, -{ "reconnect": {} }, -{ "handshake": {"major": 1, "sourceDirectory": "", "buildDirectory": "buildsystem1"} }, - -{ "message": "Cache after reconnect is again populated:" }, -{ "send": { "type": "cache" } }, -{ "validateCache": { "isEmpty": false } }, - -{ "message": "Everything ok." } -] diff --git a/Tests/Server/tc_globalSettings.json b/Tests/Server/tc_globalSettings.json deleted file mode 100644 index d72fb41..0000000 --- a/Tests/Server/tc_globalSettings.json +++ /dev/null @@ -1,140 +0,0 @@ -[ -{ "message": "Testing globalSettings" }, - -{ "handshake": {"major": 1} }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - - - -{ "message": "Change settings:" }, - -{ "send": { "type": "setGlobalSettings", "warnUnused": true } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "warnUnused": false } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "debugOutput": true } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": true, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "debugOutput": false } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "warnUninitialized": true } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": true, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "warnUninitialized": false } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "traceExpand": true } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": true, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "traceExpand": false } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - - - -{ "send": { "type": "setGlobalSettings", "trace": true } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": true, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "trace": false } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "warnUnusedCli": false } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": false, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "warnUnusedCli": true } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "checkSystemVars": true } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": true } }, - -{ "send": { "type": "setGlobalSettings", "checkSystemVars": false } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": false, "debugOutput": false, "warnUninitialized": false, "traceExpand": false, "trace": false, "warnUnusedCli": true, "checkSystemVars": false } }, - -{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } }, - -{ "message": "Ignore unknown/readonly" }, - -{ "send": { "type": "setGlobalSettings", "unknownKey": "unknownValue", "extraGenerator": "XXX", "generator": "YYY", "sourceDirectory": "/tmp/source", "buildDirectory": "/tmp/build" } }, -{ "reply": { "type": "setGlobalSettings" } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } }, - -{ "message": "Error paths:" }, - -{ "send": { "type": "setGlobalSettings", "debugOutput": true, "warnUnused": 1 } }, -{ "error": { "type": "setGlobalSettings", "message": "\"warnUnused\" must be unset or a bool value." } }, - -{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": 1 } }, -{ "error": { "type": "setGlobalSettings", "message": "\"debugOutput\" must be unset or a bool value." } }, - -{ "send": { "type": "setGlobalSettings", "warnUninitialized": 1, "warnUnused": true, "debugOutput": true } }, -{ "error": { "type": "setGlobalSettings", "message": "\"warnUninitialized\" must be unset or a bool value." } }, - -{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "traceExpand": 1 } }, -{ "error": { "type": "setGlobalSettings", "message": "\"traceExpand\" must be unset or a bool value." } }, - -{ "send": { "type": "setGlobalSettings", "debugOutput": true, "trace": 1, "warnUnused": true } }, -{ "error": { "type": "setGlobalSettings", "message": "\"trace\" must be unset or a bool value." } }, - -{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "warnUnusedCli": 1.0 } }, -{ "error": { "type": "setGlobalSettings", "message": "\"warnUnusedCli\" must be unset or a bool value." } }, - -{ "send": { "type": "setGlobalSettings", "warnUnused": true, "debugOutput": true, "checkSystemVars": "some string" } }, -{ "error": { "type": "setGlobalSettings", "message": "\"checkSystemVars\" must be unset or a bool value." } }, - -{ "send": { "type": "globalSettings"} }, -{ "validateGlobalSettings": { "warnUnused": true, "debugOutput": true, "warnUninitialized": true, "traceExpand": true, "trace": true, "warnUnusedCli": false, "checkSystemVars": true } }, - -{ "message": "Everything ok." } -] diff --git a/Tests/Server/tc_handshake.json b/Tests/Server/tc_handshake.json deleted file mode 100644 index 4bb7fa7..0000000 --- a/Tests/Server/tc_handshake.json +++ /dev/null @@ -1,75 +0,0 @@ -[ -{ "message": "Testing basic message handling:" }, - -{ "sendRaw": "Sometext"}, -{ "recv": {"cookie":"","errorMessage":"Failed to parse JSON input.","inReplyTo":"","type":"error"} }, - -{ "message": "Testing invalid json input"}, -{ "send": { "test": "sometext" } }, -{ "recv": {"cookie":"","errorMessage":"No type given in request.","inReplyTo":"","type":"error"} }, - -{ "send": {"test": "sometext","cookie":"monster"} }, -{ "recv": {"cookie":"monster","errorMessage":"No type given in request.","inReplyTo":"","type":"error"} }, - -{ "message": "Testing commands before handshake" }, -{ "send": {"type": "cache","cookie":"monster"} }, -{ "recv": {"cookie":"monster","errorMessage":"Waiting for type \"handshake\".","inReplyTo":"cache","type":"error"} }, - -{ "message": "Testing handshake" }, -{ "send": {"type": "sometype","cookie":"monster2"} }, -{ "recv": {"cookie":"monster2","errorMessage":"Waiting for type \"handshake\".","inReplyTo":"sometype","type":"error"} }, - -{ "send": {"type": "handshake"} }, -{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" is required for \"handshake\".","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","foo":"bar"} }, -{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" is required for \"handshake\".","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","protocolVersion":"bar"} }, -{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" must be a JSON object.","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","protocolVersion":{}} }, -{ "recv": {"cookie":"","errorMessage":"\"major\" must be set and an integer.","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","protocolVersion":{"major":"foo"}} }, -{ "recv": {"cookie":"","errorMessage":"\"major\" must be set and an integer.","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","protocolVersion":{"major":1, "minor":"foo"}} }, -{ "recv": {"cookie":"","errorMessage":"\"minor\" must be unset or an integer.","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","protocolVersion":{"major":-1, "minor":-1}} }, -{ "recv": {"cookie":"","errorMessage":"\"major\" must be >= 0.","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","protocolVersion":{"major":10, "minor":-1}} }, -{ "recv": {"cookie":"","errorMessage":"\"minor\" must be >= 0 when set.","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","protocolVersion":{"major":10000}} }, -{ "recv": {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"type": "handshake","protocolVersion":{"major":1, "minor":10000}} }, -{ "recv": {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"} }, - -{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1}} }, -{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"buildDirectory\" is missing."} }, - -{ "message": "Testing protocol version specific options (1.0):" }, -{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":"/tmp/src"} }, -{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"buildDirectory\" is missing."} }, - -{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":"/tmp/src","buildDirectory":"/tmp/build"} }, -{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"sourceDirectory\" is not a directory."} }, - -{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","extraGenerator":"CodeBlocks"} }, -{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"generator\" is unset but required."} }, - -{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"XXXX","extraGenerator":"CodeBlocks"} }, -{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: Generator \"XXXX\" not supported."} }, - -{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"Ninja","extraGenerator":"XXXX"} }, -{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: The combination of generator \"Ninja\" and extra generator \"XXXX\" is not supported."} }, - -{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"Ninja","extraGenerator":"CodeBlocks"} }, -{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"} }, - -{ "message": "Everything ok." } -] -- cgit v0.12 From 64449c9f949948aa956ea03682530df9317f37ef Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Thu, 15 Oct 2020 00:01:13 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 46f6226..e049bae 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 19) -set(CMake_VERSION_PATCH 20201014) +set(CMake_VERSION_PATCH 20201015) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From eee8fc40c9e2bd7c3b58fcb020356c42cb79eb81 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Fri, 16 Oct 2020 00:01:14 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index e049bae..e31bf44 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 19) -set(CMake_VERSION_PATCH 20201015) +set(CMake_VERSION_PATCH 20201016) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From bddc54a37d6d04cc574f9edfc49f941e69dd5379 Mon Sep 17 00:00:00 2001 From: Samir Benmendil Date: Fri, 16 Oct 2020 12:21:46 +0100 Subject: CheckLanguage: Pass CMAKE_TOOLCHAIN_FILE to test project Fixes: #20545 --- Modules/CheckLanguage.cmake | 6 ++++++ Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt | 1 + Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake | 4 ++++ Tests/RunCMake/ToolchainFile/CheckLanguage.cmake | 2 ++ Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake | 1 + 5 files changed, 14 insertions(+) create mode 100644 Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt create mode 100644 Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake create mode 100644 Tests/RunCMake/ToolchainFile/CheckLanguage.cmake diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake index 44387d4..928881c 100644 --- a/Modules/CheckLanguage.cmake +++ b/Modules/CheckLanguage.cmake @@ -68,6 +68,11 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" else() set(_D_CMAKE_MAKE_PROGRAM "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}") endif() + if(CMAKE_TOOLCHAIN_FILE) + set(_D_CMAKE_TOOLCHAIN_FILE "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}") + else() + set(_D_CMAKE_TOOLCHAIN_FILE "") + endif() execute_process( WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang} COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR} @@ -75,6 +80,7 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" -T "${CMAKE_GENERATOR_TOOLSET}" ${_D_CMAKE_GENERATOR_INSTANCE} ${_D_CMAKE_MAKE_PROGRAM} + ${_D_CMAKE_TOOLCHAIN_FILE} OUTPUT_VARIABLE _cl_output ERROR_VARIABLE _cl_output RESULT_VARIABLE _cl_result diff --git a/Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt b/Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt new file mode 100644 index 0000000..b96eee6 --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/CheckLanguage-stdout.txt @@ -0,0 +1 @@ +-- Looking for a C compiler - NOTFOUND diff --git a/Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake b/Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake new file mode 100644 index 0000000..081f905 --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/CheckLanguage-toolchain.cmake @@ -0,0 +1,4 @@ +get_property(in_try_compile GLOBAL PROPERTY IN_TRY_COMPILE) +if(in_try_compile) + message(FATAL_ERROR "Toolchain file included") +endif() diff --git a/Tests/RunCMake/ToolchainFile/CheckLanguage.cmake b/Tests/RunCMake/ToolchainFile/CheckLanguage.cmake new file mode 100644 index 0000000..854b3d4 --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/CheckLanguage.cmake @@ -0,0 +1,2 @@ +include(CheckLanguage) +check_language(C) diff --git a/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake b/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake index 7eb4485..659523c 100644 --- a/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake +++ b/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake @@ -7,6 +7,7 @@ endfunction() run_cmake_toolchain(CallEnableLanguage) run_cmake_toolchain(CallProject) +run_cmake_toolchain(CheckLanguage) run_cmake_toolchain(FlagsInit) run_cmake_toolchain(LinkFlagsInit) -- cgit v0.12 From 7c916e0929a1ae038a70f17f714508ee73c31f80 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Sat, 17 Oct 2020 00:01:13 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index e31bf44..a04215b 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 19) -set(CMake_VERSION_PATCH 20201016) +set(CMake_VERSION_PATCH 20201017) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 52be712ad83ecd66d9f975309bd223724bd227ac Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Sun, 18 Oct 2020 00:01:13 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index a04215b..154acf7 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 19) -set(CMake_VERSION_PATCH 20201017) +set(CMake_VERSION_PATCH 20201018) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From c1a214a4f651eb55e0fdea7b62b6d50fc993944d Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Mon, 19 Oct 2020 00:01:27 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 154acf7..e0bf0ad 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 19) -set(CMake_VERSION_PATCH 20201018) +set(CMake_VERSION_PATCH 20201019) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From c92b96234acfe142df88cd1ba5815373721d5c22 Mon Sep 17 00:00:00 2001 From: Johnny Jazeix Date: Mon, 19 Oct 2020 19:53:56 +0200 Subject: CPack/NSIS: Template file in UTF-8 BOM to support Unicode Fixes: #21318 --- Help/release/dev/cpack-nsis-utf-8-bom.rst | 6 ++++++ Modules/Internal/CPack/NSIS.template.in | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 Help/release/dev/cpack-nsis-utf-8-bom.rst diff --git a/Help/release/dev/cpack-nsis-utf-8-bom.rst b/Help/release/dev/cpack-nsis-utf-8-bom.rst new file mode 100644 index 0000000..b2a20ce --- /dev/null +++ b/Help/release/dev/cpack-nsis-utf-8-bom.rst @@ -0,0 +1,6 @@ +cpack-nsis-utf8-bom +------------------- + +* The :cpack_gen:`CPack NSIS Generator` now handles correctly Unicode characters. + If you want to have a ``CPACK_RESOURCE_FILE_LICENSE`` with UTF-8 characters + it needs to be encoded in UTF-8 BOM. diff --git a/Modules/Internal/CPack/NSIS.template.in b/Modules/Internal/CPack/NSIS.template.in index 6009ce0..b448c76 100644 --- a/Modules/Internal/CPack/NSIS.template.in +++ b/Modules/Internal/CPack/NSIS.template.in @@ -1,4 +1,4 @@ -; CPack install script designed for a nmake build +; CPack install script designed for a nmake build ;-------------------------------- ; You must define these values -- cgit v0.12 From bd705788f67741df88bf153825a5943b4b518818 Mon Sep 17 00:00:00 2001 From: Cengizhan Pasaoglu Date: Sun, 18 Oct 2020 02:00:29 +0300 Subject: Constify some code as suggested by clang-tidy --- Source/cmFindCommon.cxx | 2 +- Source/cmGeneratorExpressionEvaluator.h | 2 +- Source/cmGeneratorExpressionNode.cxx | 14 +++++++------- Source/cmGeneratorTarget.cxx | 6 +++--- Source/cmGlobalGenerator.cxx | 6 +++--- Source/cmGlobalGenerator.h | 7 ++++--- Source/cmGlobalGhsMultiGenerator.cxx | 4 ++-- Source/cmGlobalNinjaGenerator.cxx | 4 ++-- Source/cmGlobalNinjaGenerator.h | 6 +++--- Source/cmLocalGenerator.cxx | 4 ++-- Source/cmLocalGenerator.h | 4 ++-- Source/cmLocalUnixMakefileGenerator3.h | 4 ++-- Source/cmMakefile.cxx | 10 +++++----- Source/cmMakefile.h | 10 +++++----- Source/cmQtAutoGen.h | 4 ++-- Source/cmTarget.cxx | 9 +++++---- Source/cmTarget.h | 2 +- Source/cmake.cxx | 6 +++--- Source/cmake.h | 16 ++++++++-------- 19 files changed, 61 insertions(+), 59 deletions(-) diff --git a/Source/cmFindCommon.cxx b/Source/cmFindCommon.cxx index dee91d7..7952336 100644 --- a/Source/cmFindCommon.cxx +++ b/Source/cmFindCommon.cxx @@ -182,7 +182,7 @@ void cmFindCommon::SelectDefaultSearchModes() { this->NoCMakeSystemPath, "CMAKE_FIND_USE_CMAKE_SYSTEM_PATH" } } }; - for (auto& path : search_paths) { + for (auto const& path : search_paths) { cmProp def = this->Makefile->GetDefinition(path.second); if (def) { path.first = !cmIsOn(*def); diff --git a/Source/cmGeneratorExpressionEvaluator.h b/Source/cmGeneratorExpressionEvaluator.h index 3e7737e..af2afd6 100644 --- a/Source/cmGeneratorExpressionEvaluator.h +++ b/Source/cmGeneratorExpressionEvaluator.h @@ -60,7 +60,7 @@ struct TextContent : public cmGeneratorExpressionEvaluator void Extend(size_t length) { this->Length += length; } - size_t GetLength() { return this->Length; } + size_t GetLength() const { return this->Length; } private: const char* Content; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 4ca7405..e40316e 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -677,7 +677,7 @@ struct CompilerIdNode : public cmGeneratorExpressionNode } static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$"); - for (auto& param : parameters) { + for (auto const& param : parameters) { if (!compilerIdValidator.find(param)) { reportError(context, content->GetOriginalExpression(), @@ -805,7 +805,7 @@ struct PlatformIdNode : public cmGeneratorExpressionNode return parameters.front().empty() ? "1" : "0"; } - for (auto& param : parameters) { + for (auto const& param : parameters) { if (param == platformId) { return "1"; } @@ -901,7 +901,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode return std::string(); } context->HadContextSensitiveCondition = true; - for (auto& param : parameters) { + for (auto const& param : parameters) { if (context->Config.empty()) { if (param.empty()) { return "1"; @@ -927,7 +927,7 @@ static const struct ConfigurationTestNode : public cmGeneratorExpressionNode if (cmProp mapValue = context->CurrentTarget->GetProperty(mapProp)) { cmExpandList(cmSystemTools::UpperCase(*mapValue), mappedConfigs); - for (auto& param : parameters) { + for (auto const& param : parameters) { if (cm::contains(mappedConfigs, cmSystemTools::UpperCase(param))) { return "1"; } @@ -995,7 +995,7 @@ static const struct CompileLanguageNode : public cmGeneratorExpressionNode return context->Language; } - for (auto& param : parameters) { + for (auto const& param : parameters) { if (context->Language == param) { return "1"; } @@ -1101,7 +1101,7 @@ static const struct LinkLanguageNode : public cmGeneratorExpressionNode return context->Language; } - for (auto& param : parameters) { + for (auto const& param : parameters) { if (context->Language == param) { return "1"; } @@ -1129,7 +1129,7 @@ struct LinkerId } static cmsys::RegularExpression linkerIdValidator("^[A-Za-z0-9_]*$"); - for (auto& param : parameters) { + for (auto const& param : parameters) { if (!linkerIdValidator.find(param)) { reportError(context, content->GetOriginalExpression(), "Expression syntax not recognized."); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 3b47550..1ed82fd 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -254,7 +254,7 @@ EvaluatedTargetPropertyEntries EvaluateTargetPropertyEntries( { EvaluatedTargetPropertyEntries out; out.Entries.reserve(in.size()); - for (auto& entry : in) { + for (auto const& entry : in) { out.Entries.emplace_back(EvaluateTargetPropertyEntry( thisTarget, config, lang, dagChecker, *entry)); } @@ -332,7 +332,7 @@ cmGeneratorTarget::~cmGeneratorTarget() = default; const std::string& cmGeneratorTarget::GetSourcesProperty() const { std::vector values; - for (auto& se : this->SourceEntries) { + for (auto const& se : this->SourceEntries) { values.push_back(se->GetInput()); } static std::string value; @@ -2504,7 +2504,7 @@ public: } } - bool GetHadLinkLanguageSensitiveCondition() + bool GetHadLinkLanguageSensitiveCondition() const { return HadLinkLanguageSensitiveCondition; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 1197db6..52f1d52 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -2601,7 +2601,7 @@ void cmGlobalGenerator::AddGlobalTarget_Test( } void cmGlobalGenerator::AddGlobalTarget_EditCache( - std::vector& targets) + std::vector& targets) const { const char* editCacheTargetName = this->GetEditCacheTargetName(); if (!editCacheTargetName) { @@ -2635,7 +2635,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache( } void cmGlobalGenerator::AddGlobalTarget_RebuildCache( - std::vector& targets) + std::vector& targets) const { const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName(); if (!rebuildCacheTargetName) { @@ -2758,7 +2758,7 @@ void cmGlobalGenerator::AddGlobalTarget_Install( } } -std::string cmGlobalGenerator::GetPredefinedTargetsFolder() +std::string cmGlobalGenerator::GetPredefinedTargetsFolder() const { cmProp prop = this->GetCMakeInstance()->GetState()->GetGlobalProperty( "PREDEFINED_TARGETS_FOLDER"); diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index de5eba7..afafba9 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -574,8 +574,9 @@ protected: void AddGlobalTarget_Package(std::vector& targets); void AddGlobalTarget_PackageSource(std::vector& targets); void AddGlobalTarget_Test(std::vector& targets); - void AddGlobalTarget_EditCache(std::vector& targets); - void AddGlobalTarget_RebuildCache(std::vector& targets); + void AddGlobalTarget_EditCache(std::vector& targets) const; + void AddGlobalTarget_RebuildCache( + std::vector& targets) const; void AddGlobalTarget_Install(std::vector& targets); cmTarget CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf); @@ -601,7 +602,7 @@ protected: cmGeneratorTarget* FindGeneratorTargetImpl(std::string const& name) const; - std::string GetPredefinedTargetsFolder(); + std::string GetPredefinedTargetsFolder() const; private: using TargetMap = std::unordered_map; diff --git a/Source/cmGlobalGhsMultiGenerator.cxx b/Source/cmGlobalGhsMultiGenerator.cxx index c08c9cf..33bf830 100644 --- a/Source/cmGlobalGhsMultiGenerator.cxx +++ b/Source/cmGlobalGhsMultiGenerator.cxx @@ -704,7 +704,7 @@ bool cmGlobalGhsMultiGenerator::ComputeTargetBuildOrder( std::set temp; std::set perm; - for (auto ti : tgt) { + for (auto const ti : tgt) { bool r = VisitTarget(temp, perm, build, ti); if (r) { return r; @@ -726,7 +726,7 @@ bool cmGlobalGhsMultiGenerator::VisitTarget( * in the same order */ OrderedTargetDependSet sortedTargets(this->GetTargetDirectDepends(ti), ""); - for (auto& di : sortedTargets) { + for (auto const& di : sortedTargets) { if (this->VisitTarget(temp, perm, order, di)) { return true; } diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 9e25a54..9b27bc5 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -1057,7 +1057,7 @@ void cmGlobalNinjaGenerator::CloseCompileCommandsStream() } } -void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) +void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) const { os << "# CMAKE generated file: DO NOT EDIT!\n" << "# Generated by \"" << this->GetName() << "\"" @@ -1088,7 +1088,7 @@ std::string cmGlobalNinjaGenerator::OrderDependsTargetForTarget( void cmGlobalNinjaGenerator::AppendTargetOutputs( cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config, cmNinjaTargetDepends depends) + const std::string& config, cmNinjaTargetDepends depends) const { // for frameworks, we want the real name, not smple name // frameworks always appear versioned, and the build.ninja diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 8d6ebdc..94abb40 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -252,7 +252,7 @@ public: : GG(gg) { } - std::string operator()(std::string const& path) + std::string operator()(std::string const& path) const { return this->GG->ConvertToNinjaPath(path); } @@ -323,7 +323,7 @@ public: void AppendTargetOutputs(cmGeneratorTarget const* target, cmNinjaDeps& outputs, const std::string& config, - cmNinjaTargetDepends depends); + cmNinjaTargetDepends depends) const; void AppendTargetDepends(cmGeneratorTarget const* target, cmNinjaDeps& outputs, const std::string& config, const std::string& fileConfig, @@ -463,7 +463,7 @@ private: void CleanMetaData(); /// Write the common disclaimer text at the top of each build file. - void WriteDisclaimer(std::ostream& os); + void WriteDisclaimer(std::ostream& os) const; void WriteAssumedSourceDependencies(); diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index b7ad78a..47e10e0 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -279,7 +279,7 @@ static void MoveSystemIncludesToEnd(std::vector>& includeDirs, }); } -void cmLocalGenerator::TraceDependencies() +void cmLocalGenerator::TraceDependencies() const { // Generate the rule files for each target. const auto& targets = this->GetGeneratorTargets(); @@ -3210,7 +3210,7 @@ std::string cmLocalGenerator::GetProjectName() const } std::string cmLocalGenerator::ConstructComment( - cmCustomCommandGenerator const& ccg, const char* default_comment) + cmCustomCommandGenerator const& ccg, const char* default_comment) const { // Check for a comment provided with the command. if (ccg.GetComment()) { diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 162e70f..b8bd3bc 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -77,7 +77,7 @@ public: /** * Calls TraceVSDependencies() on all targets of this generator. */ - void TraceDependencies(); + void TraceDependencies() const; virtual void AddHelperCommands() {} @@ -451,7 +451,7 @@ public: const std::string& fname); /** Construct a comment for a custom command. */ std::string ConstructComment(cmCustomCommandGenerator const& ccg, - const char* default_comment = ""); + const char* default_comment = "") const; // Compute object file names. std::string GetObjectFileNameWithoutTarget( const cmSourceFile& source, std::string const& dir_max, diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 8286d67..5edca2a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -178,11 +178,11 @@ public: /** Get whether to create rules to generate preprocessed and assembly sources. This could be converted to a variable lookup later. */ - bool GetCreatePreprocessedSourceRules() + bool GetCreatePreprocessedSourceRules() const { return !this->SkipPreprocessedSourceRules; } - bool GetCreateAssemblySourceRules() + bool GetCreateAssemblySourceRules() const { return !this->SkipAssemblySourceRules; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 22594bd..6d1868c 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -2029,7 +2029,7 @@ void cmMakefile::RemoveDefinition(const std::string& name) #endif } -void cmMakefile::RemoveCacheDefinition(const std::string& name) +void cmMakefile::RemoveCacheDefinition(const std::string& name) const { this->GetState()->RemoveCacheEntry(name); } @@ -2839,7 +2839,7 @@ void cmMakefile::SetRecursionDepth(int recursionDepth) this->RecursionDepth = recursionDepth; } -std::string cmMakefile::NewDeferId() +std::string cmMakefile::NewDeferId() const { return this->GetGlobalGenerator()->NewDeferId(); } @@ -4039,7 +4039,7 @@ cmTest* cmMakefile::GetTest(const std::string& testName) const } void cmMakefile::GetTests(const std::string& config, - std::vector& tests) + std::vector& tests) const { for (const auto& generator : this->GetTestGenerators()) { if (generator->TestsForConfig(config)) { @@ -4389,7 +4389,7 @@ cmPolicies::PolicyStatus cmMakefile::GetPolicyStatus(cmPolicies::PolicyID id, return this->StateSnapshot.GetPolicy(id, parent_scope); } -bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) +bool cmMakefile::PolicyOptionalWarningEnabled(std::string const& var) const { // Check for an explicit CMAKE_POLICY_WARNING_CMP setting. if (cmProp val = this->GetDefinition(var)) { @@ -4494,7 +4494,7 @@ bool cmMakefile::HasCMP0054AlreadyBeenReported( return !this->CMP0054ReportedIds.insert(context).second; } -void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) +void cmMakefile::RecordPolicies(cmPolicies::PolicyMap& pm) const { /* Record the setting of every policy. */ using PolicyID = cmPolicies::PolicyID; diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index ecc6aab..26ed737 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -304,7 +304,7 @@ public: */ void RemoveDefinition(const std::string& name); //! Remove a definition from the cache. - void RemoveCacheDefinition(const std::string& name); + void RemoveCacheDefinition(const std::string& name) const; /** * Specify the name of the project for this build. @@ -345,7 +345,7 @@ public: bool parent_scope = false) const; bool SetPolicyVersion(std::string const& version_min, std::string const& version_max); - void RecordPolicies(cmPolicies::PolicyMap& pm); + void RecordPolicies(cmPolicies::PolicyMap& pm) const; //@} /** Helper class to push and pop policies automatically. */ @@ -738,7 +738,7 @@ public: /** * Get all tests that run under the given configuration. */ - void GetTests(const std::string& config, std::vector& tests); + void GetTests(const std::string& config, std::vector& tests) const; /** * Return a location of a file in cmake or custom modules directory @@ -885,7 +885,7 @@ public: return this->SystemIncludeDirectories; } - bool PolicyOptionalWarningEnabled(std::string const& var); + bool PolicyOptionalWarningEnabled(std::string const& var) const; void PushLoopBlock(); void PopLoopBlock(); @@ -926,7 +926,7 @@ public: int GetRecursionDepth() const; void SetRecursionDepth(int recursionDepth); - std::string NewDeferId(); + std::string NewDeferId() const; bool DeferCall(std::string id, std::string fileName, cmListFileFunction lff); bool DeferCancelCall(std::string const& id); cm::optional DeferGetCallIds() const; diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index cf90417..2db1b84 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -29,13 +29,13 @@ public: { } - bool operator>(IntegerVersion const version) + bool operator>(IntegerVersion const version) const { return (this->Major > version.Major) || ((this->Major == version.Major) && (this->Minor > version.Minor)); } - bool operator>=(IntegerVersion const version) + bool operator>=(IntegerVersion const version) const { return (this->Major > version.Major) || ((this->Major == version.Major) && (this->Minor >= version.Minor)); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index e076d1e..4eebec6 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -213,7 +213,7 @@ public: bool CheckImportedLibName(std::string const& prop, std::string const& value) const; - std::string ProcessSourceItemCMP0049(const std::string& s); + std::string ProcessSourceItemCMP0049(const std::string& s) const; }; namespace { @@ -740,7 +740,8 @@ void cmTarget::AddSources(std::vector const& srcs) } } -std::string cmTargetInternals::ProcessSourceItemCMP0049(const std::string& s) +std::string cmTargetInternals::ProcessSourceItemCMP0049( + const std::string& s) const { std::string src = s; @@ -791,7 +792,7 @@ struct CreateLocation { } - cmSourceFileLocation operator()(const std::string& filename) + cmSourceFileLocation operator()(const std::string& filename) const { return cmSourceFileLocation(this->Makefile, filename); } @@ -857,7 +858,7 @@ cmSourceFile* cmTarget::AddSource(const std::string& src, bool before) cmSourceFileLocationKind::Known); } -void cmTarget::ClearDependencyInformation(cmMakefile& mf) +void cmTarget::ClearDependencyInformation(cmMakefile& mf) const { std::string depname = cmStrCat(this->GetName(), "_LIB_DEPENDS"); mf.RemoveCacheDefinition(depname); diff --git a/Source/cmTarget.h b/Source/cmTarget.h index d8f66bc..c2a4d86 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -114,7 +114,7 @@ public: LinkLibraryVectorType const& GetOriginalLinkLibraries() const; //! Clear the dependency information recorded for this target, if any. - void ClearDependencyInformation(cmMakefile& mf); + void ClearDependencyInformation(cmMakefile& mf) const; void AddLinkLibrary(cmMakefile& mf, std::string const& lib, cmTargetLinkLibraryType llt); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 720a567..80a6edc 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -1938,7 +1938,7 @@ int cmake::ActualConfigure() } } - auto& mf = this->GlobalGenerator->GetMakefiles()[0]; + const auto& mf = this->GlobalGenerator->GetMakefiles()[0]; if (mf->IsOn("CTEST_USE_LAUNCHERS") && !this->State->GetGlobalProperty("RULE_LAUNCH_COMPILE")) { cmSystemTools::Error( @@ -2280,12 +2280,12 @@ cmProp cmake::GetCacheDefinition(const std::string& name) const return this->State->GetInitializedCacheValue(name); } -void cmake::AddScriptingCommands() +void cmake::AddScriptingCommands() const { GetScriptingCommands(this->GetState()); } -void cmake::AddProjectCommands() +void cmake::AddProjectCommands() const { GetProjectCommands(this->GetState()); } diff --git a/Source/cmake.h b/Source/cmake.h index 262d673..f70fd14 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -411,7 +411,7 @@ public: WorkingMode GetWorkingMode() { return this->CurrentWorkingMode; } //! Debug the try compile stuff by not deleting the files - bool GetDebugTryCompile() { return this->DebugTryCompile; } + bool GetDebugTryCompile() const { return this->DebugTryCompile; } void DebugTryCompileOn() { this->DebugTryCompile = true; } /** @@ -456,11 +456,11 @@ public: void SetShowLogContext(bool b) { this->LogContext = b; } //! Do we want debug output during the cmake run. - bool GetDebugOutput() { return this->DebugOutput; } + bool GetDebugOutput() const { return this->DebugOutput; } void SetDebugOutputOn(bool b) { this->DebugOutput = b; } //! Do we want debug output from the find commands during the cmake run. - bool GetDebugFindOutput() { return this->DebugFindOutput; } + bool GetDebugFindOutput() const { return this->DebugFindOutput; } void SetDebugFindOutputOn(bool b) { this->DebugFindOutput = b; } //! Do we want trace output during the cmake run. @@ -482,11 +482,11 @@ public: void SetTraceFile(std::string const& file); void PrintTraceFormatVersion(); - bool GetWarnUninitialized() { return this->WarnUninitialized; } + bool GetWarnUninitialized() const { return this->WarnUninitialized; } void SetWarnUninitialized(bool b) { this->WarnUninitialized = b; } - bool GetWarnUnusedCli() { return this->WarnUnusedCli; } + bool GetWarnUnusedCli() const { return this->WarnUnusedCli; } void SetWarnUnusedCli(bool b) { this->WarnUnusedCli = b; } - bool GetCheckSystemVars() { return this->CheckSystemVars; } + bool GetCheckSystemVars() const { return this->CheckSystemVars; } void SetCheckSystemVars(bool b) { this->CheckSystemVars = b; } void MarkCliAsUsed(const std::string& variable); @@ -591,8 +591,8 @@ protected: using RegisteredExtraGeneratorsVector = std::vector; RegisteredExtraGeneratorsVector ExtraGenerators; - void AddScriptingCommands(); - void AddProjectCommands(); + void AddScriptingCommands() const; + void AddProjectCommands() const; void AddDefaultGenerators(); void AddDefaultExtraGenerators(); -- cgit v0.12 From 7bac94e38c7ced903919b1ac1b34c673125629d5 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Tue, 20 Oct 2020 00:01:15 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index e0bf0ad..41c84af 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 19) -set(CMake_VERSION_PATCH 20201019) +set(CMake_VERSION_PATCH 20201020) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 9df1f33c9ad6c9cf98cd374ba242e41b4f819f9d Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Thu, 15 Oct 2020 15:31:51 -0400 Subject: VisualStudio: move PCH rules to projects when possible. This dramatically helps reduce the size of the solution files when PCH is enabled, since 2 entries per source file are removed. This also corrects a subtle issue where when UNITY + PCH was enabled, the PCH would not be used if a user explicitly tried to compile a source file from outside the unity group. This is possible via the compile source option in the Visual Studio GUI. --- Source/cmVisualStudio10TargetGenerator.cxx | 66 +++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 0becee2..1ca7de8 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2402,27 +2402,28 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( configDefines += *ccdefs; } - // Add precompile headers compile options. - std::string customAndPchOptions = options; + // We have pch state in the following situation: + // 1. We have SKIP_PRECOMPILE_HEADERS == true + // 2. We are creating the pre-compiled header + // 3. We are a different language than the linker language AND pch is + // enabled const std::string pchSource = this->GeneratorTarget->GetPchSource(config, lang); - if (!pchSource.empty() && !sf.GetProperty("SKIP_PRECOMPILE_HEADERS")) { - std::string pchOptions; - if (sf.GetFullPath() == pchSource) { - pchOptions = - this->GeneratorTarget->GetPchCreateCompileOptions(config, lang); - } else { - pchOptions = - this->GeneratorTarget->GetPchUseCompileOptions(config, lang); - } - customAndPchOptions = cmStrCat(customAndPchOptions, ';', pchOptions); - } + const bool skipPCH = + pchSource.empty() || sf.GetPropertyAsBool("SKIP_PRECOMPILE_HEADERS"); + const bool makePCH = (sf.GetFullPath() == pchSource); + const bool useSharedPCH = + !skipPCH && (lang == this->GeneratorTarget->GetLinkerLanguage(config)); + const bool useDifferentLangPCH = + !skipPCH && (lang != this->GeneratorTarget->GetLinkerLanguage(config)); + const bool needsPCHFlags = + (makePCH || useSharedPCH || useDifferentLangPCH); // if we have flags or defines for this config then // use them if (!flags.empty() || !options.empty() || !configDefines.empty() || - !includes.empty() || compileAs || noWinRT || - !customAndPchOptions.empty()) { + !includes.empty() || compileAs || noWinRT || !options.empty() || + needsPCHFlags) { cmGlobalVisualStudio10Generator* gg = this->GlobalGenerator; cmIDEFlagTable const* flagtable = nullptr; const std::string& srclang = source->GetLanguage(); @@ -2455,15 +2456,35 @@ void cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( } else { clOptions.Parse(flags); } - if (!customAndPchOptions.empty()) { + + if (needsPCHFlags) { + // Add precompile headers compile options. + std::string expandedOptions; + std::string pchOptions; + if (makePCH) { + pchOptions = + this->GeneratorTarget->GetPchCreateCompileOptions(config, lang); + } else if (useSharedPCH) { + std::string pchHeader = + this->GeneratorTarget->GetPchHeader(config, lang); + clOptions.AddFlag("ForcedIncludeFiles", pchHeader); + } else if (useDifferentLangPCH) { + pchOptions = + this->GeneratorTarget->GetPchUseCompileOptions(config, lang); + } + this->LocalGenerator->AppendCompileOptions(expandedOptions, + pchOptions); + clOptions.Parse(expandedOptions); + } + + if (!options.empty()) { std::string expandedOptions; if (configDependentOptions) { this->LocalGenerator->AppendCompileOptions( expandedOptions, - genexInterpreter.Evaluate(customAndPchOptions, "COMPILE_OPTIONS")); + genexInterpreter.Evaluate(options, "COMPILE_OPTIONS")); } else { - this->LocalGenerator->AppendCompileOptions(expandedOptions, - customAndPchOptions); + this->LocalGenerator->AppendCompileOptions(expandedOptions, options); } clOptions.Parse(expandedOptions); } @@ -2786,6 +2807,13 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( this->GeneratorTarget->GetPchHeader(configName, linkLanguage); if (this->MSTools && vcxproj == this->ProjectType && pchHeader.empty()) { clOptions.AddFlag("PrecompiledHeader", "NotUsing"); + } else if (this->MSTools && vcxproj == this->ProjectType && + !pchHeader.empty()) { + clOptions.AddFlag("PrecompiledHeader", "Use"); + clOptions.AddFlag("PrecompiledHeaderFile", pchHeader); + std::string pchFile = + this->GeneratorTarget->GetPchFile(configName, linkLanguage); + clOptions.AddFlag("PrecompiledHeaderOutputFile", pchFile); } // Get preprocessor definitions for this directory. -- cgit v0.12 From 7398b4783e870b0887b449af556be3f455b2e212 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Wed, 21 Oct 2020 00:01:17 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 41c84af..8148eac 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 19) -set(CMake_VERSION_PATCH 20201020) +set(CMake_VERSION_PATCH 20201021) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 3c324689a7a3e16b7f232b943efd4ded971467bf Mon Sep 17 00:00:00 2001 From: Asit Dhal Date: Wed, 21 Oct 2020 11:20:37 +0200 Subject: include: refactor call sites of cmMakefile::ReadDependentFile Fixes: #16773 --- Source/CTest/cmCTestTestHandler.cxx | 2 +- Source/cmIncludeCommand.cxx | 21 ++++++++++++++++----- Source/cmProjectCommand.cxx | 13 ++++++++++++- .../RunCMake/include/ExportExportInclude-stderr.txt | 2 +- .../RunCMake/include/IncludeIsDirectory-result.txt | 1 + .../RunCMake/include/IncludeIsDirectory-stderr.txt | 6 ++++++ Tests/RunCMake/include/IncludeIsDirectory.cmake | 1 + Tests/RunCMake/include/IncludeMalformed-result.txt | 1 + Tests/RunCMake/include/IncludeMalformed-stderr.txt | 13 +++++++++++++ Tests/RunCMake/include/IncludeMalformed.cmake | 1 + Tests/RunCMake/include/RunCMakeTest.cmake | 2 ++ Tests/RunCMake/include/malformedInclude.cmake | 1 + 12 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 Tests/RunCMake/include/IncludeIsDirectory-result.txt create mode 100644 Tests/RunCMake/include/IncludeIsDirectory-stderr.txt create mode 100644 Tests/RunCMake/include/IncludeIsDirectory.cmake create mode 100644 Tests/RunCMake/include/IncludeMalformed-result.txt create mode 100644 Tests/RunCMake/include/IncludeMalformed-stderr.txt create mode 100644 Tests/RunCMake/include/IncludeMalformed.cmake create mode 100644 Tests/RunCMake/include/malformedInclude.cmake diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 4d1a589..84bb791 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -122,7 +122,7 @@ bool cmCTestSubdirCommand(std::vector const& args, readit = status.GetMakefile().ReadDependentFile(fname); } if (!readit) { - status.SetError(cmStrCat("Could not find include file: ", fname)); + status.SetError(cmStrCat("Could not load include file: ", fname)); return false; } } diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index ae801bb..5e3aec5 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -146,11 +146,24 @@ bool cmIncludeCommand(std::vector const& args, std::string listFile = cmSystemTools::CollapseFullPath( fname, status.GetMakefile().GetCurrentSourceDirectory()); - if (optional && !cmSystemTools::FileExists(listFile)) { + + const bool fileDoesnotExist = !cmSystemTools::FileExists(listFile); + const bool fileIsDirectory = cmSystemTools::FileIsDirectory(listFile); + if (fileDoesnotExist || fileIsDirectory) { if (!resultVarName.empty()) { status.GetMakefile().AddDefinition(resultVarName, "NOTFOUND"); } - return true; + if (optional) { + return true; + } + if (fileDoesnotExist) { + status.SetError(cmStrCat("could not find requested file:\n ", fname)); + return false; + } + if (fileIsDirectory) { + status.SetError(cmStrCat("requested file is a directory:\n ", fname)); + return false; + } } bool readit = @@ -163,9 +176,7 @@ bool cmIncludeCommand(std::vector const& args, } if (!optional && !readit && !cmSystemTools::GetFatalErrorOccured()) { - std::string m = cmStrCat("could not find load file:\n" - " ", - fname); + std::string m = cmStrCat("could not load requested file:\n ", fname); status.SetError(m); return false; } diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 0cfba63..ed32de9 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -358,6 +358,17 @@ static bool IncludeByVariable(cmExecutionStatus& status, return true; } + std::string includeFile = + cmSystemTools::CollapseFullPath(*include, mf.GetCurrentSourceDirectory()); + if (!cmSystemTools::FileExists(includeFile)) { + status.SetError(cmStrCat("could not find requested file:\n ", *include)); + return false; + } + if (cmSystemTools::FileIsDirectory(includeFile)) { + status.SetError(cmStrCat("requested file is a directory:\n ", *include)); + return false; + } + const bool readit = mf.ReadDependentFile(*include); if (readit) { return true; @@ -367,7 +378,7 @@ static bool IncludeByVariable(cmExecutionStatus& status, return true; } - status.SetError(cmStrCat("could not find file:\n ", *include)); + status.SetError(cmStrCat("could not load requested file:\n ", *include)); return false; } diff --git a/Tests/RunCMake/include/ExportExportInclude-stderr.txt b/Tests/RunCMake/include/ExportExportInclude-stderr.txt index 70d013c..6d5c02f 100644 --- a/Tests/RunCMake/include/ExportExportInclude-stderr.txt +++ b/Tests/RunCMake/include/ExportExportInclude-stderr.txt @@ -1,5 +1,5 @@ CMake Error at ExportExportInclude.cmake:6 \(include\): - include could not find load file: + include could not find requested file: .*/Tests/RunCMake/include/ExportExportInclude-build/theTargets.cmake Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/include/IncludeIsDirectory-result.txt b/Tests/RunCMake/include/IncludeIsDirectory-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/include/IncludeIsDirectory-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt b/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt new file mode 100644 index 0000000..5735c29 --- /dev/null +++ b/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt @@ -0,0 +1,6 @@ +CMake Error at IncludeIsDirectory.cmake:1 \(include\): + include requested file is a directory: + + .*/Tests/RunCMake/include/IncludeIsDirectory-build +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/include/IncludeIsDirectory.cmake b/Tests/RunCMake/include/IncludeIsDirectory.cmake new file mode 100644 index 0000000..74189e3 --- /dev/null +++ b/Tests/RunCMake/include/IncludeIsDirectory.cmake @@ -0,0 +1 @@ +include("${CMAKE_CURRENT_BINARY_DIR}") diff --git a/Tests/RunCMake/include/IncludeMalformed-result.txt b/Tests/RunCMake/include/IncludeMalformed-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/include/IncludeMalformed-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/include/IncludeMalformed-stderr.txt b/Tests/RunCMake/include/IncludeMalformed-stderr.txt new file mode 100644 index 0000000..fc75549 --- /dev/null +++ b/Tests/RunCMake/include/IncludeMalformed-stderr.txt @@ -0,0 +1,13 @@ +CMake Error at malformedInclude.cmake:1: + Parse error. Function missing ending "\)". End of file reached. +Call Stack \(most recent call first\): + IncludeMalformed.cmake:1 \(include\) + CMakeLists.txt:3 \(include\) + + +CMake Error at IncludeMalformed.cmake:1 \(include\): + include could not load requested file: + + malformedInclude.cmake +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/include/IncludeMalformed.cmake b/Tests/RunCMake/include/IncludeMalformed.cmake new file mode 100644 index 0000000..9560142 --- /dev/null +++ b/Tests/RunCMake/include/IncludeMalformed.cmake @@ -0,0 +1 @@ +include("malformedInclude.cmake") diff --git a/Tests/RunCMake/include/RunCMakeTest.cmake b/Tests/RunCMake/include/RunCMakeTest.cmake index bea7d5c..8fb7201 100644 --- a/Tests/RunCMake/include/RunCMakeTest.cmake +++ b/Tests/RunCMake/include/RunCMakeTest.cmake @@ -5,3 +5,5 @@ run_cmake(EmptyStringOptional) run_cmake(CMP0024-WARN) run_cmake(CMP0024-NEW) run_cmake(ExportExportInclude) +run_cmake(IncludeIsDirectory) +run_cmake(IncludeMalformed) diff --git a/Tests/RunCMake/include/malformedInclude.cmake b/Tests/RunCMake/include/malformedInclude.cmake new file mode 100644 index 0000000..3cec3ad --- /dev/null +++ b/Tests/RunCMake/include/malformedInclude.cmake @@ -0,0 +1 @@ +if( -- cgit v0.12 From 066812039873991416f04ebb3c051ac8cb669d14 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Tue, 20 Oct 2020 17:34:27 -0400 Subject: cm::optional: Fix move assignment --- Tests/CMakeLib/testOptional.cxx | 28 ++++++++++++++++++++++++ Utilities/std/cm/optional | 47 +++++++++++++++++++++++++++++------------ 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/Tests/CMakeLib/testOptional.cxx b/Tests/CMakeLib/testOptional.cxx index de09c0f..2d7dd7c 100644 --- a/Tests/CMakeLib/testOptional.cxx +++ b/Tests/CMakeLib/testOptional.cxx @@ -82,6 +82,18 @@ public: int Value = 0; }; +class NoMoveAssignEventLogger : public EventLogger +{ +public: + using EventLogger::EventLogger; + + NoMoveAssignEventLogger(const NoMoveAssignEventLogger&) = default; + NoMoveAssignEventLogger(NoMoveAssignEventLogger&&) = default; + + NoMoveAssignEventLogger& operator=(const NoMoveAssignEventLogger&) = default; + NoMoveAssignEventLogger& operator=(NoMoveAssignEventLogger&&) = delete; +}; + #define ASSERT_TRUE(x) \ do { \ if (!(x)) { \ @@ -328,12 +340,28 @@ static bool testCopyAssign(std::vector& expected) o1 = o4; // Intentionally duplicated to test assigning an empty optional to // an empty optional + cm::optional o5{ 1 }; + auto const* v5 = &*o5; + const cm::optional o6{ 2 }; + auto const* v6 = &*o6; + o5 = std::move(o6); + const NoMoveAssignEventLogger e7{ 3 }; + o5 = std::move(e7); + expected = { { Event::VALUE_CONSTRUCT, v2, nullptr, 4 }, { Event::COPY_CONSTRUCT, v1, v2, 4 }, { Event::VALUE_CONSTRUCT, v3, nullptr, 5 }, { Event::COPY_ASSIGN, v1, v3, 5 }, { Event::DESTRUCT, v1, nullptr, 5 }, + { Event::VALUE_CONSTRUCT, v5, nullptr, 1 }, + { Event::VALUE_CONSTRUCT, v6, nullptr, 2 }, + { Event::COPY_ASSIGN, v5, v6, 2 }, + { Event::VALUE_CONSTRUCT, &e7, nullptr, 3 }, + { Event::COPY_ASSIGN, v5, &e7, 3 }, + { Event::DESTRUCT, &e7, nullptr, 3 }, + { Event::DESTRUCT, v6, nullptr, 2 }, + { Event::DESTRUCT, v5, nullptr, 3 }, { Event::DESTRUCT, v3, nullptr, 5 }, { Event::DESTRUCT, v2, nullptr, 4 }, }; diff --git a/Utilities/std/cm/optional b/Utilities/std/cm/optional index 9a5d840..4eb7f27 100644 --- a/Utilities/std/cm/optional +++ b/Utilities/std/cm/optional @@ -68,16 +68,22 @@ public: optional& operator=(nullopt_t) noexcept; optional& operator=(const optional& other); - optional& operator=(optional&& other) noexcept; - template < - typename U = T, - typename = typename std::enable_if< - !std::is_same::type, cm::optional>::value && - std::is_constructible::value && std::is_assignable::value && + template + typename std::enable_if::value && + std::is_assignable::value, + optional&>::type + operator=(optional&& other) noexcept; + + template + typename std::enable_if< + !std::is_same::type, cm::optional>::value && + std::is_constructible::value && + std::is_assignable::value && (!std::is_scalar::value || - !std::is_same::type, T>::value)>::type> - optional& operator=(U&& v); + !std::is_same::type, T>::value), + optional&>::type + operator=(U&& v); const T* operator->() const; T* operator->(); @@ -140,13 +146,17 @@ optional::optional(nullopt_t) noexcept template optional::optional(const optional& other) { - *this = other; + if (other.has_value()) { + this->emplace(*other); + } } template optional::optional(optional&& other) noexcept { - *this = std::move(other); + if (other.has_value()) { + this->emplace(std::move(*other)); + } } template @@ -192,7 +202,11 @@ optional& optional::operator=(const optional& other) } template -optional& optional::operator=(optional&& other) noexcept +template +typename std::enable_if::value && + std::is_assignable::value, + optional&>::type +optional::operator=(optional&& other) noexcept { if (other.has_value()) { if (this->has_value()) { @@ -207,8 +221,15 @@ optional& optional::operator=(optional&& other) noexcept } template -template -optional& optional::operator=(U&& v) +template +typename std::enable_if< + !std::is_same::type, cm::optional>::value && + std::is_constructible::value && + std::is_assignable::value && + (!std::is_scalar::value || + !std::is_same::type, T>::value), + optional&>::type +optional::operator=(U&& v) { if (this->has_value()) { this->value() = v; -- cgit v0.12 From 3870f57ac5b3297dc61d27dcf0b0afb4e520ccf1 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Thu, 22 Oct 2020 00:01:13 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 8148eac..67d986a 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 19) -set(CMake_VERSION_PATCH 20201021) +set(CMake_VERSION_PATCH 20201022) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 585cc7c9301ff474a40d7702ce429b93f474d44f Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 22 Oct 2020 09:28:08 -0400 Subject: ci: install gmock in the Fedora 31 image The gmock libraries are referenced by GTest's CMake package files. While at it, also explicitly install gettext. It is installed already, but make it explicit for future testing of the FindGettext module. --- .gitlab/ci/docker/fedora31/install_deps.sh | 2 ++ .gitlab/os-linux.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab/ci/docker/fedora31/install_deps.sh b/.gitlab/ci/docker/fedora31/install_deps.sh index fa57f61..c1391e3 100755 --- a/.gitlab/ci/docker/fedora31/install_deps.sh +++ b/.gitlab/ci/docker/fedora31/install_deps.sh @@ -39,8 +39,10 @@ dnf install --setopt=install_weak_deps=False -y \ fontconfig-devel \ freetype-devel \ gdal-devel \ + gettext \ giflib-devel \ glew-devel \ + gmock \ gnutls-devel \ gsl-devel \ gtest-devel \ diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml index 315552b..bab4f5a 100644 --- a/.gitlab/os-linux.yml +++ b/.gitlab/os-linux.yml @@ -49,7 +49,7 @@ ### Fedora .fedora31: - image: "kitware/cmake:ci-fedora31-x86_64-2020-10-20" + image: "kitware/cmake:ci-fedora31-x86_64-2020-10-22" variables: GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes" -- cgit v0.12 From 98d5f033ede95133519b8c4b961c058dc3a5d491 Mon Sep 17 00:00:00 2001 From: Mario Emmenlauer Date: Wed, 21 Oct 2020 17:38:18 +0200 Subject: FindGTest: Ensure target names follow upstream GTest --- Modules/FindGTest.cmake | 55 ++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/Modules/FindGTest.cmake b/Modules/FindGTest.cmake index 10e31b2..f905e36 100644 --- a/Modules/FindGTest.cmake +++ b/Modules/FindGTest.cmake @@ -12,6 +12,15 @@ Imported targets This module defines the following :prop_tgt:`IMPORTED` targets: +``GTest::gtest`` + The Google Test ``gtest`` library, if found; adds Thread::Thread + automatically +``GTest::gtest_main`` + The Google Test ``gtest_main`` library, if found + +For backwards compatibility, this module defines additionally the +following deprecated :prop_tgt:`IMPORTED` targets: + ``GTest::GTest`` The Google Test ``gtest`` library, if found; adds Thread::Thread automatically @@ -62,7 +71,7 @@ Example usage find_package(GTest REQUIRED) add_executable(foo foo.cc) - target_link_libraries(foo GTest::GTest GTest::Main) + target_link_libraries(foo GTest::gtest GTest::gtest_main) add_test(AllTestsInFoo foo) @@ -228,43 +237,43 @@ if(GTEST_FOUND) find_package(Threads QUIET) - if(NOT TARGET GTest::GTest) + if(NOT TARGET GTest::gtest) __gtest_determine_library_type(GTEST_LIBRARY) - add_library(GTest::GTest ${GTEST_LIBRARY_TYPE} IMPORTED) + add_library(GTest::gtest ${GTEST_LIBRARY_TYPE} IMPORTED) if(TARGET Threads::Threads) - set_target_properties(GTest::GTest PROPERTIES + set_target_properties(GTest::gtest PROPERTIES INTERFACE_LINK_LIBRARIES Threads::Threads) endif() if(GTEST_LIBRARY_TYPE STREQUAL "SHARED") - set_target_properties(GTest::GTest PROPERTIES + set_target_properties(GTest::gtest PROPERTIES INTERFACE_COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") endif() if(GTEST_INCLUDE_DIRS) - set_target_properties(GTest::GTest PROPERTIES + set_target_properties(GTest::gtest PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIRS}") endif() - __gtest_import_library(GTest::GTest GTEST_LIBRARY "") - __gtest_import_library(GTest::GTest GTEST_LIBRARY "RELEASE") - __gtest_import_library(GTest::GTest GTEST_LIBRARY "DEBUG") + __gtest_import_library(GTest::gtest GTEST_LIBRARY "") + __gtest_import_library(GTest::gtest GTEST_LIBRARY "RELEASE") + __gtest_import_library(GTest::gtest GTEST_LIBRARY "DEBUG") endif() - if(NOT TARGET GTest::Main) + if(NOT TARGET GTest::gtest_main) __gtest_determine_library_type(GTEST_MAIN_LIBRARY) - add_library(GTest::Main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED) - set_target_properties(GTest::Main PROPERTIES - INTERFACE_LINK_LIBRARIES "GTest::GTest") - __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "") - __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "RELEASE") - __gtest_import_library(GTest::Main GTEST_MAIN_LIBRARY "DEBUG") + add_library(GTest::gtest_main ${GTEST_MAIN_LIBRARY_TYPE} IMPORTED) + set_target_properties(GTest::gtest_main PROPERTIES + INTERFACE_LINK_LIBRARIES "GTest::gtest") + __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "") + __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "RELEASE") + __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "DEBUG") endif() # Add targets mapping the same library names as defined in - # GTest's CMake package config. - if(NOT TARGET GTest::gtest) - add_library(GTest::gtest INTERFACE IMPORTED) - target_link_libraries(GTest::gtest INTERFACE GTest::GTest) + # older versions of CMake's FindGTest + if(NOT TARGET GTest::GTest) + add_library(GTest::GTest INTERFACE IMPORTED) + target_link_libraries(GTest::GTest INTERFACE GTest::gtest) endif() - if(NOT TARGET GTest::gtest_main) - add_library(GTest::gtest_main INTERFACE IMPORTED) - target_link_libraries(GTest::gtest_main INTERFACE GTest::Main) + if(NOT TARGET GTest::Main) + add_library(GTest::Main INTERFACE IMPORTED) + target_link_libraries(GTest::Main INTERFACE GTest::gtest_main) endif() endif() -- cgit v0.12 From 6d45f951ed0eba8feefc3c5aeeaeed628bf6497c Mon Sep 17 00:00:00 2001 From: Mario Emmenlauer Date: Wed, 21 Oct 2020 17:39:31 +0200 Subject: FindGTest: Minor whitespace change, moved an include upwards --- Modules/FindGTest.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/FindGTest.cmake b/Modules/FindGTest.cmake index f905e36..1470b45 100644 --- a/Modules/FindGTest.cmake +++ b/Modules/FindGTest.cmake @@ -178,6 +178,8 @@ endfunction() # +include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) + if(NOT DEFINED GTEST_MSVC_SEARCH) set(GTEST_MSVC_SEARCH MD) endif() @@ -226,7 +228,6 @@ if(NOT GTEST_MAIN_LIBRARY) __gtest_find_and_select_library_configurations(GTEST_MAIN gtest_main) endif() -include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY) if(GTEST_FOUND) -- cgit v0.12 From 2327b4330cce157d616ff8b611b3e77568d00351 Mon Sep 17 00:00:00 2001 From: Mario Emmenlauer Date: Wed, 21 Oct 2020 17:47:17 +0200 Subject: FindGTest: Added support for CONFIG mode Upstream GTest provides its own CMake package files. Use them if available. Fixes: #18801 --- Modules/FindGTest.cmake | 49 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/Modules/FindGTest.cmake b/Modules/FindGTest.cmake index 1470b45..ff50869 100644 --- a/Modules/FindGTest.cmake +++ b/Modules/FindGTest.cmake @@ -33,7 +33,7 @@ Result variables This module will set the following variables in your project: -``GTEST_FOUND`` +``GTest_FOUND`` Found the Google Testing framework ``GTEST_INCLUDE_DIRS`` the directory containing the Google Test headers @@ -176,10 +176,41 @@ function(__gtest_import_library _target _var _config) endif() endfunction() +function(__gtest_define_backwards_compatible_library_targets) + set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} PARENT_SCOPE) + + # Add targets mapping the same library names as defined in + # older versions of CMake's FindGTest + if(NOT TARGET GTest::GTest) + add_library(GTest::GTest INTERFACE IMPORTED) + target_link_libraries(GTest::GTest INTERFACE GTest::gtest) + endif() + if(NOT TARGET GTest::Main) + add_library(GTest::Main INTERFACE IMPORTED) + target_link_libraries(GTest::Main INTERFACE GTest::gtest_main) + endif() +endfunction() + # include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +# first specifically look for the CMake version of GTest +find_package(GTest QUIET NO_MODULE) + +# if we found the GTest cmake package then we are done, and +# can print what we found and return. +if(GTest_FOUND) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest HANDLE_COMPONENTS CONFIG_MODE) + + set(GTEST_LIBRARIES GTest::gtest) + set(GTEST_MAIN_LIBRARIES GTest::gtest_main) + + __gtest_define_backwards_compatible_library_targets() + + return() +endif() + if(NOT DEFINED GTEST_MSVC_SEARCH) set(GTEST_MSVC_SEARCH MD) endif() @@ -219,8 +250,6 @@ find_path(GTEST_INCLUDE_DIR gtest/gtest.h ) mark_as_advanced(GTEST_INCLUDE_DIR) -# Allow GTEST_LIBRARY and GTEST_MAIN_LIBRARY to be set manually, as the -# locations of the gtest and gtest_main libraries, respectively. if(NOT GTEST_LIBRARY) __gtest_find_and_select_library_configurations(GTEST gtest) endif() @@ -230,11 +259,10 @@ endif() FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY) -if(GTEST_FOUND) +if(GTest_FOUND) set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR}) __gtest_append_debugs(GTEST_LIBRARIES GTEST_LIBRARY) __gtest_append_debugs(GTEST_MAIN_LIBRARIES GTEST_MAIN_LIBRARY) - set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) find_package(Threads QUIET) @@ -267,14 +295,5 @@ if(GTEST_FOUND) __gtest_import_library(GTest::gtest_main GTEST_MAIN_LIBRARY "DEBUG") endif() - # Add targets mapping the same library names as defined in - # older versions of CMake's FindGTest - if(NOT TARGET GTest::GTest) - add_library(GTest::GTest INTERFACE IMPORTED) - target_link_libraries(GTest::GTest INTERFACE GTest::gtest) - endif() - if(NOT TARGET GTest::Main) - add_library(GTest::Main INTERFACE IMPORTED) - target_link_libraries(GTest::Main INTERFACE GTest::gtest_main) - endif() + __gtest_define_backwards_compatible_library_targets() endif() -- cgit v0.12 From 94c6295db1c7ae759b466d4fb06f25b889ac888b Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 22 Oct 2020 10:20:08 -0400 Subject: Help: Document site_name command use of HOSTNAME variable --- Help/command/site_name.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Help/command/site_name.rst b/Help/command/site_name.rst index 1bcaead..09b5a9f 100644 --- a/Help/command/site_name.rst +++ b/Help/command/site_name.rst @@ -6,3 +6,7 @@ Set the given variable to the name of the computer. .. code-block:: cmake site_name(variable) + +On UNIX-like platforms, if the variable ``HOSTNAME`` is set, its value +will be executed as a command expected to print out the host name, +much like the ``hostname`` command-line tool. -- cgit v0.12 From 3f3762856fbe56a244ad45995e37b3318e80b119 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 22 Oct 2020 10:12:51 -0400 Subject: Tests: Add case verifying CTest module SITE variable --- Tests/RunCMake/CTest/RunCMakeTest.cmake | 1 + Tests/RunCMake/CTest/Site.cmake | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 Tests/RunCMake/CTest/Site.cmake diff --git a/Tests/RunCMake/CTest/RunCMakeTest.cmake b/Tests/RunCMake/CTest/RunCMakeTest.cmake index ffc8f78..b81f319 100644 --- a/Tests/RunCMake/CTest/RunCMakeTest.cmake +++ b/Tests/RunCMake/CTest/RunCMakeTest.cmake @@ -5,6 +5,7 @@ run_cmake(BeforeProject) unset(RunCMake_TEST_OPTIONS) run_cmake(NotOn) +run_cmake(Site) function(run_CMakeCTestArguments) run_cmake_with_options(CMakeCTestArguments "-DCMAKE_CTEST_ARGUMENTS=--quiet\\;--output-log\\;output-log.txt") diff --git a/Tests/RunCMake/CTest/Site.cmake b/Tests/RunCMake/CTest/Site.cmake new file mode 100644 index 0000000..2c96f23 --- /dev/null +++ b/Tests/RunCMake/CTest/Site.cmake @@ -0,0 +1,5 @@ +include(CTest) +get_property(site CACHE SITE PROPERTY VALUE) +if(NOT "${site}" STREQUAL "${SITE}") + message(FATAL_ERROR "SITE is not a cache entry") +endif() -- cgit v0.12 From 11d21c1c4e7028570e78c134b36187dbf03aaa4e Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 22 Oct 2020 10:20:45 -0400 Subject: CTest: Avoid invoking external tool to get the host name Populate the SITE cache entry using an internal query instead. --- Modules/CTest.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Modules/CTest.cmake b/Modules/CTest.cmake index 8109108..ca9fcf5 100644 --- a/Modules/CTest.cmake +++ b/Modules/CTest.cmake @@ -194,7 +194,14 @@ if(BUILD_TESTING) "Extra command line flags to pass to the coverage tool") # set the site name - site_name(SITE) + if(COMMAND cmake_host_system_information) + cmake_host_system_information(RESULT _ctest_hostname QUERY HOSTNAME) + set(SITE "${_ctest_hostname}" CACHE STRING "Name of the computer/site where compile is being run") + unset(_ctest_hostname) + else() + # This code path is needed for CMake itself during bootstrap. + site_name(SITE) + endif() # set the build name if(NOT BUILDNAME) set(DART_COMPILER "${CMAKE_CXX_COMPILER}") -- cgit v0.12 From 67383725bd40a92db85738f8d0c120e2c9bb2100 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Thu, 22 Oct 2020 11:39:48 -0400 Subject: cm::optional: Add constructor delegation to nullopt_t constructor Some static analysis tools incorrectly identify this constructor as leaving _has_value in an undefined state. Explicitly call the default constructor to force _has_value to false. --- Utilities/std/cm/optional | 1 + 1 file changed, 1 insertion(+) diff --git a/Utilities/std/cm/optional b/Utilities/std/cm/optional index 4eb7f27..0defae1 100644 --- a/Utilities/std/cm/optional +++ b/Utilities/std/cm/optional @@ -140,6 +140,7 @@ optional make_optional(Args&&... args) template optional::optional(nullopt_t) noexcept + : optional() { } -- cgit v0.12 From 12f6e37eb79ad66c30269a3f19dfc28a9cb834e2 Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Tue, 20 Oct 2020 10:47:38 -0400 Subject: cmListFileCache: Enforce proper nesting of flow control statements Fixes: #19153 --- Source/cmListFileCache.cxx | 118 +++++++++++++++++++++ Source/cmListFileCache.h | 8 ++ Tests/CMakeTests/EndStuffTestScript.cmake | 60 +++-------- Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt | 10 +- .../Syntax/FunctionUnmatchedForeach-stderr.txt | 10 +- Tests/RunCMake/Syntax/ImproperNesting-result.txt | 1 + Tests/RunCMake/Syntax/ImproperNesting-stderr.txt | 4 + Tests/RunCMake/Syntax/ImproperNesting.cmake | 7 ++ Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt | 10 +- .../Syntax/MacroUnmatchedForeach-stderr.txt | 10 +- Tests/RunCMake/Syntax/RunCMakeTest.cmake | 1 + Tests/RunCMake/if/duplicate-deep-else-stderr.txt | 6 +- .../if/duplicate-else-after-elseif-stderr.txt | 6 +- Tests/RunCMake/if/duplicate-else-stderr.txt | 6 +- Tests/RunCMake/if/misplaced-elseif-stderr.txt | 6 +- Tests/RunCMake/while/EndAlone-stderr.txt | 7 +- Tests/RunCMake/while/EndAloneArgs-stderr.txt | 7 +- Tests/RunCMake/while/EndMissing-stderr.txt | 10 +- Tests/RunCMake/while/MissingArgument-stderr.txt | 11 +- Tests/RunCMake/while/MissingArgument.cmake | 1 + 20 files changed, 198 insertions(+), 101 deletions(-) create mode 100644 Tests/RunCMake/Syntax/ImproperNesting-result.txt create mode 100644 Tests/RunCMake/Syntax/ImproperNesting-stderr.txt create mode 100644 Tests/RunCMake/Syntax/ImproperNesting.cmake diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 70ef5af..3658d11 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -30,6 +30,7 @@ struct cmListFileParser bool ParseFunction(const char* name, long line); bool AddArgument(cmListFileLexer_Token* token, cmListFileArgument::Delimiter delim); + cm::optional CheckNesting(); cmListFile* ListFile; cmListFileBacktrace Backtrace; cmMessenger* Messenger; @@ -158,6 +159,17 @@ bool cmListFileParser::Parse() return false; } } + + // Check if all functions are nested properly. + if (auto badNesting = this->CheckNesting()) { + this->Messenger->IssueMessage( + MessageType::FATAL_ERROR, + "Flow control statements are not properly nested.", + this->Backtrace.Push(*badNesting)); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + return true; } @@ -317,6 +329,112 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, return true; } +namespace { +enum class NestingStateEnum +{ + If, + Else, + While, + Foreach, + Function, + Macro, +}; + +struct NestingState +{ + NestingStateEnum State; + cmListFileContext Context; +}; + +bool TopIs(std::vector& stack, NestingStateEnum state) +{ + return !stack.empty() && stack.back().State == state; +} +} + +cm::optional cmListFileParser::CheckNesting() +{ + std::vector stack; + + for (auto const& func : this->ListFile->Functions) { + auto const& name = func.LowerCaseName(); + if (name == "if") { + stack.push_back({ + NestingStateEnum::If, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "elseif") { + if (!TopIs(stack, NestingStateEnum::If)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.back() = { + NestingStateEnum::If, + cmListFileContext::FromCommandContext(func, this->FileName), + }; + } else if (name == "else") { + if (!TopIs(stack, NestingStateEnum::If)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.back() = { + NestingStateEnum::Else, + cmListFileContext::FromCommandContext(func, this->FileName), + }; + } else if (name == "endif") { + if (!TopIs(stack, NestingStateEnum::If) && + !TopIs(stack, NestingStateEnum::Else)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } else if (name == "while") { + stack.push_back({ + NestingStateEnum::While, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "endwhile") { + if (!TopIs(stack, NestingStateEnum::While)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } else if (name == "foreach") { + stack.push_back({ + NestingStateEnum::Foreach, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "endforeach") { + if (!TopIs(stack, NestingStateEnum::Foreach)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } else if (name == "function") { + stack.push_back({ + NestingStateEnum::Function, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "endfunction") { + if (!TopIs(stack, NestingStateEnum::Function)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } else if (name == "macro") { + stack.push_back({ + NestingStateEnum::Macro, + cmListFileContext::FromCommandContext(func, this->FileName), + }); + } else if (name == "endmacro") { + if (!TopIs(stack, NestingStateEnum::Macro)) { + return cmListFileContext::FromCommandContext(func, this->FileName); + } + stack.pop_back(); + } + } + + if (!stack.empty()) { + return stack.back().Context; + } + + return cm::nullopt; +} + // We hold either the bottom scope of a directory or a call/file context. // Discriminate these cases via the parent pointer. struct cmListFileBacktrace::Entry diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 727fc60..ed45c07 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -89,6 +89,14 @@ public: { } +#if __cplusplus < 201703L && (!defined(_MSVC_LANG) || _MSVC_LANG < 201703L) + cmListFileContext(const cmListFileContext& /*other*/) = default; + cmListFileContext(cmListFileContext&& /*other*/) = default; + + cmListFileContext& operator=(const cmListFileContext& /*other*/) = default; + cmListFileContext& operator=(cmListFileContext&& /*other*/) = delete; +#endif + static cmListFileContext FromCommandContext( cmCommandContext const& lfcc, std::string const& fileName, cm::optional deferId = {}) diff --git a/Tests/CMakeTests/EndStuffTestScript.cmake b/Tests/CMakeTests/EndStuffTestScript.cmake index 9f40818..6a6b162 100644 --- a/Tests/CMakeTests/EndStuffTestScript.cmake +++ b/Tests/CMakeTests/EndStuffTestScript.cmake @@ -1,68 +1,40 @@ message(STATUS "testname='${testname}'") -if(testname STREQUAL bad_else) # fail - file(WRITE "${dir}/${testname}.cmake" -"else() -") +function(do_end content) + file(WRITE "${dir}/${testname}.cmake" "${content}") execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake" RESULT_VARIABLE rv) if(NOT rv EQUAL 0) message(FATAL_ERROR "${testname} failed") endif() +endfunction() + +if(testname STREQUAL bad_else) # fail + do_end("else()\n") elseif(testname STREQUAL bad_elseif) # fail - file(WRITE "${dir}/${testname}.cmake" -"elseif() -") - execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake" - RESULT_VARIABLE rv) - if(NOT rv EQUAL 0) - message(FATAL_ERROR "${testname} failed") - endif() + do_end("elseif()\n") elseif(testname STREQUAL bad_endforeach) # fail - endforeach() + do_end("endforeach()\n") elseif(testname STREQUAL bad_endfunction) # fail - endfunction() + do_end("endfunction()\n") elseif(testname STREQUAL bad_endif) # fail - file(WRITE "${dir}/${testname}.cmake" -"cmake_minimum_required(VERSION 2.8) -endif() -") - execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake" - RESULT_VARIABLE rv) - if(NOT rv EQUAL 0) - message(FATAL_ERROR "${testname} failed") - endif() + do_end("cmake_minimum_required(VERSION 2.8)\nendif()\n") -elseif(testname STREQUAL endif_low_min_version) # pass - file(WRITE "${dir}/${testname}.cmake" -"cmake_minimum_required(VERSION 1.2) -endif() -") - execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake" - RESULT_VARIABLE rv) - if(NOT rv EQUAL 0) - message(FATAL_ERROR "${testname} failed") - endif() +elseif(testname STREQUAL endif_low_min_version) # fail + do_end("cmake_minimum_required(VERSION 1.2)\nendif()\n") -elseif(testname STREQUAL endif_no_min_version) # pass - file(WRITE "${dir}/${testname}.cmake" -"endif() -") - execute_process(COMMAND ${CMAKE_COMMAND} -P "${dir}/${testname}.cmake" - RESULT_VARIABLE rv) - if(NOT rv EQUAL 0) - message(FATAL_ERROR "${testname} failed") - endif() +elseif(testname STREQUAL endif_no_min_version) # fail + do_end("endif()\n") elseif(testname STREQUAL bad_endmacro) # fail - endmacro() + do_end("endmacro()\n") elseif(testname STREQUAL bad_endwhile) # fail - endwhile() + do_end("endwhile()\n") else() # fail message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'") diff --git a/Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt b/Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt index 306c255..87fa746 100644 --- a/Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt +++ b/Tests/RunCMake/Syntax/FunctionUnmatched-stderr.txt @@ -1,8 +1,4 @@ -^CMake Error in FunctionUnmatched.cmake: - A logical block opening on the line - - .*/Tests/RunCMake/Syntax/FunctionUnmatched.cmake:[0-9]+ \(function\) - - is not closed. +^CMake Error at FunctionUnmatched\.cmake:[0-9]+ \(function\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt b/Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt index f4ff709..7904b87 100644 --- a/Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt +++ b/Tests/RunCMake/Syntax/FunctionUnmatchedForeach-stderr.txt @@ -1,8 +1,4 @@ -^CMake Error at FunctionUnmatchedForeach.cmake:[0-9]+ \(f\): - A logical block opening on the line - - .*/Tests/RunCMake/Syntax/FunctionUnmatchedForeach.cmake:[0-9]+ \(foreach\) - - is not closed. +^CMake Error at FunctionUnmatchedForeach\.cmake:[0-9]+ \(endfunction\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/Syntax/ImproperNesting-result.txt b/Tests/RunCMake/Syntax/ImproperNesting-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/ImproperNesting-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/ImproperNesting-stderr.txt b/Tests/RunCMake/Syntax/ImproperNesting-stderr.txt new file mode 100644 index 0000000..a209ef6 --- /dev/null +++ b/Tests/RunCMake/Syntax/ImproperNesting-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at ImproperNesting\.cmake:[0-9]+ \(endforeach\): + Flow control statements are not properly nested\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/Syntax/ImproperNesting.cmake b/Tests/RunCMake/Syntax/ImproperNesting.cmake new file mode 100644 index 0000000..47ff9f9 --- /dev/null +++ b/Tests/RunCMake/Syntax/ImproperNesting.cmake @@ -0,0 +1,7 @@ +message(FATAL_ERROR "This should not happen") + +foreach(i 1 2) + if(1) +endforeach() +endif() +endif() diff --git a/Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt b/Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt index 440d863..a7af590 100644 --- a/Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt +++ b/Tests/RunCMake/Syntax/MacroUnmatched-stderr.txt @@ -1,8 +1,4 @@ -^CMake Error in MacroUnmatched.cmake: - A logical block opening on the line - - .*/Tests/RunCMake/Syntax/MacroUnmatched.cmake:[0-9]+ \(macro\) - - is not closed. +^CMake Error at MacroUnmatched\.cmake:[0-9]+ \(macro\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt b/Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt index 820cd2e..30c4a4c 100644 --- a/Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt +++ b/Tests/RunCMake/Syntax/MacroUnmatchedForeach-stderr.txt @@ -1,8 +1,4 @@ -^CMake Error at MacroUnmatchedForeach.cmake:[0-9]+ \(m\): - A logical block opening on the line - - .*/Tests/RunCMake/Syntax/MacroUnmatchedForeach.cmake:[0-9]+ \(foreach\) - - is not closed. +^CMake Error at MacroUnmatchedForeach\.cmake:[0-9]+ \(endmacro\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/Syntax/RunCMakeTest.cmake b/Tests/RunCMake/Syntax/RunCMakeTest.cmake index 8d74dc1..34885b8 100644 --- a/Tests/RunCMake/Syntax/RunCMakeTest.cmake +++ b/Tests/RunCMake/Syntax/RunCMakeTest.cmake @@ -72,6 +72,7 @@ run_cmake(UnterminatedBrace2) run_cmake(UnterminatedBracket0) run_cmake(UnterminatedBracket1) run_cmake(UnterminatedBracketComment) +run_cmake(ImproperNesting) # Variable expansion tests run_cmake(ExpandInAt) diff --git a/Tests/RunCMake/if/duplicate-deep-else-stderr.txt b/Tests/RunCMake/if/duplicate-deep-else-stderr.txt index ac2335c..ee886e0 100644 --- a/Tests/RunCMake/if/duplicate-deep-else-stderr.txt +++ b/Tests/RunCMake/if/duplicate-deep-else-stderr.txt @@ -1,4 +1,4 @@ -CMake Error at duplicate-deep-else.cmake:[0-9]+ \(else\): - A duplicate ELSE command was found inside an IF block. +CMake Error at duplicate-deep-else\.cmake:[0-9]+ \(else\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt b/Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt index ba6765c..60c8484 100644 --- a/Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt +++ b/Tests/RunCMake/if/duplicate-else-after-elseif-stderr.txt @@ -1,4 +1,4 @@ -CMake Error at duplicate-else-after-elseif.cmake:[0-9]+ \(else\): - A duplicate ELSE command was found inside an IF block. +CMake Error at duplicate-else-after-elseif\.cmake:[0-9]+ \(else\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/if/duplicate-else-stderr.txt b/Tests/RunCMake/if/duplicate-else-stderr.txt index e0dd01f..518c43f 100644 --- a/Tests/RunCMake/if/duplicate-else-stderr.txt +++ b/Tests/RunCMake/if/duplicate-else-stderr.txt @@ -1,4 +1,4 @@ -CMake Error at duplicate-else.cmake:[0-9]+ \(else\): - A duplicate ELSE command was found inside an IF block. +CMake Error at duplicate-else\.cmake:[0-9]+ \(else\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/if/misplaced-elseif-stderr.txt b/Tests/RunCMake/if/misplaced-elseif-stderr.txt index c4b0266..5138f11 100644 --- a/Tests/RunCMake/if/misplaced-elseif-stderr.txt +++ b/Tests/RunCMake/if/misplaced-elseif-stderr.txt @@ -1,4 +1,4 @@ -CMake Error at misplaced-elseif.cmake:[0-9]+ \(elseif\): - An ELSEIF command was found after an ELSE command. +CMake Error at misplaced-elseif\.cmake:[0-9]+ \(elseif\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/while/EndAlone-stderr.txt b/Tests/RunCMake/while/EndAlone-stderr.txt index 5fe6655..3195fa0 100644 --- a/Tests/RunCMake/while/EndAlone-stderr.txt +++ b/Tests/RunCMake/while/EndAlone-stderr.txt @@ -1,5 +1,4 @@ -^CMake Error at EndAlone.cmake:1 \(endwhile\): - endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE - structure. Or its arguments did not match the opening WHILE command. +^CMake Error at EndAlone\.cmake:[0-9]+ \(endwhile\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/while/EndAloneArgs-stderr.txt b/Tests/RunCMake/while/EndAloneArgs-stderr.txt index a8c043d..1634e3b 100644 --- a/Tests/RunCMake/while/EndAloneArgs-stderr.txt +++ b/Tests/RunCMake/while/EndAloneArgs-stderr.txt @@ -1,5 +1,4 @@ -^CMake Error at EndAloneArgs.cmake:1 \(endwhile\): - endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE - structure. Or its arguments did not match the opening WHILE command. +^CMake Error at EndAloneArgs\.cmake:[0-9]+ \(endwhile\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/while/EndMissing-stderr.txt b/Tests/RunCMake/while/EndMissing-stderr.txt index 964792f..1e3be4d 100644 --- a/Tests/RunCMake/while/EndMissing-stderr.txt +++ b/Tests/RunCMake/while/EndMissing-stderr.txt @@ -1,8 +1,4 @@ -^CMake Error in EndMissing.cmake: - A logical block opening on the line - - .*/Tests/RunCMake/while/EndMissing.cmake:1 \(while\) - - is not closed. +^CMake Error at EndMissing\.cmake:[0-9]+ \(while\): + Flow control statements are not properly nested\. Call Stack \(most recent call first\): - CMakeLists.txt:[0-9]+ \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/while/MissingArgument-stderr.txt b/Tests/RunCMake/while/MissingArgument-stderr.txt index 7ff0971..59e8ee3 100644 --- a/Tests/RunCMake/while/MissingArgument-stderr.txt +++ b/Tests/RunCMake/while/MissingArgument-stderr.txt @@ -1,4 +1,11 @@ -^CMake Error at MissingArgument.cmake:1 \(while\): +^CMake Error at MissingArgument\.cmake:[0-9]+ \(while\): while called with incorrect number of arguments Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\)$ + CMakeLists\.txt:[0-9]+ \(include\) + + +CMake Error at MissingArgument\.cmake:[0-9]+ \(endwhile\): + endwhile An ENDWHILE command was found outside of a proper WHILE ENDWHILE + structure\. Or its arguments did not match the opening WHILE command\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/while/MissingArgument.cmake b/Tests/RunCMake/while/MissingArgument.cmake index 32eaa26..3fe2d97 100644 --- a/Tests/RunCMake/while/MissingArgument.cmake +++ b/Tests/RunCMake/while/MissingArgument.cmake @@ -1 +1,2 @@ while() +endwhile() -- cgit v0.12 From 8aee7fdb32a7099e3e4efdf1bf0a00732ee1c46b Mon Sep 17 00:00:00 2001 From: Kyle Edwards Date: Thu, 22 Oct 2020 16:50:42 -0400 Subject: cmState: Prohibit override of flow control commands --- Source/cmCommands.cxx | 17 ++++++------ Source/cmFunctionCommand.cxx | 7 +++-- Source/cmLoadCommandCommand.cxx | 11 ++++---- Source/cmMacroCommand.cxx | 7 +++-- Source/cmState.cxx | 31 +++++++++++++++++++--- Source/cmState.h | 8 +++++- Tests/RunCMake/Syntax/Override.cmake | 6 +++++ Tests/RunCMake/Syntax/OverrideBreak-result.txt | 1 + Tests/RunCMake/Syntax/OverrideContinue-result.txt | 1 + Tests/RunCMake/Syntax/OverrideElse-result.txt | 1 + Tests/RunCMake/Syntax/OverrideElseIf-result.txt | 1 + .../RunCMake/Syntax/OverrideEndForeach-result.txt | 1 + .../RunCMake/Syntax/OverrideEndFunction-result.txt | 1 + Tests/RunCMake/Syntax/OverrideEndIf-result.txt | 1 + Tests/RunCMake/Syntax/OverrideEndMacro-result.txt | 1 + Tests/RunCMake/Syntax/OverrideEndWhile-result.txt | 1 + Tests/RunCMake/Syntax/OverrideForeach-result.txt | 1 + Tests/RunCMake/Syntax/OverrideFunction-result.txt | 1 + Tests/RunCMake/Syntax/OverrideIf-result.txt | 1 + Tests/RunCMake/Syntax/OverrideMacro-result.txt | 1 + Tests/RunCMake/Syntax/OverrideReturn-result.txt | 1 + Tests/RunCMake/Syntax/OverrideWhile-result.txt | 1 + Tests/RunCMake/Syntax/RunCMakeTest.cmake | 27 +++++++++++++++++++ 23 files changed, 108 insertions(+), 21 deletions(-) create mode 100644 Tests/RunCMake/Syntax/Override.cmake create mode 100644 Tests/RunCMake/Syntax/OverrideBreak-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideContinue-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideElse-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideElseIf-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideEndForeach-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideEndFunction-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideEndIf-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideEndMacro-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideEndWhile-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideForeach-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideFunction-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideIf-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideMacro-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideReturn-result.txt create mode 100644 Tests/RunCMake/Syntax/OverrideWhile-result.txt diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index 37be542..9e5b783 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -119,12 +119,19 @@ void GetScriptingCommands(cmState* state) { - state->AddBuiltinCommand("break", cmBreakCommand); + state->AddFlowControlCommand("break", cmBreakCommand); + state->AddFlowControlCommand("continue", cmContinueCommand); + state->AddFlowControlCommand("foreach", cmForEachCommand); + state->AddFlowControlCommand("function", cmFunctionCommand); + state->AddFlowControlCommand("if", cmIfCommand); + state->AddFlowControlCommand("macro", cmMacroCommand); + state->AddFlowControlCommand("return", cmReturnCommand); + state->AddFlowControlCommand("while", cmWhileCommand); + state->AddBuiltinCommand("cmake_minimum_required", cmCMakeMinimumRequired); state->AddBuiltinCommand("cmake_path", cmCMakePathCommand); state->AddBuiltinCommand("cmake_policy", cmCMakePolicyCommand); state->AddBuiltinCommand("configure_file", cmConfigureFileCommand); - state->AddBuiltinCommand("continue", cmContinueCommand); state->AddBuiltinCommand("exec_program", cmExecProgramCommand); state->AddBuiltinCommand("execute_process", cmExecuteProcessCommand); state->AddBuiltinCommand("file", cmFileCommand); @@ -133,26 +140,21 @@ void GetScriptingCommands(cmState* state) state->AddBuiltinCommand("find_package", cmFindPackage); state->AddBuiltinCommand("find_path", cmFindPath); state->AddBuiltinCommand("find_program", cmFindProgram); - state->AddBuiltinCommand("foreach", cmForEachCommand); - state->AddBuiltinCommand("function", cmFunctionCommand); state->AddBuiltinCommand("get_cmake_property", cmGetCMakePropertyCommand); state->AddBuiltinCommand("get_directory_property", cmGetDirectoryPropertyCommand); state->AddBuiltinCommand("get_filename_component", cmGetFilenameComponentCommand); state->AddBuiltinCommand("get_property", cmGetPropertyCommand); - state->AddBuiltinCommand("if", cmIfCommand); state->AddBuiltinCommand("include", cmIncludeCommand); state->AddBuiltinCommand("include_guard", cmIncludeGuardCommand); state->AddBuiltinCommand("list", cmListCommand); - state->AddBuiltinCommand("macro", cmMacroCommand); state->AddBuiltinCommand("make_directory", cmMakeDirectoryCommand); state->AddBuiltinCommand("mark_as_advanced", cmMarkAsAdvancedCommand); state->AddBuiltinCommand("math", cmMathCommand); state->AddBuiltinCommand("message", cmMessageCommand); state->AddBuiltinCommand("option", cmOptionCommand); state->AddBuiltinCommand("cmake_parse_arguments", cmParseArgumentsCommand); - state->AddBuiltinCommand("return", cmReturnCommand); state->AddBuiltinCommand("separate_arguments", cmSeparateArgumentsCommand); state->AddBuiltinCommand("set", cmSetCommand); state->AddBuiltinCommand("set_directory_properties", @@ -161,7 +163,6 @@ void GetScriptingCommands(cmState* state) state->AddBuiltinCommand("site_name", cmSiteNameCommand); state->AddBuiltinCommand("string", cmStringCommand); state->AddBuiltinCommand("unset", cmUnsetCommand); - state->AddBuiltinCommand("while", cmWhileCommand); state->AddUnexpectedCommand( "else", diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 71c82d6..1359009 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -163,8 +163,11 @@ bool cmFunctionFunctionBlocker::Replay( f.FilePath = this->GetStartingContext().FilePath; f.Line = this->GetStartingContext().Line; mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args.front(), std::move(f)); - return true; + return mf.GetState()->AddScriptedCommand( + this->Args.front(), + BT(std::move(f), + mf.GetBacktrace().Push(this->GetStartingContext())), + mf); } } // anonymous namespace diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index 5790e16..adebe02 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -24,6 +24,7 @@ #include "cmCommand.h" #include "cmDynamicLoader.h" #include "cmExecutionStatus.h" +#include "cmListFileCache.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmState.h" @@ -36,8 +37,6 @@ # include /* for malloc/free on QNX */ #endif -class cmListFileBacktrace; - namespace { const char* LastName = nullptr; @@ -256,10 +255,12 @@ bool cmLoadCommandCommand(std::vector const& args, // if the symbol is found call it to set the name on the // function blocker if (initFunction) { - status.GetMakefile().GetState()->AddScriptedCommand( + return status.GetMakefile().GetState()->AddScriptedCommand( args[0], - cmLegacyCommandWrapper(cm::make_unique(initFunction))); - return true; + BT( + cmLegacyCommandWrapper(cm::make_unique(initFunction)), + status.GetMakefile().GetBacktrace()), + status.GetMakefile()); } status.SetError("Attempt to load command failed. " "No init function found."); diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index 98f88c1..8c4b2a7 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -171,8 +171,11 @@ bool cmMacroFunctionBlocker::Replay(std::vector functions, f.Functions = std::move(functions); f.FilePath = this->GetStartingContext().FilePath; mf.RecordPolicies(f.Policies); - mf.GetState()->AddScriptedCommand(this->Args[0], std::move(f)); - return true; + return mf.GetState()->AddScriptedCommand( + this->Args[0], + BT(std::move(f), + mf.GetBacktrace().Push(this->GetStartingContext())), + mf); } } diff --git a/Source/cmState.cxx b/Source/cmState.cxx index d5ac9ae..77665f1 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -436,6 +436,19 @@ void cmState::AddBuiltinCommand(std::string const& name, }); } +void cmState::AddFlowControlCommand(std::string const& name, Command command) +{ + this->FlowControlCommands.insert(name); + this->AddBuiltinCommand(name, std::move(command)); +} + +void cmState::AddFlowControlCommand(std::string const& name, + BuiltinCommand command) +{ + this->FlowControlCommands.insert(name); + this->AddBuiltinCommand(name, command); +} + void cmState::AddDisallowedCommand(std::string const& name, BuiltinCommand command, cmPolicies::PolicyID policy, @@ -465,7 +478,7 @@ void cmState::AddDisallowedCommand(std::string const& name, void cmState::AddUnexpectedCommand(std::string const& name, const char* error) { - this->AddBuiltinCommand( + this->AddFlowControlCommand( name, [name, error](std::vector const&, cmExecutionStatus& status) -> bool { @@ -480,16 +493,28 @@ void cmState::AddUnexpectedCommand(std::string const& name, const char* error) }); } -void cmState::AddScriptedCommand(std::string const& name, Command command) +bool cmState::AddScriptedCommand(std::string const& name, BT command, + cmMakefile& mf) { std::string sName = cmSystemTools::LowerCase(name); + if (this->FlowControlCommands.count(sName)) { + mf.GetCMakeInstance()->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Built-in flow control command \"", sName, + "\" cannot be overridden."), + command.Backtrace); + cmSystemTools::SetFatalErrorOccured(); + return false; + } + // if the command already exists, give a new name to the old command. if (Command oldCmd = this->GetCommandByExactName(sName)) { this->ScriptedCommands["_" + sName] = oldCmd; } - this->ScriptedCommands[sName] = std::move(command); + this->ScriptedCommands[sName] = std::move(command.Value); + return true; } cmState::Command cmState::GetCommand(std::string const& name) const diff --git a/Source/cmState.h b/Source/cmState.h index 2aa57e0..0744f64 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "cmDefinitions.h" @@ -24,6 +25,7 @@ class cmCacheManager; class cmCommand; class cmGlobVerificationManager; +class cmMakefile; class cmStateSnapshot; class cmMessenger; class cmExecutionStatus; @@ -157,10 +159,13 @@ public: std::unique_ptr command); void AddBuiltinCommand(std::string const& name, Command command); void AddBuiltinCommand(std::string const& name, BuiltinCommand command); + void AddFlowControlCommand(std::string const& name, Command command); + void AddFlowControlCommand(std::string const& name, BuiltinCommand command); void AddDisallowedCommand(std::string const& name, BuiltinCommand command, cmPolicies::PolicyID policy, const char* message); void AddUnexpectedCommand(std::string const& name, const char* error); - void AddScriptedCommand(std::string const& name, Command command); + bool AddScriptedCommand(std::string const& name, BT command, + cmMakefile& mf); void RemoveBuiltinCommand(std::string const& name); void RemoveUserDefinedCommands(); std::vector GetCommandNames() const; @@ -223,6 +228,7 @@ private: std::vector EnabledLanguages; std::unordered_map BuiltinCommands; std::unordered_map ScriptedCommands; + std::unordered_set FlowControlCommands; cmPropertyMap GlobalProperties; std::unique_ptr CacheManager; std::unique_ptr GlobVerificationManager; diff --git a/Tests/RunCMake/Syntax/Override.cmake b/Tests/RunCMake/Syntax/Override.cmake new file mode 100644 index 0000000..af62db1 --- /dev/null +++ b/Tests/RunCMake/Syntax/Override.cmake @@ -0,0 +1,6 @@ +function(override) + function(${FUNCTION_NAME}) + endfunction() +endfunction() +override() +message(FATAL_ERROR "This shouldn't happen") diff --git a/Tests/RunCMake/Syntax/OverrideBreak-result.txt b/Tests/RunCMake/Syntax/OverrideBreak-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideBreak-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideContinue-result.txt b/Tests/RunCMake/Syntax/OverrideContinue-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideContinue-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideElse-result.txt b/Tests/RunCMake/Syntax/OverrideElse-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideElse-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideElseIf-result.txt b/Tests/RunCMake/Syntax/OverrideElseIf-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideElseIf-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideEndForeach-result.txt b/Tests/RunCMake/Syntax/OverrideEndForeach-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideEndForeach-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideEndFunction-result.txt b/Tests/RunCMake/Syntax/OverrideEndFunction-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideEndFunction-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideEndIf-result.txt b/Tests/RunCMake/Syntax/OverrideEndIf-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideEndIf-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideEndMacro-result.txt b/Tests/RunCMake/Syntax/OverrideEndMacro-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideEndMacro-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideEndWhile-result.txt b/Tests/RunCMake/Syntax/OverrideEndWhile-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideEndWhile-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideForeach-result.txt b/Tests/RunCMake/Syntax/OverrideForeach-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideForeach-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideFunction-result.txt b/Tests/RunCMake/Syntax/OverrideFunction-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideFunction-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideIf-result.txt b/Tests/RunCMake/Syntax/OverrideIf-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideIf-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideMacro-result.txt b/Tests/RunCMake/Syntax/OverrideMacro-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideMacro-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideReturn-result.txt b/Tests/RunCMake/Syntax/OverrideReturn-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideReturn-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/OverrideWhile-result.txt b/Tests/RunCMake/Syntax/OverrideWhile-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/Syntax/OverrideWhile-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/Syntax/RunCMakeTest.cmake b/Tests/RunCMake/Syntax/RunCMakeTest.cmake index 8d74dc1..3fc769d 100644 --- a/Tests/RunCMake/Syntax/RunCMakeTest.cmake +++ b/Tests/RunCMake/Syntax/RunCMakeTest.cmake @@ -122,3 +122,30 @@ run_cmake(FunctionUnmatched) run_cmake(FunctionUnmatchedForeach) run_cmake(MacroUnmatched) run_cmake(MacroUnmatchedForeach) + +function(run_override name) + string(TOLOWER "${name}" lname) + set(RunCMake_DEFAULT_stderr "^CMake Error at [^ +]*/Tests/RunCMake/Syntax/Override\\.cmake:[0-9]+ \\(function\\): + Built-in flow control command \"${lname}\" cannot be overridden\\. +Call Stack \\(most recent call first\\): + [^ +]*/Tests/RunCMake/Syntax/Override\\.cmake:[0-9]+ \\(override\\)$") + run_cmake_command(Override${name} "${CMAKE_COMMAND}" -DFUNCTION_NAME=${name} -P "${RunCMake_SOURCE_DIR}/Override.cmake") +endfunction() + +run_override(Break) +run_override(Continue) +run_override(Else) +run_override(ElseIf) +run_override(EndForeach) +run_override(EndFunction) +run_override(EndIf) +run_override(EndMacro) +run_override(EndWhile) +run_override(Foreach) +run_override(Function) +run_override(If) +run_override(Macro) +run_override(Return) +run_override(While) -- cgit v0.12 From 6d306a42da59e1277942078a5df7863c489e9600 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Fri, 23 Oct 2020 00:01:14 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 67d986a..48ea3f6 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 19) -set(CMake_VERSION_PATCH 20201022) +set(CMake_VERSION_PATCH 20201023) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From fb95d022522c76375506bc974552a04ffd87fd23 Mon Sep 17 00:00:00 2001 From: Christopher Tetreault Date: Thu, 22 Oct 2020 14:04:39 -0700 Subject: Help: Document case insensitivity for CMAKE_BUILD_TYPE The value of CMAKE_BUILD_TYPE is case insensitive. Furthermore, the actual value of the variable will have the same casing as the user specifies on the command line. --- Help/variable/CMAKE_BUILD_TYPE.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Help/variable/CMAKE_BUILD_TYPE.rst b/Help/variable/CMAKE_BUILD_TYPE.rst index 2d35635..405f7d5 100644 --- a/Help/variable/CMAKE_BUILD_TYPE.rst +++ b/Help/variable/CMAKE_BUILD_TYPE.rst @@ -18,3 +18,8 @@ in a build tree configured to build type ``Debug``, CMake will see to having :variable:`CMAKE_C_FLAGS_DEBUG _FLAGS_DEBUG>` settings get added to the :variable:`CMAKE_C_FLAGS _FLAGS>` settings. See also :variable:`CMAKE_CONFIGURATION_TYPES`. + +Note that configuration names are case-insensitive. The value of this +variable will be the same as it is specified when invoking CMake. +For instance, if ``-DCMAKE_BUILD_TYPE=ReLeAsE`` is specified, then the +value of ``CMAKE_BUILD_TYPE`` will be ``ReLeAsE``. -- cgit v0.12 From 5cdf37e4cccf85f7b4648591731c13d72d971c32 Mon Sep 17 00:00:00 2001 From: Haibo Huang Date: Mon, 12 Oct 2020 15:32:19 -0700 Subject: Android: Root searches within the NDK for unified toolchains Set `CMAKE_FIND_ROOT_PATH_MODE_*` appropriately. --- Modules/Platform/Android.cmake | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake index 8ffa1b2..17d056a 100644 --- a/Modules/Platform/Android.cmake +++ b/Modules/Platform/Android.cmake @@ -22,3 +22,41 @@ set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "") if(CMAKE_VS_PLATFORM_NAME STREQUAL "Tegra-Android") set(CMAKE_LINK_LIBRARY_FLAG "") endif() + +# Commonly used Android toolchain files that pre-date CMake upstream support +# set CMAKE_SYSTEM_VERSION to 1. Avoid interfering with them. +if(CMAKE_SYSTEM_VERSION EQUAL 1) + return() +endif() + +if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED) + # Tell CMake not to search host sysroots for headers/libraries. + # CMAKE_FIND_ROOT_PATH must be non-empty for CMAKE_FIND_ROOT_PATH_MODE_* == ONLY + # to be meaningful. The actual path used here is fairly meaningless since CMake + # doesn't handle the NDK sysroot layout (per-arch and per-verion subdirectories for + # libraries), so find_library is handled separately by CMAKE_SYSTEM_LIBRARY_PATH. + # https://github.com/android-ndk/ndk/issues/890 + if(NOT CMAKE_FIND_ROOT_PATH) + list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_ANDROID_NDK}") + endif() + + # Allow users to override these values in case they want more strict behaviors. + # For example, they may want to prevent the NDK's libz from being picked up so + # they can use their own. + # https://github.com/android-ndk/ndk/issues/517 + if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + endif() + + if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + endif() + + if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + endif() + + if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + endif() +endif() -- cgit v0.12 From a7f41a7ee4ba2564a03a1f9a752ff79828ef4b19 Mon Sep 17 00:00:00 2001 From: Haibo Huang Date: Tue, 13 Oct 2020 19:23:39 -0700 Subject: Android: Fix find_* search order within NDK for unified toolchains --- Modules/Platform/Android.cmake | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Modules/Platform/Android.cmake b/Modules/Platform/Android.cmake index 17d056a..80d81aa 100644 --- a/Modules/Platform/Android.cmake +++ b/Modules/Platform/Android.cmake @@ -59,4 +59,40 @@ if(CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED) if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) endif() + + # find_library's default search paths below a prefix do not match the Android + # sysroot layout, so we need to give the direct path to the libraries + # via CMAKE_SYSTEM_*_PATH. + # + # Ideally we'd set CMAKE_SYSTEM_PREFIX_PATH. But that causes the + # non-api-level-specific path to be searched first for find_library, which will + # cause libdl.a to be found before libdl.so. + # https://github.com/android/ndk/issues/929 + + # Clears the paths set by UnixPaths.cmake. + set(CMAKE_SYSTEM_PREFIX_PATH) + set(CMAKE_SYSTEM_INCLUDE_PATH) + set(CMAKE_SYSTEM_LIBRARY_PATH) + + # Don't search paths in PATH environment variable. + if(NOT DEFINED CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH) + set(CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH OFF) + endif() + + # Allows CMake to find headers in the architecture-specific include directories. + set(CMAKE_LIBRARY_ARCHITECTURE "${CMAKE_ANDROID_ARCH_TRIPLE}") + + set(_ANDROID_SYSROOT_PREFIX "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/sysroot/usr") + + list(APPEND CMAKE_SYSTEM_INCLUDE_PATH + "${_ANDROID_SYSROOT_PREFIX}/include/${CMAKE_LIBRARY_ARCHITECTURE}") + list(APPEND CMAKE_SYSTEM_INCLUDE_PATH "${_ANDROID_SYSROOT_PREFIX}/include") + + # Instructs CMake to search the correct API level for libraries. + list(APPEND CMAKE_SYSTEM_LIBRARY_PATH + "${_ANDROID_SYSROOT_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}/${CMAKE_SYSTEM_VERSION}") + list(APPEND CMAKE_SYSTEM_LIBRARY_PATH + "${_ANDROID_SYSROOT_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}") + + list(APPEND CMAKE_SYSTEM_PROGRAM_PATH "${CMAKE_ANDROID_NDK_TOOLCHAIN_UNIFIED}/bin") endif() -- cgit v0.12 From ae7c81c6226cea5ae2fb5af53fa0d5a7b4bd3990 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 23 Oct 2020 08:42:02 -0400 Subject: ExternalData: add support for suppressing progress during the build During CI builds (at least), download progress is just noise. Allow it to be suppressed. Default to `OFF` for Ninja due to the tool's behavior of not showing output until a command is complete (which makes any progress reporting of little use) and `ON` otherwise. --- .../release/dev/ExternalData-suppress-progress.rst | 6 ++++ Modules/ExternalData.cmake | 40 ++++++++++++++++++++-- .../RunCMake/ExternalData/BadArguments-stderr.txt | 7 ++++ Tests/RunCMake/ExternalData/BadArguments.cmake | 5 +++ Tests/RunCMake/ExternalData/RunCMakeTest.cmake | 1 + 5 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 Help/release/dev/ExternalData-suppress-progress.rst create mode 100644 Tests/RunCMake/ExternalData/BadArguments-stderr.txt create mode 100644 Tests/RunCMake/ExternalData/BadArguments.cmake diff --git a/Help/release/dev/ExternalData-suppress-progress.rst b/Help/release/dev/ExternalData-suppress-progress.rst new file mode 100644 index 0000000..bf4183f --- /dev/null +++ b/Help/release/dev/ExternalData-suppress-progress.rst @@ -0,0 +1,6 @@ +ExternalData-suppress-progress +------------------------------ + +* The :module:`ExternalData` module ``ExternalData_add_target`` now supports a + ``SHOW_PROGRESS `` argument to suppress progress output during the + build. diff --git a/Modules/ExternalData.cmake b/Modules/ExternalData.cmake index 6fe8685..294167c 100644 --- a/Modules/ExternalData.cmake +++ b/Modules/ExternalData.cmake @@ -78,7 +78,8 @@ Module Functions manage local instances of data files stored externally:: ExternalData_Add_Target( - # Name of data management target + # Name of data management target + [SHOW_PROGRESS ] # Show progress during the download ) It creates custom commands in the target as necessary to make data @@ -89,6 +90,11 @@ Module Functions in one of the paths specified in the ``ExternalData_OBJECT_STORES`` variable. + The ``SHOW_PROGRESS`` argument may be passed to suppress progress information + during the download of objects. If not provided, it defaults to ``OFF`` for + :generator:`Ninja` and :generator:`Ninja Multi-Config` generators and ``ON`` + otherwise. + Typically only one target is needed to manage all external data within a project. Call this function once at the end of configuration after all data references have been processed. @@ -344,6 +350,30 @@ function(ExternalData_add_target target) endif() set(_ExternalData_CONFIG_CODE "") + cmake_parse_arguments(PARSE_ARGV 1 _ExternalData_add_target + "" + "SHOW_PROGRESS" + "") + if (_ExternalData_add_target_UNPARSED_ARGUMENTS) + message(AUTHOR_WARNING + "Ignoring unrecognized arguments passed to ExternalData_add_target: " + "`${_ExternalData_add_target_UNPARSED_ARGUMENTS}`") + endif () + + # Turn `SHOW_PROGRESS` into a boolean + if (NOT DEFINED _ExternalData_add_target_SHOW_PROGRESS) + # The default setting + if (CMAKE_GENERATOR MATCHES "Ninja") + set(_ExternalData_add_target_SHOW_PROGRESS OFF) + else () + set(_ExternalData_add_target_SHOW_PROGRESS ON) + endif () + elseif (_ExternalData_add_target_SHOW_PROGRESS) + set(_ExternalData_add_target_SHOW_PROGRESS ON) + else () + set(_ExternalData_add_target_SHOW_PROGRESS OFF) + endif () + # Store custom script configuration. foreach(url_template IN LISTS ExternalData_URL_TEMPLATES) if("${url_template}" MATCHES "^ExternalDataCustomScript://([^/]*)/(.*)$") @@ -423,6 +453,7 @@ function(ExternalData_add_target target) COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR} -Dfile=${file} -Dname=${name} -DExternalData_ACTION=local + -DExternalData_SHOW_PROGRESS=${_ExternalData_add_target_SHOW_PROGRESS} -DExternalData_CONFIG=${config} -P ${_ExternalData_SELF} MAIN_DEPENDENCY "${name}" @@ -459,6 +490,7 @@ function(ExternalData_add_target target) COMMAND ${CMAKE_COMMAND} -Drelative_top=${CMAKE_BINARY_DIR} -Dfile=${file} -Dname=${name} -Dexts=${exts} -DExternalData_ACTION=fetch + -DExternalData_SHOW_PROGRESS=${_ExternalData_add_target_SHOW_PROGRESS} -DExternalData_CONFIG=${config} -P ${_ExternalData_SELF} # Update whenever the object hash changes. @@ -925,7 +957,11 @@ function(_ExternalData_download_file url file err_var msg_var) else() set(absolute_timeout "") endif() - file(DOWNLOAD "${url}" "${file}" STATUS status LOG log ${inactivity_timeout} ${absolute_timeout} SHOW_PROGRESS) + set(show_progress_args) + if (ExternalData_SHOW_PROGRESS) + list(APPEND show_progress_args SHOW_PROGRESS) + endif () + file(DOWNLOAD "${url}" "${file}" STATUS status LOG log ${inactivity_timeout} ${absolute_timeout} ${show_progress_args}) list(GET status 0 err) list(GET status 1 msg) if(err) diff --git a/Tests/RunCMake/ExternalData/BadArguments-stderr.txt b/Tests/RunCMake/ExternalData/BadArguments-stderr.txt new file mode 100644 index 0000000..44efe7e --- /dev/null +++ b/Tests/RunCMake/ExternalData/BadArguments-stderr.txt @@ -0,0 +1,7 @@ +CMake Warning \(dev\) at .*/Modules/ExternalData.cmake:[0-9]+ \(message\): + Ignoring unrecognized arguments passed to ExternalData_add_target: + `UNKNOWN_ARGUMENT` +Call Stack \(most recent call first\): + BadArguments.cmake:[0-9]+ \(ExternalData_Add_Target\) + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it. diff --git a/Tests/RunCMake/ExternalData/BadArguments.cmake b/Tests/RunCMake/ExternalData/BadArguments.cmake new file mode 100644 index 0000000..dad0007 --- /dev/null +++ b/Tests/RunCMake/ExternalData/BadArguments.cmake @@ -0,0 +1,5 @@ +include(ExternalData) +set(ExternalData_URL_TEMPLATES + "file:///path/to/%(algo)/%(hash)" + ) +ExternalData_Add_Target(Data UNKNOWN_ARGUMENT) diff --git a/Tests/RunCMake/ExternalData/RunCMakeTest.cmake b/Tests/RunCMake/ExternalData/RunCMakeTest.cmake index b5ab22d..b4cc95e 100644 --- a/Tests/RunCMake/ExternalData/RunCMakeTest.cmake +++ b/Tests/RunCMake/ExternalData/RunCMakeTest.cmake @@ -2,6 +2,7 @@ include(RunCMake) run_cmake(BadAlgoMap1) run_cmake(BadAlgoMap2) +run_cmake(BadArguments) run_cmake(BadCustom1) run_cmake(BadCustom2) run_cmake(BadCustom3) -- cgit v0.12 From a8e9208f700dd37c2cee744f612741f5e9a3d9a1 Mon Sep 17 00:00:00 2001 From: Kitware Robot Date: Sat, 24 Oct 2020 00:01:19 -0400 Subject: CMake Nightly Date Stamp --- Source/CMakeVersion.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 48ea3f6..a410f6f 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 19) -set(CMake_VERSION_PATCH 20201023) +set(CMake_VERSION_PATCH 20201024) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) -- cgit v0.12 From 03ad0e61c19304ae145cfa0683b43d9756d37ff5 Mon Sep 17 00:00:00 2001 From: Asit Dhal Date: Sun, 4 Oct 2020 19:44:31 +0200 Subject: configure_file: Add option for user defined permissions User defined permissions and options to copy permissions are implemented. Fixes: #20866 --- Help/command/configure_file.rst | 9 +- .../dev/configure_file-user-permissions.rst | 6 ++ Source/CPack/cmCPackGenerator.cxx | 2 +- Source/cmConfigureFileCommand.cxx | 109 ++++++++++++++++++++- Source/cmCreateTestSourceList.cxx | 2 +- Source/cmLocalGenerator.cxx | 4 +- Source/cmMakefile.cxx | 20 +--- Source/cmMakefile.h | 5 +- Source/cmVisualStudio10TargetGenerator.cxx | 2 +- Tests/RunCMake/configure_file/RunCMakeTest.cmake | 7 ++ .../configure_file/SourcePermissions-result.txt | 0 .../configure_file/SourcePermissions-stderr.txt | 0 .../configure_file/SourcePermissions.cmake | 34 +++++++ .../SourcePermissionsInvalidArg-1-result.txt | 1 + .../SourcePermissionsInvalidArg-1-stderr.txt | 5 + .../SourcePermissionsInvalidArg-1.cmake | 5 + .../SourcePermissionsInvalidArg-2-result.txt | 1 + .../SourcePermissionsInvalidArg-2-stderr.txt | 5 + .../SourcePermissionsInvalidArg-2.cmake | 5 + .../SourcePermissionsInvalidArg-3-result.txt | 1 + .../SourcePermissionsInvalidArg-3-stderr.txt | 5 + .../SourcePermissionsInvalidArg-3.cmake | 5 + .../SourcePermissionsInvalidArg-4-result.txt | 1 + .../SourcePermissionsInvalidArg-4-stderr.txt | 4 + .../SourcePermissionsInvalidArg-4.cmake | 4 + .../SourcePermissionsInvalidArg-5-result.txt | 1 + .../SourcePermissionsInvalidArg-5-stderr.txt | 4 + .../SourcePermissionsInvalidArg-5.cmake | 6 ++ .../configure_file/UseSourcePermissions.cmake | 40 ++++++++ Tests/RunCMake/configure_file/sourcefile.txt | 1 + 30 files changed, 266 insertions(+), 28 deletions(-) create mode 100644 Help/release/dev/configure_file-user-permissions.rst create mode 100644 Tests/RunCMake/configure_file/SourcePermissions-result.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissions-stderr.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissions.cmake create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-result.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1-stderr.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-1.cmake create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-result.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2-stderr.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-2.cmake create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-result.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3-stderr.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-3.cmake create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-result.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4-stderr.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-4.cmake create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-result.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5-stderr.txt create mode 100644 Tests/RunCMake/configure_file/SourcePermissionsInvalidArg-5.cmake create mode 100644 Tests/RunCMake/configure_file/UseSourcePermissions.cmake create mode 100644 Tests/RunCMake/configure_file/sourcefile.txt diff --git a/Help/command/configure_file.rst b/Help/command/configure_file.rst index 46d1a05..5d55626 100644 --- a/Help/command/configure_file.rst +++ b/Help/command/configure_file.rst @@ -6,8 +6,9 @@ Copy a file to another location and modify its contents. .. code-block:: cmake configure_file( + [FILE_PERMISSIONS ...] [COPYONLY] [ESCAPE_QUOTES] [@ONLY] - [NO_SOURCE_PERMISSIONS] + [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS] [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ]) Copies an ```` file to an ```` file and substitutes @@ -72,6 +73,9 @@ The arguments are: If the path names an existing directory the output file is placed in that directory with the same file name as the input file. +``FILE_PERMISSIONS ...`` + Use user provided permissions for the output file. + ``COPYONLY`` Copy the file without replacing any variable references or other content. This option may not be used with ``NEWLINE_STYLE``. @@ -88,6 +92,9 @@ The arguments are: The copied file permissions default to the standard 644 value (-rw-r--r--). +``USE_SOURCE_PERMISSIONS`` + Transfer the file permissions of the original file to the output file. + ``NEWLINE_STYLE