aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2023-08-15 17:38:39 -0400
committerXavier Claessens <xclaesse@gmail.com>2023-09-18 13:51:27 -0400
commitdacd11a6247b97be4981ceabaa75b3a25282f3b4 (patch)
tree291ca57371490a514ef7e21fcd3f9857e2e97ec5
parentdec85c41a9e5d6f8bb2c4431a78a0a9ade3651fd (diff)
downloadmeson-dacd11a6247b97be4981ceabaa75b3a25282f3b4.zip
meson-dacd11a6247b97be4981ceabaa75b3a25282f3b4.tar.gz
meson-dacd11a6247b97be4981ceabaa75b3a25282f3b4.tar.bz2
pkgconfig: Cache the implementation instance
-rw-r--r--mesonbuild/dependencies/pkgconfig.py73
-rw-r--r--mesonbuild/utils/universal.py4
-rwxr-xr-xrun_tests.py13
3 files changed, 42 insertions, 48 deletions
diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py
index 1d9863a..9729baa 100644
--- a/mesonbuild/dependencies/pkgconfig.py
+++ b/mesonbuild/dependencies/pkgconfig.py
@@ -16,7 +16,7 @@ from __future__ import annotations
from pathlib import Path
from .base import ExternalDependency, DependencyException, sort_libpaths, DependencyTypeName
-from ..mesonlib import EnvironmentVariables, OptionKey, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged
+from ..mesonlib import EnvironmentVariables, OptionKey, OrderedSet, PerMachine, Popen_safe, Popen_safe_logged, MachineChoice
from ..programs import find_external_program, ExternalProgram
from .. import mlog
from pathlib import PurePath
@@ -29,20 +29,31 @@ if T.TYPE_CHECKING:
from typing_extensions import Literal
from ..environment import Environment
- from ..mesonlib import MachineChoice
from ..utils.core import EnvironOrDict
from ..interpreter.type_checking import PkgConfigDefineType
class PkgConfigInterface:
'''Base class wrapping a pkg-config implementation'''
+ class_impl: PerMachine[T.Union[Literal[False], T.Optional[PkgConfigInterface]]] = PerMachine(False, False)
+
@staticmethod
def instance(env: Environment, for_machine: MachineChoice, silent: bool) -> T.Optional[PkgConfigInterface]:
- impl = PkgConfigCLI(env, for_machine, silent)
- if not impl.found():
- return None
+ for_machine = for_machine if env.is_cross_build() else MachineChoice.HOST
+ impl = PkgConfigInterface.class_impl[for_machine]
+ if impl is False:
+ impl = PkgConfigCLI(env, for_machine, silent)
+ if not impl.found():
+ impl = None
+ if not impl and not silent:
+ mlog.log('Found pkg-config:', mlog.red('NO'))
+ PkgConfigInterface.class_impl[for_machine] = impl
return impl
+ def __init__(self, env: Environment, for_machine: MachineChoice) -> None:
+ self.env = env
+ self.for_machine = for_machine
+
def found(self) -> bool:
'''Return whether pkg-config is supported'''
raise NotImplementedError
@@ -78,9 +89,6 @@ class PkgConfigInterface:
class PkgConfigCLI(PkgConfigInterface):
'''pkg-config CLI implementation'''
- # The class's copy of the pkg-config path. Avoids having to search for it
- # multiple times in the same Meson invocation.
- class_pkgbin: PerMachine[T.Union[None, Literal[False], ExternalProgram]] = PerMachine(None, None)
# We cache all pkg-config subprocess invocations to avoid redundant calls
pkgbin_cache: T.Dict[
T.Tuple[ExternalProgram, T.Tuple[str, ...], T.FrozenSet[T.Tuple[str, str]]],
@@ -88,11 +96,12 @@ class PkgConfigCLI(PkgConfigInterface):
] = {}
def __init__(self, env: Environment, for_machine: MachineChoice, silent: bool) -> None:
- self.env = env
- self.for_machine = for_machine
+ super().__init__(env, for_machine)
# Store a copy of the pkg-config path on the object itself so it is
# stored in the pickled coredata and recovered.
- self.pkgbin = self._detect_pkgbin(env, for_machine, silent)
+ self.pkgbin = self._detect_pkgbin(env, for_machine)
+ if self.pkgbin and not silent:
+ mlog.log('Found pkg-config:', mlog.green('YES'), mlog.blue(self.pkgbin.get_path()))
def found(self) -> bool:
return bool(self.pkgbin)
@@ -162,41 +171,21 @@ class PkgConfigCLI(PkgConfigInterface):
raise DependencyException(f'could not list modules:\n{err}\n')
return [i.split(' ', 1)[0] for i in out.splitlines()]
- def _split_args(self, cmd: str) -> T.List[str]:
+ @staticmethod
+ def _split_args(cmd: str) -> T.List[str]:
# pkg-config paths follow Unix conventions, even on Windows; split the
# output using shlex.split rather than mesonlib.split_args
return shlex.split(cmd)
- @classmethod
- def _detect_pkgbin(cls, env: Environment, for_machine: MachineChoice, silent: bool) -> T.Optional[ExternalProgram]:
- # Only search for pkg-config for each machine the first time and store
- # the result in the class definition
- if cls.class_pkgbin[for_machine] is False:
- mlog.debug(f'Pkg-config binary for {for_machine} is cached as not found.')
- elif cls.class_pkgbin[for_machine] is not None:
- mlog.debug(f'Pkg-config binary for {for_machine} is cached.')
- else:
- assert cls.class_pkgbin[for_machine] is None, 'for mypy'
- mlog.debug(f'Pkg-config binary for {for_machine} is not cached.')
- for potential_pkgbin in find_external_program(
- env, for_machine, 'pkgconfig', 'Pkg-config',
- env.default_pkgconfig, allow_default_for_cross=False):
- version_if_ok = cls.check_pkgconfig(env, potential_pkgbin)
- if not version_if_ok:
- continue
- if not silent:
- mlog.log('Found pkg-config:', mlog.bold(potential_pkgbin.get_path()),
- f'({version_if_ok})')
- cls.class_pkgbin[for_machine] = potential_pkgbin
- break
- else:
- if not silent:
- mlog.log('Found pkg-config:', mlog.red('NO'))
- # Set to False instead of None to signify that we've already
- # searched for it and not found it
- cls.class_pkgbin[for_machine] = False
-
- return cls.class_pkgbin[for_machine] or None
+ @staticmethod
+ def _detect_pkgbin(env: Environment, for_machine: MachineChoice) -> T.Optional[ExternalProgram]:
+ for potential_pkgbin in find_external_program(
+ env, for_machine, 'pkgconfig', 'Pkg-config',
+ env.default_pkgconfig, allow_default_for_cross=False):
+ version_if_ok = PkgConfigCLI.check_pkgconfig(env, potential_pkgbin)
+ if version_if_ok:
+ return potential_pkgbin
+ return None
def _call_pkgbin_real(self, args: T.List[str], env: T.Dict[str, str]) -> T.Tuple[int, str, str]:
assert isinstance(self.pkgbin, ExternalProgram)
diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py
index 1d0e382..8216e78 100644
--- a/mesonbuild/utils/universal.py
+++ b/mesonbuild/utils/universal.py
@@ -524,6 +524,10 @@ class PerMachine(T.Generic[_T]):
unfreeze.host = None
return unfreeze
+ def assign(self, build: _T, host: _T) -> None:
+ self.build = build
+ self.host = host
+
def __repr__(self) -> str:
return f'PerMachine({self.build!r}, {self.host!r})'
diff --git a/run_tests.py b/run_tests.py
index 699e293..a959d6a 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -36,7 +36,7 @@ import typing as T
from mesonbuild.compilers.c import CCompiler
from mesonbuild.compilers.detect import detect_c_compiler
-from mesonbuild.dependencies.pkgconfig import PkgConfigCLI
+from mesonbuild.dependencies.pkgconfig import PkgConfigInterface
from mesonbuild import mesonlib
from mesonbuild import mesonmain
from mesonbuild import mtest
@@ -161,6 +161,8 @@ def get_fake_env(sdir='', bdir=None, prefix='', opts=None):
env = Environment(sdir, bdir, opts)
env.coredata.options[OptionKey('args', lang='c')] = FakeCompilerOptions()
env.machines.host.cpu_family = 'x86_64' # Used on macOS inside find_library
+ # Invalidate cache when using a different Environment object.
+ clear_meson_configure_class_caches()
return env
def get_convincing_fake_env_and_cc(bdir, prefix):
@@ -309,11 +311,10 @@ def run_mtest_inprocess(commandlist: T.List[str]) -> T.Tuple[int, str, str]:
return returncode, out.getvalue()
def clear_meson_configure_class_caches() -> None:
- CCompiler.find_library_cache = {}
- CCompiler.find_framework_cache = {}
- PkgConfigCLI.pkgbin_cache = {}
- PkgConfigCLI.class_pkgbin = mesonlib.PerMachine(None, None)
- mesonlib.project_meson_versions = collections.defaultdict(str)
+ CCompiler.find_library_cache.clear()
+ CCompiler.find_framework_cache.clear()
+ PkgConfigInterface.class_impl.assign(False, False)
+ mesonlib.project_meson_versions.clear()
def run_configure_inprocess(commandlist: T.List[str], env: T.Optional[T.Dict[str, str]] = None, catch_exception: bool = False) -> T.Tuple[int, str, str]:
stderr = StringIO()