diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index b4b60f651e..35afd91056 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -2049,13 +2049,34 @@ Json::Value Target::DumpArtifacts() } // Add Windows-specific artifacts produced by the linker. + // NOTE: HasImportLibrary() only checks if the target SHOULD have an import + // library, not whether it has one set. if (this->GT->HasImportLibrary(this->Config)) { - Json::Value artifact = Json::objectValue; - artifact["path"] = - RelativeIfUnder(this->TopBuild, - this->GT->GetFullPath( - this->Config, cmStateEnums::ImportLibraryArtifact)); - artifacts.append(std::move(artifact)); // NOLINT(*) + std::string fullPath; + if (this->GT->IsImported()) { + // This imported target might not be well-formed. For Windows, it should + // have its IMPORTED_IMPLIB property set, and CMP0111's NEW behavior is + // intended to catch and report that. But if nothing uses the imported + // target, there won't have been any opportunity to detect that property + // being missing before here. Therefore, we tell ImportedGetFullPath() + // not to raise that CMP0111 error if it sees the problem. We don't want + // to trigger an error for a target that nothing uses, as that would be a + // regression compared to CMake 4.1 and earlier behavior. + fullPath = this->GT->Target->ImportedGetFullPath( + this->Config, cmStateEnums::ImportLibraryArtifact, + cmTarget::ImportArtifactMissingOk::Yes); + if (cmHasLiteralSuffix(fullPath, "-NOTFOUND")) { + fullPath.clear(); + } + } else { + fullPath = this->GT->NormalGetFullPath( + this->Config, cmStateEnums::ImportLibraryArtifact, false); + } + if (!fullPath.empty()) { + Json::Value artifact = Json::objectValue; + artifact["path"] = RelativeIfUnder(this->TopBuild, fullPath); + artifacts.append(std::move(artifact)); // NOLINT(*) + } } if (this->GT->IsDLLPlatform() && this->GT->GetType() != cmStateEnums::STATIC_LIBRARY) { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 6c0cd8b6cc..ad37fe0ae0 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -2993,7 +2993,8 @@ char const* cmTarget::GetPrefixVariableInternal( } std::string cmTarget::ImportedGetFullPath( - std::string const& config, cmStateEnums::ArtifactType artifact) const + std::string const& config, cmStateEnums::ArtifactType artifact, + ImportArtifactMissingOk missingOk) const { assert(this->IsImported()); @@ -3074,7 +3075,7 @@ std::string cmTarget::ImportedGetFullPath( } } - if (result.empty()) { + if (result.empty() && missingOk != ImportArtifactMissingOk::Yes) { if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY) { auto message = [&]() -> std::string { std::string unset; diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 1eed1006a9..96a067b4d7 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -328,8 +328,15 @@ public: cmBTStringRange GetInterfaceHeaderSetsEntries() const; cmBTStringRange GetInterfaceCxxModuleSetsEntries() const; - std::string ImportedGetFullPath(std::string const& config, - cmStateEnums::ArtifactType artifact) const; + enum class ImportArtifactMissingOk + { + No, + Yes + }; + + std::string ImportedGetFullPath( + std::string const& config, cmStateEnums::ArtifactType artifact, + ImportArtifactMissingOk missingOk = ImportArtifactMissingOk::No) const; struct StrictTargetComparison { diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py index 8b2e1c30e8..8d140aba71 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py +++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py @@ -1224,6 +1224,7 @@ def gen_check_abstract_targets(c, g, inSource): read_codemodel_json_data("targets/imported_object_lib.json"), read_codemodel_json_data("targets/imported_shared_lib.json"), read_codemodel_json_data("targets/imported_static_lib.json"), + read_codemodel_json_data("targets/unused_imported_shared_lib.json"), read_codemodel_json_data("targets/iface_none.json"), read_codemodel_json_data("targets/iface_symbolic.json"), diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json index bbb77ecb83..6dd03a6ac2 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json +++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/imported.json @@ -20,7 +20,8 @@ "^imported_lib::@ba7eb709d0b48779c6c8$", "^imported_object_lib::@ba7eb709d0b48779c6c8$", "^imported_shared_lib::@ba7eb709d0b48779c6c8$", - "^imported_static_lib::@ba7eb709d0b48779c6c8$" + "^imported_static_lib::@ba7eb709d0b48779c6c8$", + "^unused_imported_shared_lib::@ba7eb709d0b48779c6c8$" ], "projectName": "Imported", "minimumCMakeVersion": "3.13", diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/projects/imported.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/projects/imported.json index 56734181a6..80d24177b8 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-data/projects/imported.json +++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/projects/imported.json @@ -22,6 +22,7 @@ "^imported_interface_symbolic_lib::@ba7eb709d0b48779c6c8$", "^imported_object_lib::@ba7eb709d0b48779c6c8$", "^imported_shared_lib::@ba7eb709d0b48779c6c8$", - "^imported_static_lib::@ba7eb709d0b48779c6c8$" + "^imported_static_lib::@ba7eb709d0b48779c6c8$", + "^unused_imported_shared_lib::@ba7eb709d0b48779c6c8$" ] } diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/unused_imported_shared_lib.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/unused_imported_shared_lib.json new file mode 100644 index 0000000000..133c78f989 --- /dev/null +++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/targets/unused_imported_shared_lib.json @@ -0,0 +1,50 @@ +{ + "name": "unused_imported_shared_lib", + "id": "^unused_imported_shared_lib::@ba7eb709d0b48779c6c8$", + "directorySource": "^imported$", + "projectName": "Imported", + "type": "SHARED_LIBRARY", + "imported": true, + "local": true, + "abstract": true, + "symbolic": null, + "isGeneratorProvided": null, + "fileSets": null, + "sources": [], + "sourceGroups": null, + "compileGroups": null, + "backtrace": [ + { + "file": "^imported/CMakeLists\\.txt$", + "line": 48, + "command": "add_library", + "hasParent": true + }, + { + "file": "^imported/CMakeLists\\.txt$", + "line": null, + "command": null, + "hasParent": false + } + ], + "folder": null, + "nameOnDisk": "^(lib|cyg|msys-)?unused_imported_shared\\.(so|dylib|dll)$", + "artifacts": [ + { + "path": "^((Debug|Release|RelWithDebInfo|MinSizeRel)/)?(lib|cyg|msys-)?unused_imported_shared\\.(so|dylib|dll)$", + "_dllExtra": false + } + ], + "build": "^imported$", + "source": "^imported$", + "install": null, + "link": null, + "archive": null, + "dependencies": null, + "linkLibraries": null, + "interfaceLinkLibraries": null, + "compileDependencies": null, + "interfaceCompileDependencies": null, + "objectDependencies": null, + "orderDependencies": null +} diff --git a/Tests/RunCMake/FileAPI/imported/CMakeLists.txt b/Tests/RunCMake/FileAPI/imported/CMakeLists.txt index d9b5902079..9d6ec39f6d 100644 --- a/Tests/RunCMake/FileAPI/imported/CMakeLists.txt +++ b/Tests/RunCMake/FileAPI/imported/CMakeLists.txt @@ -42,3 +42,10 @@ install(IMPORTED_RUNTIME_ARTIFACTS imported_shared_lib install(IMPORTED_RUNTIME_ARTIFACTS imported_shared_lib DESTINATION lib2 OPTIONAL ) + +# This is deliberately missing the IMPORTED_IMPLIB property. +# The file API needs to tolerate this for unused imported targets. +add_library(unused_imported_shared_lib SHARED IMPORTED) +set_target_properties(unused_imported_shared_lib PROPERTIES + IMPORTED_LOCATION "unused_imported_shared${CMAKE_SHARED_LIBRARY_SUFFIX}" +)