fileapi: Handle unused imported libraries with missing IMPORTED_IMPLIB

CMake 4.1 and earlier did not issue an error if an imported shared library target
was missing an IMPORTED_IMPLIB property and nothing used that imported
library. There was no code path checking for the CMP0111 NEW behavior. Since
b626843d71 (fileAPI: Output all INTERFACE and IMPORTED targets, 2025-09-13),
we now include all imported targets in the file API replies, and that does trigger
that check. We need to tolerate such imported targets to preserve backward
compatibility, and to avoid issuing errors for problems in targets likely to be
coming from outside the project and beyond the developer's control.

Fixes: #27496
This commit is contained in:
Craig Scott
2026-01-10 00:26:55 +11:00
parent 7792c68838
commit c6a940761c
8 changed files with 101 additions and 12 deletions
+27 -6
View File
@@ -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) {
+3 -2
View File
@@ -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;
+9 -2
View File
@@ -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
{
@@ -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"),
@@ -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",
@@ -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$"
]
}
@@ -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
}
@@ -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}"
)