diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 173 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 5 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.cxx | 26 | ||||
-rw-r--r-- | Source/cmGlobalGenerator.h | 2 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 1 |
5 files changed, 207 insertions, 0 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 1a13bdb..f1ab85c 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -8522,3 +8522,176 @@ cmGeneratorTarget::ManagedType cmGeneratorTarget::GetManagedType( // has to be set manually for C# targets. return this->IsCSharpOnly() ? ManagedType::Managed : ManagedType::Native; } + +bool cmGeneratorTarget::AddHeaderSetVerification() +{ + if (!this->GetPropertyAsBool("VERIFY_HEADER_SETS")) { + return true; + } + + if (this->GetType() != cmStateEnums::STATIC_LIBRARY && + this->GetType() != cmStateEnums::SHARED_LIBRARY && + this->GetType() != cmStateEnums::UNKNOWN_LIBRARY && + this->GetType() != cmStateEnums::OBJECT_LIBRARY && + this->GetType() != cmStateEnums::INTERFACE_LIBRARY && + !this->IsExecutableWithExports()) { + return true; + } + + cmTarget* verifyTarget = nullptr; + + auto interfaceFileSetEntries = this->Target->GetInterfaceHeaderSetsEntries(); + + std::set<cmFileSet*> fileSets; + auto const addFileSets = [&fileSets, this](const cmBTStringRange& entries) { + for (auto const& entry : entries) { + for (auto const& name : cmExpandedList(entry.Value)) { + fileSets.insert(this->Target->GetFileSet(name)); + } + } + }; + addFileSets(interfaceFileSetEntries); + + cm::optional<std::set<std::string>> languages; + for (auto* fileSet : fileSets) { + auto dirCges = fileSet->CompileDirectoryEntries(); + auto fileCges = fileSet->CompileFileEntries(); + + static auto const contextSensitive = + [](const std::unique_ptr<cmCompiledGeneratorExpression>& cge) { + return cge->GetHadContextSensitiveCondition(); + }; + bool dirCgesContextSensitive = false; + bool fileCgesContextSensitive = false; + + std::vector<std::string> dirs; + std::map<std::string, std::vector<std::string>> filesPerDir; + bool first = true; + for (auto const& config : this->Makefile->GetGeneratorConfigs( + cmMakefile::GeneratorConfigQuery::IncludeEmptyConfig)) { + if (first || dirCgesContextSensitive) { + dirs = fileSet->EvaluateDirectoryEntries(dirCges, this->LocalGenerator, + config, this); + dirCgesContextSensitive = + std::any_of(dirCges.begin(), dirCges.end(), contextSensitive); + } + if (first || fileCgesContextSensitive) { + filesPerDir.clear(); + for (auto const& fileCge : fileCges) { + fileSet->EvaluateFileEntry(dirs, filesPerDir, fileCge, + this->LocalGenerator, config, this); + if (fileCge->GetHadContextSensitiveCondition()) { + fileCgesContextSensitive = true; + } + } + } + + for (auto const& files : filesPerDir) { + for (auto const& file : files.second) { + std::string filename = this->GenerateHeaderSetVerificationFile( + *this->Makefile->GetOrCreateSource(file), files.first, languages); + if (filename.empty()) { + continue; + } + + if (!verifyTarget) { + { + cmMakefile::PolicyPushPop polScope(this->Makefile); + this->Makefile->SetPolicy(cmPolicies::CMP0119, cmPolicies::NEW); + verifyTarget = this->Makefile->AddLibrary( + cmStrCat(this->GetName(), "_verify_header_sets"), + cmStateEnums::OBJECT_LIBRARY, {}, true); + } + + verifyTarget->AddLinkLibrary( + *this->Makefile, this->GetName(), + cmTargetLinkLibraryType::GENERAL_LibraryType); + verifyTarget->SetProperty("AUTOMOC", "OFF"); + verifyTarget->SetProperty("AUTORCC", "OFF"); + verifyTarget->SetProperty("AUTOUIC", "OFF"); + verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON"); + verifyTarget->SetProperty("UNITY_BUILD", "OFF"); + } + + if (fileCgesContextSensitive) { + filename = cmStrCat("$<$<CONFIG:", config, ">:", filename, ">"); + } + verifyTarget->AddSource(filename); + } + } + + if (!dirCgesContextSensitive && !fileCgesContextSensitive) { + break; + } + first = false; + } + } + + if (verifyTarget) { + this->LocalGenerator->AddGeneratorTarget( + cm::make_unique<cmGeneratorTarget>(verifyTarget, this->LocalGenerator)); + } + + return true; +} + +std::string cmGeneratorTarget::GenerateHeaderSetVerificationFile( + cmSourceFile& source, const std::string& dir, + cm::optional<std::set<std::string>>& languages) const +{ + std::string extension; + std::string language = source.GetOrDetermineLanguage(); + + if (language.empty()) { + if (!languages) { + languages.emplace(); + for (auto const& tgtSource : this->GetAllConfigSources()) { + auto const& tgtSourceLanguage = + tgtSource.Source->GetOrDetermineLanguage(); + if (tgtSourceLanguage == "CXX") { + languages->insert("CXX"); + break; // C++ overrides everything else, so we don't need to keep + // checking. + } + if (tgtSourceLanguage == "C") { + languages->insert("C"); + } + } + } + + if (languages->count("CXX")) { + language = "CXX"; + } else if (languages->count("C")) { + language = "C"; + } + } + + if (language == "C") { + extension = ".c"; + } else if (language == "CXX") { + extension = ".cxx"; + } else { + return ""; + } + + std::string headerFilename = dir; + if (!headerFilename.empty()) { + headerFilename += '/'; + } + headerFilename += source.GetLocation().GetName(); + + auto filename = cmStrCat(this->LocalGenerator->GetCurrentBinaryDirectory(), + '/', this->GetName(), "_verify_header_sets/", + headerFilename, extension); + auto* verificationSource = this->Makefile->GetOrCreateSource(filename); + verificationSource->SetProperty("LANGUAGE", language); + + cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(filename)); + + cmGeneratedFileStream fout(filename); + fout.SetCopyIfDifferent(true); + fout << "#include <" << headerFilename << ">\n"; + fout.close(); + + return filename; +} diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 96e48a4..53844ae 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -868,6 +868,11 @@ public: std::vector<std::string> GetGeneratedISPCObjects( std::string const& config) const; + bool AddHeaderSetVerification(); + std::string GenerateHeaderSetVerificationFile( + cmSourceFile& source, const std::string& dir, + cm::optional<std::set<std::string>>& languages) const; + private: void AddSourceCommon(const std::string& src, bool before = false); diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index baa54e5..b869308 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1499,6 +1499,11 @@ bool cmGlobalGenerator::Compute() return false; } + // Iterate through all targets and add verification targets for header sets + if (!this->AddHeaderSetVerification()) { + return false; + } + // Iterate through all targets and set up AUTOMOC, AUTOUIC and AUTORCC if (!this->QtAutoGen()) { return false; @@ -1720,6 +1725,27 @@ bool cmGlobalGenerator::QtAutoGen() #endif } +bool cmGlobalGenerator::AddHeaderSetVerification() +{ + for (auto const& gen : this->LocalGenerators) { + // Because AddHeaderSetVerification() adds generator targets, we need to + // cache the existing list of generator targets before starting. + std::vector<cmGeneratorTarget*> genTargets; + genTargets.reserve(gen->GetGeneratorTargets().size()); + for (auto const& tgt : gen->GetGeneratorTargets()) { + genTargets.push_back(tgt.get()); + } + + for (auto* tgt : genTargets) { + if (!tgt->AddHeaderSetVerification()) { + return false; + } + } + } + + return true; +} + bool cmGlobalGenerator::AddAutomaticSources() { for (const auto& lg : this->LocalGenerators) { diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index a4b2ae3..5965a16 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -573,6 +573,8 @@ protected: /// @return true on success bool QtAutoGen(); + bool AddHeaderSetVerification(); + bool AddAutomaticSources(); std::string SelectMakeProgram(const std::string& makeProgram, diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 4ca1b9b..e2314e2 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -425,6 +425,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, } initProp("FOLDER"); + initProp("VERIFY_HEADER_SETS"); if (this->GetGlobalGenerator()->IsXcode()) { initProp("XCODE_GENERATE_SCHEME"); |