Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pkg_config][PkgConfigDeps] Checking PC files creation order #10344

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion conan/tools/gnu/pkgconfigdeps/pc_files_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,16 @@ def _get_components_pc_files_and_content(conanfile, dep, components_info):

def _get_package_with_components_pc_files_and_content(conanfile, dep, package_info, components_info):
"""
Get the PC files and content for dependencies with components
Get the PC files and content for dependencies with components.
The PC files will be saved in this order:
1- Package components.
2- Root component.

Note: If the root-package PC name matches with any other of the components one, the first one
is not going to be created. Components have more priority than root package.
"""
pc_files = {}
# First, let's load all the components PC files
pc_files.update(_get_components_pc_files_and_content(conanfile, dep, components_info))
description = "Conan package: %s" % package_info.name
pc_name, pc_content = get_alias_pc_filename_and_content(
Expand All @@ -72,6 +79,9 @@ def _get_package_with_components_pc_files_and_content(conanfile, dep, package_in
package_info.requires,
description
)
# Second, let's load the root package's PC file ONLY
# if it does not already exist in components one
# Issue related: https://github.com/conan-io/conan/issues/10341
if pc_name in pc_files:
conanfile.output.warn("[%s] The PC package name %s already exists and it matches with "
"another component one. Please, review all the "
Expand Down
3 changes: 3 additions & 0 deletions conans/client/generators/pkg_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ def content(self):
comp,
comp_requires_gennames)
comp_gennames = [comp_genname for comp_genname, _, _ in components]
# Mechanism to avoid overwriting the component PC file in case of being
# the same as the root package one.
# Issue related: https://github.com/conan-io/conan/issues/10341
if pkg_genname not in comp_gennames:
ret["%s.pc" % pkg_genname] = self.global_pc_file_contents(pkg_genname, cpp_info,
comp_gennames)
Expand Down
65 changes: 63 additions & 2 deletions conans/test/functional/generators/pkg_config_test.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import glob
import os
import platform
import textwrap
import unittest

import pytest

from conans.test.assets.genconanfile import GenConanfile
from conans.test.utils.tools import TestClient
from conans.util.files import load


def get_requires_from_content(content):
for line in content.splitlines():
if "Requires:" in line:
return line
return ""


class PkgGeneratorTest(unittest.TestCase):

# Without compiler, def rpath_flags(settings, os_build, lib_paths): doesn't append the -Wl...etc
Expand Down Expand Up @@ -256,3 +262,58 @@ def package_info(self):

pc_content = client.load("mycomponent.pc")
self.assertIn("componentdir=${prefix}/mydir", pc_content)


def test_components_and_package_pc_creation_order():
"""
Testing if the root package PC file name matches with any of the components one, the first one
is not going to be created. Components have more priority than root package.

Issue related: https://github.com/conan-io/conan/issues/10341
"""
client = TestClient()
conanfile = textwrap.dedent("""
from conans import ConanFile

class PkgConfigConan(ConanFile):

def package_info(self):
self.cpp_info.set_property("pkg_config_name", "OpenCL")
self.cpp_info.components["_opencl-headers"].set_property("pkg_config_name", "OpenCL")
self.cpp_info.components["_opencl-other"].set_property("pkg_config_name", "OtherCL")
""")
client.save({"conanfile.py": conanfile})
client.run("create . opencl/1.0@")

conanfile = textwrap.dedent("""
from conans import ConanFile

class PkgConfigConan(ConanFile):
requires = "opencl/1.0"

def package_info(self):
self.cpp_info.components["comp"].set_property("pkg_config_name", "pkgb")
self.cpp_info.components["comp"].requires.append("opencl::_opencl-headers")
""")
client.save({"conanfile.py": conanfile}, clean_first=True)
client.run("create . pkgb/1.0@")

conanfile = textwrap.dedent("""
[requires]
pkgb/1.0

[generators]
pkg_config
""")
client.save({"conanfile.txt": conanfile}, clean_first=True)
client.run("install .")
pc_files = [os.path.basename(i) for i in glob.glob(os.path.join(client.current_folder, '*.pc'))]
pc_files.sort()
# Let's check all the PC file names created just in case
assert pc_files == ['OpenCL.pc', 'OtherCL.pc', 'pkgb.pc']
pc_content = client.load("OpenCL.pc")
assert "Name: OpenCL-OpenCL" in pc_content
assert "Description: Conan package: OpenCL-OpenCL" in pc_content
assert "Requires:" not in pc_content
pc_content = client.load("pkgb.pc")
assert "Requires: OpenCL" in get_requires_from_content(pc_content)
96 changes: 76 additions & 20 deletions conans/test/functional/toolchains/gnu/test_pkgconfigdeps.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ def test_duplicated_names_warnings():
"""
Testing some WARN messages if there are duplicated pkg_config_name/pkg_config_aliases defined

Scenario: consumer -> pkgA/1.0 -> pkgB/1.0
Scenario: consumer -> pkga/1.0 -> pkgb/1.0
Expected WARN cases:
- Duplicated aliases.
- Duplicated names, alias and component name
Expand All @@ -492,18 +492,18 @@ def package_info(self):
self.cpp_info.components["cmp3"].set_property("pkg_config_name", "libpkg")
""")
client.save({"conanfile.py": conanfile})
client.run("create . pkgB/1.0@")
client.run("create . pkgb/1.0@")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To lowercase, to avoid failures in Conan 2.0


conanfile = textwrap.dedent("""
from conans import ConanFile

class PkgConfigConan(ConanFile):
requires = "pkgB/1.0"
requires = "pkgb/1.0"

def package_info(self):
# Duplicated name as pkgB
# Duplicated name as pkgb
self.cpp_info.set_property("pkg_config_name", "libpkg")
self.cpp_info.components["cmp1"].requires.append("pkgB::cmp1")
self.cpp_info.components["cmp1"].requires.append("pkgb::cmp1")
self.cpp_info.components["cmp1"].set_property("pkg_config_name", "component1")
# Duplicated aliases
self.cpp_info.components["cmp2"].set_property("pkg_config_aliases", ["alias1"])
Expand All @@ -513,37 +513,93 @@ def package_info(self):
self.cpp_info.components["cmp4"].set_property("pkg_config_aliases", ["libcmp"])
""")
client.save({"conanfile.py": conanfile}, clean_first=True)
client.run("create . pkgA/1.0@")
client.run("create . pkga/1.0@")

conanfile = textwrap.dedent("""
[requires]
pkgA/1.0
pkga/1.0

[generators]
PkgConfigDeps
""")
client.save({"conanfile.txt": conanfile}, clean_first=True)
client.run("install .")
output = client.out
# Duplicated aliases from pkgA
assert "WARN: [pkgA/1.0] The PC alias name alias1.pc already exists and it matches with " \
# Duplicated aliases from pkga
assert "WARN: [pkga/1.0] The PC alias name alias1.pc already exists and it matches with " \
"another alias one" in output
# Duplicated names, alias and component name from pkgA
assert "WARN: [pkgA/1.0] The PC alias name libcmp.pc already exists and it matches with " \
# Duplicated names, alias and component name from pkga
# Issue related: https://github.com/conan-io/conan/issues/10341
assert "WARN: [pkga/1.0] The PC alias name libcmp.pc already exists and it matches with " \
"another package/component one" in output
# Duplicated components from pkgB
assert "WARN: [pkgB/1.0] The PC component name component1.pc already exists and it matches " \
# Duplicated components from pkgb
assert "WARN: [pkgb/1.0] The PC component name component1.pc already exists and it matches " \
"with another component one" in output
# Duplicated package and component name from pkgB
assert "WARN: [pkgB/1.0] The PC package name libpkg.pc already exists and it matches with " \
# Duplicated package and component name from pkgb
assert "WARN: [pkgb/1.0] The PC package name libpkg.pc already exists and it matches with " \
"another component one" in output
# Duplicated names between pkgB and pkgA
assert "WARN: [pkgB/1.0] The PC file name component1.pc already exists and it matches with " \
"another name/alias declared in pkgA/1.0 package" in output
assert "WARN: [pkgB/1.0] The PC file name libpkg.pc already exists and it matches with " \
"another name/alias declared in pkgA/1.0 package" in output
# Duplicated names between pkgb and pkga
assert "WARN: [pkgb/1.0] The PC file name component1.pc already exists and it matches with " \
"another name/alias declared in pkga/1.0 package" in output
assert "WARN: [pkgb/1.0] The PC file name libpkg.pc already exists and it matches with " \
"another name/alias declared in pkga/1.0 package" in output
pc_files = [os.path.basename(i) for i in glob.glob(os.path.join(client.current_folder, '*.pc'))]
pc_files.sort()
# Let's check all the PC file names created just in case
assert pc_files == ['alias1.pc', 'component1.pc', 'libcmp.pc', 'libpkg-cmp3.pc',
'libpkg-cmp4.pc', 'libpkg.pc']


def test_components_and_package_pc_creation_order():
"""
Testing if the root package PC file name matches with any of the components one, the first one
is not going to be created. Components have more priority than root package.

Issue related: https://github.com/conan-io/conan/issues/10341
"""
client = TestClient()
conanfile = textwrap.dedent("""
from conans import ConanFile

class PkgConfigConan(ConanFile):

def package_info(self):
self.cpp_info.set_property("pkg_config_name", "OpenCL")
self.cpp_info.components["_opencl-headers"].set_property("pkg_config_name", "OpenCL")
self.cpp_info.components["_opencl-other"].set_property("pkg_config_name", "OtherCL")
""")
client.save({"conanfile.py": conanfile})
client.run("create . opencl/1.0@")

conanfile = textwrap.dedent("""
from conans import ConanFile

class PkgConfigConan(ConanFile):
requires = "opencl/1.0"

def package_info(self):
self.cpp_info.components["comp"].set_property("pkg_config_name", "pkgb")
self.cpp_info.components["comp"].requires.append("opencl::_opencl-headers")
""")
client.save({"conanfile.py": conanfile}, clean_first=True)
client.run("create . pkgb/1.0@")

conanfile = textwrap.dedent("""
[requires]
pkgb/1.0

[generators]
PkgConfigDeps
""")
client.save({"conanfile.txt": conanfile}, clean_first=True)
client.run("install .")
pc_files = [os.path.basename(i) for i in glob.glob(os.path.join(client.current_folder, '*.pc'))]
pc_files.sort()
# Let's check all the PC file names created just in case
assert pc_files == ['OpenCL.pc', 'OtherCL.pc', 'pkgb.pc']
pc_content = client.load("OpenCL.pc")
assert "Name: OpenCL" in pc_content
assert "Description: Conan component: OpenCL" in pc_content
assert "Requires:" not in pc_content
pc_content = client.load("pkgb.pc")
assert "Requires: OpenCL" in get_requires_from_content(pc_content)