introspection: untangle install_plan implemetation, fix a bunch of wrong ones

Generally plumb through the values of get_option() passed to
install_dir, and use this to establish the install plan name. Fixes
several odd cases, such as:

- {datadir} being prepended to "share" or "include"

- dissociating custom install directories and writing them out as
  {prefix}/share/foo or {prefix}/lib/python3.10/site-packages

This is the second half of #9478
Fixes #10601
pull/10652/head
Eli Schwartz 2 years ago
parent e19e9ce6f1
commit 3e73d4d77d
No known key found for this signature in database
GPG Key ID: CEB167EFB5722BD6
  1. 22
      mesonbuild/backend/backends.py
  2. 5
      mesonbuild/build.py
  3. 17
      mesonbuild/interpreter/interpreter.py
  4. 2
      mesonbuild/mintro.py
  5. 21
      mesonbuild/modules/python.py
  6. 34
      unittests/allplatformstests.py

@ -1534,7 +1534,7 @@ class Backend:
for t in self.build.get_targets().values():
if not t.should_install():
continue
outdirs, default_install_dir_name, custom_install_dir = t.get_install_dir()
outdirs, install_dir_names, custom_install_dir = t.get_install_dir()
# Sanity-check the outputs and install_dirs
num_outdirs, num_out = len(outdirs), len(t.get_outputs())
if num_outdirs != 1 and num_outdirs != num_out:
@ -1544,7 +1544,9 @@ class Backend:
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()
first_outdir = outdirs[0] # because mypy get's confused type narrowing in lists
# because mypy get's confused type narrowing in lists
first_outdir = outdirs[0]
first_outdir_name = install_dir_names[0]
# Install the target output(s)
if isinstance(t, build.BuildTarget):
@ -1570,7 +1572,7 @@ class Backend:
tag = t.install_tag[0] or ('devel' if isinstance(t, build.StaticLibrary) else 'runtime')
mappings = t.get_link_deps_mapping(d.prefix)
i = TargetInstallData(self.get_target_filename(t), first_outdir,
default_install_dir_name,
first_outdir_name,
should_strip, mappings, t.rpath_dirs_to_remove,
t.install_rpath, install_mode, t.subproject,
tag=tag, can_strip=can_strip)
@ -1595,7 +1597,7 @@ class Backend:
implib_install_dir = self.environment.get_import_lib_dir()
# Install the import library; may not exist for shared modules
i = TargetInstallData(self.get_target_filename_for_linking(t),
implib_install_dir, default_install_dir_name,
implib_install_dir, first_outdir_name,
False, {}, set(), '', install_mode,
t.subproject, optional=isinstance(t, build.SharedModule),
tag='devel')
@ -1604,19 +1606,19 @@ class Backend:
if not should_strip and t.get_debug_filename():
debug_file = os.path.join(self.get_target_dir(t), t.get_debug_filename())
i = TargetInstallData(debug_file, first_outdir,
default_install_dir_name,
first_outdir_name,
False, {}, set(), '',
install_mode, t.subproject,
optional=True, tag='devel')
d.targets.append(i)
# Install secondary outputs. Only used for Vala right now.
if num_outdirs > 1:
for output, outdir, tag in zip(t.get_outputs()[1:], outdirs[1:], t.install_tag[1:]):
for output, outdir, outdir_name, tag in zip(t.get_outputs()[1:], outdirs[1:], install_dir_names[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)
i = TargetInstallData(f, outdir, default_install_dir_name, False, {}, set(), None,
i = TargetInstallData(f, outdir, outdir_name, False, {}, set(), None,
install_mode, t.subproject,
tag=tag)
d.targets.append(i)
@ -1635,18 +1637,18 @@ class Backend:
if first_outdir is not False:
for output, tag in zip(t.get_outputs(), t.install_tag):
f = os.path.join(self.get_target_dir(t), output)
i = TargetInstallData(f, first_outdir, default_install_dir_name,
i = TargetInstallData(f, first_outdir, first_outdir_name,
False, {}, set(), None, install_mode,
t.subproject, optional=not t.build_by_default,
tag=tag)
d.targets.append(i)
else:
for output, outdir, tag in zip(t.get_outputs(), outdirs, t.install_tag):
for output, outdir, outdir_name, tag in zip(t.get_outputs(), outdirs, install_dir_names, 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)
i = TargetInstallData(f, outdir, default_install_dir_name,
i = TargetInstallData(f, outdir, outdir_name,
False, {}, set(), None, install_mode,
t.subproject, optional=not t.build_by_default,
tag=tag)

@ -628,7 +628,7 @@ class Target(HoldableObject):
# False (which means we want this specific output out of many
# outputs to not be installed).
custom_install_dir = True
default_install_dir_name = None
install_dir_names = [getattr(i, 'optname', None) for i in outdirs]
else:
custom_install_dir = False
# if outdirs is empty we need to set to something, otherwise we set
@ -637,8 +637,9 @@ class Target(HoldableObject):
outdirs[0] = default_install_dir
else:
outdirs = [default_install_dir]
install_dir_names = [default_install_dir_name] * len(outdirs)
return outdirs, default_install_dir_name, custom_install_dir
return outdirs, install_dir_names, custom_install_dir
def get_basename(self) -> str:
return self.name

@ -2342,14 +2342,8 @@ class Interpreter(InterpreterBase, HoldableObject):
'"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)}.')
install_dir_name = kwargs['install_dir']
if install_dir_name:
if not os.path.isabs(install_dir_name):
install_dir_name = os.path.join('{datadir}', install_dir_name)
else:
install_dir_name = '{datadir}'
return self.install_data_impl(sources, kwargs['install_dir'], kwargs['install_mode'],
rename, kwargs['install_tag'], install_dir_name,
rename, kwargs['install_tag'],
preserve_path=kwargs['preserve_path'])
def install_data_impl(self, sources: T.List[mesonlib.File], install_dir: T.Optional[str],
@ -2361,7 +2355,9 @@ class Interpreter(InterpreterBase, HoldableObject):
"""Just the implementation with no validation."""
idir = install_dir or ''
idir_name = install_dir_name or idir
idir_name = install_dir_name or idir or '{datadir}'
if isinstance(idir_name, P_OBJ.OptionString):
idir_name = idir_name.optname
dirs = collections.defaultdict(list)
ret_data = []
if preserve_path:
@ -2594,10 +2590,13 @@ class Interpreter(InterpreterBase, HoldableObject):
if not idir:
raise InterpreterException(
'"install_dir" must be specified when "install" in a configure_file is true')
idir_name = idir
if isinstance(idir_name, P_OBJ.OptionString):
idir_name = idir_name.optname
cfile = mesonlib.File.from_built_file(ofile_path, ofile_fname)
install_mode = kwargs['install_mode']
install_tag = kwargs['install_tag']
self.build.data.append(build.Data([cfile], idir, idir, install_mode, self.subproject,
self.build.data.append(build.Data([cfile], idir, idir_name, install_mode, self.subproject,
install_tag=install_tag, data_type='configure'))
return mesonlib.File.from_built_file(self.subdir, output)

@ -143,8 +143,6 @@ def list_install_plan(installdata: backends.InstallData) -> T.Dict[str, T.Dict[s
install_path_name = data.install_path_name
if key == 'headers': # in the headers, install_path_name is the directory
install_path_name = os.path.join(install_path_name, os.path.basename(data.path))
elif data_type == 'configure':
install_path_name = os.path.join('{prefix}', install_path_name)
plan[data_type] = plan.get(data_type, {})
plan[data_type][data.path] = {

@ -30,6 +30,7 @@ from ..dependencies.base import process_method_kw
from ..dependencies.detect import get_dep_identifier
from ..environment import detect_cpu_family
from ..interpreter import ExternalProgramHolder, extract_required_kwarg, permitted_dependency_kwargs
from ..interpreter import primitives as P_OBJ
from ..interpreter.type_checking import NoneType, PRESERVE_PATH_KW
from ..interpreterbase import (
noPosargs, noKwargs, permittedKwargs, ContainerTypeInfo,
@ -514,7 +515,7 @@ class PythonInstallation(ExternalProgramHolder):
if not isinstance(subdir, str):
raise InvalidArguments('"subdir" argument must be a string.')
kwargs['install_dir'] = os.path.join(self.platlib_install_path, subdir)
kwargs['install_dir'] = self._get_install_dir_impl(False, subdir)
new_deps = []
has_pydep = False
@ -598,11 +599,12 @@ class PythonInstallation(ExternalProgramHolder):
def install_sources_method(self, args: T.Tuple[T.List[T.Union[str, mesonlib.File]]],
kwargs: 'PyInstallKw') -> 'Data':
tag = kwargs['install_tag'] or 'runtime'
install_dir = self._get_install_dir_impl(kwargs['pure'], kwargs['subdir'])
return self.interpreter.install_data_impl(
self.interpreter.source_strings_to_files(args[0]),
self._get_install_dir_impl(kwargs['pure'], kwargs['subdir']),
install_dir,
mesonlib.FileMode(), rename=None, tag=tag, install_data_type='python',
install_dir_name=self._get_install_dir_name_impl(kwargs['pure'], kwargs['subdir']),
install_dir_name=install_dir.optname,
preserve_path=kwargs['preserve_path'])
@noPosargs
@ -610,12 +612,15 @@ class PythonInstallation(ExternalProgramHolder):
def get_install_dir_method(self, args: T.List['TYPE_var'], kwargs: 'PyInstallKw') -> str:
return self._get_install_dir_impl(kwargs['pure'], kwargs['subdir'])
def _get_install_dir_impl(self, pure: bool, subdir: str) -> str:
return os.path.join(
self.purelib_install_path if pure else self.platlib_install_path, subdir)
def _get_install_dir_impl(self, pure: bool, subdir: str) -> P_OBJ.OptionString:
if pure:
base = self.purelib_install_path
name = '{py_purelib}'
else:
base = self.platlib_install_path
name = '{py_platlib}'
def _get_install_dir_name_impl(self, pure: bool, subdir: str) -> str:
return os.path.join('{py_purelib}' if pure else '{py_platlib}', subdir)
return P_OBJ.OptionString(os.path.join(base, subdir), os.path.join(name, subdir))
@noPosargs
@noKwargs

@ -4145,11 +4145,11 @@ class AllPlatformTests(BasePlatformTests):
expected = {
'targets': {
f'{self.builddir}/out1-notag.txt': {
'destination': '{prefix}/share/out1-notag.txt',
'destination': '{datadir}/out1-notag.txt',
'tag': None,
},
f'{self.builddir}/out2-notag.txt': {
'destination': '{prefix}/share/out2-notag.txt',
'destination': '{datadir}/out2-notag.txt',
'tag': None,
},
f'{self.builddir}/libstatic.a': {
@ -4197,67 +4197,67 @@ class AllPlatformTests(BasePlatformTests):
'tag': 'devel',
},
f'{self.builddir}/out1-custom.txt': {
'destination': '{prefix}/share/out1-custom.txt',
'destination': '{datadir}/out1-custom.txt',
'tag': 'custom',
},
f'{self.builddir}/out2-custom.txt': {
'destination': '{prefix}/share/out2-custom.txt',
'destination': '{datadir}/out2-custom.txt',
'tag': 'custom',
},
f'{self.builddir}/out3-custom.txt': {
'destination': '{prefix}/share/out3-custom.txt',
'destination': '{datadir}/out3-custom.txt',
'tag': 'custom',
},
f'{self.builddir}/subdir/out1.txt': {
'destination': '{prefix}/share/out1.txt',
'destination': '{datadir}/out1.txt',
'tag': None,
},
f'{self.builddir}/subdir/out2.txt': {
'destination': '{prefix}/share/out2.txt',
'destination': '{datadir}/out2.txt',
'tag': None,
},
f'{self.builddir}/out-devel.h': {
'destination': '{prefix}/include/out-devel.h',
'destination': '{includedir}/out-devel.h',
'tag': 'devel',
},
f'{self.builddir}/out3-notag.txt': {
'destination': '{prefix}/share/out3-notag.txt',
'destination': '{datadir}/out3-notag.txt',
'tag': None,
},
},
'configure': {
f'{self.builddir}/foo-notag.h': {
'destination': '{prefix}/share/foo-notag.h',
'destination': '{datadir}/foo-notag.h',
'tag': None,
},
f'{self.builddir}/foo2-devel.h': {
'destination': '{prefix}/include/foo2-devel.h',
'destination': '{includedir}/foo2-devel.h',
'tag': 'devel',
},
f'{self.builddir}/foo-custom.h': {
'destination': '{prefix}/share/foo-custom.h',
'destination': '{datadir}/foo-custom.h',
'tag': 'custom',
},
f'{self.builddir}/subdir/foo2.h': {
'destination': '{prefix}/share/foo2.h',
'destination': '{datadir}/foo2.h',
'tag': None,
},
},
'data': {
f'{testdir}/bar-notag.txt': {
'destination': '{datadir}/share/bar-notag.txt',
'destination': '{datadir}/bar-notag.txt',
'tag': None,
},
f'{testdir}/bar-devel.h': {
'destination': '{datadir}/include/bar-devel.h',
'destination': '{includedir}/bar-devel.h',
'tag': 'devel',
},
f'{testdir}/bar-custom.txt': {
'destination': '{datadir}/share/bar-custom.txt',
'destination': '{datadir}/bar-custom.txt',
'tag': 'custom',
},
f'{testdir}/subdir/bar2-devel.h': {
'destination': '{datadir}/include/bar2-devel.h',
'destination': '{includedir}/bar2-devel.h',
'tag': 'devel',
},
},

Loading…
Cancel
Save