pkgconfig: add support to override pkg-config

pull/13805/head
Andoni Morales Alastruey 2 months ago committed by Nirbheek Chauhan
parent 5f0bd8ff1e
commit 5cc511b1e6
  1. 38
      mesonbuild/dependencies/pkgconfig.py
  2. 3
      mesonbuild/interpreter/interpreter.py
  3. 5
      run_project_tests.py
  4. 8
      test cases/common/279 pkgconfig override/meson.build
  5. 5
      test cases/common/279 pkgconfig override/subprojects/pkg-config.wrap
  6. 13
      test cases/common/279 pkgconfig override/subprojects/pkg-config/bin/pkg-config.py
  7. 4
      test cases/common/279 pkgconfig override/subprojects/pkg-config/meson.build

@ -6,7 +6,8 @@ from __future__ import annotations
from pathlib import Path from pathlib import Path
from .base import ExternalDependency, DependencyException, sort_libpaths, DependencyTypeName from .base import ExternalDependency, DependencyException, sort_libpaths, DependencyTypeName
from ..mesonlib import EnvironmentVariables, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged, MachineChoice, join_args from ..mesonlib import (EnvironmentVariables, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged, MachineChoice,
join_args, MesonException)
from ..options import OptionKey from ..options import OptionKey
from ..programs import find_external_program, ExternalProgram from ..programs import find_external_program, ExternalProgram
from .. import mlog from .. import mlog
@ -30,6 +31,14 @@ class PkgConfigInterface:
class_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigInterface]]] = PerMachine(False, False) class_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigInterface]]] = PerMachine(False, False)
class_cli_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigCLI]]] = PerMachine(False, False) class_cli_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigCLI]]] = PerMachine(False, False)
pkg_bin_per_machine: PerMachine[T.Optional[ExternalProgram]] = PerMachine(None, None)
@staticmethod
def set_program_override(pkg_bin: ExternalProgram, for_machine: MachineChoice) -> None:
if PkgConfigInterface.class_impl[for_machine]:
raise MesonException(f'Tried to override pkg-config for machine {for_machine} but it was already initialized.\n'
'pkg-config must be overridden before it\'s used.')
PkgConfigInterface.pkg_bin_per_machine[for_machine] = pkg_bin
@staticmethod @staticmethod
def instance(env: Environment, for_machine: MachineChoice, silent: bool) -> T.Optional[PkgConfigInterface]: def instance(env: Environment, for_machine: MachineChoice, silent: bool) -> T.Optional[PkgConfigInterface]:
@ -37,7 +46,7 @@ class PkgConfigInterface:
for_machine = for_machine if env.is_cross_build() else MachineChoice.HOST for_machine = for_machine if env.is_cross_build() else MachineChoice.HOST
impl = PkgConfigInterface.class_impl[for_machine] impl = PkgConfigInterface.class_impl[for_machine]
if impl is False: if impl is False:
impl = PkgConfigCLI(env, for_machine, silent) impl = PkgConfigCLI(env, for_machine, silent, PkgConfigInterface.pkg_bin_per_machine[for_machine])
if not impl.found(): if not impl.found():
impl = None impl = None
if not impl and not silent: if not impl and not silent:
@ -57,7 +66,7 @@ class PkgConfigInterface:
if impl and not isinstance(impl, PkgConfigCLI): if impl and not isinstance(impl, PkgConfigCLI):
impl = PkgConfigInterface.class_cli_impl[for_machine] impl = PkgConfigInterface.class_cli_impl[for_machine]
if impl is False: if impl is False:
impl = PkgConfigCLI(env, for_machine, silent) impl = PkgConfigCLI(env, for_machine, silent, PkgConfigInterface.pkg_bin_per_machine[for_machine])
if not impl.found(): if not impl.found():
impl = None impl = None
PkgConfigInterface.class_cli_impl[for_machine] = impl PkgConfigInterface.class_cli_impl[for_machine] = impl
@ -113,9 +122,10 @@ class PkgConfigInterface:
class PkgConfigCLI(PkgConfigInterface): class PkgConfigCLI(PkgConfigInterface):
'''pkg-config CLI implementation''' '''pkg-config CLI implementation'''
def __init__(self, env: Environment, for_machine: MachineChoice, silent: bool) -> None: def __init__(self, env: Environment, for_machine: MachineChoice, silent: bool,
pkgbin: T.Optional[ExternalProgram] = None) -> None:
super().__init__(env, for_machine) super().__init__(env, for_machine)
self._detect_pkgbin() self._detect_pkgbin(pkgbin)
if self.pkgbin and not silent: if self.pkgbin and not silent:
mlog.log('Found pkg-config:', mlog.green('YES'), mlog.bold(f'({self.pkgbin.get_path()})'), mlog.blue(self.pkgbin_version)) mlog.log('Found pkg-config:', mlog.green('YES'), mlog.bold(f'({self.pkgbin.get_path()})'), mlog.blue(self.pkgbin_version))
@ -200,14 +210,21 @@ class PkgConfigCLI(PkgConfigInterface):
# output using shlex.split rather than mesonlib.split_args # output using shlex.split rather than mesonlib.split_args
return shlex.split(cmd) return shlex.split(cmd)
def _detect_pkgbin(self) -> None: def _detect_pkgbin(self, pkgbin: T.Optional[ExternalProgram] = None) -> None:
for potential_pkgbin in find_external_program( def validate(potential_pkgbin: ExternalProgram) -> bool:
self.env, self.for_machine, 'pkg-config', 'Pkg-config',
self.env.default_pkgconfig, allow_default_for_cross=False):
version_if_ok = self._check_pkgconfig(potential_pkgbin) version_if_ok = self._check_pkgconfig(potential_pkgbin)
if version_if_ok: if version_if_ok:
self.pkgbin = potential_pkgbin self.pkgbin = potential_pkgbin
self.pkgbin_version = version_if_ok self.pkgbin_version = version_if_ok
return True
return False
if pkgbin and validate(pkgbin):
return
for potential_pkgbin in find_external_program(self.env, self.for_machine, "pkg-config", "Pkg-config",
self.env.default_pkgconfig, allow_default_for_cross=False):
if validate(potential_pkgbin):
return return
self.pkgbin = None self.pkgbin = None
@ -274,7 +291,8 @@ class PkgConfigCLI(PkgConfigInterface):
class PkgConfigDependency(ExternalDependency): class PkgConfigDependency(ExternalDependency):
def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None: def __init__(self, name: str, environment: Environment, kwargs: T.Dict[str, T.Any],
language: T.Optional[str] = None) -> None:
super().__init__(DependencyTypeName('pkgconfig'), environment, kwargs, language=language) super().__init__(DependencyTypeName('pkgconfig'), environment, kwargs, language=language)
self.name = name self.name = name
self.is_libtool = False self.is_libtool = False

@ -1640,6 +1640,9 @@ class Interpreter(InterpreterBase, HoldableObject):
if name in self.build.find_overrides: if name in self.build.find_overrides:
raise InterpreterException(f'Tried to override executable "{name}" which has already been overridden.') raise InterpreterException(f'Tried to override executable "{name}" which has already been overridden.')
self.build.find_overrides[name] = exe self.build.find_overrides[name] = exe
if name == 'pkg-config' and isinstance(exe, ExternalProgram):
from ..dependencies.pkgconfig import PkgConfigInterface
PkgConfigInterface.set_program_override(exe, MachineChoice.HOST)
def notfound_program(self, args: T.List[mesonlib.FileOrString]) -> ExternalProgram: def notfound_program(self, args: T.List[mesonlib.FileOrString]) -> ExternalProgram:
return NonExistingExternalProgram(' '.join( return NonExistingExternalProgram(' '.join(

@ -551,9 +551,14 @@ def validate_output(test: TestDef, stdo: str, stde: str) -> str:
def clear_internal_caches() -> None: def clear_internal_caches() -> None:
import mesonbuild.interpreterbase import mesonbuild.interpreterbase
from mesonbuild.dependencies.cmake import CMakeDependency from mesonbuild.dependencies.cmake import CMakeDependency
from mesonbuild.dependencies.pkgconfig import PkgConfigInterface
from mesonbuild.mesonlib import PerMachine from mesonbuild.mesonlib import PerMachine
mesonbuild.interpreterbase.FeatureNew.feature_registry = {} mesonbuild.interpreterbase.FeatureNew.feature_registry = {}
CMakeDependency.class_cmakeinfo = PerMachine(None, None) CMakeDependency.class_cmakeinfo = PerMachine(None, None)
PkgConfigInterface.class_impl = PerMachine(False, False)
PkgConfigInterface.class_cli_impl = PerMachine(False, False)
PkgConfigInterface.pkg_bin_per_machine = PerMachine(None, None)
def run_test_inprocess(testdir: str) -> T.Tuple[int, str, str, str]: def run_test_inprocess(testdir: str) -> T.Tuple[int, str, str, str]:
old_stdout = sys.stdout old_stdout = sys.stdout

@ -0,0 +1,8 @@
project('override pkg-config', 'c')
subproject('pkg-config')
pkgconfig = find_program('pkg-config')
# This dependency can only be found if pkg-config is overridden with our custom pkg-config.py
gobj = dependency('test-package-0.0', version : '= 0.0.0')

@ -0,0 +1,5 @@
[wrap-file]
directory = pkg-config
[provide]
program_names = pkg-config

@ -0,0 +1,13 @@
#!/usr/bin/env python3
import sys
if len(sys.argv) > 1:
if sys.argv[1] == "--modversion":
if sys.argv[2] == "test-package-0.0":
print("0.0.0")
else:
exit(-1)
elif sys.argv[1] == "--version":
print("0.0.0")
exit(0)

@ -0,0 +1,4 @@
project('pkg-config')
pkgconfig = find_program(meson.project_source_root() / 'bin' / 'pkg-config.py')
meson.override_find_program('pkg-config', pkgconfig)
Loading…
Cancel
Save