diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py index b07b7501502..13fe1179537 100644 --- a/conan/tools/gnu/pkgconfigdeps.py +++ b/conan/tools/gnu/pkgconfigdeps.py @@ -48,33 +48,37 @@ class PkgConfigDeps(object): def __init__(self, conanfile): self._conanfile = conanfile - def _get_require_comp_name(self, pkg_name, req): + def _get_require_comp_name(self, dep, req): + # FIXME: this str() is only needed for python2.7 (unicode values). Remove it for Conan 2.0 + pkg_name = str(dep.ref.name) pkg, comp_name = req.split("::") if "::" in req else (pkg_name, req) - req = self._conanfile.dependencies.direct_host[pkg] + # FIXME: it could allow defining requires to not direct dependencies + req = self._conanfile.dependencies.host[pkg] cmp_name = get_component_alias(req, comp_name) return cmp_name - def _get_components(self, pkg_name, dep): + def _get_components(self, dep): ret = [] for comp_name, comp in dep.new_cpp_info.get_sorted_components().items(): comp_genname = get_component_alias(dep, comp_name) comp_requires_gennames = [] for require in comp.requires: - comp_requires_gennames.append(self._get_require_comp_name(pkg_name, require)) + comp_requires_gennames.append(self._get_require_comp_name(dep, require)) ret.append((comp_genname, comp, comp_requires_gennames)) return ret - def _get_public_require_deps(self, comp): + def _get_public_require_deps(self, dep): public_comp_deps = [] - for require in comp.requires: + + for require in dep.new_cpp_info.requires: if "::" in require: # Points to a component of a different package pkg, cmp_name = require.split("::") - req = self._conanfile.dependencies.direct_host[pkg] + req = dep.dependencies.direct_host[pkg] public_comp_deps.append( (get_target_namespace(req), get_component_alias(req, cmp_name))) else: # Points to a component of same package - public_comp_deps.append((get_target_namespace(self._conanfile), - get_component_alias(self._conanfile, require))) + public_comp_deps.append((get_target_namespace(dep), + get_component_alias(dep, require))) return public_comp_deps @property @@ -85,7 +89,7 @@ def content(self): pkg_genname = get_target_namespace(dep) if dep.new_cpp_info.has_components: - components = self._get_components(dep.ref.name, dep) + components = self._get_components(dep) for comp_genname, comp_cpp_info, comp_requires_gennames in components: pkg_comp_genname = "%s-%s" % (pkg_genname, comp_genname) ret["%s.pc" % pkg_comp_genname] = self._pc_file_content( @@ -99,7 +103,7 @@ def content(self): comp_gennames) else: require_public_deps = [_d for _, _d in - self._get_public_require_deps(dep.new_cpp_info)] + self._get_public_require_deps(dep)] ret["%s.pc" % pkg_genname] = self._pc_file_content(pkg_genname, dep.new_cpp_info, require_public_deps, dep.package_folder, diff --git a/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py b/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py index 95331eb1537..0ddca780fb1 100644 --- a/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py +++ b/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py @@ -5,6 +5,7 @@ import pytest +from conans.test.assets.genconanfile import GenConanfile from conans.test.utils.tools import TestClient from conans.util.files import load @@ -251,6 +252,84 @@ def package_info(self): client.save({"conanfile.py": conanfile}) client.run("create . pkg/0.1@") client.run("install pkg/0.1@ -g PkgConfigDeps") - pc_content = client.load("pkg-mycomponent.pc") assert "componentdir=${prefix}/mydir" in pc_content + + +def test_pkg_with_component_requires(): + client = TestClient() + client.save({"conanfile.py": GenConanfile("other", "0.1").with_package_file("file.h", "0.1")}) + client.run("create . user/channel") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class PkgConfigConan(ConanFile): + requires = "other/0.1@user/channel" + + def package_info(self): + self.cpp_info.components["mycomponent"].requires.append("other::other") + self.cpp_info.components["myothercomp"].requires.append("mycomponent") + + """) + client.save({"conanfile.py": conanfile}) + client.run("create . pkg/0.1@") + + client2 = TestClient(cache_folder=client.cache_folder) + conanfile = textwrap.dedent(""" + [requires] + pkg/0.1 + + [generators] + PkgConfigDeps + """) + client2.save({"conanfile.txt": conanfile}) + client2.run("install .") + pc_content = client2.load("pkg-mycomponent.pc") + assert "Requires: other" in pc_content + + +def test_pkg_getting_public_requires(): + client = TestClient() + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class Recipe(ConanFile): + + def package_info(self): + self.cpp_info.components["cmp1"].libs = ["other_cmp1"] + self.cpp_info.components["cmp2"].libs = ["other_cmp2"] + self.cpp_info.components["cmp3"].requires.append("cmp1") + + """) + client.save({"conanfile.py": conanfile}) + client.run("create . other/1.0@") + + conanfile = textwrap.dedent(""" + from conans import ConanFile + + class PkgConfigConan(ConanFile): + requires = "other/1.0" + + def package_info(self): + self.cpp_info.requires = ["other::cmp1"] + """) + client.save({"conanfile.py": conanfile}) + client.run("create . pkg/0.1@") + + client2 = TestClient(cache_folder=client.cache_folder) + conanfile = textwrap.dedent(""" + [requires] + pkg/0.1 + + [generators] + PkgConfigDeps + """) + client2.save({"conanfile.txt": conanfile}) + client2.run("install .") + pc_content = client2.load("pkg.pc") + assert "Requires: cmp1" in pc_content + assert client2.load("other-cmp1.pc") + assert client2.load("other-cmp2.pc") + pc_content = client2.load("other-cmp3.pc") + assert "Requires: cmp1" in pc_content