diff options
author | Daniel Mensinger <daniel@mensinger-ka.de> | 2021-06-17 00:16:58 +0200 |
---|---|---|
committer | Daniel Mensinger <daniel@mensinger-ka.de> | 2021-06-18 23:48:33 +0200 |
commit | 84a3e459a8618956eb3364900d2bd522a70b7fe7 (patch) | |
tree | d1800de6d5e026c5368f9395ed5ff24e49fa3758 | |
parent | c2c7f7c9d7b05dddb1cee028b1b685c7f2bd424c (diff) | |
download | meson-84a3e459a8618956eb3364900d2bd522a70b7fe7.zip meson-84a3e459a8618956eb3364900d2bd522a70b7fe7.tar.gz meson-84a3e459a8618956eb3364900d2bd522a70b7fe7.tar.bz2 |
holders: Introduce BothLibraries
-rw-r--r-- | mesonbuild/build.py | 20 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreter.py | 12 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreterobjects.py | 121 | ||||
-rw-r--r-- | mesonbuild/modules/pkgconfig.py | 29 |
4 files changed, 106 insertions, 76 deletions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py index a9abcf9..e2be9b1 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1251,6 +1251,8 @@ You probably should put it in link_with instead.''') def link(self, target): for t in unholder(listify(target)): + if isinstance(t, BothLibraries): + t = t.get_preferred_library() if isinstance(self, StaticLibrary) and self.need_install: if isinstance(t, (CustomTarget, CustomTargetIndex)): if not t.should_install(): @@ -1279,6 +1281,9 @@ You probably should put it in link_with instead.''') def link_whole(self, target): for t in unholder(listify(target)): + # Always use the static library from BothLibraries, since shared libs aren't supported anyway + if isinstance(t, BothLibraries): + t = t.static if isinstance(t, (CustomTarget, CustomTargetIndex)): if not t.is_linkable_target(): raise InvalidArguments(f'Custom target {t!r} is not linkable.') @@ -1840,6 +1845,8 @@ class SharedLibrary(BuildTarget): self.gcc_import_filename = None # The debugging information file this target will generate self.debug_filename = None + # Use by the pkgconfig module + self.shared_library_only = False super().__init__(name, subdir, subproject, for_machine, sources, objects, environment, kwargs) if 'rust' in self.compilers: # If no crate type is specified, or it's the generic lib type, use dylib @@ -2159,6 +2166,19 @@ class SharedModule(SharedLibrary): def get_default_install_dir(self, environment): return environment.get_shared_module_dir() +class BothLibraries(HoldableObject): + def __init__(self, shared: SharedLibrary, static: StaticLibrary) -> None: + self._preferred_library = 'shared' + self.shared = shared + self.static = static + + def get_preferred_library(self) -> BuildTarget: + if self._preferred_library == 'shared': + return self.shared + elif self._preferred_library == 'static': + return self.static + raise MesonBugException(f'self._preferred_library == "{self._preferred_library}" is neither "shared" nor "static".') + class CommandBase: def flatten_command(self, cmd): cmd = unholder(listify(cmd)) diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 13be8e4..494807a 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -2517,7 +2517,7 @@ Try setting b_lundef to false instead.'''.format(self.coredata.options[OptionKey @FeatureNew('both_libraries', '0.46.0') def build_both_libraries(self, node, args, kwargs): - shared_holder = self.build_target(node, args, kwargs, SharedLibraryHolder) + shared_lib = self.build_target(node, args, kwargs, build.SharedLibrary) # Check if user forces non-PIC static library. pic = True @@ -2543,21 +2543,21 @@ Try setting b_lundef to false instead.'''.format(self.coredata.options[OptionKey static_args = [args[0]] static_kwargs = kwargs.copy() static_kwargs['sources'] = [] - static_kwargs['objects'] = shared_holder.held_object.extract_all_objects() + static_kwargs['objects'] = shared_lib.extract_all_objects() else: static_args = args static_kwargs = kwargs - static_holder = self.build_target(node, static_args, static_kwargs, StaticLibraryHolder) + static_lib = self.build_target(node, static_args, static_kwargs, build.StaticLibrary) - return BothLibrariesHolder(shared_holder, static_holder, self) + return build.BothLibraries(shared_lib, static_lib) def build_library(self, node, args, kwargs): default_library = self.coredata.get_option(OptionKey('default_library', subproject=self.subproject)) if default_library == 'shared': - return self.build_target(node, args, kwargs, SharedLibraryHolder) + return self.build_target(node, args, kwargs, build.SharedLibrary) elif default_library == 'static': - return self.build_target(node, args, kwargs, StaticLibraryHolder) + return self.build_target(node, args, kwargs, build.StaticLibrary) elif default_library == 'both': return self.build_both_libraries(node, args, kwargs) else: diff --git a/mesonbuild/interpreter/interpreterobjects.py b/mesonbuild/interpreter/interpreterobjects.py index 8b62496..c0eecca 100644 --- a/mesonbuild/interpreter/interpreterobjects.py +++ b/mesonbuild/interpreter/interpreterobjects.py @@ -799,18 +799,10 @@ class MutableModuleObjectHolder(ModuleObjectHolder, MutableInterpreterObject): modobj = copy.deepcopy(self.held_object, memo) return MutableModuleObjectHolder(modobj, self.interpreter) -_Target = T.TypeVar('_Target', bound=build.Target) +_BuildTarget = T.TypeVar('_BuildTarget', bound=T.Union[build.BuildTarget, build.BothLibraries]) -class TargetHolder(ObjectHolder[_Target]): - def __init__(self, target: _Target, interp: 'Interpreter'): - super().__init__(target, subproject=interp.subproject) - self.interpreter = interp - - -_BuildTarget = T.TypeVar('_BuildTarget', bound=build.BuildTarget) - -class BuildTargetHolder(TargetHolder[_BuildTarget]): +class BuildTargetHolder(ObjectHolder[_BuildTarget]): def __init__(self, target: _BuildTarget, interp: 'Interpreter'): super().__init__(target, interp) self.methods.update({'extract_objects': self.extract_objects_method, @@ -822,59 +814,67 @@ class BuildTargetHolder(TargetHolder[_BuildTarget]): 'private_dir_include': self.private_dir_include_method, }) - def __repr__(self): + def __repr__(self) -> str: r = '<{} {}: {}>' h = self.held_object return r.format(self.__class__.__name__, h.get_id(), h.filename) - def is_cross(self): - return not self.held_object.environment.machines.matches_build_machine(self.held_object.for_machine) + @property + def _target_object(self) -> build.BuildTarget: + if isinstance(self.held_object, build.BothLibraries): + return self.held_object.get_preferred_library() + assert isinstance(self.held_object, build.BuildTarget) + return self.held_object + + def is_cross(self) -> bool: + return not self._target_object.environment.machines.matches_build_machine(self._target_object.for_machine) @noPosargs - @permittedKwargs({}) - def private_dir_include_method(self, args, kwargs): - return IncludeDirsHolder(build.IncludeDirs('', [], False, - [self.interpreter.backend.get_target_private_dir(self.held_object)])) + @noKwargs + def private_dir_include_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.IncludeDirs: + return build.IncludeDirs('', [], False, [self.interpreter.backend.get_target_private_dir(self._target_object)]) @noPosargs - @permittedKwargs({}) - def full_path_method(self, args, kwargs): - return self.interpreter.backend.get_target_filename_abs(self.held_object) + @noKwargs + def full_path_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: + return self.interpreter.backend.get_target_filename_abs(self._target_object) @noPosargs - @permittedKwargs({}) - def outdir_method(self, args, kwargs): - return self.interpreter.backend.get_target_dir(self.held_object) + @noKwargs + def outdir_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: + return self.interpreter.backend.get_target_dir(self._target_object) - @permittedKwargs({}) - def extract_objects_method(self, args, kwargs): - gobjs = self.held_object.extract_objects(args) - return GeneratedObjectsHolder(gobjs) + @noKwargs + @typed_pos_args('extract_objects', varargs=(mesonlib.File, str)) + def extract_objects_method(self, args: T.Tuple[T.List[mesonlib.FileOrString]], kwargs: TYPE_nkwargs) -> build.ExtractedObjects: + return self._target_object.extract_objects(args[0]) - @FeatureNewKwargs('extract_all_objects', '0.46.0', ['recursive']) @noPosargs - @permittedKwargs({'recursive'}) - def extract_all_objects_method(self, args, kwargs): - recursive = kwargs.get('recursive', False) - gobjs = self.held_object.extract_all_objects(recursive) - if gobjs.objlist and 'recursive' not in kwargs: - mlog.warning('extract_all_objects called without setting recursive ' - 'keyword argument. Meson currently defaults to ' - 'non-recursive to maintain backward compatibility but ' - 'the default will be changed in the future.', - location=self.current_node) - return GeneratedObjectsHolder(gobjs) + @typed_kwargs( + 'extract_all_objects', + KwargInfo( + 'recursive', bool, default=False, since='0.46.0', + not_set_warning=textwrap.dedent('''\ + extract_all_objects called without setting recursive + keyword argument. Meson currently defaults to + non-recursive to maintain backward compatibility but + the default will be changed in the future. + ''') + ) + ) + def extract_all_objects_method(self, args: T.List[TYPE_nvar], kwargs: 'kwargs.BuildTargeMethodExtractAllObjects') -> build.ExtractedObjects: + return self._target_object.extract_all_objects(kwargs['recursive']) @noPosargs - @permittedKwargs({}) - def get_id_method(self, args, kwargs): - return self.held_object.get_id() + @noKwargs + def get_id_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: + return self._target_object.get_id() @FeatureNew('name', '0.54.0') @noPosargs - @permittedKwargs({}) - def name_method(self, args, kwargs): - return self.held_object.name + @noKwargs + def name_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> str: + return self._target_object.name class ExecutableHolder(BuildTargetHolder[build.Executable]): pass @@ -883,37 +883,32 @@ class StaticLibraryHolder(BuildTargetHolder[build.StaticLibrary]): pass class SharedLibraryHolder(BuildTargetHolder[build.SharedLibrary]): - def __init__(self, target: build.SharedLibrary, interp: 'Interpreter'): - super().__init__(target, interp) - # Set to True only when called from self.func_shared_lib(). - target.shared_library_only = False + pass -class BothLibrariesHolder(BuildTargetHolder): - def __init__(self, shared_holder, static_holder, interp): +class BothLibrariesHolder(BuildTargetHolder[build.BothLibraries]): + def __init__(self, libs: build.BothLibraries, interp: 'Interpreter'): # FIXME: This build target always represents the shared library, but # that should be configurable. - super().__init__(shared_holder.held_object, interp) - self.shared_holder = shared_holder - self.static_holder = static_holder + super().__init__(libs, interp) self.methods.update({'get_shared_lib': self.get_shared_lib_method, 'get_static_lib': self.get_static_lib_method, }) - def __repr__(self): + def __repr__(self) -> str: r = '<{} {}: {}, {}: {}>' - h1 = self.shared_holder.held_object - h2 = self.static_holder.held_object + h1 = self.held_object.shared + h2 = self.held_object.static return r.format(self.__class__.__name__, h1.get_id(), h1.filename, h2.get_id(), h2.filename) @noPosargs - @permittedKwargs({}) - def get_shared_lib_method(self, args, kwargs): - return self.shared_holder + @noKwargs + def get_shared_lib_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.SharedLibrary: + return self.held_object.shared @noPosargs - @permittedKwargs({}) - def get_static_lib_method(self, args, kwargs): - return self.static_holder + @noKwargs + def get_static_lib_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> build.StaticLibrary: + return self.held_object.static class SharedModuleHolder(BuildTargetHolder[build.SharedModule]): pass diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 5cebd28..13af3a6 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -110,6 +110,7 @@ class DependenciesHelper: def _process_libs(self, libs, public): libs = mesonlib.unholder(mesonlib.listify(libs)) + libs = [x.get_preferred_library() if isinstance(x, build.BothLibraries) else x for x in libs] processed_libs = [] processed_reqs = [] processed_cflags = [] @@ -136,7 +137,7 @@ class DependenciesHelper: if obj.found(): processed_libs += obj.get_link_args() processed_cflags += obj.get_compile_args() - elif isinstance(obj, build.SharedLibrary) and shared_library_only: + elif isinstance(obj, build.SharedLibrary) and obj.shared_library_only: # Do not pull dependencies for shared libraries because they are # only required for static linking. Adding private requires has # the side effect of exposing their cflags, which is the @@ -161,7 +162,7 @@ class DependenciesHelper: elif isinstance(obj, str): processed_libs.append(obj) else: - raise mesonlib.MesonException('library argument not a string, library or dependency object.') + raise mesonlib.MesonException(f'library argument of type {type(obj).__name__} not a string, library or dependency object.') return processed_libs, processed_reqs, processed_cflags @@ -330,9 +331,9 @@ class PkgConfigModule(ExtensionModule): except ValueError: return subdir.as_posix() - def generate_pkgconfig_file(self, state, deps, subdirs, name, description, - url, version, pcfile, conflicts, variables, - unescaped_variables, uninstalled=False, dataonly=False): + def _generate_pkgconfig_file(self, state, deps, subdirs, name, description, + url, version, pcfile, conflicts, variables, + unescaped_variables, uninstalled=False, dataonly=False): coredata = state.environment.get_coredata() if uninstalled: outdir = os.path.join(state.environment.build_dir, 'meson-uninstalled') @@ -452,6 +453,19 @@ class PkgConfigModule(ExtensionModule): if cflags and not dataonly: ofile.write('Cflags: {}\n'.format(' '.join(cflags))) + + @staticmethod + def _handle_both_libraries(args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Tuple[T.List[TYPE_var], TYPE_kwargs]: + def _do_extract(arg: TYPE_var) -> TYPE_var: + if isinstance(arg, list): + return [_do_extract(x) for x in arg] + elif isinstance(arg, dict): + return {k: _do_extract(v) for k, v in arg.items()} + elif isinstance(arg, build.BothLibraries): + return arg.get_preferred_library() + return arg + return [_do_extract(x) for x in args], {k: _do_extract(v) for k, v in kwargs.items()} + @FeatureNewKwargs('pkgconfig.generate', '0.59.0', ['unescaped_variables', 'unescaped_uninstalled_variables']) @FeatureNewKwargs('pkgconfig.generate', '0.54.0', ['uninstalled_variables']) @FeatureNewKwargs('pkgconfig.generate', '0.42.0', ['extra_cflags']) @@ -469,6 +483,7 @@ class PkgConfigModule(ExtensionModule): default_name = None mainlib = None default_subdirs = ['.'] + args, kwargs = PkgConfigModule._handle_both_libraries(args, kwargs) if not args and 'version' not in kwargs: FeatureNew.single_use('pkgconfig.generate implicit version keyword', '0.46.0', state.subproject) elif len(args) == 1: @@ -556,7 +571,7 @@ class PkgConfigModule(ExtensionModule): pkgroot = os.path.join(state.environment.coredata.get_option(mesonlib.OptionKey('libdir')), 'pkgconfig') if not isinstance(pkgroot, str): raise mesonlib.MesonException('Install_dir must be a string.') - self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, + self._generate_pkgconfig_file(state, deps, subdirs, name, description, url, version, pcfile, conflicts, variables, unescaped_variables, False, dataonly) res = build.Data([mesonlib.File(True, state.environment.get_scratch_dir(), pcfile)], pkgroot, None, state.subproject) @@ -566,7 +581,7 @@ class PkgConfigModule(ExtensionModule): unescaped_variables = parse_variable_list(unescaped_variables) pcfile = filebase + '-uninstalled.pc' - self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, + self._generate_pkgconfig_file(state, deps, subdirs, name, description, url, version, pcfile, conflicts, variables, unescaped_variables, uninstalled=True, dataonly=dataonly) # Associate the main library with this generated pc file. If the library |