| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 | 
							- /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
 
-    file Copyright.txt or https://cmake.org/licensing for details.  */
 
- #include "cmStandardLevelResolver.h"
 
- #include <algorithm>
 
- #include <cassert>
 
- #include <cstddef>
 
- #include <sstream>
 
- #include <unordered_map>
 
- #include <utility>
 
- #include <vector>
 
- #include <cm/iterator>
 
- #include <cmext/algorithm>
 
- #include "cmGeneratorExpression.h"
 
- #include "cmGeneratorTarget.h"
 
- #include "cmGlobalGenerator.h"
 
- #include "cmMakefile.h"
 
- #include "cmMessageType.h"
 
- #include "cmProperty.h"
 
- #include "cmStringAlgorithms.h"
 
- #include "cmTarget.h"
 
- #include "cmake.h"
 
- namespace {
 
- #define FEATURE_STRING(F) , #F
 
- const char* const C_FEATURES[] = { nullptr FOR_EACH_C_FEATURE(
 
-   FEATURE_STRING) };
 
- const char* const CXX_FEATURES[] = { nullptr FOR_EACH_CXX_FEATURE(
 
-   FEATURE_STRING) };
 
- const char* const CUDA_FEATURES[] = { nullptr FOR_EACH_CUDA_FEATURE(
 
-   FEATURE_STRING) };
 
- #undef FEATURE_STRING
 
- struct StandardNeeded
 
- {
 
-   int index;
 
-   int value;
 
- };
 
- struct StanardLevelComputer
 
- {
 
-   explicit StanardLevelComputer(std::string lang, std::vector<int> levels)
 
-     : Language(std::move(lang))
 
-     , Levels(std::move(levels))
 
-   {
 
-   }
 
-   bool GetNewRequiredStandard(cmMakefile* makefile,
 
-                               std::string const& targetName,
 
-                               const std::string& feature,
 
-                               cmProp currentLangStandardValue,
 
-                               std::string& newRequiredStandard,
 
-                               std::string* error) const
 
-   {
 
-     newRequiredStandard.clear();
 
-     auto needed = this->HighestStandardNeeded(makefile, feature);
 
-     cmProp existingStandard = currentLangStandardValue;
 
-     if (existingStandard == nullptr) {
 
-       cmProp defaultStandard = makefile->GetDef(
 
-         cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
 
-       if (defaultStandard && !defaultStandard->empty()) {
 
-         existingStandard = defaultStandard;
 
-       }
 
-     }
 
-     auto existingLevelIter = cm::cend(this->Levels);
 
-     if (existingStandard) {
 
-       existingLevelIter =
 
-         std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
 
-                   std::stoi(*existingStandard));
 
-       if (existingLevelIter == cm::cend(this->Levels)) {
 
-         const std::string e =
 
-           cmStrCat("The ", this->Language, "_STANDARD property on target \"",
 
-                    targetName, "\" contained an invalid value: \"",
 
-                    *existingStandard, "\".");
 
-         if (error) {
 
-           *error = e;
 
-         } else {
 
-           makefile->IssueMessage(MessageType::FATAL_ERROR, e);
 
-         }
 
-         return false;
 
-       }
 
-     }
 
-     if (needed.index != -1) {
 
-       // Ensure the C++ language level is high enough to support
 
-       // the needed C++ features.
 
-       if (existingLevelIter == cm::cend(this->Levels) ||
 
-           existingLevelIter < this->Levels.begin() + needed.index) {
 
-         newRequiredStandard = std::to_string(this->Levels[needed.index]);
 
-       }
 
-     }
 
-     return true;
 
-   }
 
-   bool HaveStandardAvailable(cmMakefile* makefile,
 
-                              cmGeneratorTarget const* target,
 
-                              std::string const& config,
 
-                              std::string const& feature) const
 
-   {
 
-     cmProp defaultStandard = makefile->GetDef(
 
-       cmStrCat("CMAKE_", this->Language, "_STANDARD_DEFAULT"));
 
-     if (!defaultStandard) {
 
-       makefile->IssueMessage(
 
-         MessageType::INTERNAL_ERROR,
 
-         cmStrCat("CMAKE_", this->Language,
 
-                  "_STANDARD_DEFAULT is not set.  COMPILE_FEATURES support "
 
-                  "not fully configured for this compiler."));
 
-       // Return true so the caller does not try to lookup the default standard.
 
-       return true;
 
-     }
 
-     // convert defaultStandard to an integer
 
-     if (std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
 
-                   std::stoi(*defaultStandard)) == cm::cend(this->Levels)) {
 
-       const std::string e = cmStrCat("The CMAKE_", this->Language,
 
-                                      "_STANDARD_DEFAULT variable contains an "
 
-                                      "invalid value: \"",
 
-                                      *defaultStandard, "\".");
 
-       makefile->IssueMessage(MessageType::INTERNAL_ERROR, e);
 
-       return false;
 
-     }
 
-     cmProp existingStandard =
 
-       target->GetLanguageStandard(this->Language, config);
 
-     if (!existingStandard) {
 
-       existingStandard = defaultStandard;
 
-     }
 
-     auto existingLevelIter =
 
-       std::find(cm::cbegin(this->Levels), cm::cend(this->Levels),
 
-                 std::stoi(*existingStandard));
 
-     if (existingLevelIter == cm::cend(this->Levels)) {
 
-       const std::string e =
 
-         cmStrCat("The ", this->Language, "_STANDARD property on target \"",
 
-                  target->GetName(), "\" contained an invalid value: \"",
 
-                  *existingStandard, "\".");
 
-       makefile->IssueMessage(MessageType::FATAL_ERROR, e);
 
-       return false;
 
-     }
 
-     auto needed = this->HighestStandardNeeded(makefile, feature);
 
-     return (needed.index == -1) ||
 
-       (this->Levels.begin() + needed.index) <= existingLevelIter;
 
-   }
 
-   StandardNeeded HighestStandardNeeded(cmMakefile* makefile,
 
-                                        std::string const& feature) const
 
-   {
 
-     std::string prefix = cmStrCat("CMAKE_", this->Language);
 
-     StandardNeeded maxLevel = { -1, -1 };
 
-     for (size_t i = 0; i < this->Levels.size(); ++i) {
 
-       if (const char* prop = makefile->GetDefinition(cmStrCat(
 
-             prefix, std::to_string(this->Levels[i]), "_COMPILE_FEATURES"))) {
 
-         std::vector<std::string> props = cmExpandedList(prop);
 
-         if (cm::contains(props, feature)) {
 
-           maxLevel = { static_cast<int>(i), this->Levels[i] };
 
-         }
 
-       }
 
-     }
 
-     return maxLevel;
 
-   }
 
-   bool IsLaterStandard(int lhs, int rhs) const
 
-   {
 
-     auto rhsIt =
 
-       std::find(cm::cbegin(this->Levels), cm::cend(this->Levels), rhs);
 
-     return std::find(rhsIt, cm::cend(this->Levels), lhs) !=
 
-       cm::cend(this->Levels);
 
-   }
 
-   std::string Language;
 
-   std::vector<int> Levels;
 
- };
 
- std::unordered_map<std::string, StanardLevelComputer> StandardComputerMapping =
 
-   {
 
-     { "C", StanardLevelComputer{ "C", std::vector<int>{ 90, 99, 11 } } },
 
-     { "CXX",
 
-       StanardLevelComputer{ "CXX", std::vector<int>{ 98, 11, 14, 17, 20 } } },
 
-     { "CUDA",
 
-       StanardLevelComputer{ "CUDA", std::vector<int>{ 03, 11, 14, 17, 20 } } },
 
-     { "OBJC", StanardLevelComputer{ "OBJC", std::vector<int>{ 90, 99, 11 } } },
 
-     { "OBJCXX",
 
-       StanardLevelComputer{ "OBJCXX",
 
-                             std::vector<int>{ 98, 11, 14, 17, 20 } } },
 
-   };
 
- }
 
- bool cmStandardLevelResolver::AddRequiredTargetFeature(
 
-   cmTarget* target, const std::string& feature, std::string* error) const
 
- {
 
-   if (cmGeneratorExpression::Find(feature) != std::string::npos) {
 
-     target->AppendProperty("COMPILE_FEATURES", feature);
 
-     return true;
 
-   }
 
-   std::string lang;
 
-   if (!this->CheckCompileFeaturesAvailable(target->GetName(), feature, lang,
 
-                                            error)) {
 
-     return false;
 
-   }
 
-   target->AppendProperty("COMPILE_FEATURES", feature);
 
-   // FIXME: Add a policy to avoid updating the <LANG>_STANDARD target
 
-   // property due to COMPILE_FEATURES.  The language standard selection
 
-   // should be done purely at generate time based on whatever the project
 
-   // code put in these properties explicitly.  That is mostly true now,
 
-   // but for compatibility we need to continue updating the property here.
 
-   std::string newRequiredStandard;
 
-   bool newRequired = this->GetNewRequiredStandard(
 
-     target->GetName(), feature,
 
-     target->GetProperty(cmStrCat(lang, "_STANDARD")), newRequiredStandard,
 
-     error);
 
-   if (!newRequiredStandard.empty()) {
 
-     target->SetProperty(cmStrCat(lang, "_STANDARD"), newRequiredStandard);
 
-   }
 
-   return newRequired;
 
- }
 
- bool cmStandardLevelResolver::CheckCompileFeaturesAvailable(
 
-   const std::string& targetName, const std::string& feature, std::string& lang,
 
-   std::string* error) const
 
- {
 
-   if (!this->CompileFeatureKnown(targetName, feature, lang, error)) {
 
-     return false;
 
-   }
 
-   const char* features = this->CompileFeaturesAvailable(lang, error);
 
-   if (!features) {
 
-     return false;
 
-   }
 
-   std::vector<std::string> availableFeatures = cmExpandedList(features);
 
-   if (!cm::contains(availableFeatures, feature)) {
 
-     std::ostringstream e;
 
-     e << "The compiler feature \"" << feature << "\" is not known to " << lang
 
-       << " compiler\n\""
 
-       << this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILER_ID")
 
-       << "\"\nversion "
 
-       << this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILER_VERSION")
 
-       << ".";
 
-     if (error) {
 
-       *error = e.str();
 
-     } else {
 
-       this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
 
-     }
 
-     return false;
 
-   }
 
-   return true;
 
- }
 
- bool cmStandardLevelResolver::CompileFeatureKnown(
 
-   const std::string& targetName, const std::string& feature, std::string& lang,
 
-   std::string* error) const
 
- {
 
-   assert(cmGeneratorExpression::Find(feature) == std::string::npos);
 
-   bool isCFeature =
 
-     std::find_if(cm::cbegin(C_FEATURES) + 1, cm::cend(C_FEATURES),
 
-                  cmStrCmp(feature)) != cm::cend(C_FEATURES);
 
-   if (isCFeature) {
 
-     lang = "C";
 
-     return true;
 
-   }
 
-   bool isCxxFeature =
 
-     std::find_if(cm::cbegin(CXX_FEATURES) + 1, cm::cend(CXX_FEATURES),
 
-                  cmStrCmp(feature)) != cm::cend(CXX_FEATURES);
 
-   if (isCxxFeature) {
 
-     lang = "CXX";
 
-     return true;
 
-   }
 
-   bool isCudaFeature =
 
-     std::find_if(cm::cbegin(CUDA_FEATURES) + 1, cm::cend(CUDA_FEATURES),
 
-                  cmStrCmp(feature)) != cm::cend(CUDA_FEATURES);
 
-   if (isCudaFeature) {
 
-     lang = "CUDA";
 
-     return true;
 
-   }
 
-   std::ostringstream e;
 
-   if (error) {
 
-     e << "specified";
 
-   } else {
 
-     e << "Specified";
 
-   }
 
-   e << " unknown feature \"" << feature
 
-     << "\" for "
 
-        "target \""
 
-     << targetName << "\".";
 
-   if (error) {
 
-     *error = e.str();
 
-   } else {
 
-     this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
 
-   }
 
-   return false;
 
- }
 
- const char* cmStandardLevelResolver::CompileFeaturesAvailable(
 
-   const std::string& lang, std::string* error) const
 
- {
 
-   if (!this->Makefile->GetGlobalGenerator()->GetLanguageEnabled(lang)) {
 
-     std::ostringstream e;
 
-     if (error) {
 
-       e << "cannot";
 
-     } else {
 
-       e << "Cannot";
 
-     }
 
-     e << " use features from non-enabled language " << lang;
 
-     if (error) {
 
-       *error = e.str();
 
-     } else {
 
-       this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
 
-     }
 
-     return nullptr;
 
-   }
 
-   const char* featuresKnown =
 
-     this->Makefile->GetDefinition("CMAKE_" + lang + "_COMPILE_FEATURES");
 
-   if (!featuresKnown || !*featuresKnown) {
 
-     std::ostringstream e;
 
-     if (error) {
 
-       e << "no";
 
-     } else {
 
-       e << "No";
 
-     }
 
-     e << " known features for " << lang << " compiler\n\""
 
-       << this->Makefile->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_ID")
 
-       << "\"\nversion "
 
-       << this->Makefile->GetSafeDefinition("CMAKE_" + lang +
 
-                                            "_COMPILER_VERSION")
 
-       << ".";
 
-     if (error) {
 
-       *error = e.str();
 
-     } else {
 
-       this->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str());
 
-     }
 
-     return nullptr;
 
-   }
 
-   return featuresKnown;
 
- }
 
- bool cmStandardLevelResolver::GetNewRequiredStandard(
 
-   const std::string& targetName, const std::string& feature,
 
-   cmProp currentLangStandardValue, std::string& newRequiredStandard,
 
-   std::string* error) const
 
- {
 
-   std::string lang;
 
-   if (!this->CheckCompileFeaturesAvailable(targetName, feature, lang, error)) {
 
-     return false;
 
-   }
 
-   auto mapping = StandardComputerMapping.find(lang);
 
-   if (mapping != cm::cend(StandardComputerMapping)) {
 
-     return mapping->second.GetNewRequiredStandard(
 
-       this->Makefile, targetName, feature, currentLangStandardValue,
 
-       newRequiredStandard, error);
 
-   }
 
-   return false;
 
- }
 
- bool cmStandardLevelResolver::HaveStandardAvailable(
 
-   cmGeneratorTarget const* target, std::string const& lang,
 
-   std::string const& config, const std::string& feature) const
 
- {
 
-   auto mapping = StandardComputerMapping.find(lang);
 
-   if (mapping != cm::cend(StandardComputerMapping)) {
 
-     return mapping->second.HaveStandardAvailable(this->Makefile, target,
 
-                                                  config, feature);
 
-   }
 
-   return false;
 
- }
 
- bool cmStandardLevelResolver::IsLaterStandard(std::string const& lang,
 
-                                               std::string const& lhs,
 
-                                               std::string const& rhs) const
 
- {
 
-   auto mapping = StandardComputerMapping.find(lang);
 
-   if (mapping != cm::cend(StandardComputerMapping)) {
 
-     return mapping->second.IsLaterStandard(std::stoi(lhs), std::stoi(rhs));
 
-   }
 
-   return false;
 
- }
 
 
  |