summaryrefslogtreecommitdiff
path: root/Source/cmGeneratorTarget.cxx
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2022-02-24 18:09:53 -0500
committerKyle Edwards <kyle.edwards@kitware.com>2022-03-29 13:58:27 -0400
commitc798744f8193e97f00f1b6e47dc5bc6fdc34b222 (patch)
tree27b2dc2cbd04d45026319bbe006acd72bb0f3dff /Source/cmGeneratorTarget.cxx
parentfdbef2a2be1f070e0f0809536639ff20d80584e6 (diff)
downloadcmake-c798744f8193e97f00f1b6e47dc5bc6fdc34b222.tar.gz
FILE_SET: Add VERIFY_HEADER_SETS target property
Fixes: #23338
Diffstat (limited to 'Source/cmGeneratorTarget.cxx')
-rw-r--r--Source/cmGeneratorTarget.cxx173
1 files changed, 173 insertions, 0 deletions
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 1a13bdbf41..f1ab85ca91 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;
+}