From 2f9637338940ee5c1848044eb6e3f74acb7ec566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Germain?= Date: Tue, 17 Mar 2026 20:32:10 -0700 Subject: [PATCH] cmGeneratorTarget: refactor header set verification to collect then create Separate the collection of verification stubs from the creation of the verification target. Previously, the target was created lazily on the first stub found, with subsequent stubs added incrementally. Now, all stubs are collected into a vector first, and the target is created afterward with all sources at once. No behavior change; this is a pure refactoring to prepare for creating targets even when no stubs are found. --- Source/cmGeneratorTarget.cxx | 179 +++++++++++++++++------------------ 1 file changed, 89 insertions(+), 90 deletions(-) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 1b3b38528d..327fef8d64 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -5863,6 +5863,10 @@ bool cmGeneratorTarget::AddHeaderSetVerification() } cm::optional> defaultLanguage; + + // First, collect all verification stubs before creating the target, + // so we know whether to create an OBJECT library or not. + std::vector stubSources; for (auto const* fileSet : fileSets) { auto const& dirCges = fileSet->CompileDirectoryEntries(); auto const& fileCges = fileSet->CompileFileEntries(); @@ -5907,93 +5911,10 @@ bool cmGeneratorTarget::AddHeaderSetVerification() } std::string filename = *filenameOpt; - if (!verifyTarget) { - { - cmMakefile::PolicyPushPop polScope(this->Makefile); - this->Makefile->SetPolicy(cmPolicies::CMP0119, - cmPolicies::NEW); - verifyTarget = this->Makefile->AddLibrary( - verifyTargetName, cmStateEnums::OBJECT_LIBRARY, {}, true); - } - - if (isInterface) { - // Link to the original target so that we pick up its - // interface compile options just like a consumer would. - // This also ensures any generated headers in the original - // target will be created. - verifyTarget->AddLinkLibrary( - *this->Makefile, this->GetName(), - cmTargetLinkLibraryType::GENERAL_LibraryType); - } else { - // For private file sets, we need to simulate compiling the - // same way as the original target. That includes linking to - // the same things so we pick up the same transitive - // properties. For the _... properties, we don't care if - // we set them for languages this target won't eventually use. - // Copy language-standard properties for all supported - // languages. We don't care if we set properties for languages - // this target won't eventually use. - static std::array const propertiesToCopy{ { - "COMPILE_DEFINITIONS", "COMPILE_FEATURES", - "COMPILE_FLAGS", "COMPILE_OPTIONS", - "DEFINE_SYMBOL", "INCLUDE_DIRECTORIES", - "LINK_LIBRARIES", "C_STANDARD", - "C_STANDARD_REQUIRED", "C_EXTENSIONS", - "CXX_STANDARD", "CXX_STANDARD_REQUIRED", - "CXX_EXTENSIONS", "OBJC_STANDARD", - "OBJC_STANDARD_REQUIRED", "OBJC_EXTENSIONS", - "OBJCXX_STANDARD", "OBJCXX_STANDARD_REQUIRED", - "OBJCXX_EXTENSIONS", - } }; - for (std::string const& prop : propertiesToCopy) { - cmValue propValue = this->Target->GetProperty(prop); - if (propValue.IsSet()) { - verifyTarget->SetProperty(prop, propValue); - } - } - // The original target might have generated headers. Since - // we only link to the original target for compilation, - // there's nothing to force such generation to happen yet. - // Our verify target must depend on the original target to - // ensure such generated files will be created. - verifyTarget->AddUtility(this->GetName(), false, - this->Makefile); - verifyTarget->AddCodegenDependency(this->GetName()); - } - - verifyTarget->SetProperty("AUTOMOC", "OFF"); - verifyTarget->SetProperty("AUTORCC", "OFF"); - verifyTarget->SetProperty("AUTOUIC", "OFF"); - verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON"); - verifyTarget->SetProperty("UNITY_BUILD", "OFF"); - verifyTarget->SetProperty("CXX_SCAN_FOR_MODULES", "OFF"); - - if (isInterface) { - verifyTarget->FinalizeTargetConfiguration( - this->Makefile->GetCompileDefinitionsEntries()); - } else { - // Private verification only needs to add the directory scope - // definitions here - for (auto const& def : - this->Makefile->GetCompileDefinitionsEntries()) { - verifyTarget->InsertCompileDefinition(def); - } - } - - if (!allVerifyTarget) { - allVerifyTarget = - this->GlobalGenerator->GetMakefiles() - .front() - ->AddNewUtilityTarget(allVerifyTargetName, true); - } - - allVerifyTarget->AddUtility(verifyTargetName, false); - } - if (fileCgesContextSensitive) { filename = cmStrCat("$<$:", filename, '>'); } - verifyTarget->AddSource(filename); + stubSources.emplace_back(std::move(filename)); } } @@ -6004,13 +5925,91 @@ bool cmGeneratorTarget::AddHeaderSetVerification() } } - if (verifyTarget) { - this->LocalGenerator->AddGeneratorTarget( - cm::make_unique(verifyTarget, - this->LocalGenerator)); - } - } + if (!stubSources.empty()) { + { + cmMakefile::PolicyPushPop polScope(this->Makefile); + this->Makefile->SetPolicy(cmPolicies::CMP0119, cmPolicies::NEW); + verifyTarget = this->Makefile->AddLibrary( + verifyTargetName, cmStateEnums::OBJECT_LIBRARY, {}, true); + } + if (isInterface) { + // Link to the original target so that we pick up its + // interface compile options just like a consumer would. + // This also ensures any generated headers in the original + // target will be created. + verifyTarget->AddLinkLibrary( + *this->Makefile, this->GetName(), + cmTargetLinkLibraryType::GENERAL_LibraryType); + } else { + // For private file sets, we need to simulate compiling the + // same way as the original target. That includes linking to + // the same things so we pick up the same transitive + // properties. For the _... properties, we don't care if + // we set them for languages this target won't eventually use. + // Copy language-standard properties for all supported + // languages. We don't care if we set properties for languages + // this target won't eventually use. + static std::array const propertiesToCopy{ { + "COMPILE_DEFINITIONS", "COMPILE_FEATURES", + "COMPILE_FLAGS", "COMPILE_OPTIONS", + "DEFINE_SYMBOL", "INCLUDE_DIRECTORIES", + "LINK_LIBRARIES", "C_STANDARD", + "C_STANDARD_REQUIRED", "C_EXTENSIONS", + "CXX_STANDARD", "CXX_STANDARD_REQUIRED", + "CXX_EXTENSIONS", "OBJC_STANDARD", + "OBJC_STANDARD_REQUIRED", "OBJC_EXTENSIONS", + "OBJCXX_STANDARD", "OBJCXX_STANDARD_REQUIRED", + "OBJCXX_EXTENSIONS", + } }; + for (std::string const& prop : propertiesToCopy) { + cmValue propValue = this->Target->GetProperty(prop); + if (propValue.IsSet()) { + verifyTarget->SetProperty(prop, propValue); + } + } + // The original target might have generated headers. Since + // we only link to the original target for compilation, + // there's nothing to force such generation to happen yet. + // Our verify target must depend on the original target to + // ensure such generated files will be created. + verifyTarget->AddUtility(this->GetName(), false, this->Makefile); + verifyTarget->AddCodegenDependency(this->GetName()); + } + + verifyTarget->SetProperty("AUTOMOC", "OFF"); + verifyTarget->SetProperty("AUTORCC", "OFF"); + verifyTarget->SetProperty("AUTOUIC", "OFF"); + verifyTarget->SetProperty("DISABLE_PRECOMPILE_HEADERS", "ON"); + verifyTarget->SetProperty("UNITY_BUILD", "OFF"); + verifyTarget->SetProperty("CXX_SCAN_FOR_MODULES", "OFF"); + + if (isInterface) { + verifyTarget->FinalizeTargetConfiguration( + this->Makefile->GetCompileDefinitionsEntries()); + } else { + // Private verification only needs to add the directory scope + // definitions here + for (auto const& def : + this->Makefile->GetCompileDefinitionsEntries()) { + verifyTarget->InsertCompileDefinition(def); + } + } + + for (auto const& source : stubSources) { + verifyTarget->AddSource(source); + } + } + if (!allVerifyTarget) { + allVerifyTarget = + this->GlobalGenerator->GetMakefiles().front()->AddNewUtilityTarget( + allVerifyTargetName, true); + } + allVerifyTarget->AddUtility(verifyTargetName, false); + + this->LocalGenerator->AddGeneratorTarget( + cm::make_unique(verifyTarget, this->LocalGenerator)); + } return true; }