summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/cmGeneratorTarget.cxx173
-rw-r--r--Source/cmGeneratorTarget.h5
-rw-r--r--Source/cmGlobalGenerator.cxx26
-rw-r--r--Source/cmGlobalGenerator.h2
-rw-r--r--Source/cmTarget.cxx1
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");