diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 67bc8bf18..42f625539 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.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) diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 2729373a3..c7f5997b9 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -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 diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 8caf010df..131f0731c 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -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) diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index eee2e7c28..fd5c16fa0 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -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] = { diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 91443b804..9b50de418 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -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 diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 3238a39a7..824d97b17 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -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', }, },