From 93d9b39e5786c351fec8fa4ce4bbb9657f64a68e Mon Sep 17 00:00:00 2001 From: Francisco Ramirez de Anton Date: Wed, 28 Jul 2021 13:31:11 +0200 Subject: [PATCH 1/4] Test reproducing the PkgConfigDeps bug --- .../toolchains/gnu/test_pkgconfigdeps.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py b/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py index 95331eb1537..282e9327eab 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 @@ -254,3 +255,33 @@ def package_info(self): pc_content = client.load("pkg-mycomponent.pc") assert "componentdir=${prefix}/mydir" in pc_content + + +def test_components_with_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") + + """) + 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 .") From b993b52eaaebf9eb132efcc7a6e6967441b002e8 Mon Sep 17 00:00:00 2001 From: Francisco Ramirez de Anton Date: Wed, 28 Jul 2021 18:39:05 +0200 Subject: [PATCH 2/4] Added tests reproducing the bug --- conan/tools/gnu/pkgconfigdeps.py | 24 +++++----- .../toolchains/gnu/test_pkgconfigdeps.py | 48 ++++++++++++++++++- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py index b07b7501502..ab5dfbaeb19 100644 --- a/conan/tools/gnu/pkgconfigdeps.py +++ b/conan/tools/gnu/pkgconfigdeps.py @@ -48,33 +48,35 @@ 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): + pkg_name = dep.ref.name pkg, comp_name = req.split("::") if "::" in req else (pkg_name, req) - req = self._conanfile.dependencies.direct_host[pkg] + req = dep.dependencies.direct_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 +87,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 +101,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 282e9327eab..2079f59139f 100644 --- a/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py +++ b/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py @@ -252,12 +252,11 @@ 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_components_with_requires(): +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") @@ -270,7 +269,48 @@ class PkgConfigConan(ConanFile): 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"] + """) + 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@") @@ -285,3 +325,7 @@ def package_info(self): """) 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") From dbbfc4e855cc14ec6e71dc4f6bb8ff370e62f588 Mon Sep 17 00:00:00 2001 From: Francisco Ramirez de Anton Date: Thu, 29 Jul 2021 12:04:56 +0200 Subject: [PATCH 3/4] Fixed bug. Tests are passing --- conan/tools/gnu/pkgconfigdeps.py | 3 ++- conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py index ab5dfbaeb19..02b7fb65579 100644 --- a/conan/tools/gnu/pkgconfigdeps.py +++ b/conan/tools/gnu/pkgconfigdeps.py @@ -51,7 +51,8 @@ def __init__(self, conanfile): def _get_require_comp_name(self, dep, req): pkg_name = dep.ref.name pkg, comp_name = req.split("::") if "::" in req else (pkg_name, req) - req = dep.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 diff --git a/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py b/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py index 2079f59139f..0ddca780fb1 100644 --- a/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py +++ b/conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py @@ -299,6 +299,8 @@ 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@") @@ -329,3 +331,5 @@ def package_info(self): 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 From 105a296a363ba81fab278904dc058f411bf30136 Mon Sep 17 00:00:00 2001 From: Francisco Ramirez de Anton Date: Thu, 29 Jul 2021 12:57:38 +0200 Subject: [PATCH 4/4] Adapted code to Python2.7 --- conan/tools/gnu/pkgconfigdeps.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conan/tools/gnu/pkgconfigdeps.py b/conan/tools/gnu/pkgconfigdeps.py index 02b7fb65579..13fe1179537 100644 --- a/conan/tools/gnu/pkgconfigdeps.py +++ b/conan/tools/gnu/pkgconfigdeps.py @@ -49,7 +49,8 @@ def __init__(self, conanfile): self._conanfile = conanfile def _get_require_comp_name(self, dep, req): - pkg_name = dep.ref.name + # 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) # FIXME: it could allow defining requires to not direct dependencies req = self._conanfile.dependencies.host[pkg]