From 7c1e52be875548c243168a5630a054e84b47026a Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 10:53:34 -0500 Subject: Tests/FortranModules: add test for TARGET_OBJECTS-as-sources module usage Test module usage across a `$`-as-sources use case. See: #25425 --- Tests/FortranModules/CMakeLists.txt | 4 ++++ .../ModulesViaSubdirTargetObjectsSource/CMakeLists.txt | 6 ++++++ .../subdir/CMakeLists.txt | 1 + .../ModulesViaSubdirTargetObjectsSource/subdir/obj.f90 | 11 +++++++++++ .../ModulesViaSubdirTargetObjectsSource/use.f90 | 13 +++++++++++++ .../ModulesViaTargetObjectsSource/CMakeLists.txt | 4 ++++ Tests/FortranModules/ModulesViaTargetObjectsSource/obj.f90 | 11 +++++++++++ Tests/FortranModules/ModulesViaTargetObjectsSource/use.f90 | 13 +++++++++++++ 8 files changed, 63 insertions(+) create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/CMakeLists.txt create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/subdir/CMakeLists.txt create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/subdir/obj.f90 create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsSource/use.f90 create mode 100644 Tests/FortranModules/ModulesViaTargetObjectsSource/CMakeLists.txt create mode 100644 Tests/FortranModules/ModulesViaTargetObjectsSource/obj.f90 create mode 100644 Tests/FortranModules/ModulesViaTargetObjectsSource/use.f90 diff --git a/Tests/FortranModules/CMakeLists.txt b/Tests/FortranModules/CMakeLists.txt index 16ea0d4..8e95152e 100644 --- a/Tests/FortranModules/CMakeLists.txt +++ b/Tests/FortranModules/CMakeLists.txt @@ -137,3 +137,7 @@ add_subdirectory(Issue25252-iface-sources) add_subdirectory(Issue25365-target-objects) add_subdirectory(Issue25365-target-objects-iface) + +# Issue#25425 +add_subdirectory(ModulesViaTargetObjectsSource) +add_subdirectory(ModulesViaSubdirTargetObjectsSource) 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_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/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 "$") +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 -- cgit v0.12 From 9d2769ecbd497dd51405ae2586ae62b828712a07 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 10:53:34 -0500 Subject: Tests/FortranModules: add test for TARGET_OBJECTS-as-linked-items module usage Test module usage across a `$`-as-linked-items use case. See: #25425 --- Tests/FortranModules/CMakeLists.txt | 2 ++ .../ModulesViaSubdirTargetObjectsLink/CMakeLists.txt | 7 +++++++ .../ModulesViaSubdirTargetObjectsLink/dummy.f90 | 3 +++ .../ModulesViaSubdirTargetObjectsLink/subdir/CMakeLists.txt | 1 + .../ModulesViaSubdirTargetObjectsLink/subdir/obj.f90 | 11 +++++++++++ .../ModulesViaSubdirTargetObjectsLink/use.f90 | 13 +++++++++++++ .../ModulesViaTargetObjectsLink/CMakeLists.txt | 5 +++++ Tests/FortranModules/ModulesViaTargetObjectsLink/dummy.f90 | 3 +++ Tests/FortranModules/ModulesViaTargetObjectsLink/obj.f90 | 11 +++++++++++ Tests/FortranModules/ModulesViaTargetObjectsLink/use.f90 | 13 +++++++++++++ 10 files changed, 69 insertions(+) create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/CMakeLists.txt create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/dummy.f90 create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/subdir/CMakeLists.txt create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/subdir/obj.f90 create mode 100644 Tests/FortranModules/ModulesViaSubdirTargetObjectsLink/use.f90 create mode 100644 Tests/FortranModules/ModulesViaTargetObjectsLink/CMakeLists.txt create mode 100644 Tests/FortranModules/ModulesViaTargetObjectsLink/dummy.f90 create mode 100644 Tests/FortranModules/ModulesViaTargetObjectsLink/obj.f90 create mode 100644 Tests/FortranModules/ModulesViaTargetObjectsLink/use.f90 diff --git a/Tests/FortranModules/CMakeLists.txt b/Tests/FortranModules/CMakeLists.txt index 8e95152e..1e5ff89 100644 --- a/Tests/FortranModules/CMakeLists.txt +++ b/Tests/FortranModules/CMakeLists.txt @@ -141,3 +141,5 @@ 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_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/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 "$") +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 -- cgit v0.12 From b34a8fcb8ef434183c1a5ab26b46165a854822a9 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:44:45 -0500 Subject: cmGeneratorTarget: track object libraries using a `set` This avoids having to do manual "is already present" checks. The order the targets are processed does not need to be preserved because the resulting `languages` result is already a `set`. --- Source/cmGeneratorTarget.cxx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 930922c..372caab 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -8044,27 +8044,21 @@ void cmGeneratorTarget::GetLanguages(std::set& languages, } } - std::vector objectLibraries; - std::vector externalObjects; + std::set objectLibraries; if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) { std::vector objectTargets; this->GetObjectLibrariesCMP0026(objectTargets); - objectLibraries.reserve(objectTargets.size()); for (cmGeneratorTarget* gt : objectTargets) { - objectLibraries.push_back(gt); + objectLibraries.insert(gt); } } else { + std::vector externalObjects; 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.insert(tgt); } } } -- cgit v0.12 From ee4e85e615aa21323f4d5c88a162e4ddc1e83c46 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:46:21 -0500 Subject: cmGeneratorTarget: use pointers to `const` generator targets for languages --- Source/cmGeneratorTarget.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 372caab..333ed07 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -8044,7 +8044,7 @@ void cmGeneratorTarget::GetLanguages(std::set& languages, } } - std::set objectLibraries; + std::set objectLibraries; if (!this->GlobalGenerator->GetConfigureDoneCMP0026()) { std::vector objectTargets; this->GetObjectLibrariesCMP0026(objectTargets); @@ -8062,7 +8062,7 @@ void cmGeneratorTarget::GetLanguages(std::set& languages, } } } - for (cmGeneratorTarget* objLib : objectLibraries) { + for (cmGeneratorTarget const* objLib : objectLibraries) { objLib->GetLanguages(languages, config); } } -- cgit v0.12 From d8182105a1d62307aa5f5aa8388e074ecacf0773 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:47:23 -0500 Subject: cmGeneratorTarget: add a query for targets with objects in the source list This will be eventually be used to inform the collator of this information so that Fortran modules provided by the resulting objects can also be used as intended. --- Source/cmGeneratorTarget.cxx | 27 ++++++++++++++++++--------- Source/cmGeneratorTarget.h | 5 +++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 333ed07..29d2af3 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -8052,21 +8052,30 @@ void cmGeneratorTarget::GetLanguages(std::set& languages, objectLibraries.insert(gt); } } else { - std::vector 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); - } - } + objectLibraries = this->GetSourceObjectLibraries(config); } for (cmGeneratorTarget const* objLib : objectLibraries) { objLib->GetLanguages(languages, config); } } +std::set cmGeneratorTarget::GetSourceObjectLibraries( + std::string const& config) const +{ + std::set objectLibraries; + std::vector 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 { 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 GetSourceObjectLibraries( + std::string const& config) const; + bool IsCSharpOnly() const; bool IsDotNetSdkTarget() const; -- cgit v0.12 From 515ca5fcd16f97c9f0a516046dfe22ecfc9676c4 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:59:28 -0500 Subject: cmCommonTargetGenerator: use modules from object-referenced targets Fortran modules provided by objects added as sources via `$` should also be considered as "linked targets" for collation purposes. As C++ modules have their own visibility rules through their `FILE_SET` feature, do not expose these for C++ module collation. --- Source/cmCommonTargetGenerator.cxx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index a29dd76..1d670fe 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -201,6 +201,14 @@ std::vector cmCommonTargetGenerator::GetLinkedTargetDirectories( for (cmGeneratorTarget const* target : cli->GetExternalObjectTargets()) { addLinkedTarget(target); } + if (lang == "Fortran"_s) { + // Fortran modules provided by `$` as sources should be + // collated for use in this target. + for (cmGeneratorTarget const* target : + this->GeneratorTarget->GetSourceObjectLibraries(config)) { + addLinkedTarget(target); + } + } } return dirs; } -- cgit v0.12 From c1fc5455b192e2791010c4bec20b300c7652b712 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:50:14 -0500 Subject: cmGeneratorTarget: also check included objects for Fortran modules Fortran modules provided by objects in `$` should also count as "has Fortran modules" for the target referencing the objects. --- Source/cmGeneratorTarget.cxx | 46 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 29d2af3..146319a 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -9090,19 +9090,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 const& sf) -> bool { - return sf.Value->GetLanguage() == "Fortran"_s; - }); + bool const have_direct = std::any_of( + sources.begin(), sources.end(), [](BT 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 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 -- cgit v0.12 From 6afe841e620f9149cd70821a952ec3a0460b8d3c Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:51:47 -0500 Subject: cmNinjaTargetGenerator: handle object-referencing Fortran modules Targets only using Fortran modules via `$` also need a collation step to be performed. Check for this case and trigger the collation rule to be added and used. --- Source/cmNinjaTargetGenerator.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index dabb078..f6b51aa 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 const& scanningFiles = langScanningFiles.second; -- cgit v0.12 From f8729ab3667c695a734df0164cca692393bb6810 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:51:47 -0500 Subject: cmLocalUnixMakefileGenerator3: handle object-referencing Fortran modules Targets only using Fortran modules via `$` also need a collation step to be performed. Check for this case and trigger the depends rule to be used. --- Source/cmLocalUnixMakefileGenerator3.cxx | 11 +++++++++++ 1 file changed, 11 insertions(+) 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"; -- cgit v0.12 From 06df59b9308d74b3f8a5eada84cf2402dd22b434 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Mon, 20 Nov 2023 10:10:16 -0500 Subject: cmCommonTargetGenerator: return forward linked target dirs too This will be used for module forwarding in order to support `$` usage in source and link libraries calls. --- Source/cmCommonTargetGenerator.cxx | 73 ++++++++++++++++++++++-------------- Source/cmCommonTargetGenerator.h | 11 +++++- Source/cmMakefileTargetGenerator.cxx | 4 +- Source/cmNinjaTargetGenerator.cxx | 12 +++--- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 1d670fe..0896216 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -163,50 +163,65 @@ std::string cmCommonTargetGenerator::GetIncludes(std::string const& l, return i->second; } -std::vector cmCommonTargetGenerator::GetLinkedTargetDirectories( +cmCommonTargetGenerator::LinkedTargetDirs +cmCommonTargetGenerator::GetLinkedTargetDirectories( const std::string& lang, const std::string& config) const { - std::vector dirs; - std::set emitted; + LinkedTargetDirs dirs; + std::set forward_emitted; + std::set 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); + addLinkedTarget(item.Target, Forwarding::No); } for (cmGeneratorTarget const* target : cli->GetExternalObjectTargets()) { - addLinkedTarget(target); + addLinkedTarget(target, Forwarding::No); } if (lang == "Fortran"_s) { // Fortran modules provided by `$` as sources should be // collated for use in this target. for (cmGeneratorTarget const* target : this->GeneratorTarget->GetSourceObjectLibraries(config)) { - addLinkedTarget(target); + addLinkedTarget(target, Forwarding::Yes); } } } 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 GetLinkedTargetDirectories( - const std::string& lang, const std::string& config) const; + + struct LinkedTargetDirs + { + std::vector Direct; + std::vector 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/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 0c2a719..3ad0928 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1440,9 +1440,9 @@ 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 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"; diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index f6b51aa..1adcaad 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1206,10 +1206,10 @@ 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")); } this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), @@ -1909,7 +1909,9 @@ 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); } -- cgit v0.12 From ec1e589bec6567c955db24adeb6294258e3db463 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 21 Nov 2023 09:19:08 -0500 Subject: Ninja: Revert exact collation dependencies for 3.27 Revert commit b6a5382217 (Ninja: depend on language module information files directly, 2023-02-10, v3.27.0-rc1~502^2) from !8197. This reverts the "exact dependencies" for collation inputs and returns to "get all targets" and target-ordering. Use of exact dependencies caused a parade of use cases that had not been tested previously to be found and need fixing over the 3.27 release series. To stop the flow on 3.27, revert to the 3.26 strategy. We will continue in 3.28. Note that this is a restoration of 3.26 semantics where incremental rebuilds may be subtly incorrect in the presence of stale `Modules.json` files. However, since C++ support is experimental and Fortran has always had this problem as of 3.27, it is not considered a regression. See: #25112 See: #25123 See: #25252 See: #25365 See: #25417 See: #25425 --- Source/cmNinjaTargetGenerator.cxx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index d712d71..bc04d1f 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1034,11 +1034,6 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( cmNinjaBuild build(this->LanguageDyndepRule(language, config)); build.Outputs.push_back(this->GetDyndepFilePath(language, config)); - build.ImplicitOuts.push_back( - cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), '/', - this->LocalGenerator->GetTargetDirectory(this->GeneratorTarget), - this->GetGlobalGenerator()->ConfigDirectory(config), '/', - language, "Modules.json")); for (auto const& scanFiles : scanningFiles) { if (!scanFiles.ScanningOutput.empty()) { build.ExplicitDeps.push_back(scanFiles.ScanningOutput); @@ -1050,10 +1045,17 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( this->WriteTargetDependInfo(language, config); - for (std::string const& l : - this->GetLinkedTargetDirectories(language, config)) { - build.ImplicitDeps.push_back(cmStrCat(l, '/', language, "Modules.json")); - } + // Make sure dyndep files for all our dependencies have already + // been generated so that the 'Modules.json' files they + // produced as side-effects are available for us to read. + // Ideally we should depend on the 'Modules.json' files + // from our dependencies directly, but we don't know which of + // our dependencies produces them. Fixing this will require + // refactoring the Ninja generator to generate targets in + // dependency order so that we can collect the needed information. + this->GetLocalGenerator()->AppendTargetDepends( + this->GeneratorTarget, build.OrderOnlyDeps, config, fileConfig, + DependOnTargetArtifact); this->GetGlobalGenerator()->WriteBuild(this->GetImplFileStream(fileConfig), build); -- cgit v0.12 From d2fa56772f290c61925a70161c77be5f4334fd77 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:53:45 -0500 Subject: Ninja: support "forwarding" modules from other targets When a target uses objects from another target which provides modules as sources, the modules provided by the referenced target must also be treated as if they were provided by the referencing target. Add the concept of "forwarding" modules so that consumers can use modules created by these sources as well. Note that this is only sensible for Fortran where module usages are implicit as far as CMake's visibility model is concerned. C++ modules have their own concept of visibility which does not require or support such `$` reuse in this way. --- Source/cmGlobalNinjaGenerator.cxx | 59 +++++++++++++++++++++- Source/cmGlobalNinjaGenerator.h | 1 + Source/cmNinjaTargetGenerator.cxx | 9 ++++ .../expect/NinjaDependInfoBMIInstall-private.json | 1 + .../expect/NinjaDependInfoBMIInstall-public.json | 1 + .../expect/NinjaDependInfoExport-private.json | 1 + .../expect/NinjaDependInfoExport-public.json | 1 + .../expect/NinjaDependInfoFileSet-private.json | 1 + .../expect/NinjaDependInfoFileSet-public.json | 1 + 9 files changed, 74 insertions(+), 1 deletion(-) 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 const& arg_ddis, std::string const& module_dir, std::vector const& linked_target_dirs, + std::vector 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::const_iterator argBeg, linked_target_dirs.push_back(tdi_linked_target_dir.asString()); } } + std::vector 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::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 const& arg_ddis, std::string const& module_dir, std::vector const& linked_target_dirs, + std::vector const& forward_modules_from_target_dirs, std::string const& arg_lang, std::string const& arg_modmapfmt, cmCxxModuleExportInfo const& export_info); diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 1adcaad..2283923 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -1211,6 +1211,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( 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), build); @@ -1915,6 +1918,12 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, 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/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": "/CMakeFiles/ninja-bmi-install-private.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": "/CMakeFiles/ninja-bmi-install-public.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": "/CMakeFiles/ninja-exports-private.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": "/CMakeFiles/ninja-exports-public.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": "/CMakeFiles/ninja-file-sets-private.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": "/CMakeFiles/ninja-file-sets-public.dir" } -- cgit v0.12 From 1175f1c874a7cd34d643902bc428df92bce3471a Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 23:04:35 -0500 Subject: LinkItem: track `cmSourceFile` instances for external objects The target may be required in order to provide Fortran modules, so track the source file so that the target may be looked up when needed. --- Source/cmComputeLinkDepends.cxx | 1 + Source/cmComputeLinkDepends.h | 4 ++++ Source/cmComputeLinkInformation.cxx | 26 +++++++++++++------------- Source/cmComputeLinkInformation.h | 6 ++++++ Source/cmGeneratorTarget.cxx | 2 ++ Source/cmLinkItem.h | 4 ++++ 6 files changed, 30 insertions(+), 13 deletions(-) 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(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 Item; cmGeneratorTarget const* Target = nullptr; + // The source file representing the external object (used when linking + // `$`) + cmSourceFile const* ObjectSource = nullptr; EntryKind Kind = Library; // The following member is for the management of items specified // through genex $ 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(exe, item.Backtrace), ItemIsPath::Yes, tgt, + BT(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 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 Value; ItemIsPath IsPath = ItemIsPath::No; cmGeneratorTarget const* Target = nullptr; + // The source file representing the external object (used when linking + // `$`) + cmSourceFile const* ObjectSource = nullptr; bool HasFeature() const { return this->Feature != nullptr; } const std::string& GetFeatureName() const diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 146319a..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; } @@ -8489,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; } 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 + // `$`) + cmSourceFile const* ObjectSource = nullptr; bool Cross = false; cmListFileBacktrace Backtrace; friend bool operator<(cmLinkItem const& l, cmLinkItem const& r); -- cgit v0.12 From 7cd0adab1b0149fe227c4eda3bd085e2d1f4dd52 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Fri, 17 Nov 2023 22:59:28 -0500 Subject: cmCommonTargetGenerator: use modules from linked object-referenced targets Fortran modules provided by objects added as linked items via `$` should also be considered as "linked targets" for collation purposes. As C++ modules have their own visibility rules through their `FILE_SET` feature, do not expose these for C++ module collation. --- Source/cmCommonTargetGenerator.cxx | 13 ++++++++++++- Source/cmMakefile.cxx | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 0896216..90f0d55 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -211,7 +211,18 @@ cmCommonTargetGenerator::GetLinkedTargetDirectories( } }; for (auto const& item : cli->GetItems()) { - addLinkedTarget(item.Target, Forwarding::No); + 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 `$` 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, Forwarding::No); 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()); -- cgit v0.12 From a033dce326016c304a299fa51b8c13b9f832c8d0 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Sun, 19 Nov 2023 18:02:19 -0500 Subject: Makefiles: provide, but do not consume, "forward linked" target dirs Makefiles do not have a per-object sense of where they come from, so forwarding any module information here would end up with incorrect module file path construction by consuming targets. Leave a TODO item in its place. --- Source/cmDependsFortran.cxx | 6 ++++++ Source/cmMakefileTargetGenerator.cxx | 11 +++++++++++ 2 files changed, 17 insertions(+) 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/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 3ad0928..74b4b75 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -1446,6 +1446,17 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() *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"; } std::string const& working_dir = -- cgit v0.12