Skip to content

Commit

Permalink
fix incubating CMakeDeps replace_requires (#17566)
Browse files Browse the repository at this point in the history
* fix incubating CMakeDeps replace_requires

* fix tests

* possible fix

* add PkgConfigDeps check

* Fixed bug using the replace_requires mechanism in PkgConfigDeps. Some variables renames (clearer names)

* More tests

* Minor changes

---------

Co-authored-by: Francisco Ramirez de Anton <[email protected]>
  • Loading branch information
memsharded and franramirez688 authored Jan 27, 2025
1 parent c3561df commit 626b50f
Show file tree
Hide file tree
Showing 6 changed files with 338 additions and 15 deletions.
2 changes: 1 addition & 1 deletion conan/internal/model/cpp_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ def deduce_full_cpp_info(self, conanfile):

for lib in self.libs:
c = _Component() # Do not do a full clone, we don't need the properties
c.type = self.type # This should be a string
c.type = self.type
c.includedirs = self.includedirs
c.libdirs = self.libdirs
c.bindirs = self.bindirs
Expand Down
8 changes: 5 additions & 3 deletions conan/internal/model/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def transitive_requires(self, other):
for k, v in self._data.items():
for otherk, otherv in other._data.items():
if v == otherv:
data[k] = v
data[otherk] = v # Use otherk to respect original replace_requires
return ConanFileDependencies(data)

@property
Expand Down Expand Up @@ -182,6 +182,8 @@ def get_transitive_requires(consumer, dependency):
# The build dependencies cannot be transitive in generators like CMakeDeps,
# even if users make them visible
pkg_deps = dependency.dependencies.filter({"direct": True, "build": False})
result = consumer.dependencies.transitive_requires(pkg_deps)
result = result.filter({"skip": False})
# First we filter the skipped dependencies
result = consumer.dependencies.filter({"skip": False})
# and we keep those that are really dependencies of the current package
result = result.transitive_requires(pkg_deps)
return result
2 changes: 1 addition & 1 deletion conan/tools/cmake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def CMakeDeps(conanfile): # noqa
if conanfile.conf.get("tools.cmake.cmakedeps:new", choices=["will_break_next"]):
from conan.tools.cmake.cmakedeps2.cmakedeps import CMakeDeps2
conanfile.output.warning("Using the new CMakeDeps generator, behind the "
"'tools.cmake.cmakedeps:new' gate conf. This conf will change"
"'tools.cmake.cmakedeps:new' gate conf. This conf will change "
"next release, breaking, so use it only for testing and dev")
return CMakeDeps2(conanfile)
from conan.tools.cmake.cmakedeps.cmakedeps import CMakeDeps as _CMakeDeps
Expand Down
4 changes: 3 additions & 1 deletion conan/tools/cmake/cmakedeps2/target_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@ def _requires(self, info, components):
# It must be the interface pkgname::pkgname target
assert required_pkg == required_comp
comp = None
default_target = f"{dep.ref.name}::{dep.ref.name}" # replace_requires
else:
comp = required_comp
default_target = f"{required_pkg}::{required_comp}"
dep_target = self._cmakedeps.get_property("cmake_target_name", dep, comp)
dep_target = dep_target or f"{required_pkg}::{required_comp}"
dep_target = dep_target or default_target
result.append(dep_target)
return result

Expand Down
25 changes: 16 additions & 9 deletions conan/tools/gnu/pkgconfigdeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def package_info(self):
continue # If the dependency is not in the transitive, might be skipped
else: # For instance, dep == "hello/1.0" and req == "hello::cmp1" -> hello == hello
req_conanfile = self._dep
comp_name = self._get_component_name(req_conanfile, comp_ref_name)
comp_name = self._get_component_name(req_conanfile, pkg_ref_name, comp_ref_name)
if not comp_name:
pkg_name = self._get_package_name(req_conanfile)
# Creating a component name with namespace, e.g., dep-comp1
Expand All @@ -203,13 +203,13 @@ def _components_info(self):
for comp_ref_name, cpp_info in self._dep.cpp_info.get_sorted_components().items():
# At first, let's check if we have defined some components requires, e.g., "dep::cmp1"
comp_requires_names = self._get_cpp_info_requires_names(cpp_info)
comp_name = self._get_component_name(self._dep, comp_ref_name)
comp_name = self._get_component_name(self._dep, pkg_name, comp_ref_name)
if not comp_name:
comp_name = self._get_name_with_namespace(pkg_name, comp_ref_name)
comp_description = f"Conan component: {comp_name}"
else:
comp_description = f"Conan component: {pkg_name}-{comp_name}"
comp_aliases = self._get_component_aliases(self._dep, comp_ref_name)
comp_aliases = self._get_component_aliases(self._dep, pkg_name, comp_ref_name)
comp_version = (self.get_property("component_version", self._dep, comp_ref_name) or
self.get_property("system_package_version", self._dep, comp_ref_name) or
self._dep.ref.version)
Expand Down Expand Up @@ -314,10 +314,14 @@ def _get_package_aliases(self, dep):
pkg_aliases = self.get_property("pkg_config_aliases", dep, check_type=list)
return pkg_aliases or []

def _get_component_aliases(self, dep, comp_name):
def _get_component_aliases(self, dep, pkg_name, comp_name):
# TODO: LET'S DEPRECATE ALL THE ALIASES MECHANISM!!
if comp_name not in dep.cpp_info.components:
# foo::foo might be referencing the root cppinfo
if dep.ref.name == comp_name:
# Either foo::foo might be referencing the root cpp_info
if (dep.ref.name == comp_name or
# Or a "replace_require" is used and cpp_info.requires is the root one, e.g.,
# zlib/*: zlib-ng/*, and self.cpp_info.requires = ["zlib::zlib"]
(dep.ref.name != pkg_name and pkg_name == comp_name)):
return self._get_package_aliases(dep)
raise ConanException("Component '{name}::{cname}' not found in '{name}' "
"package requirement".format(name=dep.ref.name,
Expand All @@ -329,10 +333,13 @@ def _get_package_name(self, dep):
pkg_name = self.get_property("pkg_config_name", dep) or dep.ref.name
return f"{pkg_name}{self._suffix}"

def _get_component_name(self, dep, comp_name):
def _get_component_name(self, dep, pkg_name, comp_name):
if comp_name not in dep.cpp_info.components:
# foo::foo might be referencing the root cppinfo
if dep.ref.name == comp_name:
# Either foo::foo might be referencing the root cpp_info
if (dep.ref.name == comp_name or
# Or a "replace_require" is used and cpp_info.requires is the root one, e.g.,
# zlib/*: zlib-ng/*, and self.cpp_info.requires = ["zlib::zlib"]
(dep.ref.name != pkg_name and pkg_name == comp_name)):
return self._get_package_name(dep)
raise ConanException("Component '{name}::{cname}' not found in '{name}' "
"package requirement".format(name=dep.ref.name,
Expand Down
Loading

0 comments on commit 626b50f

Please sign in to comment.