From 3101d7090277efc8a1e2c5e31d2157feeebd8dff Mon Sep 17 00:00:00 2001 From: Vito Gamberini Date: Fri, 27 Feb 2026 14:48:55 -0500 Subject: [PATCH] c++modules: Restore use of local target for `import std` Restore use of a project-local `STATIC` library to provide the stdlib's module initialization symbols, as CMake 4.2's experimental support did. In commit fa10dc6c22 (Experimental/CXXModules: Implement EcoStd Module Metadata parser, 2025-10-21, v4.3.0-rc1~483^2) we switched to an imported target to provide the BMI under the assumption that stdlib implementations provide the symbols themselves, but they don't yet. While refactoring the module metadata parser's properties logic, also fix a relative path issue for local arguments. Fixes: #27426, #27626, #27635 --- Source/cmCxxModuleMetadata.cxx | 143 +++++++++++++++++++++++---------- Source/cmGeneratorTarget.cxx | 20 +++-- 2 files changed, 113 insertions(+), 50 deletions(-) diff --git a/Source/cmCxxModuleMetadata.cxx b/Source/cmCxxModuleMetadata.cxx index dfd7aab005..202a26099d 100644 --- a/Source/cmCxxModuleMetadata.cxx +++ b/Source/cmCxxModuleMetadata.cxx @@ -435,99 +435,140 @@ cmCxxModuleMetadata::SaveResult cmCxxModuleMetadata::SaveToFile( return st; } -void cmCxxModuleMetadata::PopulateTarget( - cmTarget& target, cmCxxModuleMetadata const& meta, - std::vector const& configs) +namespace { + +struct MetaDataProperties { - std::set allIncludeDirectories; - std::set allCompileOptions; - std::set allCompileFeatures; - std::set allCompileDefinitions; - std::set baseDirs; + std::string MetadataDir; + std::set AllCompileFeatures; + std::set AllCompileOptions; + std::set AllIncludeDirectories; + std::set AllCompileDefinitions; + std::set BaseDirs; + std::set Sources; - std::string metadataDir = - cmSystemTools::GetFilenamePath(meta.MetadataFilePath); + std::string NormalizePath(std::string const& in) const + { + std::string out = in; + if (!cmSystemTools::FileIsFullPath(in)) { + out = cmStrCat(MetadataDir, '/', in); + } + return cmSystemTools::CollapseFullPath(out); + } +}; - auto fileSet = target.GetOrCreateFileSet("CXX_MODULES", "CXX_MODULES", - cmFileSetVisibility::Interface); +MetaDataProperties CollectMetaProperties(cmCxxModuleMetadata const& meta) +{ + MetaDataProperties props; + + props.MetadataDir = cmSystemTools::GetFilenamePath(meta.MetadataFilePath); for (auto const& module : meta.Modules) { - std::string sourcePath = module.SourcePath; - if (!cmSystemTools::FileIsFullPath(sourcePath)) { - sourcePath = cmStrCat(metadataDir, '/', sourcePath); - } - - sourcePath = cmSystemTools::ToNormalizedPathOnDisk(std::move(sourcePath)); + std::string sourcePath = props.NormalizePath(module.SourcePath); + props.Sources.insert(sourcePath); // Module metadata files can reference files in different roots, // just use the immediate parent directory as a base directory - baseDirs.insert(cmSystemTools::GetFilenamePath(sourcePath)); - - fileSet.first->AddFileEntry(sourcePath); + props.BaseDirs.insert(cmSystemTools::GetFilenamePath(sourcePath)); if (module.LocalArguments) { for (auto const& incDir : module.LocalArguments->IncludeDirectories) { - allIncludeDirectories.emplace(incDir); + props.AllIncludeDirectories.emplace(incDir); } for (auto const& sysIncDir : module.LocalArguments->SystemIncludeDirectories) { - allIncludeDirectories.emplace(sysIncDir); + props.AllIncludeDirectories.emplace(sysIncDir); } for (auto const& opt : module.LocalArguments->CompileOptions) { - allCompileOptions.emplace(opt); + props.AllCompileOptions.emplace(opt); } for (auto const& opt : module.LocalArguments->CompileFeatures) { - allCompileFeatures.emplace(opt); + props.AllCompileFeatures.emplace(opt); } for (auto const& def : module.LocalArguments->Definitions) { if (!def.Undef) { if (def.Value) { - allCompileDefinitions.emplace( + props.AllCompileDefinitions.emplace( cmStrCat(def.Name, "="_s, *def.Value)); } else { - allCompileDefinitions.emplace(def.Name); + props.AllCompileDefinitions.emplace(def.Name); } } } } } - for (auto const& baseDir : baseDirs) { + return props; +} + +void PopulateFileSet(cmTarget& target, MetaDataProperties const& props) +{ + auto fileSet = target.GetOrCreateFileSet("CXX_MODULES", "CXX_MODULES", + cmFileSetVisibility::Public); + + for (auto const& source : props.Sources) { + fileSet.first->AddFileEntry(source); + } + + for (auto const& baseDir : props.BaseDirs) { fileSet.first->AddDirectoryEntry(baseDir); } +} - if (!allIncludeDirectories.empty()) { +void PopulateLocalTarget(cmTarget& target, MetaDataProperties const& props) +{ + if (!props.AllIncludeDirectories.empty()) { + target.AppendProperty("INCLUDE_DIRECTORIES", + cmJoin(props.AllIncludeDirectories, ";")); + } + + if (!props.AllCompileDefinitions.empty()) { + target.AppendProperty("COMPILE_DEFINITIONS", + cmJoin(props.AllCompileDefinitions, ";")); + } + + if (!props.AllCompileOptions.empty()) { + target.AppendProperty("COMPILE_OPTIONS", + cmJoin(props.AllCompileOptions, ";")); + } + + if (!props.AllCompileFeatures.empty()) { + target.AppendProperty("COMPILE_FEATURES", + cmJoin(props.AllCompileFeatures, ";")); + } +} + +void PopulateImportedTarget(cmTarget& target, MetaDataProperties const& props, + cmCxxModuleMetadata const& meta, + std::vector const& configs) +{ + if (!props.AllIncludeDirectories.empty()) { target.SetProperty("IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES", - cmJoin(allIncludeDirectories, ";")); + cmJoin(props.AllIncludeDirectories, ";")); } - if (!allCompileDefinitions.empty()) { + if (!props.AllCompileDefinitions.empty()) { target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS", - cmJoin(allCompileDefinitions, ";")); + cmJoin(props.AllCompileDefinitions, ";")); } - if (!allCompileOptions.empty()) { + if (!props.AllCompileOptions.empty()) { target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_OPTIONS", - cmJoin(allCompileOptions, ";")); + cmJoin(props.AllCompileOptions, ";")); } - if (!allCompileFeatures.empty()) { + if (!props.AllCompileFeatures.empty()) { target.SetProperty("IMPORTED_CXX_MODULES_COMPILE_FEATURES", - cmJoin(allCompileFeatures, ";")); + cmJoin(props.AllCompileFeatures, ";")); } for (auto const& config : configs) { std::vector moduleList; for (auto const& module : meta.Modules) { if (module.IsInterface) { - std::string sourcePath = module.SourcePath; - if (!cmSystemTools::FileIsFullPath(sourcePath)) { - sourcePath = cmStrCat(metadataDir, '/', sourcePath); - } - sourcePath = - cmSystemTools::ToNormalizedPathOnDisk(std::move(sourcePath)); - moduleList.push_back(cmStrCat(module.LogicalName, "="_s, sourcePath)); + moduleList.push_back(cmStrCat(module.LogicalName, "="_s, + props.NormalizePath(module.SourcePath))); } } @@ -539,3 +580,19 @@ void cmCxxModuleMetadata::PopulateTarget( } } } + +} // namespace + +void cmCxxModuleMetadata::PopulateTarget( + cmTarget& target, cmCxxModuleMetadata const& meta, + std::vector const& configs) +{ + auto props = CollectMetaProperties(meta); + PopulateFileSet(target, props); + + if (target.IsImported()) { + PopulateImportedTarget(target, props, meta, configs); + } else { + PopulateLocalTarget(target, props); + } +} diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 2bc13d9534..98049236af 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -5194,13 +5194,20 @@ bool CreateCxxStdlibTarget(cmMakefile* makefile, cmLocalGenerator* lg, metadata = std::move(*parseResult.Meta); } - auto* stdlibTgt = makefile->AddImportedTarget( - cxxTargetName, cmStateEnums::INTERFACE_LIBRARY, true); + auto const localTargetName = cmStrCat("__cmake_cxx_std_", stdLevel); + cmStandardLevelResolver standardResolver(makefile); + auto* stdlibTgt = makefile->AddLibrary( + localTargetName, cmStateEnums::STATIC_LIBRARY, {}, true); cmCxxModuleMetadata::PopulateTarget(*stdlibTgt, *metadata, configs); - stdlibTgt->AppendProperty("IMPORTED_CXX_MODULES_COMPILE_FEATURES", - cmStrCat("cxx_std_", stdLevel)); + standardResolver.AddRequiredTargetFeature(stdlibTgt, + cmStrCat("cxx_std_", stdLevel)); + auto gt = cm::make_unique(stdlibTgt, lg); + for (auto const& config : configs) { + gt->ComputeCompileFeatures(config); + } - lg->AddGeneratorTarget(cm::make_unique(stdlibTgt, lg)); + lg->AddGeneratorTarget(std::move(gt)); + makefile->AddAlias(cxxTargetName, localTargetName); #endif // CMAKE_BOOTSTRAP @@ -5291,8 +5298,7 @@ bool cmGeneratorTarget::ApplyCXXStdTargets() standardResolver.GetLevelString("CXX", *explicitLevel); auto const cxxTargetName = cmStrCat("__CMAKE::CXX", stdLevel); - // Create the __CMAKE::CXX## IMPORTED interface target if it doesn't - // already exist + // Create the __CMAKE::CXX## target if it doesn't already exist if (!this->Makefile->FindTargetToUse(cxxTargetName) && !CreateCxxStdlibTarget(this->Makefile, this->LocalGenerator, this->GetName(), cxxTargetName, stdLevel,