Describe the bug
Environment
- Conan version: 2.29.1 (mechanism also present on
develop2 as of 2026-08)
- OS: Windows (generator-agnostic; the CPS parsing is platform-independent)
- Generator:
CMakeConfigDeps (experimental CPS consumption)
- Producer: CMake 4.4
export(PACKAGE_INFO) / install(PACKAGE_INFO), multi-config
generator (Ninja Multi-Config)
Summary
When a dependency's CPS descriptor stores per-configuration artifact locations in the
inline per-component configurations map (a valid CPS representation, and what CMake's
export(PACKAGE_INFO) emits for a multi-config build), Conan's CPS reader does not read it.
CPS.to_conan() therefore produces components with no libraries (libs/libdirs
empty), so a consumer fails to link (unresolved external / Cannot obtain 'location').
How to reproduce it
Reproduction
- A multi-component package built with a multi-config generator that emits a CPS via
export(PACKAGE_INFO) (e.g. consuming it as a Conan editable).
- Consume with
CMakeConfigDeps and self.cpp_info = CPS.load(cps_path).to_conan().
- Inspect the generated dependency data: every component's
*_LIBS_<CONFIG> and
*_LIB_DIRS_<CONFIG> are empty; linking the consumer fails with unresolved externals.
Inspecting the descriptor shows the data is present, just inline:
{
"components": {
"MyLib": {
"type": "dylib",
"configurations": {
"Debug": { "link_location": ".../lib/Debug/MyLib.lib", "location": ".../bin/Debug/MyLib.dll" },
"Release": { "link_location": ".../lib/Release/MyLib.lib", "location": ".../bin/Release/MyLib.dll" }
}
}
}
}
Consumer-side workaround
Hoist the active build type's inline config data to the component top level before
deserializing:
import json
from conan.cps.cps import CPS
with open(cps_path, encoding="utf-8") as fh:
document = json.load(fh)
components = document.get("components", {})
if any("configurations" in c for c in components.values()):
build_type = str(self.settings.build_type)
for comp in components.values():
cfg = (comp.get("configurations") or {}).get(build_type) or {}
for key in ("location", "link_location", "link_libraries", "link_languages"):
if not comp.get(key) and cfg.get(key):
comp[key] = cfg[key]
cpp_info = CPS.deserialize(document).to_conan()
else:
cpp_info = CPS.load(cps_path).to_conan()
Describe the bug
Environment
develop2as of 2026-08)CMakeConfigDeps(experimental CPS consumption)export(PACKAGE_INFO)/install(PACKAGE_INFO), multi-configgenerator (Ninja Multi-Config)
Summary
When a dependency's CPS descriptor stores per-configuration artifact locations in the
inline per-component
configurationsmap (a valid CPS representation, and what CMake'sexport(PACKAGE_INFO)emits for a multi-config build), Conan's CPS reader does not read it.CPS.to_conan()therefore produces components with no libraries (libs/libdirsempty), so a consumer fails to link (
unresolved external/Cannot obtain 'location').How to reproduce it
Reproduction
export(PACKAGE_INFO)(e.g. consuming it as a Conan editable).CMakeConfigDepsandself.cpp_info = CPS.load(cps_path).to_conan().*_LIBS_<CONFIG>and*_LIB_DIRS_<CONFIG>are empty; linking the consumer fails with unresolved externals.Inspecting the descriptor shows the data is present, just inline:
{ "components": { "MyLib": { "type": "dylib", "configurations": { "Debug": { "link_location": ".../lib/Debug/MyLib.lib", "location": ".../bin/Debug/MyLib.dll" }, "Release": { "link_location": ".../lib/Release/MyLib.lib", "location": ".../bin/Release/MyLib.dll" } } } } }Consumer-side workaround
Hoist the active build type's inline config data to the component top level before
deserializing: