diff options
author | Dylan Baker <dylan@pnwbakers.com> | 2022-03-09 12:35:49 -0800 |
---|---|---|
committer | Eli Schwartz <eschwartz93@gmail.com> | 2022-08-18 21:57:36 -0400 |
commit | 26f02f50b823af5ef6025e62bf7d6943d00ef2bc (patch) | |
tree | de8bb4e723518f471f608064e23bdbe377f51d88 | |
parent | e84f293f672a372d2434d0ce4fa39d3f902b6ce8 (diff) | |
download | meson-26f02f50b823af5ef6025e62bf7d6943d00ef2bc.zip meson-26f02f50b823af5ef6025e62bf7d6943d00ef2bc.tar.gz meson-26f02f50b823af5ef6025e62bf7d6943d00ef2bc.tar.bz2 |
modules/pkgconfig: Get most type annotations added
There are still a lot of errors here due to a mixture of really bad
design (adding extra attributes to objects), and legitimate type errors
(passing a str where a List[str] is expected). I suspect a lot of these
cases aren't hit for some reason.
-rw-r--r-- | mesonbuild/modules/pkgconfig.py | 130 |
1 files changed, 80 insertions, 50 deletions
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index ce0fa53..a113d13 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -13,6 +13,7 @@ # limitations under the License. from __future__ import annotations +from collections import defaultdict from pathlib import PurePath import os import typing as T @@ -60,6 +61,7 @@ if T.TYPE_CHECKING: unescaped_variables: T.Dict[str, str] unescaped_uninstalled_variables: T.Dict[str, str] + already_warned_objs = set() _PKG_LIBRARIES: KwargInfo[T.List[T.Union[str, dependencies.Dependency, build.SharedLibrary, build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]]] = KwargInfo( @@ -78,33 +80,39 @@ _PKG_REQUIRES: KwargInfo[T.List[T.Union[str, build.SharedLibrary, build.StaticLi listify=True, ) + +def _as_str(obj: object) -> str: + assert isinstance(obj, str) + return obj + + class DependenciesHelper: def __init__(self, state: ModuleState, name: str) -> None: self.state = state self.name = name - self.pub_libs = [] - self.pub_reqs = [] - self.priv_libs = [] - self.priv_reqs = [] - self.cflags = [] - self.version_reqs = {} - self.link_whole_targets = [] - - def add_pub_libs(self, libs) -> None: - libs, reqs, cflags = self._process_libs(libs, True) - self.pub_libs = libs + self.pub_libs # prepend to preserve dependencies + self.pub_libs: T.List[LIBS] = [] + self.pub_reqs: T.List[str] = [] + self.priv_libs: T.List[LIBS] = [] + self.priv_reqs: T.List[str] = [] + self.cflags: T.List[str] = [] + self.version_reqs: T.DefaultDict[str, T.Set[str]] = defaultdict(set) + self.link_whole_targets: T.List[T.Union[build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary]] = [] + + def add_pub_libs(self, libs: T.Sequence[ANY_DEP]) -> None: + p_libs, reqs, cflags = self._process_libs(libs, True) + self.pub_libs = p_libs + self.pub_libs # prepend to preserve dependencies self.pub_reqs += reqs self.cflags += cflags - def add_priv_libs(self, libs) -> None: - libs, reqs, _ = self._process_libs(libs, False) - self.priv_libs = libs + self.priv_libs + def add_priv_libs(self, libs: T.Sequence[ANY_DEP]) -> None: + p_libs, reqs, _ = self._process_libs(libs, False) + self.priv_libs = p_libs + self.priv_libs self.priv_reqs += reqs - def add_pub_reqs(self, reqs) -> None: + def add_pub_reqs(self, reqs: T.Sequence[T.Union[str, dependencies.Dependency]]) -> None: self.pub_reqs += self._process_reqs(reqs) - def add_priv_reqs(self, reqs) -> None: + def add_priv_reqs(self, reqs: T.Sequence[T.Union[str, dependencies.Dependency]]) -> None: self.priv_reqs += self._process_reqs(reqs) def _check_generated_pc_deprecation(self, obj) -> None: @@ -124,9 +132,9 @@ class DependenciesHelper: location=obj.generated_pc_warn[1]) already_warned_objs.add((name, obj.name)) - def _process_reqs(self, reqs: T.List[T.Union[str, dependencies.Dependency]]): + def _process_reqs(self, reqs: T.Sequence[T.Union[str, dependencies.Dependency]]) -> T.List[str]: '''Returns string names of requirements''' - processed_reqs = [] + processed_reqs: T.List[str] = [] for obj in mesonlib.listify(reqs): if not isinstance(obj, str): FeatureNew.single_use('pkgconfig.generate requirement from non-string object', '0.46.0', self.state.subproject) @@ -151,14 +159,16 @@ class DependenciesHelper: f'or pkgconfig-dependency object, got {obj!r}') return processed_reqs - def add_cflags(self, cflags) -> None: + def add_cflags(self, cflags: T.List[str]) -> None: self.cflags += mesonlib.stringlistify(cflags) - def _process_libs(self, libs, public: bool) -> T.Tuple[T.List, T.List, T.List]: + def _process_libs( + self, libs: T.Sequence[ANY_DEP], public: bool + ) -> T.Tuple[T.List[T.Union[str, build.SharedLibrary, build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]], T.List[str], T.List[str]]: libs = mesonlib.listify(libs) - processed_libs = [] - processed_reqs = [] - processed_cflags = [] + processed_libs: T.List[T.Union[str, build.SharedLibrary, build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]] = [] + processed_reqs: T.List[str] = [] + processed_cflags: T.List[str] = [] for obj in libs: if hasattr(obj, 'generated_pc'): self._check_generated_pc_deprecation(obj) @@ -207,7 +217,12 @@ class DependenciesHelper: return processed_libs, processed_reqs, processed_cflags - def _add_lib_dependencies(self, link_targets, link_whole_targets, external_deps, public, private_external_deps: bool = False) -> None: + def _add_lib_dependencies( + self, link_targets: T.List[T.Union[build.StaticLibrary, build.SharedLibrary, build.CustomTarget, build.CustomTargetIndex]], + link_whole_targets: T.List[T.Union[build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex]], + external_deps: T.List[dependencies.Dependency], + public: bool, + private_external_deps: bool = False) -> None: add_libs = self.add_pub_libs if public else self.add_priv_libs # Recursively add all linked libraries for t in link_targets: @@ -225,7 +240,7 @@ class DependenciesHelper: else: add_libs(external_deps) - def _add_link_whole(self, t, public) -> None: + def _add_link_whole(self, t: T.Union[build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary, build.SharedLibrary], public: bool) -> None: # Don't include static libraries that we link_whole. But we still need to # include their dependencies: a static library we link_whole # could itself link to a shared library or an installed static library. @@ -236,10 +251,8 @@ class DependenciesHelper: if isinstance(t, build.BuildTarget): self._add_lib_dependencies(t.link_targets, t.link_whole_targets, t.external_deps, public) - def add_version_reqs(self, name, version_reqs) -> None: + def add_version_reqs(self, name: str, version_reqs: T.Optional[T.List[str]]) -> None: if version_reqs: - if name not in self.version_reqs: - self.version_reqs[name] = set() # Note that pkg-config is picky about whitespace. # 'foo > 1.2' is ok but 'foo>1.2' is not. # foo, bar' is ok, but 'foo,bar' is not. @@ -260,8 +273,8 @@ class DependenciesHelper: return op + ' ' + vreq[len(op):] return vreq - def format_reqs(self, reqs) -> str: - result = [] + def format_reqs(self, reqs: T.List[str]) -> str: + result: T.List[str] = [] for name in reqs: vreqs = self.version_reqs.get(name, None) if vreqs: @@ -272,11 +285,11 @@ class DependenciesHelper: def remove_dups(self) -> None: # Set of ids that have already been handled and should not be added any more - exclude = set() + exclude: T.Set[build.Target] = set() # We can't just check if 'x' is excluded because we could have copies of # the same SharedLibrary object for example. - def _ids(x): + def _ids(x: T.Union[str, build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary]) -> T.Iterable[str]: if hasattr(x, 'generated_pc'): yield x.generated_pc if isinstance(x, build.Target): @@ -284,7 +297,7 @@ class DependenciesHelper: yield x # Exclude 'x' in all its forms and return if it was already excluded - def _add_exclude(x): + def _add_exclude(x: T.Union[str, build.CustomTarget, build.CustomTargetIndex, build.StaticLibrary]) -> bool: was_excluded = False for i in _ids(x): if i in exclude: @@ -297,7 +310,17 @@ class DependenciesHelper: for t in self.link_whole_targets: _add_exclude(t) - def _fn(xs, libs=False): + # Mypy thinks these overlap, but since List is invariant they don't, + # `List[str]`` is not a valid input to `List[str | BuildTarget]`. + # pylance/pyright gets this right, but for mypy we have to ignore the + # error + @T.overload + def _fn(xs: T.List[str], libs: bool = False) -> T.List[str]: ... # type: ignore + + @T.overload + def _fn(xs: T.List[LIBS], libs: bool = False) -> T.List[LIBS]: ... + + def _fn(xs: T.Union[T.List[str], T.List[LIBS]], libs: bool = False) -> T.Union[T.List[str], T.List[LIBS]]: # Remove duplicates whilst preserving original order result = [] for x in xs: @@ -332,7 +355,8 @@ class PkgConfigModule(ExtensionModule): 'generate': self.generate, }) - def _get_lname(self, l, msg, pcfile, is_custom_target): + def _get_lname(self, l: T.Union[build.SharedLibrary, build.StaticLibrary, build.CustomTarget, build.CustomTargetIndex], + msg: str, pcfile: str, is_custom_target: bool) -> str: if is_custom_target: basename = os.path.basename(l.get_filename()) name = os.path.splitext(basename)[0] @@ -356,7 +380,7 @@ class PkgConfigModule(ExtensionModule): mlog.warning(msg.format(l.name, 'name_prefix', l.name, pcfile)) return l.name - def _escape(self, value): + def _escape(self, value: T.Union[str, PurePath]) -> str: ''' We cannot use quote_arg because it quotes with ' and " which does not work with pkg-config and pkgconf at all. @@ -368,7 +392,7 @@ class PkgConfigModule(ExtensionModule): value = value.as_posix() return value.replace(' ', r'\ ') - def _make_relative(self, prefix, subdir): + def _make_relative(self, prefix: T.Union[PurePath, str], subdir: T.Union[PurePath, str]) -> str: prefix = PurePath(prefix) subdir = PurePath(subdir) try: @@ -378,10 +402,14 @@ class PkgConfigModule(ExtensionModule): # pathlib joining makes sure absolute libdir is not appended to '${prefix}' return ('${prefix}' / libdir).as_posix() - def _generate_pkgconfig_file(self, state: ModuleState, deps, subdirs, name, description, - url, version, pcfile, conflicts, variables, - unescaped_variables, uninstalled=False, dataonly=False, - pkgroot=None): + def _generate_pkgconfig_file(self, state: ModuleState, deps: DependenciesHelper, + subdirs: T.List[str], name: T.Optional[str], + description: T.Optional[str], url: str, version: str, + pcfile: str, conflicts: T.List[str], + variables: T.List[T.Tuple[str, str]], + unescaped_variables: T.List[T.Tuple[str, str]], + uninstalled: bool = False, dataonly: bool = False, + pkgroot: T.Optional[str] = None) -> None: coredata = state.environment.get_coredata() referenced_vars = set() optnames = [x.name for x in BUILTIN_DIR_OPTIONS.keys()] @@ -426,7 +454,7 @@ class PkgConfigModule(ExtensionModule): srcdir = PurePath(state.environment.get_source_dir()) else: outdir = state.environment.scratch_dir - prefix = PurePath(coredata.get_option(mesonlib.OptionKey('prefix'))) + prefix = PurePath(_as_str(coredata.get_option(mesonlib.OptionKey('prefix')))) if pkgroot: pkgroot = PurePath(pkgroot) if not pkgroot.is_absolute(): @@ -443,7 +471,7 @@ class PkgConfigModule(ExtensionModule): if optname == 'prefix': ofile.write('prefix={}\n'.format(self._escape(prefix))) else: - dirpath = PurePath(coredata.get_option(mesonlib.OptionKey(optname))) + dirpath = PurePath(_as_str(coredata.get_option(mesonlib.OptionKey(optname)))) ofile.write('{}={}\n'.format(optname, self._escape('${prefix}' / dirpath))) if uninstalled and not dataonly: ofile.write('srcdir={}\n'.format(self._escape(srcdir))) @@ -469,7 +497,7 @@ class PkgConfigModule(ExtensionModule): if len(conflicts) > 0: ofile.write('Conflicts: {}\n'.format(' '.join(conflicts))) - def generate_libs_flags(libs): + def generate_libs_flags(libs: T.List[LIBS]) -> T.Iterable[str]: msg = 'Library target {0!r} has {1!r} set. Compilers ' \ 'may not find it from its \'-l{2}\' linker flag in the ' \ '{3!r} pkg-config file.' @@ -478,6 +506,7 @@ class PkgConfigModule(ExtensionModule): if isinstance(l, str): yield l else: + install_dir: T.Union[str, bool] if uninstalled: install_dir = os.path.dirname(state.backend.get_target_filename_abs(l)) else: @@ -507,8 +536,8 @@ class PkgConfigModule(ExtensionModule): if is_custom_target or 'cs' not in l.compilers: yield f'-l{lname}' - def get_uninstalled_include_dirs(libs): - result = [] + def get_uninstalled_include_dirs(libs: T.List[LIBS]) -> T.List[str]: + result: T.List[str] = [] for l in libs: if isinstance(l, (str, build.CustomTarget, build.CustomTargetIndex)): continue @@ -522,7 +551,7 @@ class PkgConfigModule(ExtensionModule): result.append(path) return result - def generate_uninstalled_cflags(libs): + def generate_uninstalled_cflags(libs: T.List[LIBS]) -> T.Iterable[str]: for d in get_uninstalled_include_dirs(libs): for basedir in ['${prefix}', '${srcdir}']: path = PurePath(basedir, d) @@ -533,7 +562,7 @@ class PkgConfigModule(ExtensionModule): if len(deps.priv_libs) > 0: ofile.write('Libs.private: {}\n'.format(' '.join(generate_libs_flags(deps.priv_libs)))) - cflags = [] + cflags: T.List[str] = [] if uninstalled: cflags += generate_uninstalled_cflags(deps.pub_libs + deps.priv_libs) else: @@ -680,5 +709,6 @@ class PkgConfigModule(ExtensionModule): lib.generated_pc_warn = [name, location] return ModuleReturnValue(res, [res]) -def initialize(*args, **kwargs): - return PkgConfigModule(*args, **kwargs) + +def initialize(interp: Interpreter) -> PkgConfigModule: + return PkgConfigModule(interp) |