diff options
author | Brad King <brad.king@kitware.com> | 2023-11-27 13:36:28 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2023-11-27 13:36:44 (GMT) |
commit | 4b2960b1f3e214dd30b32925b00eef5f64b99b71 (patch) | |
tree | 106a8dc355a73556244ba1701b38faab5181a240 | |
parent | 66149dd1a93f4f22f68d7465de74b14d7c03f89d (diff) | |
parent | beb1393f8f29302197b80741bec41a13b7f207c7 (diff) | |
download | CMake-4b2960b1f3e214dd30b32925b00eef5f64b99b71.zip CMake-4b2960b1f3e214dd30b32925b00eef5f64b99b71.tar.gz CMake-4b2960b1f3e214dd30b32925b00eef5f64b99b71.tar.bz2 |
Merge topic 'fortran-objects-as-sources-fix' into release-3.28
beb1393f8f Merge branch 'revert-exact-collation-depends-3.27' into fortran-objects-as-sources-fix
a033dce326 Makefiles: provide, but do not consume, "forward linked" target dirs
7cd0adab1b cmCommonTargetGenerator: use modules from linked object-referenced targets
1175f1c874 LinkItem: track `cmSourceFile` instances for external objects
d2fa56772f Ninja: support "forwarding" modules from other targets
ec1e589bec Ninja: Revert exact collation dependencies for 3.27
06df59b930 cmCommonTargetGenerator: return forward linked target dirs too
f8729ab366 cmLocalUnixMakefileGenerator3: handle object-referencing Fortran modules
...
Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !8989
39 files changed, 419 insertions, 78 deletions
diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index a29dd76..90f0d55 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -163,43 +163,77 @@ std::string cmCommonTargetGenerator::GetIncludes(std::string const& l, return i->second; } -std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories( +cmCommonTargetGenerator::LinkedTargetDirs +cmCommonTargetGenerator::GetLinkedTargetDirectories( const std::string& lang, const std::string& config) const { - std::vector<std::string> dirs; - std::set<cmGeneratorTarget const*> emitted; + LinkedTargetDirs dirs; + std::set<cmGeneratorTarget const*> forward_emitted; + std::set<cmGeneratorTarget const*> direct_emitted; cmGlobalCommonGenerator* const gg = this->GlobalCommonGenerator; + + enum class Forwarding + { + Yes, + No + }; + if (cmComputeLinkInformation* cli = this->GeneratorTarget->GetLinkInformation(config)) { - auto addLinkedTarget = [this, &lang, &config, &dirs, &emitted, - gg](cmGeneratorTarget const* linkee) { - if (linkee && - !linkee->IsImported() - // Skip targets that build after this one in a static lib cycle. - && gg->TargetOrderIndexLess(linkee, this->GeneratorTarget) - // We can ignore the INTERFACE_LIBRARY items because - // Target->GetLinkInformation already processed their - // link interface and they don't have any output themselves. - && (linkee->GetType() != cmStateEnums::INTERFACE_LIBRARY - // Synthesized targets may have relevant rules. - || linkee->IsSynthetic()) && - ((lang == "CXX"_s && linkee->HaveCxx20ModuleSources()) || - (lang == "Fortran"_s && linkee->HaveFortranSources(config))) && - emitted.insert(linkee).second) { - cmLocalGenerator* lg = linkee->GetLocalGenerator(); - std::string di = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', - lg->GetTargetDirectory(linkee)); - if (lg->GetGlobalGenerator()->IsMultiConfig()) { - di = cmStrCat(di, '/', config); + auto addLinkedTarget = + [this, &lang, &config, &dirs, &direct_emitted, &forward_emitted, + gg](cmGeneratorTarget const* linkee, Forwarding forward) { + if (linkee && + !linkee->IsImported() + // Skip targets that build after this one in a static lib cycle. + && gg->TargetOrderIndexLess(linkee, this->GeneratorTarget) + // We can ignore the INTERFACE_LIBRARY items because + // Target->GetLinkInformation already processed their + // link interface and they don't have any output themselves. + && (linkee->GetType() != cmStateEnums::INTERFACE_LIBRARY + // Synthesized targets may have relevant rules. + || linkee->IsSynthetic()) && + ((lang == "CXX"_s && linkee->HaveCxx20ModuleSources()) || + (lang == "Fortran"_s && linkee->HaveFortranSources(config)))) { + cmLocalGenerator* lg = linkee->GetLocalGenerator(); + std::string di = cmStrCat(lg->GetCurrentBinaryDirectory(), '/', + lg->GetTargetDirectory(linkee)); + if (lg->GetGlobalGenerator()->IsMultiConfig()) { + di = cmStrCat(di, '/', config); + } + if (forward == Forwarding::Yes && + forward_emitted.insert(linkee).second) { + dirs.Forward.push_back(di); + } + if (direct_emitted.insert(linkee).second) { + dirs.Direct.emplace_back(di); + } } - dirs.push_back(std::move(di)); - } - }; + }; for (auto const& item : cli->GetItems()) { - addLinkedTarget(item.Target); + if (item.Target) { + addLinkedTarget(item.Target, Forwarding::No); + } else if (item.ObjectSource && lang == "Fortran"_s + /* Object source files do not have a language associated with + them. */ + /* && item.ObjectSource->GetLanguage() == "Fortran"_s*/) { + // Fortran modules provided by `$<TARGET_OBJECTS>` as linked items + // should be collated for use in this target. + addLinkedTarget(this->LocalCommonGenerator->FindGeneratorTargetToUse( + item.ObjectSource->GetObjectLibrary()), + Forwarding::Yes); + } } for (cmGeneratorTarget const* target : cli->GetExternalObjectTargets()) { - addLinkedTarget(target); + addLinkedTarget(target, Forwarding::No); + } + if (lang == "Fortran"_s) { + // Fortran modules provided by `$<TARGET_OBJECTS>` as sources should be + // collated for use in this target. + for (cmGeneratorTarget const* target : + this->GeneratorTarget->GetSourceObjectLibraries(config)) { + addLinkedTarget(target, Forwarding::Yes); + } } } return dirs; diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index c9886d0..0452649 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -74,8 +74,15 @@ protected: std::string GetCompilerLauncher(std::string const& lang, std::string const& config); - std::vector<std::string> GetLinkedTargetDirectories( - const std::string& lang, const std::string& config) const; + + struct LinkedTargetDirs + { + std::vector<std::string> Direct; + std::vector<std::string> Forward; + }; + + LinkedTargetDirs GetLinkedTargetDirectories(const std::string& lang, + const std::string& config) const; std::string ComputeTargetCompilePDB(const std::string& config) const; std::string GetLinkerLauncher(const std::string& config); diff --git a/Source/cmComputeLinkDepends.cxx b/Source/cmComputeLinkDepends.cxx index 1b1f640..320c57c 100644 --- a/Source/cmComputeLinkDepends.cxx +++ b/Source/cmComputeLinkDepends.cxx @@ -515,6 +515,7 @@ void cmComputeLinkDepends::AddLinkObject(cmLinkItem const& item) LinkEntry& entry = this->EntryList[index]; entry.Item = BT<std::string>(item.AsStr(), item.Backtrace); entry.Kind = LinkEntry::Object; + entry.ObjectSource = item.ObjectSource; // Record explicitly linked object files separately. this->ObjectEntries.emplace_back(index); diff --git a/Source/cmComputeLinkDepends.h b/Source/cmComputeLinkDepends.h index 22c4e2a..3233217 100644 --- a/Source/cmComputeLinkDepends.h +++ b/Source/cmComputeLinkDepends.h @@ -22,6 +22,7 @@ class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; +class cmSourceFile; class cmake; /** \class cmComputeLinkDepends @@ -63,6 +64,9 @@ public: BT<std::string> Item; cmGeneratorTarget const* Target = nullptr; + // The source file representing the external object (used when linking + // `$<TARGET_OBJECTS>`) + cmSourceFile const* ObjectSource = nullptr; EntryKind Kind = Library; // The following member is for the management of items specified // through genex $<LINK_LIBRARY:...> diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 297ae1d..c58dc68 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -1176,7 +1176,7 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry) : cmStateEnums::RuntimeBinaryArtifact; std::string exe = tgt->GetFullPath(config, artifact, true); this->Items.emplace_back( - BT<std::string>(exe, item.Backtrace), ItemIsPath::Yes, tgt, + BT<std::string>(exe, item.Backtrace), ItemIsPath::Yes, tgt, nullptr, this->FindLibraryFeature(entry.Feature == DEFAULT ? "__CMAKE_LINK_EXECUTABLE" : entry.Feature)); @@ -1197,7 +1197,7 @@ void cmComputeLinkInformation::AddItem(LinkEntry const& entry) } else if (this->GlobalGenerator->IsXcode() && !tgt->GetImportedXcFrameworkPath(config).empty()) { this->Items.emplace_back( - tgt->GetImportedXcFrameworkPath(config), ItemIsPath::Yes, tgt, + tgt->GetImportedXcFrameworkPath(config), ItemIsPath::Yes, tgt, nullptr, this->FindLibraryFeature(entry.Feature == DEFAULT ? "__CMAKE_LINK_XCFRAMEWORK" : entry.Feature)); @@ -1679,15 +1679,15 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) if (isImportedFrameworkFolderOnApple) { if (entry.Feature == DEFAULT) { this->AddLibraryFeature("FRAMEWORK"); - this->Items.emplace_back(item, ItemIsPath::Yes, target, + this->Items.emplace_back(item, ItemIsPath::Yes, target, nullptr, this->FindLibraryFeature("FRAMEWORK")); } else { - this->Items.emplace_back(item, ItemIsPath::Yes, target, + this->Items.emplace_back(item, ItemIsPath::Yes, target, nullptr, this->FindLibraryFeature(entry.Feature)); } } else { this->Items.emplace_back( - item, ItemIsPath::Yes, target, + item, ItemIsPath::Yes, target, nullptr, this->FindLibraryFeature(entry.Feature == DEFAULT ? "__CMAKE_LINK_FRAMEWORK" : entry.Feature)); @@ -1695,17 +1695,17 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) } else { if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) { this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes, - target, + target, nullptr, this->FindLibraryFeature(entry.Feature)); } else if (entry.Feature == DEFAULT && isImportedFrameworkFolderOnApple) { this->AddLibraryFeature("FRAMEWORK"); this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes, - target, + target, nullptr, this->FindLibraryFeature("FRAMEWORK")); } else { this->Items.emplace_back( - item, ItemIsPath::Yes, target, + item, ItemIsPath::Yes, target, nullptr, this->FindLibraryFeature(entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature)); @@ -1714,7 +1714,7 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) } else { // Now add the full path to the library. this->Items.emplace_back( - item, ItemIsPath::Yes, target, + item, ItemIsPath::Yes, target, nullptr, this->FindLibraryFeature( entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature)); } @@ -1774,7 +1774,7 @@ void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry) // Now add the full path to the library. this->Items.emplace_back( - item, ItemIsPath::Yes, nullptr, + item, ItemIsPath::Yes, nullptr, entry.ObjectSource, this->FindLibraryFeature( entry.Feature == DEFAULT ? (entry.Kind == cmComputeLinkDepends::LinkEntry::Object @@ -2000,13 +2000,13 @@ void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry) if (this->GlobalGenerator->IsXcode()) { // Add framework path - it will be handled by Xcode after it's added to // "Link Binary With Libraries" build phase - this->Items.emplace_back(item, ItemIsPath::Yes, nullptr, + this->Items.emplace_back(item, ItemIsPath::Yes, nullptr, nullptr, this->FindLibraryFeature(entry.Feature == DEFAULT ? "FRAMEWORK" : entry.Feature)); } else { this->Items.emplace_back( - fwDescriptor->GetLinkName(), ItemIsPath::Yes, nullptr, + fwDescriptor->GetLinkName(), ItemIsPath::Yes, nullptr, nullptr, this->FindLibraryFeature(entry.Feature == DEFAULT ? "FRAMEWORK" : entry.Feature)); } @@ -2024,7 +2024,7 @@ void cmComputeLinkInformation::AddXcFrameworkItem(LinkEntry const& entry) plist->SelectSuitableLibrary(*this->Makefile, entry.Item.Backtrace)) { if (this->GlobalGenerator->IsXcode()) { this->Items.emplace_back( - entry.Item.Value, ItemIsPath::Yes, nullptr, + entry.Item.Value, ItemIsPath::Yes, nullptr, nullptr, this->FindLibraryFeature(entry.Feature == DEFAULT ? "__CMAKE_LINK_XCFRAMEWORK" : entry.Feature)); diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 1e8556d..3ee995f 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -22,6 +22,7 @@ class cmGeneratorTarget; class cmGlobalGenerator; class cmMakefile; class cmOrderDirectories; +class cmSourceFile; class cmake; /** \class cmComputeLinkInformation @@ -51,16 +52,21 @@ public: { Item(BT<std::string> v, ItemIsPath isPath, cmGeneratorTarget const* target = nullptr, + cmSourceFile const* objectSource = nullptr, FeatureDescriptor const* feature = nullptr) : Value(std::move(v)) , IsPath(isPath) , Target(target) + , ObjectSource(objectSource) , Feature(feature) { } BT<std::string> Value; ItemIsPath IsPath = ItemIsPath::No; cmGeneratorTarget const* Target = nullptr; + // The source file representing the external object (used when linking + // `$<TARGET_OBJECTS>`) + cmSourceFile const* ObjectSource = nullptr; bool HasFeature() const { return this->Feature != nullptr; } const std::string& GetFeatureName() const diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index 2a50565..b23dabd 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -258,6 +258,12 @@ bool cmDependsFortran::LocateModules() } this->MatchRemoteModules(fin, targetDir); } + + // TODO: Use `CMAKE_Fortran_TARGET_FORWARD_LINKED_INFO_FILES` to handle cases + // described in #25425. Note that because Makefiles generators do not + // implement relaxed object compilation as described in #15555, the issues + // never actually cause build failures; only incremental build incorrectness. + return true; } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 930922c..8d21e63 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -6898,6 +6898,7 @@ void cmGeneratorTarget::ExpandLinkItems( cmSourceFile const* sf = mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { + item.ObjectSource = sf; iface.Objects.emplace_back(std::move(item)); continue; } @@ -8044,35 +8045,38 @@ void cmGeneratorTarget::GetLanguages(std::set<std::string>& languages, } } - std::vector<cmGeneratorTarget*> objectLibraries; - std::vector<cmSourceFile const*> externalObjects; + std::set<cmGeneratorTarget const*> objectLibraries; if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) { std::vector<cmGeneratorTarget*> objectTargets; this->GetObjectLibrariesCMP0026(objectTargets); - objectLibraries.reserve(objectTargets.size()); for (cmGeneratorTarget* gt : objectTargets) { - objectLibraries.push_back(gt); + objectLibraries.insert(gt); } } else { - this->GetExternalObjects(externalObjects, config); - for (cmSourceFile const* extObj : externalObjects) { - std::string objLib = extObj->GetObjectLibrary(); - if (cmGeneratorTarget* tgt = - this->LocalGenerator->FindGeneratorTargetToUse(objLib)) { - auto const objLibIt = - std::find_if(objectLibraries.cbegin(), objectLibraries.cend(), - [tgt](cmGeneratorTarget* t) { return t == tgt; }); - if (objectLibraries.cend() == objLibIt) { - objectLibraries.push_back(tgt); - } - } - } + objectLibraries = this->GetSourceObjectLibraries(config); } - for (cmGeneratorTarget* objLib : objectLibraries) { + for (cmGeneratorTarget const* objLib : objectLibraries) { objLib->GetLanguages(languages, config); } } +std::set<cmGeneratorTarget const*> cmGeneratorTarget::GetSourceObjectLibraries( + std::string const& config) const +{ + std::set<cmGeneratorTarget const*> objectLibraries; + std::vector<cmSourceFile const*> externalObjects; + this->GetExternalObjects(externalObjects, config); + for (cmSourceFile const* extObj : externalObjects) { + std::string objLib = extObj->GetObjectLibrary(); + if (cmGeneratorTarget* tgt = + this->LocalGenerator->FindGeneratorTargetToUse(objLib)) { + objectLibraries.insert(tgt); + } + } + + return objectLibraries; +} + bool cmGeneratorTarget::IsLanguageUsed(std::string const& language, std::string const& config) const { @@ -8486,6 +8490,7 @@ void cmGeneratorTarget::ComputeLinkImplementationLibraries( cmSourceFile const* sf = mf->GetSource(maybeObj, cmSourceFileLocationKind::Known); if (sf && sf->GetPropertyAsBool("EXTERNAL_OBJECT")) { + item.ObjectSource = sf; impl.Objects.emplace_back(std::move(item)); continue; } @@ -9087,19 +9092,47 @@ std::string cmGeneratorTarget::GetImportedXcFrameworkPath( bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const { auto sources = this->GetSourceFiles(config); - return std::any_of(sources.begin(), sources.end(), - [](BT<cmSourceFile*> const& sf) -> bool { - return sf.Value->GetLanguage() == "Fortran"_s; - }); + bool const have_direct = std::any_of( + sources.begin(), sources.end(), [](BT<cmSourceFile*> const& sf) -> bool { + return sf.Value->GetLanguage() == "Fortran"_s; + }); + bool have_via_target_objects = false; + if (!have_direct) { + auto const sourceObjectLibraries = this->GetSourceObjectLibraries(config); + have_via_target_objects = + std::any_of(sourceObjectLibraries.begin(), sourceObjectLibraries.end(), + [&config](cmGeneratorTarget const* tgt) -> bool { + return tgt->HaveFortranSources(config); + }); + } + return have_direct || have_via_target_objects; } bool cmGeneratorTarget::HaveFortranSources() const { - auto sources = cmGeneratorTarget::GetAllConfigSources(); - return std::any_of(sources.begin(), sources.end(), - [](AllConfigSource const& sf) -> bool { - return sf.Source->GetLanguage() == "Fortran"_s; - }); + auto sources = this->GetAllConfigSources(); + bool const have_direct = std::any_of( + sources.begin(), sources.end(), [](AllConfigSource const& sf) -> bool { + return sf.Source->GetLanguage() == "Fortran"_s; + }); + bool have_via_target_objects = false; + if (!have_direct) { + std::vector<std::string> configs = + this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig); + for (auto const& config : configs) { + auto const sourceObjectLibraries = + this->GetSourceObjectLibraries(config); + have_via_target_objects = + std::any_of(sourceObjectLibraries.begin(), sourceObjectLibraries.end(), + [&config](cmGeneratorTarget const* tgt) -> bool { + return tgt->HaveFortranSources(config); + }); + if (have_via_target_objects) { + break; + } + } + } + return have_direct || have_via_target_objects; } bool cmGeneratorTarget::HaveCxx20ModuleSources(std::string* errorMessage) const diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index bf49914..2a301e3 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -463,6 +463,11 @@ public: bool IsLanguageUsed(std::string const& language, std::string const& config) const; + // Get the set of targets directly referenced via `TARGET_OBJECTS` in the + // source list for a configuration. + std::set<cmGeneratorTarget const*> GetSourceObjectLibraries( + std::string const& config) const; + bool IsCSharpOnly() const; bool IsDotNetSdkTarget() const; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index d691d88..cba48f4 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -2527,6 +2527,7 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( std::string const& arg_dd, std::vector<std::string> const& arg_ddis, std::string const& module_dir, std::vector<std::string> const& linked_target_dirs, + std::vector<std::string> const& forward_modules_from_target_dirs, std::string const& arg_lang, std::string const& arg_modmapfmt, cmCxxModuleExportInfo const& export_info) { @@ -2804,6 +2805,51 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( // use by dependents that reference this target in linked-target-dirs. std::string const target_mods_file = cmStrCat( cmSystemTools::GetFilenamePath(arg_dd), '/', arg_lang, "Modules.json"); + + // Populate the module map with those provided by linked targets first. + for (std::string const& forward_modules_from_target_dir : + forward_modules_from_target_dirs) { + std::string const fmftn = + cmStrCat(forward_modules_from_target_dir, '/', arg_lang, "Modules.json"); + Json::Value fmft; + cmsys::ifstream fmftf(fmftn.c_str(), std::ios::in | std::ios::binary); + if (!fmftf) { + cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to open ", + fmftn, " for module information")); + return false; + } + Json::Reader reader; + if (!reader.parse(fmftf, fmft, false)) { + cmSystemTools::Error(cmStrCat("-E cmake_ninja_dyndep failed to parse ", + forward_modules_from_target_dir, + reader.getFormattedErrorMessages())); + return false; + } + if (!fmft.isObject()) { + continue; + } + + auto forward_info = [](Json::Value& target, Json::Value const& source) { + if (!source.isObject()) { + return; + } + + for (auto i = source.begin(); i != source.end(); ++i) { + std::string const key = i.key().asString(); + if (target.isMember(key)) { + continue; + } + target[key] = *i; + } + }; + + // Forward info from forwarding targets into our collation. + Json::Value& tmi_target_modules = target_module_info["modules"]; + forward_info(tmi_target_modules, fmft["modules"]); + forward_info(target_references, fmft["references"]); + forward_info(target_usages, fmft["usages"]); + } + cmGeneratedFileStream tmf(target_mods_file); tmf << target_module_info; @@ -2891,6 +2937,16 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, linked_target_dirs.push_back(tdi_linked_target_dir.asString()); } } + std::vector<std::string> forward_modules_from_target_dirs; + Json::Value const& tdi_forward_modules_from_target_dirs = + tdi["forward-modules-from-target-dirs"]; + if (tdi_forward_modules_from_target_dirs.isArray()) { + for (auto const& tdi_forward_modules_from_target_dir : + tdi_forward_modules_from_target_dirs) { + forward_modules_from_target_dirs.push_back( + tdi_forward_modules_from_target_dir.asString()); + } + } std::string const compilerId = tdi["compiler-id"].asString(); std::string const simulateId = tdi["compiler-simulate-id"].asString(); std::string const compilerFrontendVariant = @@ -2914,7 +2970,8 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, # endif return gg.WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis, module_dir, linked_target_dirs, - arg_lang, arg_modmapfmt, *export_info) + forward_modules_from_target_dirs, arg_lang, + arg_modmapfmt, *export_info) ? 0 : 1; } diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index c5d6901..220d393 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -430,6 +430,7 @@ public: std::string const& arg_dd, std::vector<std::string> const& arg_ddis, std::string const& module_dir, std::vector<std::string> const& linked_target_dirs, + std::vector<std::string> const& forward_modules_from_target_dirs, std::string const& arg_lang, std::string const& arg_modmapfmt, cmCxxModuleExportInfo const& export_info); diff --git a/Source/cmLinkItem.h b/Source/cmLinkItem.h index 262728b..e4444d3 100644 --- a/Source/cmLinkItem.h +++ b/Source/cmLinkItem.h @@ -17,6 +17,7 @@ #include "cmTargetLinkLibraryType.h" class cmGeneratorTarget; +class cmSourceFile; // Basic information about each link item. class cmLinkItem @@ -29,6 +30,9 @@ public: cmLinkItem(cmGeneratorTarget const* t, bool c, cmListFileBacktrace bt); std::string const& AsStr() const; cmGeneratorTarget const* Target = nullptr; + // The source file representing the external object (used when linking + // `$<TARGET_OBJECTS>`) + cmSourceFile const* ObjectSource = nullptr; bool Cross = false; cmListFileBacktrace Backtrace; friend bool operator<(cmLinkItem const& l, cmLinkItem const& r); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index e26a6ea..7bce1d2 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -1899,6 +1899,11 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( : "OFF") << ")\n\n"; + bool requireFortran = false; + if (target->HaveFortranSources(this->GetConfigName())) { + requireFortran = true; + } + auto const& implicitLangs = this->GetImplicitDepends(target, cmDependencyScannerKind::CMake); @@ -1908,6 +1913,12 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( cmakefileStream << "set(CMAKE_DEPENDS_LANGUAGES\n"; for (auto const& implicitLang : implicitLangs) { cmakefileStream << " \"" << implicitLang.first << "\"\n"; + if (requireFortran && implicitLang.first == "Fortran"_s) { + requireFortran = false; + } + } + if (requireFortran) { + cmakefileStream << " \"Fortran\"\n"; } cmakefileStream << " )\n"; diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 4a190db..93fb8b4 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -3630,6 +3630,9 @@ void cmMakefile::AddTargetObject(std::string const& tgtName, this->GetOrCreateSource(objFile, true, cmSourceFileLocationKind::Known); sf->SetObjectLibrary(tgtName); sf->SetProperty("EXTERNAL_OBJECT", "1"); + // TODO: Compute a language for this object based on the associated source + // file that compiles to it. Needs a policy as it likely affects link + // language selection if done unconditionally. #if !defined(CMAKE_BOOTSTRAP) this->SourceGroups[this->ObjectLibrariesSourceGroupIndex].AddGroupFile( sf->ResolveFullPath()); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 0c2a719..74b4b75 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1440,9 +1440,20 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() "# Targets to which this target links which contain Fortran sources.\n" "set(CMAKE_Fortran_TARGET_LINKED_INFO_FILES\n"; /* clang-format on */ - std::vector<std::string> const dirs = + auto const dirs = this->GetLinkedTargetDirectories("Fortran", this->GetConfigName()); - for (std::string const& d : dirs) { + for (std::string const& d : dirs.Direct) { + *this->InfoFileStream << " \"" << d << "/DependInfo.cmake\"\n"; + } + *this->InfoFileStream << " )\n"; + + /* clang-format off */ + *this->InfoFileStream + << "\n" + "# Targets to which this target links which contain Fortran sources.\n" + "set(CMAKE_Fortran_TARGET_FORWARD_LINKED_INFO_FILES\n"; + /* clang-format on */ + for (std::string const& d : dirs.Forward) { *this->InfoFileStream << " \"" << d << "/DependInfo.cmake\"\n"; } *this->InfoFileStream << " )\n"; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index dabb078..2283923 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1175,6 +1175,15 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( } } + // Check if there are Fortran objects which need to participate in forwarding + // module requirements. + if (this->GeneratorTarget->HaveFortranSources(config) && + !this->Configs[config].ScanningInfo.count("Fortran")) { + ScanningFiles files; + this->Configs[config].ScanningInfo["Fortran"].emplace_back(files); + this->WriteCompileRule("Fortran", config, WithScanning::Yes); + } + for (auto const& langScanningFiles : this->Configs[config].ScanningInfo) { std::string const& language = langScanningFiles.first; std::vector<ScanningFiles> const& scanningFiles = langScanningFiles.second; @@ -1197,10 +1206,13 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( this->WriteTargetDependInfo(language, config); - for (std::string const& l : - this->GetLinkedTargetDirectories(language, config)) { - build.ImplicitDeps.emplace_back( - cmStrCat(l, '/', language, "Modules.json")); + auto const linked_directories = + this->GetLinkedTargetDirectories(language, config); + for (std::string const& l : linked_directories.Direct) { + build.ImplicitDeps.push_back(cmStrCat(l, '/', language, "Modules.json")); + } + for (std::string const& l : linked_directories.Forward) { + build.ImplicitDeps.push_back(cmStrCat(l, '/', language, "Modules.json")); } this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), @@ -1900,10 +1912,18 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, Json::Value& tdi_linked_target_dirs = tdi["linked-target-dirs"] = Json::arrayValue; - for (std::string const& l : this->GetLinkedTargetDirectories(lang, config)) { + auto const linked_directories = + this->GetLinkedTargetDirectories(lang, config); + for (std::string const& l : linked_directories.Direct) { tdi_linked_target_dirs.append(l); } + Json::Value& tdi_forward_modules_from_target_dirs = + tdi["forward-modules-from-target-dirs"] = Json::arrayValue; + for (std::string const& l : linked_directories.Forward) { + tdi_forward_modules_from_target_dirs.append(l); + } + cmDyndepGeneratorCallbacks cb; cb.ObjectFilePath = [this](cmSourceFile const* sf, std::string const& cnf) { return this->GetObjectFilePath(sf, cnf); diff --git a/Tests/FortranModules/CMakeLists.txt b/Tests/FortranModules/CMakeLists.txt index 16ea0d4..1e5ff89 100644 --- a/Tests/FortranModules/CMakeLists.txt +++ b/Tests/FortranModules/CMakeLists.txt @@ -137,3 +137,9 @@ add_subdirectory(Issue25252-iface-sources) add_subdirectory(Issue25365-target-objects) add_subdirectory(Issue25365-target-objects-iface) + +# Issue#25425 +add_subdirectory(ModulesViaTargetObjectsSource) +add_subdirectory(ModulesViaSubdirTargetObjectsSource) +add_subdirectory(ModulesViaTargetObjectsLink) +add_subdirectory(ModulesViaSubdirTargetObjectsLink) diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/CMakeLists.txt b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/CMakeLists.txt new file mode 100644 index 0000000..b52b423 --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(subdir) + +add_library(mvstol_lib dummy.f90) +target_link_libraries(mvstol_lib PRIVATE "$<TARGET_OBJECTS:mvstol_obj>") +target_include_directories(mvstol_lib PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/subdir") +add_library(mvstol_use use.f90) +target_link_libraries(mvstol_use PRIVATE mvstol_lib) diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/dummy.f90 b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/dummy.f90 new file mode 100644 index 0000000..96a8138 --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/dummy.f90 @@ -0,0 +1,3 @@ +pure real function dummy() +dummy = 4*atan(1.) +end function diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/subdir/CMakeLists.txt b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/subdir/CMakeLists.txt new file mode 100644 index 0000000..b2a250d --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/subdir/CMakeLists.txt @@ -0,0 +1 @@ +add_library(mvstol_obj STATIC obj.f90) diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/subdir/obj.f90 b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/subdir/obj.f90 new file mode 100644 index 0000000..6b5ddd5 --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/subdir/obj.f90 @@ -0,0 +1,11 @@ +module m1 + +implicit none + +contains + +pure real function pi() +pi = 4*atan(1.) +end function + +end module m1 diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/use.f90 b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/use.f90 new file mode 100644 index 0000000..f971909 --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/use.f90 @@ -0,0 +1,13 @@ +module lib + +use m1, only : pi + +implicit none + +contains + +pure real function func() +func = pi() +end function + +end module diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/CMakeLists.txt b/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/CMakeLists.txt new file mode 100644 index 0000000..255e8a7 --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/CMakeLists.txt @@ -0,0 +1,6 @@ +add_subdirectory(subdir) + +add_library(mvstos_lib "$<TARGET_OBJECTS:mvstos_obj>") +target_include_directories(mvstos_lib PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/subdir") +add_library(mvstos_use use.f90) +target_link_libraries(mvstos_use PRIVATE mvstos_lib) diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/subdir/CMakeLists.txt b/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/subdir/CMakeLists.txt new file mode 100644 index 0000000..acc0da9 --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/subdir/CMakeLists.txt @@ -0,0 +1 @@ +add_library(mvstos_obj OBJECT obj.f90) diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/subdir/obj.f90 b/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/subdir/obj.f90 new file mode 100644 index 0000000..6b5ddd5 --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/subdir/obj.f90 @@ -0,0 +1,11 @@ +module m1 + +implicit none + +contains + +pure real function pi() +pi = 4*atan(1.) +end function + +end module m1 diff --git a/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/use.f90 b/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/use.f90 new file mode 100644 index 0000000..f971909 --- /dev/null +++ b/Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/use.f90 @@ -0,0 +1,13 @@ +module lib + +use m1, only : pi + +implicit none + +contains + +pure real function func() +func = pi() +end function + +end module diff --git a/Tests/FortranModules/ModulesViaTargetObjectsLink/CMakeLists.txt b/Tests/FortranModules/ModulesViaTargetObjectsLink/CMakeLists.txt new file mode 100644 index 0000000..202e59e --- /dev/null +++ b/Tests/FortranModules/ModulesViaTargetObjectsLink/CMakeLists.txt @@ -0,0 +1,5 @@ +add_library(mvtol_obj STATIC obj.f90) +add_library(mvtol_lib dummy.f90) +target_link_libraries(mvtol_lib PRIVATE "$<TARGET_OBJECTS:mvtol_obj>") +add_library(mvtol_use use.f90) +target_link_libraries(mvtol_use PRIVATE mvtol_lib) diff --git a/Tests/FortranModules/ModulesViaTargetObjectsLink/dummy.f90 b/Tests/FortranModules/ModulesViaTargetObjectsLink/dummy.f90 new file mode 100644 index 0000000..96a8138 --- /dev/null +++ b/Tests/FortranModules/ModulesViaTargetObjectsLink/dummy.f90 @@ -0,0 +1,3 @@ +pure real function dummy() +dummy = 4*atan(1.) +end function diff --git a/Tests/FortranModules/ModulesViaTargetObjectsLink/obj.f90 b/Tests/FortranModules/ModulesViaTargetObjectsLink/obj.f90 new file mode 100644 index 0000000..6b5ddd5 --- /dev/null +++ b/Tests/FortranModules/ModulesViaTargetObjectsLink/obj.f90 @@ -0,0 +1,11 @@ +module m1 + +implicit none + +contains + +pure real function pi() +pi = 4*atan(1.) +end function + +end module m1 diff --git a/Tests/FortranModules/ModulesViaTargetObjectsLink/use.f90 b/Tests/FortranModules/ModulesViaTargetObjectsLink/use.f90 new file mode 100644 index 0000000..f971909 --- /dev/null +++ b/Tests/FortranModules/ModulesViaTargetObjectsLink/use.f90 @@ -0,0 +1,13 @@ +module lib + +use m1, only : pi + +implicit none + +contains + +pure real function func() +func = pi() +end function + +end module diff --git a/Tests/FortranModules/ModulesViaTargetObjectsSource/CMakeLists.txt b/Tests/FortranModules/ModulesViaTargetObjectsSource/CMakeLists.txt new file mode 100644 index 0000000..9113a11 --- /dev/null +++ b/Tests/FortranModules/ModulesViaTargetObjectsSource/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(mvtos_obj OBJECT obj.f90) +add_library(mvtos_lib "$<TARGET_OBJECTS:mvtos_obj>") +add_library(mvtos_use use.f90) +target_link_libraries(mvtos_use PRIVATE mvtos_lib) diff --git a/Tests/FortranModules/ModulesViaTargetObjectsSource/obj.f90 b/Tests/FortranModules/ModulesViaTargetObjectsSource/obj.f90 new file mode 100644 index 0000000..6b5ddd5 --- /dev/null +++ b/Tests/FortranModules/ModulesViaTargetObjectsSource/obj.f90 @@ -0,0 +1,11 @@ +module m1 + +implicit none + +contains + +pure real function pi() +pi = 4*atan(1.) +end function + +end module m1 diff --git a/Tests/FortranModules/ModulesViaTargetObjectsSource/use.f90 b/Tests/FortranModules/ModulesViaTargetObjectsSource/use.f90 new file mode 100644 index 0000000..f971909 --- /dev/null +++ b/Tests/FortranModules/ModulesViaTargetObjectsSource/use.f90 @@ -0,0 +1,13 @@ +module lib + +use m1, only : pi + +implicit none + +contains + +pure real function func() +func = pi() +end function + +end module diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json index 45b0396..78f7928 100644 --- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json +++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-private.json @@ -45,6 +45,7 @@ "exports": [], "include-dirs": [], "language": "CXX", + "forward-modules-from-target-dirs": [], "linked-target-dirs": [], "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-bmi-install-private.dir<CONFIG_DIR>" } diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json index 30b55e3..6c23354 100644 --- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json +++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoBMIInstall-public.json @@ -45,6 +45,7 @@ "exports": [], "include-dirs": [], "language": "CXX", + "forward-modules-from-target-dirs": [], "linked-target-dirs": [], "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-bmi-install-public.dir<CONFIG_DIR>" } diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json index f06a846..61f8f64 100644 --- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json +++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-private.json @@ -73,6 +73,7 @@ ], "include-dirs": [], "language": "CXX", + "forward-modules-from-target-dirs": [], "linked-target-dirs": [], "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-private.dir<CONFIG_DIR>" } diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json index 938481c..d0263b0 100644 --- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json +++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoExport-public.json @@ -73,6 +73,7 @@ ], "include-dirs": [], "language": "CXX", + "forward-modules-from-target-dirs": [], "linked-target-dirs": [], "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-exports-public.dir<CONFIG_DIR>" } diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json index 3a66a94..ed61e0e 100644 --- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json +++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-private.json @@ -40,6 +40,7 @@ "exports": [], "include-dirs": [], "language": "CXX", + "forward-modules-from-target-dirs": [], "linked-target-dirs": [], "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-file-sets-private.dir<CONFIG_DIR>" } diff --git a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json index ac06c0f..171935f 100644 --- a/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json +++ b/Tests/RunCMake/CXXModules/expect/NinjaDependInfoFileSet-public.json @@ -40,6 +40,7 @@ "exports": [], "include-dirs": [], "language": "CXX", + "forward-modules-from-target-dirs": [], "linked-target-dirs": [], "module-dir": "<BINARY_DIR>/CMakeFiles/ninja-file-sets-public.dir<CONFIG_DIR>" } |