Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/markdown/Python-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ the addition of the following:

Additionally, the following diverge from [[shared_module]]'s default behavior:

- `install_dir` may only be a string, boolean, or unset, but an `array` is not
allowed.

- `gnu_symbol_visibility`: if unset, it will default to `'hidden'` on versions
of Python that support this (the python headers define `PyMODINIT_FUNC` has
default visibility).
Expand Down
6 changes: 5 additions & 1 deletion docs/yaml/functions/_build_target_base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,17 @@ kwargs:
description: When set to true, this executable should be installed.

install_dir:
type: str
type: array[str | bool]
description: |
override install directory for this file. If the value is a relative path,
it will be considered relative the `prefix` option.
For example, if you want to install plugins into a subdir, you'd use
something like this: `install_dir : get_option('libdir') / 'projectname-1.0'`.

This can be set to an array of values to control the the installation path
of build targets with multiple outputs. Currently, that means Vala. Setting
them to `true` means "use the default", and `false` means, don't install.

install_mode:
type: array[str | int]
since: 0.47.0
Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -1690,10 +1690,10 @@ def generate_target_install(self, d: InstallData) -> None:
# Sanity-check the outputs and install_dirs
num_outdirs, num_out = len(outdirs), len(t.get_outputs())
if num_outdirs not in {1, num_out}:
m = 'Target {!r} has {} outputs: {!r}, but only {} "install_dir"s were found.\n' \
m = 'Target {!r} has {} outputs: {!r}, but {} "install_dir"s were found: {!r}.\n' \
"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))
raise MesonException(m.format(t.name, num_out, t.get_outputs(), num_outdirs, outdirs))
assert len(t.install_tag) == num_out
install_mode = t.get_custom_install_mode()
# because mypy gets confused type narrowing in lists
Expand Down
5 changes: 2 additions & 3 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from .mesonlib import (
HoldableObject, SecondLevelHolder,
File, MesonException, MachineChoice, PerMachine, OrderedSet, listify,
extract_as_list, typeslistify, classify_unity_sources,
extract_as_list, classify_unity_sources,
get_filenames_templates_dict, substitute_values, has_path_sep,
is_parent_path, relpath, PerMachineDefaultable,
MesonBugException, EnvironmentVariables, pickle_load, lazy_property,
Expand Down Expand Up @@ -1292,8 +1292,7 @@ def process_kwargs(self, kwargs: BuildTargetKeywordArguments) -> None:
self.add_deps(deplist)
# If an item in this list is False, the output corresponding to
# the list index of that item will not be installed
self.install_dir = typeslistify(kwargs.get('install_dir', []),
(str, bool))
self.install_dir = kwargs.get('install_dir', [])
self.install_mode = kwargs.get('install_mode', None)
self.install_tag: T.List[T.Optional[str]] = kwargs.get('install_tag') or [None]
self.extra_files = kwargs.get('extra_files', [])
Expand Down
1 change: 1 addition & 0 deletions mesonbuild/interpreter/kwargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ class _BuildTarget(_BaseBuildTarget):
d_import_dirs: T.List[T.Union[str, build.IncludeDirs]]
d_module_versions: T.List[T.Union[str, int]]
d_unittest: bool
install_dir: T.List[T.Union[str, bool]]
rust_crate_type: T.Optional[Literal['bin', 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib', 'proc-macro']]
rust_dependency_map: T.Dict[str, str]
swift_interoperability_mode: Literal['c', 'cpp']
Expand Down
6 changes: 6 additions & 0 deletions mesonbuild/interpreter/type_checking.py
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,12 @@ def _extra_files_validator(args: T.List[T.Union[File, str]]) -> T.Optional[str]:
),
INSTALL_MODE_KW,
INSTALL_TAG_KW,
KwargInfo(
'install_dir',
ContainerTypeInfo(list, (str, bool)),
default=[],
listify=True,
),
KwargInfo('implicit_include_directories', bool, default=True, since='0.42.0'),
NATIVE_KW,
KwargInfo('resources', ContainerTypeInfo(list, str), default=[], listify=True),
Expand Down
20 changes: 16 additions & 4 deletions mesonbuild/modules/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class FindInstallationKw(ExtractRequired):

class ExtensionModuleKw(SharedModuleKw):

# Yes, these are different between SharedModule and ExtensionModule
install_dir: T.Union[str, bool, None] # type: ignore[misc]
subdir: NotRequired[T.Optional[str]]

MaybePythonProg = T.Union[NonExistingExternalProgram, 'PythonExternalProgram']
Expand All @@ -60,7 +62,8 @@ class ExtensionModuleKw(SharedModuleKw):
mod_kwargs.update(known_shmod_kwargs)
mod_kwargs -= {'name_prefix', 'name_suffix'}

_MOD_KWARGS = [k for k in SHARED_MOD_KWS if k.name not in {'name_prefix', 'name_suffix'}]
_MOD_KWARGS = [k for k in SHARED_MOD_KWS if
k.name not in {'name_prefix', 'name_suffix', 'install_dir'}]


class PythonExternalProgram(BasicPythonExternalProgram):
Expand Down Expand Up @@ -139,19 +142,28 @@ def __init__(self, python: 'PythonExternalProgram', interpreter: 'Interpreter'):

@permittedKwargs(mod_kwargs)
@typed_pos_args('python.extension_module', str, varargs=(str, mesonlib.File, CustomTarget, CustomTargetIndex, GeneratedList, StructuredSources, ExtractedObjects, BuildTarget))
@typed_kwargs('python.extension_module', *_MOD_KWARGS, _DEFAULTABLE_SUBDIR_KW, _LIMITED_API_KW, allow_unknown=True)
@typed_kwargs(
'python.extension_module',
*_MOD_KWARGS,
_DEFAULTABLE_SUBDIR_KW,
_LIMITED_API_KW,
KwargInfo('install_dir', (str, bool, NoneType)),
allow_unknown=True
)
@InterpreterObject.method('extension_module')
def extension_module_method(self, args: T.Tuple[str, T.List[BuildTargetSource]], kwargs: ExtensionModuleKw) -> 'SharedModule':
if 'install_dir' in kwargs:
if kwargs['install_dir'] is not None:
if kwargs['subdir'] is not None:
raise InvalidArguments('"subdir" and "install_dir" are mutually exclusive')
# the build_target() method now expects this to be correct.
kwargs['install_dir'] = [kwargs['install_dir']]
else:
# We want to remove 'subdir', but it may be None and we want to replace it with ''
# It must be done this way since we don't allow both `install_dir`
# and `subdir` to be set at the same time
subdir = kwargs.pop('subdir') or ''

kwargs['install_dir'] = self._get_install_dir_impl(False, subdir)
kwargs['install_dir'] = [self._get_install_dir_impl(False, subdir)]

target_suffix = self.suffix

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
],
"stdout": [
{
"line": "ERROR: Target 'too-few-install-dirs' has 3 outputs: ['toofew.h', 'toofew.c', 'toofew.sh'], but only 2 \"install_dir\"s were found."
"line": "ERROR: Target 'too-few-install-dirs' has 3 outputs: \\['toofew.h', 'toofew.c', 'toofew.sh'\\], but 2 \"install_dir\"s were found: \\['([a-zA-Z]:)?/usr/include', False\\]\\.",
"match": "re"
}
]
}
Loading