diff options
author | Xavier Claessens <xavier.claessens@collabora.com> | 2021-08-12 22:13:51 -0400 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2021-08-17 15:19:18 -0400 |
commit | 8c5aa031b5ffb4eb3c61083072dcab49c8927d45 (patch) | |
tree | f62800f365cf6706fab33283436cbeef7df7206f /mesonbuild | |
parent | 6d055b1e27dc6fc0fac967fbe2f439758a4c5d07 (diff) | |
download | meson-8c5aa031b5ffb4eb3c61083072dcab49c8927d45.zip meson-8c5aa031b5ffb4eb3c61083072dcab49c8927d45.tar.gz meson-8c5aa031b5ffb4eb3c61083072dcab49c8927d45.tar.bz2 |
Add install tags
Fixes: #7007.
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/backend/backends.py | 80 | ||||
-rw-r--r-- | mesonbuild/backend/ninjabackend.py | 2 | ||||
-rw-r--r-- | mesonbuild/build.py | 20 | ||||
-rw-r--r-- | mesonbuild/interpreter/interpreter.py | 24 | ||||
-rw-r--r-- | mesonbuild/interpreter/mesonmain.py | 15 | ||||
-rw-r--r-- | mesonbuild/minstall.py | 24 | ||||
-rw-r--r-- | mesonbuild/modules/gnome.py | 4 | ||||
-rw-r--r-- | mesonbuild/modules/hotdoc.py | 1 | ||||
-rw-r--r-- | mesonbuild/modules/i18n.py | 1 | ||||
-rw-r--r-- | mesonbuild/modules/pkgconfig.py | 2 | ||||
-rw-r--r-- | mesonbuild/modules/python.py | 8 | ||||
-rw-r--r-- | mesonbuild/modules/qt.py | 1 |
12 files changed, 131 insertions, 51 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index aa8e844..6c877ea 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -115,7 +115,8 @@ class InstallData: class TargetInstallData: def __init__(self, fname: str, outdir: str, aliases: T.Dict[str, str], strip: bool, install_name_mappings: T.Dict, rpath_dirs_to_remove: T.Set[bytes], - install_rpath: str, install_mode: 'FileMode', subproject: str, optional: bool = False): + install_rpath: str, install_mode: 'FileMode', subproject: str, + optional: bool = False, tag: T.Optional[str] = None): self.fname = fname self.outdir = outdir self.aliases = aliases @@ -126,22 +127,27 @@ class TargetInstallData: self.install_mode = install_mode self.subproject = subproject self.optional = optional + self.tag = tag class InstallDataBase: - def __init__(self, path: str, install_path: str, install_mode: 'FileMode', subproject: str): + def __init__(self, path: str, install_path: str, install_mode: 'FileMode', + subproject: str, tag: T.Optional[str] = None): self.path = path self.install_path = install_path self.install_mode = install_mode self.subproject = subproject + self.tag = tag class SubdirInstallData(InstallDataBase): - def __init__(self, path: str, install_path: str, install_mode: 'FileMode', exclude, subproject: str): - super().__init__(path, install_path, install_mode, subproject) + def __init__(self, path: str, install_path: str, install_mode: 'FileMode', + exclude, subproject: str, tag: T.Optional[str] = None): + super().__init__(path, install_path, install_mode, subproject, tag) self.exclude = exclude class ExecutableSerialisation: def __init__(self, cmd_args, env: T.Optional[build.EnvironmentVariables] = None, exe_wrapper=None, - workdir=None, extra_paths=None, capture=None, feed=None) -> None: + workdir=None, extra_paths=None, capture=None, feed=None, + tag: T.Optional[str] = None) -> None: self.cmd_args = cmd_args self.env = env if exe_wrapper is not None: @@ -155,6 +161,7 @@ class ExecutableSerialisation: self.skip_if_destdir = False self.verbose = False self.subproject = '' + self.tag = tag class TestSerialisation: def __init__(self, name: str, project: str, suite: T.List[str], fname: T.List[str], @@ -443,7 +450,8 @@ class Backend: def get_executable_serialisation(self, cmd, workdir=None, extra_bdeps=None, capture=None, feed=None, - env: T.Optional[build.EnvironmentVariables] = None): + env: T.Optional[build.EnvironmentVariables] = None, + tag: T.Optional[str] = None): exe = cmd[0] cmd_args = cmd[1:] if isinstance(exe, programs.ExternalProgram): @@ -490,7 +498,7 @@ class Backend: workdir = workdir or self.environment.get_build_dir() return ExecutableSerialisation(exe_cmd + cmd_args, env, exe_wrapper, workdir, - extra_paths, capture, feed) + extra_paths, capture, feed, tag) def as_meson_exe_cmdline(self, tname, exe, cmd_args, workdir=None, extra_bdeps=None, capture=None, feed=None, @@ -1032,7 +1040,7 @@ class Backend: with open(ifilename, 'w', encoding='utf-8') as f: f.write(json.dumps(mfobj)) # Copy file from, to, and with mode unchanged - d.data.append(InstallDataBase(ifilename, ofilename, None, '')) + d.data.append(InstallDataBase(ifilename, ofilename, None, '', tag='devel')) def get_regen_filelist(self): '''List of all files whose alteration means that the build @@ -1354,6 +1362,27 @@ class Backend: with open(install_data_file, 'wb') as ofile: pickle.dump(self.create_install_data(), ofile) + def guess_install_tag(self, fname: str, outdir: T.Optional[str] = None) -> T.Optional[str]: + prefix = self.environment.get_prefix() + bindir = Path(prefix, self.environment.get_bindir()) + libdir = Path(prefix, self.environment.get_libdir()) + incdir = Path(prefix, self.environment.get_includedir()) + localedir = Path(prefix, self.environment.coredata.get_option(mesonlib.OptionKey('localedir'))) + dest_path = Path(prefix, outdir, Path(fname).name) if outdir else Path(prefix, fname) + if bindir in dest_path.parents: + return 'runtime' + elif libdir in dest_path.parents: + if dest_path.suffix in {'.a', '.pc'}: + return 'devel' + elif dest_path.suffix in {'.so', '.dll'}: + return 'runtime' + elif incdir in dest_path.parents: + return 'devel' + elif localedir in dest_path.parents: + return 'i18n' + mlog.debug('Failed to guess install tag for', dest_path) + return None + def generate_target_install(self, d: InstallData) -> None: for t in self.build.get_targets().values(): if not t.should_install(): @@ -1366,6 +1395,7 @@ class Backend: "Pass 'false' for outputs that should not be installed and 'true' for\n" \ 'using the default installation directory for an output.' raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs)) + assert len(t.install_tag) == num_out install_mode = t.get_custom_install_mode() # Install the target output(s) if isinstance(t, build.BuildTarget): @@ -1387,11 +1417,13 @@ class Backend: # Install primary build output (library/executable/jar, etc) # Done separately because of strip/aliases/rpath if outdirs[0] is not False: + tag = t.install_tag[0] or ('devel' if isinstance(t, build.StaticLibrary) else 'runtime') mappings = t.get_link_deps_mapping(d.prefix, self.environment) i = TargetInstallData(self.get_target_filename(t), outdirs[0], t.get_aliases(), should_strip, mappings, t.rpath_dirs_to_remove, - t.install_rpath, install_mode, t.subproject) + t.install_rpath, install_mode, t.subproject, + tag=tag) d.targets.append(i) if isinstance(t, (build.SharedLibrary, build.SharedModule, build.Executable)): @@ -1409,7 +1441,8 @@ class Backend: # Install the import library; may not exist for shared modules i = TargetInstallData(self.get_target_filename_for_linking(t), implib_install_dir, {}, False, {}, set(), '', install_mode, - t.subproject, optional=isinstance(t, build.SharedModule)) + t.subproject, optional=isinstance(t, build.SharedModule), + tag='devel') d.targets.append(i) if not should_strip and t.get_debug_filename(): @@ -1417,17 +1450,19 @@ class Backend: i = TargetInstallData(debug_file, outdirs[0], {}, False, {}, set(), '', install_mode, t.subproject, - optional=True) + optional=True, tag='devel') d.targets.append(i) # Install secondary outputs. Only used for Vala right now. if num_outdirs > 1: - for output, outdir in zip(t.get_outputs()[1:], outdirs[1:]): + for output, outdir, tag in zip(t.get_outputs()[1:], outdirs[1:], t.install_tag[1:]): # User requested that we not install this output if outdir is False: continue f = os.path.join(self.get_target_dir(t), output) + tag = tag or self.guess_install_tag(f, outdir) i = TargetInstallData(f, outdir, {}, False, {}, set(), None, - install_mode, t.subproject) + install_mode, t.subproject, + tag=tag) d.targets.append(i) elif isinstance(t, build.CustomTarget): # If only one install_dir is specified, assume that all @@ -1438,19 +1473,23 @@ class Backend: # To selectively install only some outputs, pass `false` as # the install_dir for the corresponding output by index if num_outdirs == 1 and num_out > 1: - for output in t.get_outputs(): + for output, tag in zip(t.get_outputs(), t.install_tag): f = os.path.join(self.get_target_dir(t), output) + tag = tag or self.guess_install_tag(f, outdirs[0]) i = TargetInstallData(f, outdirs[0], {}, False, {}, set(), None, install_mode, - t.subproject, optional=not t.build_by_default) + t.subproject, optional=not t.build_by_default, + tag=tag) d.targets.append(i) else: - for output, outdir in zip(t.get_outputs(), outdirs): + for output, outdir, tag in zip(t.get_outputs(), outdirs, t.install_tag): # User requested that we not install this output if outdir is False: continue f = os.path.join(self.get_target_dir(t), output) + tag = tag or self.guess_install_tag(f, outdir) i = TargetInstallData(f, outdir, {}, False, {}, set(), None, install_mode, - t.subproject, optional=not t.build_by_default) + t.subproject, optional=not t.build_by_default, + tag=tag) d.targets.append(i) def generate_custom_install_script(self, d: InstallData) -> None: @@ -1475,7 +1514,7 @@ class Backend: if not isinstance(f, File): raise MesonException(f'Invalid header type {f!r} can\'t be installed') abspath = f.absolute_path(srcdir, builddir) - i = InstallDataBase(abspath, outdir, h.get_custom_install_mode(), h.subproject) + i = InstallDataBase(abspath, outdir, h.get_custom_install_mode(), h.subproject, tag='devel') d.headers.append(i) def generate_man_install(self, d: InstallData) -> None: @@ -1495,7 +1534,7 @@ class Backend: fname = fname.replace(f'.{m.locale}', '') srcabs = f.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir()) dstabs = os.path.join(subdir, os.path.basename(fname)) - i = InstallDataBase(srcabs, dstabs, m.get_custom_install_mode(), m.subproject) + i = InstallDataBase(srcabs, dstabs, m.get_custom_install_mode(), m.subproject, tag='man') d.man.append(i) def generate_data_install(self, d: InstallData): @@ -1510,7 +1549,8 @@ class Backend: for src_file, dst_name in zip(de.sources, de.rename): assert(isinstance(src_file, mesonlib.File)) dst_abs = os.path.join(subdir, dst_name) - i = InstallDataBase(src_file.absolute_path(srcdir, builddir), dst_abs, de.install_mode, de.subproject) + tag = de.install_tag or self.guess_install_tag(dst_abs) + i = InstallDataBase(src_file.absolute_path(srcdir, builddir), dst_abs, de.install_mode, de.subproject, tag=tag) d.data.append(i) def generate_subdir_install(self, d: InstallData) -> None: diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 871bf9f..68c63b2 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -1513,6 +1513,7 @@ class NinjaBackend(backends.Backend): args += ['--vapi', os.path.join('..', target.vala_vapi)] valac_outputs.append(vapiname) target.outputs += [target.vala_header, target.vala_vapi] + target.install_tag += ['devel', 'devel'] # Install header and vapi to default locations if user requests this if len(target.install_dir) > 1 and target.install_dir[1] is True: target.install_dir[1] = self.environment.get_includedir() @@ -1524,6 +1525,7 @@ class NinjaBackend(backends.Backend): args += ['--gir', os.path.join('..', target.vala_gir)] valac_outputs.append(girname) target.outputs.append(target.vala_gir) + target.install_tag.append('devel') # Install GIR to default location if requested by user if len(target.install_dir) > 3 and target.install_dir[3] is True: target.install_dir[3] = os.path.join(self.environment.get_datadir(), 'gir-1.0') diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 28ad60e..69a2d76 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -90,6 +90,7 @@ buildtarget_kwargs = { 'install_rpath', 'install_dir', 'install_mode', + 'install_tag', 'name_prefix', 'name_suffix', 'native', @@ -189,7 +190,8 @@ class InstallDir(HoldableObject): install_mode: 'FileMode', exclude: T.Tuple[T.Set[str], T.Set[str]], strip_directory: bool, subproject: str, - from_source_dir: bool = True): + from_source_dir: bool = True, + install_tag: T.Optional[str] = None): self.source_subdir = src_subdir self.installable_subdir = inst_subdir self.install_dir = install_dir @@ -198,6 +200,7 @@ class InstallDir(HoldableObject): self.strip_directory = strip_directory self.from_source_dir = from_source_dir self.subproject = subproject + self.install_tag = install_tag class Build: @@ -1014,6 +1017,7 @@ class BuildTarget(Target): self.install_dir = typeslistify(kwargs.get('install_dir', [None]), (str, bool)) self.install_mode = kwargs.get('install_mode', None) + self.install_tag = stringlistify(kwargs.get('install_tag', [None])) main_class = kwargs.get('main_class', '') if not isinstance(main_class, str): raise InvalidArguments('Main class must be a string') @@ -2206,6 +2210,7 @@ class CustomTarget(Target, CommandBase): 'install', 'install_dir', 'install_mode', + 'install_tag', 'build_always', 'build_always_stale', 'depends', @@ -2339,10 +2344,19 @@ class CustomTarget(Target, CommandBase): # the list index of that item will not be installed self.install_dir = typeslistify(kwargs['install_dir'], (str, bool)) self.install_mode = kwargs.get('install_mode', None) + # If only one tag is provided, assume all outputs have the same tag. + # Otherwise, we must have as much tags as outputs. + self.install_tag = typeslistify(kwargs.get('install_tag', [None]), (str, bool)) + if len(self.install_tag) == 1: + self.install_tag = self.install_tag * len(self.outputs) + elif len(self.install_tag) != len(self.outputs): + m = f'Target {self.name!r} has {len(self.outputs)} outputs but {len(self.install_tag)} "install_tag"s were found.' + raise InvalidArguments(m) else: self.install = False self.install_dir = [None] self.install_mode = None + self.install_tag = [] if 'build_always' in kwargs and 'build_always_stale' in kwargs: raise InvalidArguments('build_always and build_always_stale are mutually exclusive. Combine build_by_default and build_always_stale.') elif 'build_always' in kwargs: @@ -2625,10 +2639,12 @@ class ConfigurationData(HoldableObject): class Data(HoldableObject): def __init__(self, sources: T.List[File], install_dir: str, install_mode: 'FileMode', subproject: str, - rename: T.List[str] = None): + rename: T.List[str] = None, + install_tag: T.Optional[str] = None): self.sources = sources self.install_dir = install_dir self.install_mode = install_mode + self.install_tag = install_tag if rename is None: self.rename = [os.path.basename(f.fname) for f in self.sources] else: diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index ab7efa0..535229c 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1598,6 +1598,7 @@ external dependencies (including libraries) must go to "dependencies".''') def func_subdir_done(self, node, args, kwargs): raise SubdirDoneRequest() + @FeatureNewKwargs('custom_target', '0.60.0', ['install_tag']) @FeatureNewKwargs('custom_target', '0.57.0', ['env']) @FeatureNewKwargs('custom_target', '0.48.0', ['console']) @FeatureNewKwargs('custom_target', '0.47.0', ['install_mode', 'build_always_stale']) @@ -1606,7 +1607,7 @@ external dependencies (including libraries) must go to "dependencies".''') @permittedKwargs({'input', 'output', 'command', 'install', 'install_dir', 'install_mode', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default', 'build_always_stale', 'console', 'env', - 'feed'}) + 'feed', 'install_tag'}) @typed_pos_args('custom_target', str) def func_custom_target(self, node: mparser.FunctionNode, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> build.CustomTarget: if 'depfile' in kwargs and ('@BASENAME@' in kwargs['depfile'] or '@PLAINNAME@' in kwargs['depfile']): @@ -1903,6 +1904,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self KwargInfo('sources', ContainerTypeInfo(list, (str, mesonlib.File)), listify=True, default=[]), KwargInfo('rename', ContainerTypeInfo(list, str), default=[], listify=True, since='0.46.0'), INSTALL_MODE_KW.evolve(since='0.38.0'), + KwargInfo('install_tag', str, since='0.60.0'), ) def func_install_data(self, node: mparser.BaseNode, args: T.Tuple[T.List['mesonlib.FileOrString']], @@ -1915,12 +1917,14 @@ This will become a hard error in the future.''' % kwargs['input'], location=self '"rename" and "sources" argument lists must be the same length if "rename" is given. ' f'Rename has {len(rename)} elements and sources has {len(sources)}.') - return self.install_data_impl(sources, kwargs['install_dir'], kwargs['install_mode'], rename) + return self.install_data_impl(sources, kwargs['install_dir'], kwargs['install_mode'], rename, + kwargs['install_tag']) def install_data_impl(self, sources: T.List[mesonlib.File], install_dir: str, - install_mode: FileMode, rename: T.Optional[str]) -> build.Data: + install_mode: FileMode, rename: T.Optional[str], + tag: T.Optional[str]) -> build.Data: """Just the implementation with no validation.""" - data = build.Data(sources, install_dir, install_mode, self.subproject, rename) + data = build.Data(sources, install_dir, install_mode, self.subproject, rename, tag) self.build.data.append(data) return data @@ -1928,6 +1932,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self @typed_kwargs( 'install_subdir', KwargInfo('install_dir', str, required=True), + KwargInfo('install_tag', str, since='0.60.0'), KwargInfo('strip_directory', bool, default=False), KwargInfo('exclude_files', ContainerTypeInfo(list, str), default=[], listify=True, since='0.42.0', @@ -1947,7 +1952,8 @@ This will become a hard error in the future.''' % kwargs['input'], location=self kwargs['install_mode'], exclude, kwargs['strip_directory'], - self.subproject) + self.subproject, + install_tag=kwargs['install_tag']) self.build.install_dirs.append(idir) return idir @@ -1956,9 +1962,10 @@ This will become a hard error in the future.''' % kwargs['input'], location=self @FeatureNewKwargs('configure_file', '0.41.0', ['capture']) @FeatureNewKwargs('configure_file', '0.50.0', ['install']) @FeatureNewKwargs('configure_file', '0.52.0', ['depfile']) + @FeatureNewKwargs('configure_file', '0.60.0', ['install_tag']) @permittedKwargs({'input', 'output', 'configuration', 'command', 'copy', 'depfile', 'install_dir', 'install_mode', 'capture', 'install', 'format', - 'output_format', 'encoding'}) + 'output_format', 'encoding', 'install_tag'}) @noPosargs def func_configure_file(self, node, args, kwargs): if 'output' not in kwargs: @@ -2139,7 +2146,10 @@ This will become a hard error in the future.''' % kwargs['input'], location=self 'is true') cfile = mesonlib.File.from_built_file(ofile_path, ofile_fname) install_mode = self._get_kwarg_install_mode(kwargs) - self.build.data.append(build.Data([cfile], idir, install_mode, self.subproject)) + install_tag = kwargs.get('install_tag') + if install_tag is not None and not isinstance(install_tag, str): + raise InvalidArguments('install_tag keyword argument must be string') + self.build.data.append(build.Data([cfile], idir, install_mode, self.subproject, install_tag=install_tag)) return mesonlib.File.from_built_file(self.subdir, output) def extract_incdirs(self, kwargs): diff --git a/mesonbuild/interpreter/mesonmain.py b/mesonbuild/interpreter/mesonmain.py index 97a695b..ea16b46 100644 --- a/mesonbuild/interpreter/mesonmain.py +++ b/mesonbuild/interpreter/mesonmain.py @@ -7,9 +7,9 @@ from .. import mlog from ..mesonlib import MachineChoice, OptionKey from ..programs import OverrideProgram, ExternalProgram -from ..interpreterbase import (MesonInterpreterObject, FeatureNewKwargs, FeatureNew, FeatureDeprecated, +from ..interpreterbase import (MesonInterpreterObject, FeatureNew, FeatureDeprecated, typed_pos_args, permittedKwargs, noArgsFlattening, noPosargs, noKwargs, - MesonVersionString, InterpreterException) + typed_kwargs, KwargInfo, MesonVersionString, InterpreterException) from .interpreterobjects import (ExecutableHolder, ExternalProgramHolder, CustomTargetHolder, CustomTargetIndexHolder, @@ -107,20 +107,19 @@ class MesonMain(MesonInterpreterObject): '0.55.0', self.interpreter.subproject) return script_args - @FeatureNewKwargs('add_install_script', '0.57.0', ['skip_if_destdir']) - @permittedKwargs({'skip_if_destdir'}) + @typed_kwargs('add_install_script', + KwargInfo('skip_if_destdir', bool, default=False, since='0.57.0'), + KwargInfo('install_tag', str, since='0.60.0')) def add_install_script_method(self, args: 'T.Tuple[T.Union[str, mesonlib.File, ExecutableHolder], T.Union[str, mesonlib.File, CustomTargetHolder, CustomTargetIndexHolder], ...]', kwargs): if len(args) < 1: raise InterpreterException('add_install_script takes one or more arguments') if isinstance(args[0], mesonlib.File): FeatureNew.single_use('Passing file object to script parameter of add_install_script', '0.57.0', self.interpreter.subproject) - skip_if_destdir = kwargs.get('skip_if_destdir', False) - if not isinstance(skip_if_destdir, bool): - raise InterpreterException('skip_if_destdir keyword argument must be boolean') script_args = self._process_script_args('add_install_script', args[1:], allow_built=True) script = self._find_source_script(args[0], script_args) - script.skip_if_destdir = skip_if_destdir + script.skip_if_destdir = kwargs['skip_if_destdir'] + script.tag = kwargs['install_tag'] self.build.install_scripts.append(script) @permittedKwargs(set()) diff --git a/mesonbuild/minstall.py b/mesonbuild/minstall.py index d8faad6..6660d6c 100644 --- a/mesonbuild/minstall.py +++ b/mesonbuild/minstall.py @@ -25,7 +25,7 @@ import sys import typing as T from . import environment -from .backend.backends import InstallData +from .backend.backends import InstallData, InstallDataBase, TargetInstallData, ExecutableSerialisation from .coredata import major_versions_differ, MesonVersionMismatchException from .coredata import version as coredata_version from .mesonlib import Popen_safe, RealPathAction, is_windows @@ -56,6 +56,7 @@ if T.TYPE_CHECKING: destdir: str dry_run: bool skip_subprojects: str + tags: str symlink_warning = '''Warning: trying to copy a symlink that points to a file. This will copy the file, @@ -81,6 +82,8 @@ def add_arguments(parser: argparse.ArgumentParser) -> None: help='Doesn\'t actually install, but print logs. (Since 0.57.0)') parser.add_argument('--skip-subprojects', nargs='?', const='*', default='', help='Do not install files from given subprojects. (Since 0.58.0)') + parser.add_argument('--tags', default=None, + help='Install only targets having one of the given tags. (Since 0.60.0)') class DirMaker: def __init__(self, lf: T.TextIO, makedirs: T.Callable[..., None]): @@ -303,6 +306,7 @@ class Installer: # ['*'] means skip all, # ['sub1', ...] means skip only those. self.skip_subprojects = [i.strip() for i in options.skip_subprojects.split(',')] + self.tags = [i.strip() for i in options.tags.split(',')] if options.tags else None def remove(self, *args: T.Any, **kwargs: T.Any) -> None: if not self.dry_run: @@ -371,8 +375,10 @@ class Installer: return run_exe(*args, **kwargs) return 0 - def install_subproject(self, subproject: str) -> bool: - if subproject and (subproject in self.skip_subprojects or '*' in self.skip_subprojects): + def should_install(self, d: T.Union[TargetInstallData, InstallDataBase, ExecutableSerialisation]) -> bool: + if d.subproject and (d.subproject in self.skip_subprojects or '*' in self.skip_subprojects): + return False + if self.tags and d.tag not in self.tags: return False return True @@ -552,7 +558,7 @@ class Installer: def install_subdirs(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None: for i in d.install_subdirs: - if not self.install_subproject(i.subproject): + if not self.should_install(i): continue self.did_install_something = True full_dst_dir = get_destdir_path(destdir, fullprefix, i.install_path) @@ -562,7 +568,7 @@ class Installer: def install_data(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None: for i in d.data: - if not self.install_subproject(i.subproject): + if not self.should_install(i): continue fullfilename = i.path outfilename = get_destdir_path(destdir, fullprefix, i.install_path) @@ -573,7 +579,7 @@ class Installer: def install_man(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None: for m in d.man: - if not self.install_subproject(m.subproject): + if not self.should_install(m): continue full_source_filename = m.path outfilename = get_destdir_path(destdir, fullprefix, m.install_path) @@ -584,7 +590,7 @@ class Installer: def install_headers(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None: for t in d.headers: - if not self.install_subproject(t.subproject): + if not self.should_install(t): continue fullfilename = t.path fname = os.path.basename(fullfilename) @@ -605,7 +611,7 @@ class Installer: env['MESON_INSTALL_QUIET'] = '1' for i in d.install_scripts: - if not self.install_subproject(i.subproject): + if not self.should_install(i): continue name = ' '.join(i.cmd_args) if i.skip_if_destdir and destdir: @@ -625,7 +631,7 @@ class Installer: def install_targets(self, d: InstallData, dm: DirMaker, destdir: str, fullprefix: str) -> None: for t in d.targets: - if not self.install_subproject(t.subproject): + if not self.should_install(t): continue if not os.path.exists(t.fname): # For example, import libraries of shared modules are optional diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index a9cd1d3..a2f98bc 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -747,6 +747,7 @@ class GnomeModule(ExtensionModule): scankwargs['install'] = kwargs['install'] scankwargs['install_dir'] = kwargs.get('install_dir_gir', os.path.join(state.environment.get_datadir(), 'gir-1.0')) + scankwargs['install_tag'] = 'devel' if 'build_by_default' in kwargs: scankwargs['build_by_default'] = kwargs['build_by_default'] @@ -764,6 +765,7 @@ class GnomeModule(ExtensionModule): typelib_kwargs['install'] = kwargs['install'] typelib_kwargs['install_dir'] = kwargs.get('install_dir_typelib', os.path.join(state.environment.get_libdir(), 'girepository-1.0')) + typelib_kwargs['install_tag'] = 'typelib' if 'build_by_default' in kwargs: typelib_kwargs['build_by_default'] = kwargs['build_by_default'] @@ -1146,7 +1148,7 @@ class GnomeModule(ExtensionModule): state.test(check_args, env=check_env, workdir=check_workdir, depends=custom_target) res = [custom_target, alias_target] if kwargs.get('install', True): - res.append(state.backend.get_executable_serialisation(command + args)) + res.append(state.backend.get_executable_serialisation(command + args, tag='doc')) return ModuleReturnValue(custom_target, res) def _get_build_args(self, kwargs, state, depends): diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index 4dccd06..19a1728 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -354,6 +354,7 @@ class HotdocTargetBuilder: '--builddir', os.path.join(self.builddir, self.subdir)] + self.hotdoc.get_command() + ['run', '--conf-file', hotdoc_config_name]) + install_script.tag = 'doc' return (target, install_script) diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index 57d25fd..539f82b 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -181,6 +181,7 @@ class I18nModule(ExtensionModule): # to custom_targets. Crude hack: set the build target's subdir manually. # Bonus: the build tree has something usable as an uninstalled bindtextdomain() target dir. 'install_dir': path.join(install_dir, l, 'LC_MESSAGES'), + 'install_tag': 'i18n', } gmotarget = build.CustomTarget(l+'.mo', path.join(state.subdir, l, 'LC_MESSAGES'), state.subproject, gmo_kwargs) targets.append(gmotarget) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 48bbc34..e57c4f6 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -548,7 +548,7 @@ class PkgConfigModule(ExtensionModule): 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) + res = build.Data([mesonlib.File(True, state.environment.get_scratch_dir(), pcfile)], pkgroot, None, state.subproject, install_tag='devel') variables = self.interpreter.extract_variables(kwargs, argname='uninstalled_variables', dict_new=True) variables = parse_variable_list(variables) unescaped_variables = self.interpreter.extract_variables(kwargs, argname='unescaped_uninstalled_variables') diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index f38becf..65a73a7 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -344,6 +344,7 @@ if T.TYPE_CHECKING: pure: bool subdir: str + install_tag: T.Optional[str] class PythonInstallation(ExternalProgramHolder): @@ -436,14 +437,15 @@ class PythonInstallation(ExternalProgramHolder): return dep @typed_pos_args('install_data', varargs=(str, mesonlib.File)) - @typed_kwargs('python_installation.install_sources', _PURE_KW, _SUBDIR_KW) + @typed_kwargs('python_installation.install_sources', _PURE_KW, _SUBDIR_KW, + KwargInfo('install_tag', str, since='0.60.0')) def install_sources_method(self, args: T.Tuple[T.List[T.Union[str, mesonlib.File]]], kwargs: 'PyInstallKw') -> 'Data': + tag = kwargs['install_tag'] or 'runtime' return self.interpreter.install_data_impl( self.interpreter.source_strings_to_files(args[0]), self._get_install_dir_impl(kwargs['pure'], kwargs['subdir']), - mesonlib.FileMode(), - None) + mesonlib.FileMode(), rename=None, tag=tag) @noPosargs @typed_kwargs('python_installation.install_dir', _PURE_KW, _SUBDIR_KW) diff --git a/mesonbuild/modules/qt.py b/mesonbuild/modules/qt.py index 5efd668..ed66ae9 100644 --- a/mesonbuild/modules/qt.py +++ b/mesonbuild/modules/qt.py @@ -513,6 +513,7 @@ class QtBaseModule(ExtensionModule): lrelease_kwargs = {'output': '@BASENAME@.qm', 'input': ts, 'install': kwargs.get('install', False), + 'install_tag': 'i18n', 'build_by_default': kwargs.get('build_by_default', False), 'command': cmd} if install_dir is not None: |