typing: Fully annotate dependencies.pkgconfig

pull/8843/head
Daniel Mensinger 4 years ago committed by Jussi Pakkanen
parent d13999f5b4
commit 6798bc8146
  1. 59
      mesonbuild/dependencies/pkgconfig.py
  2. 1
      run_mypy.py

@ -14,7 +14,7 @@
from .base import ExternalDependency, DependencyException, DependencyMethods, sort_libpaths
from ..mesonlib import LibType, MachineChoice, OptionKey, OrderedSet, PerMachine, Popen_safe
from ..programs import find_external_program
from ..programs import find_external_program, ExternalProgram
from .. import mlog
from pathlib import PurePath
import re
@ -28,17 +28,20 @@ if T.TYPE_CHECKING:
class PkgConfigDependency(ExternalDependency):
# 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(None, None)
class_pkgbin: PerMachine[T.Union[None, bool, ExternalProgram]] = PerMachine(None, None)
# We cache all pkg-config subprocess invocations to avoid redundant calls
pkgbin_cache = {}
pkgbin_cache: T.Dict[
T.Tuple[ExternalProgram, T.Tuple[str, ...], T.FrozenSet[T.Tuple[str, str]]],
T.Tuple[int, str, str]
] = {}
def __init__(self, name, environment: 'Environment', kwargs, language: T.Optional[str] = None):
def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T.Any], language: T.Optional[str] = None) -> None:
super().__init__('pkgconfig', environment, kwargs, language=language)
self.name = name
self.is_libtool = False
# Store a copy of the pkg-config path on the object itself so it is
# stored in the pickled coredata and recovered.
self.pkgbin = None
self.pkgbin: T.Union[None, bool, ExternalProgram] = None
# Only search for pkg-config for each machine the first time and store
# the result in the class definition
@ -77,6 +80,7 @@ class PkgConfigDependency(ExternalDependency):
mlog.debug(msg)
return
assert isinstance(self.pkgbin, ExternalProgram)
mlog.debug('Determining dependency {!r} with pkg-config executable '
'{!r}'.format(name, self.pkgbin.get_path()))
ret, self.version, _ = self._call_pkgbin(['--modversion', name])
@ -100,12 +104,13 @@ class PkgConfigDependency(ExternalDependency):
self.is_found = False
self.reason = e
def __repr__(self):
def __repr__(self) -> str:
s = '<{0} {1}: {2} {3}>'
return s.format(self.__class__.__name__, self.name, self.is_found,
self.version_reqs)
def _call_pkgbin_real(self, args, env):
def _call_pkgbin_real(self, args: T.List[str], env: T.Dict[str, str]) -> T.Tuple[int, str, str]:
assert isinstance(self.pkgbin, ExternalProgram)
cmd = self.pkgbin.get_command() + args
p, out, err = Popen_safe(cmd, env=env)
rc, out, err = p.returncode, out.strip(), err.strip()
@ -134,7 +139,7 @@ class PkgConfigDependency(ExternalDependency):
if key.startswith('PKG_'):
mlog.debug(f'env[{key}]: {value}')
def _call_pkgbin(self, args, env=None):
def _call_pkgbin(self, args: T.List[str], env: T.Optional[T.Dict[str, str]] = None) -> T.Tuple[int, str, str]:
# Always copy the environment since we're going to modify it
# with pkg-config variables
if env is None:
@ -142,6 +147,7 @@ class PkgConfigDependency(ExternalDependency):
else:
env = env.copy()
assert isinstance(self.pkgbin, ExternalProgram)
PkgConfigDependency.setup_env(env, self.env, self.for_machine)
fenv = frozenset(env.items())
@ -162,7 +168,7 @@ class PkgConfigDependency(ExternalDependency):
return args
converted = []
for arg in args:
pargs = []
pargs: T.Tuple[str, ...] = tuple()
# Library search path
if arg.startswith('-L/'):
pargs = PurePath(arg[2:]).parts
@ -182,12 +188,12 @@ class PkgConfigDependency(ExternalDependency):
converted.append(arg)
return converted
def _split_args(self, cmd):
def _split_args(self, 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)
def _set_cargs(self):
def _set_cargs(self) -> None:
env = None
if self.language == 'fortran':
# gfortran doesn't appear to look in system paths for INCLUDE files,
@ -200,7 +206,7 @@ class PkgConfigDependency(ExternalDependency):
(self.name, err))
self.compile_args = self._convert_mingw_paths(self._split_args(out))
def _search_libs(self, out, out_raw):
def _search_libs(self, out: str, out_raw: str) -> T.Tuple[T.List[str], T.List[str]]:
'''
@out: PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 pkg-config --libs
@out_raw: pkg-config --libs
@ -225,7 +231,7 @@ class PkgConfigDependency(ExternalDependency):
#
# Separate system and prefix paths, and ensure that prefix paths are
# always searched first.
prefix_libpaths = OrderedSet()
prefix_libpaths: OrderedSet[str] = OrderedSet()
# We also store this raw_link_args on the object later
raw_link_args = self._convert_mingw_paths(self._split_args(out_raw))
for arg in raw_link_args:
@ -246,8 +252,8 @@ class PkgConfigDependency(ExternalDependency):
# too many system_libpaths to cause library version issues.
pkg_config_path: T.List[str] = self.env.coredata.options[OptionKey('pkg_config_path', machine=self.for_machine)].value
pkg_config_path = self._convert_mingw_paths(pkg_config_path)
prefix_libpaths = sort_libpaths(prefix_libpaths, pkg_config_path)
system_libpaths = OrderedSet()
prefix_libpaths = OrderedSet(sort_libpaths(list(prefix_libpaths), pkg_config_path))
system_libpaths: OrderedSet[str] = OrderedSet()
full_args = self._convert_mingw_paths(self._split_args(out))
for arg in full_args:
if arg.startswith(('-L-l', '-L-L')):
@ -258,7 +264,7 @@ class PkgConfigDependency(ExternalDependency):
# Use this re-ordered path list for library resolution
libpaths = list(prefix_libpaths) + list(system_libpaths)
# Track -lfoo libraries to avoid duplicate work
libs_found = OrderedSet()
libs_found: OrderedSet[str] = OrderedSet()
# Track not-found libraries to know whether to add library paths
libs_notfound = []
libtype = LibType.STATIC if self.static else LibType.PREFER_SHARED
@ -328,7 +334,7 @@ class PkgConfigDependency(ExternalDependency):
link_args = ['-L' + lp for lp in prefix_libpaths] + link_args
return link_args, raw_link_args
def _set_libs(self):
def _set_libs(self) -> None:
env = None
libcmd = ['--libs']
@ -354,7 +360,7 @@ class PkgConfigDependency(ExternalDependency):
(self.name, out_raw))
self.link_args, self.raw_link_args = self._search_libs(out, out_raw)
def get_pkgconfig_variable(self, variable_name: str, kwargs: T.Dict[str, T.Any]) -> str:
def get_pkgconfig_variable(self, variable_name: str, kwargs: T.Dict[str, T.Union[str, T.List[str]]]) -> str:
options = ['--variable=' + variable_name, self.name]
if 'define_variable' in kwargs:
@ -382,6 +388,7 @@ class PkgConfigDependency(ExternalDependency):
ret, out, _ = self._call_pkgbin(['--print-variables', self.name])
if not re.search(r'^' + variable_name + r'$', out, re.MULTILINE):
if 'default' in kwargs:
assert isinstance(kwargs['default'], str)
variable = kwargs['default']
else:
mlog.warning(f"pkgconfig variable '{variable_name}' not defined for dependency {self.name}.")
@ -390,10 +397,10 @@ class PkgConfigDependency(ExternalDependency):
return variable
@staticmethod
def get_methods():
def get_methods() -> T.List[DependencyMethods]:
return [DependencyMethods.PKGCONFIG]
def check_pkgconfig(self, pkgbin):
def check_pkgconfig(self, pkgbin: ExternalProgram) -> T.Optional[str]:
if not pkgbin.found():
mlog.log(f'Did not find pkg-config by name {pkgbin.name!r}')
return None
@ -415,7 +422,7 @@ class PkgConfigDependency(ExternalDependency):
return None
return out.strip()
def extract_field(self, la_file, fieldname):
def extract_field(self, la_file: str, fieldname: str) -> T.Optional[str]:
with open(la_file) as f:
for line in f:
arr = line.strip().split('=')
@ -423,13 +430,13 @@ class PkgConfigDependency(ExternalDependency):
return arr[1][1:-1]
return None
def extract_dlname_field(self, la_file):
def extract_dlname_field(self, la_file: str) -> T.Optional[str]:
return self.extract_field(la_file, 'dlname')
def extract_libdir_field(self, la_file):
def extract_libdir_field(self, la_file: str) -> T.Optional[str]:
return self.extract_field(la_file, 'libdir')
def extract_libtool_shlib(self, la_file):
def extract_libtool_shlib(self, la_file: str) -> T.Optional[str]:
'''
Returns the path to the shared library
corresponding to this .la file
@ -450,7 +457,7 @@ class PkgConfigDependency(ExternalDependency):
# a path rather than the raw dlname
return os.path.basename(dlname)
def log_tried(self):
def log_tried(self) -> str:
return self.type_name
def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
@ -458,7 +465,7 @@ class PkgConfigDependency(ExternalDependency):
default_value: T.Optional[str] = None,
pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.List[str]]:
if pkgconfig:
kwargs = {}
kwargs: T.Dict[str, T.Union[str, T.List[str]]] = {}
if default_value is not None:
kwargs['default'] = default_value
if pkgconfig_define is not None:

@ -25,6 +25,7 @@ modules = [
'mesonbuild/dependencies/boost.py',
'mesonbuild/dependencies/hdf5.py',
'mesonbuild/dependencies/mpi.py',
'mesonbuild/dependencies/pkgconfig.py',
'mesonbuild/dependencies/qt.py',
'mesonbuild/envconfig.py',
'mesonbuild/interpreterbase.py',

Loading…
Cancel
Save