From 2f383d852d8d946a61419fe5f4b5c8501216dae9 Mon Sep 17 00:00:00 2001 From: Justin Goshi Date: Thu, 2 Jul 2020 11:26:20 -0700 Subject: fileapi: Support multiple backtraces for language standard --- Source/cmFileAPICodemodel.cxx | 69 +++++++++++++++++----- Source/cmGeneratorTarget.cxx | 19 +++--- Source/cmGeneratorTarget.h | 4 +- Source/cmStandardLevelResolver.cxx | 6 +- Source/cmTarget.cxx | 15 +++-- Source/cmTarget.h | 2 +- ...ndard_compile_feature_exe_languagestandard.json | 18 +++++- Tests/RunCMake/FileAPI/cxx/CMakeLists.txt | 1 + 8 files changed, 102 insertions(+), 32 deletions(-) diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index ca1ed56..e9af208 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -175,6 +175,38 @@ public: } }; +template +class JBTs +{ +public: + JBTs(T v = T(), std::vector ids = std::vector()) + : Value(std::move(v)) + , Backtraces(std::move(ids)) + { + } + T Value; + std::vector Backtraces; + friend bool operator==(JBTs const& l, JBTs const& r) + { + if ((l.Value == r.Value) && (l.Backtraces.size() == r.Backtraces.size())) { + for (size_t i = 0; i < l.Backtraces.size(); i++) { + if (l.Backtraces[i].Index != r.Backtraces[i].Index) { + return false; + } + } + } + return true; + } + static bool ValueEq(JBTs const& l, JBTs const& r) + { + return l.Value == r.Value; + } + static bool ValueLess(JBTs const& l, JBTs const& r) + { + return l.Value < r.Value; + } +}; + class BacktraceData { std::string TopSource; @@ -277,7 +309,7 @@ struct CompileData std::string Language; std::string Sysroot; - JBT LanguageStandard; + JBTs LanguageStandard; std::vector> Flags; std::vector> Defines; std::vector> PrecompileHeaders; @@ -323,8 +355,10 @@ struct hash hash()(i.Backtrace.Index); } if (!in.LanguageStandard.Value.empty()) { - result = result ^ hash()(in.LanguageStandard.Value) ^ - hash()(in.LanguageStandard.Backtrace.Index); + result = result ^ hash()(in.LanguageStandard.Value); + for (JBTIndex backtrace : in.LanguageStandard.Backtraces) { + result = result ^ hash()(backtrace.Index); + } } return result; } @@ -369,6 +403,16 @@ class Target return JBT(bt.Value, this->Backtraces.Add(bt.Backtrace)); } + template + JBTs ToJBTs(BTs const& bts) + { + std::vector ids; + for (cmListFileBacktrace const& backtrace : bts.Backtraces) { + ids.emplace_back(this->Backtraces.Add(backtrace)); + } + return JBTs(bts.Value, ids); + } + void ProcessLanguages(); void ProcessLanguage(std::string const& lang); @@ -383,7 +427,7 @@ class Target Json::Value DumpCompileData(CompileData const& cd); Json::Value DumpInclude(CompileData::IncludeEntry const& inc); Json::Value DumpPrecompileHeader(JBT const& header); - Json::Value DumpLanguageStandard(JBT const& standard); + Json::Value DumpLanguageStandard(JBTs const& standard); Json::Value DumpDefine(JBT const& def); Json::Value DumpSources(); Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk, @@ -845,10 +889,10 @@ void Target::ProcessLanguage(std::string const& lang) for (BT const& pch : precompileHeaders) { cd.PrecompileHeaders.emplace_back(this->ToJBT(pch)); } - BT const* languageStandard = + BTs const* languageStandard = this->GT->GetLanguageStandardProperty(lang, this->Config); if (languageStandard) { - cd.LanguageStandard = this->ToJBT(*languageStandard); + cd.LanguageStandard = this->ToJBTs(*languageStandard); } } @@ -1195,18 +1239,15 @@ Json::Value Target::DumpPrecompileHeader(JBT const& header) return precompileHeader; } -Json::Value Target::DumpLanguageStandard(JBT const& standard) +Json::Value Target::DumpLanguageStandard(JBTs const& standard) { Json::Value languageStandard = Json::objectValue; languageStandard["standard"] = standard.Value; - if (standard.Backtrace) { - // Only one backtrace is currently stored for a given language standard, - // but we represent this as an array because it's possible for multiple - // compile features to set the same language standard value. Representing - // this as an array will allow things to just work once we support storing - // multiple backtraces for a language standard value. + if (!standard.Backtraces.empty()) { Json::Value backtraces = Json::arrayValue; - backtraces.append(standard.Backtrace.Index); + for (JBTIndex backtrace : standard.Backtraces) { + backtraces.append(backtrace.Index); + } languageStandard["backtraces"] = backtraces; } return languageStandard; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index cc6f817..ccd8e7e 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -949,7 +949,7 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const return it != this->ExplicitObjectName.end(); } -BT const* cmGeneratorTarget::GetLanguageStandardProperty( +BTs const* cmGeneratorTarget::GetLanguageStandardProperty( std::string const& lang, std::string const& config) const { std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang); @@ -965,7 +965,7 @@ BT const* cmGeneratorTarget::GetLanguageStandardProperty( cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang, std::string const& config) const { - BT const* languageStandard = + BTs const* languageStandard = this->GetLanguageStandardProperty(lang, config); if (languageStandard) { @@ -4486,8 +4486,13 @@ bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const } if (!newRequiredStandard.empty()) { - this->LanguageStandardMap[key] = - BT(newRequiredStandard, f.Backtrace); + BTs& languageStandardProperty = + this->LanguageStandardMap[key]; + if (languageStandardProperty.Value != newRequiredStandard) { + languageStandardProperty.Value = newRequiredStandard; + languageStandardProperty.Backtraces.clear(); + } + languageStandardProperty.Backtraces.emplace_back(f.Backtrace); } } @@ -4498,14 +4503,14 @@ bool cmGeneratorTarget::ComputeCompileFeatures( std::string const& config, std::set const& languagePairs) const { for (const auto& language : languagePairs) { - BT const* generatorTargetLanguageStandard = + BTs const* generatorTargetLanguageStandard = this->GetLanguageStandardProperty(language.first, config); if (!generatorTargetLanguageStandard) { // If the standard isn't explicitly set we copy it over from the // specified paired language. std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', language.first); - BT const* standardToCopy = + BTs const* standardToCopy = this->GetLanguageStandardProperty(language.second, config); if (standardToCopy != nullptr) { this->LanguageStandardMap[key] = *standardToCopy; @@ -4514,7 +4519,7 @@ bool cmGeneratorTarget::ComputeCompileFeatures( cmProp defaultStandard = this->Makefile->GetDef( cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT")); if (defaultStandard != nullptr) { - this->LanguageStandardMap[key] = BT(*defaultStandard); + this->LanguageStandardMap[key] = BTs(*defaultStandard); generatorTargetLanguageStandard = &this->LanguageStandardMap[key]; } } diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 20f3a07..07f071b 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -148,7 +148,7 @@ public: bool HasExplicitObjectName(cmSourceFile const* file) const; void AddExplicitObjectName(cmSourceFile const* sf); - BT const* GetLanguageStandardProperty( + BTs const* GetLanguageStandardProperty( std::string const& lang, std::string const& config) const; cmProp GetLanguageStandard(std::string const& lang, @@ -1053,7 +1053,7 @@ private: bool GetRPATH(const std::string& config, const std::string& prop, std::string& rpath) const; - mutable std::map> LanguageStandardMap; + mutable std::map> LanguageStandardMap; cmProp GetPropertyWithPairedLanguageSupport(std::string const& lang, const char* suffix) const; diff --git a/Source/cmStandardLevelResolver.cxx b/Source/cmStandardLevelResolver.cxx index 3592b11..5e30680 100644 --- a/Source/cmStandardLevelResolver.cxx +++ b/Source/cmStandardLevelResolver.cxx @@ -58,7 +58,11 @@ struct StanardLevelComputer std::string& newRequiredStandard, std::string* error) const { - newRequiredStandard.clear(); + if (currentLangStandardValue) { + newRequiredStandard = *currentLangStandardValue; + } else { + newRequiredStandard.clear(); + } auto needed = this->HighestStandardNeeded(makefile, feature); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 72c7600..a4f9083 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -186,7 +186,7 @@ public: std::vector InstallGenerators; std::set SystemIncludeDirectories; cmTarget::LinkLibraryVectorType OriginalLinkLibraries; - std::map> LanguageStandardProperties; + std::map> LanguageStandardProperties; std::vector IncludeDirectoriesEntries; std::vector IncludeDirectoriesBacktraces; std::vector CompileOptionsEntries; @@ -600,7 +600,7 @@ cmGlobalGenerator* cmTarget::GetGlobalGenerator() const return impl->Makefile->GetGlobalGenerator(); } -BT const* cmTarget::GetLanguageStandardProperty( +BTs const* cmTarget::GetLanguageStandardProperty( const std::string& propertyName) const { auto entry = impl->LanguageStandardProperties.find(propertyName); @@ -625,8 +625,13 @@ void cmTarget::SetLanguageStandardProperty(std::string const& lang, } } - impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")] = - BT(value, featureBacktrace); + BTs& languageStandardProperty = + impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")]; + if (languageStandardProperty.Value != value) { + languageStandardProperty.Value = value; + languageStandardProperty.Backtraces.clear(); + } + languageStandardProperty.Backtraces.emplace_back(featureBacktrace); } void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf) @@ -1357,7 +1362,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value) prop == propOBJCXX_STANDARD) { if (value) { impl->LanguageStandardProperties[prop] = - BT(value, impl->Makefile->GetBacktrace()); + BTs(value, impl->Makefile->GetBacktrace()); } else { impl->LanguageStandardProperties.erase(prop); } diff --git a/Source/cmTarget.h b/Source/cmTarget.h index b3d6fe0..7a16de8 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -236,7 +236,7 @@ public: void AddSystemIncludeDirectories(std::set const& incs); std::set const& GetSystemIncludeDirectories() const; - BT const* GetLanguageStandardProperty( + BTs const* GetLanguageStandardProperty( const std::string& propertyName) const; void SetLanguageStandardProperty(std::string const& lang, diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe_languagestandard.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe_languagestandard.json index 57b4161..0c4eabb 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe_languagestandard.json +++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe_languagestandard.json @@ -15,8 +15,22 @@ "command": null, "hasParent": false } + ], + [ + { + "file": "^cxx/CMakeLists\\.txt$", + "line": 30, + "command": "target_compile_features", + "hasParent": true + }, + { + "file": "^cxx/CMakeLists\\.txt$", + "line": null, + "command": null, + "hasParent": false + } ] - ], - "standard" : "11" + ], + "standard" : "11" } } diff --git a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt index 5758cc4..76235f5 100644 --- a/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt +++ b/Tests/RunCMake/FileAPI/cxx/CMakeLists.txt @@ -27,5 +27,6 @@ add_executable(cxx_standard_compile_feature_exe ../empty.cxx) set_property(TARGET cxx_standard_compile_feature_exe PROPERTY CXX_STANDARD 98) if(CMAKE_CXX_STANDARD_DEFAULT AND DEFINED CMAKE_CXX11_STANDARD_COMPILE_OPTION) target_compile_features(cxx_standard_compile_feature_exe PRIVATE cxx_std_11) + target_compile_features(cxx_standard_compile_feature_exe PRIVATE cxx_decltype) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_std_11.txt" "") endif() -- cgit v0.12