aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Mensinger <daniel@mensinger-ka.de>2021-06-17 00:16:58 +0200
committerDaniel Mensinger <daniel@mensinger-ka.de>2021-06-18 23:48:33 +0200
commit84a3e459a8618956eb3364900d2bd522a70b7fe7 (patch)
treed1800de6d5e026c5368f9395ed5ff24e49fa3758
parentc2c7f7c9d7b05dddb1cee028b1b685c7f2bd424c (diff)
downloadmeson-84a3e459a8618956eb3364900d2bd522a70b7fe7.zip
meson-84a3e459a8618956eb3364900d2bd522a70b7fe7.tar.gz
meson-84a3e459a8618956eb3364900d2bd522a70b7fe7.tar.bz2
holders: Introduce BothLibraries
-rw-r--r--mesonbuild/build.py20
-rw-r--r--mesonbuild/interpreter/interpreter.py12
-rw-r--r--mesonbuild/interpreter/interpreterobjects.py121
-rw-r--r--mesonbuild/modules/pkgconfig.py29
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