aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Schwartz <eschwartz@archlinux.org>2021-11-05 01:03:50 -0400
committerEli Schwartz <eschwartz@archlinux.org>2022-02-22 22:22:16 -0500
commit78945fb9832e989453fbabc471d45bb71805eca8 (patch)
tree8a6dec38c143eb8645d59cc2ab01bc7a567f4f66
parente8375d20a9aeb8c3b0ad58f299ded0e5e978b447 (diff)
downloadmeson-78945fb9832e989453fbabc471d45bb71805eca8.zip
meson-78945fb9832e989453fbabc471d45bb71805eca8.tar.gz
meson-78945fb9832e989453fbabc471d45bb71805eca8.tar.bz2
python module: add option to specify a python environment to install to
The default behavior of installing relative to prefix may be unexpected, and is definitely wrong in many cases. Give users control in order to specify that yes, they actually want to install to a venv. This is particularly useful for projects that use meson as a build system for a python module, where *all* files shall be installed into the python site-packages.
-rw-r--r--docs/markdown/Builtin-options.md20
-rw-r--r--docs/markdown/snippets/python_module_env.md9
-rw-r--r--mesonbuild/coredata.py2
-rw-r--r--mesonbuild/modules/python.py21
4 files changed, 48 insertions, 4 deletions
diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md
index db3c3e8..c8e98dd 100644
--- a/docs/markdown/Builtin-options.md
+++ b/docs/markdown/Builtin-options.md
@@ -271,10 +271,11 @@ name with the module name: `-D<module>.<option>=<value>` (e.g. `-Dpython.platlib
### Python module
-| Option | Default value | Possible values | Description |
-| ------ | ------------- | --------------- | ----------- |
-| platlibdir | | Directory path | Directory for site-specific, platform-specific files (Since 0.60.0) |
-| purelibdir | | Directory path | Directory for site-specific, non-platform-specific files (Since 0.60.0) |
+| Option | Default value | Possible values | Description |
+| ------ | ------------- | ----------------- | ----------- |
+| install_env | prefix | {auto,prefix,system,venv} | Which python environment to install to (Since 0.62.0) |
+| platlibdir | | Directory path | Directory for site-specific, platform-specific files (Since 0.60.0) |
+| purelibdir | | Directory path | Directory for site-specific, non-platform-specific files (Since 0.60.0) |
*Since 0.60.0* `python.platlibdir` and `python.purelibdir` options are used by
python module methods `python.install_sources()` and `python.get_install_dir()`.
@@ -283,3 +284,14 @@ relative to the installation `prefix`, which will often result in installed pyth
modules to not be found by the interpreter unless `prefix` is `/usr` on Linux,
or for example `C:\Python39` on Windows. These options can be absolute paths
outside of `prefix`.
+
+*Since 0.62.0* The `python.install_env` option is used to detect the correct
+installation path. Setting to `system` will avoid making the paths relative to
+`prefix` and instead use the global site-packages of the selected python
+interpreter directly, even if it is a venv. Setting to `venv` will instead use
+the paths for the virtualenv the python found installation comes from (or fail
+if it is not a virtualenv). Setting to `auto` will check if the found
+installation is a virtualenv, and use `venv` or `system` as appropriate (but
+never `prefix`). This option is mutually exclusive with the `platlibdir`/`purelibdir`.
+
+For backwards compatibility purposes, the default `install_env` is `prefix`.
diff --git a/docs/markdown/snippets/python_module_env.md b/docs/markdown/snippets/python_module_env.md
new file mode 100644
index 0000000..87a156d
--- /dev/null
+++ b/docs/markdown/snippets/python_module_env.md
@@ -0,0 +1,9 @@
+## New option to choose python installation environment
+
+It is now possible to specify `-Dpython.install_env` and choose how python modules are installed.
+
+- `venv`: assume that a virtualenv is active and install to that
+- `system`: install to the global site-packages of the selected interpreter
+ (the one that the venv module calls --system-site-packages)
+- `prefix`: preserve existing behavior
+- `auto`: autodetect whether to use venv or system
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 4a84467..e5c0287 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -1218,6 +1218,8 @@ BUILTIN_CORE_OPTIONS: 'KeyedOptionDictType' = OrderedDict([
(OptionKey('force_fallback_for'), BuiltinOption(UserArrayOption, 'Force fallback for those subprojects', [])),
# Python module
+ (OptionKey('install_env', module='python'),
+ BuiltinOption(UserComboOption, 'Which python environment to install to', 'prefix', choices=['auto', 'prefix', 'system', 'venv'])),
(OptionKey('platlibdir', module='python'),
BuiltinOption(UserStringOption, 'Directory for site-specific, platform-specific files.', '')),
(OptionKey('purelibdir', module='python'),
diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py
index 2b62ea3..a91ec58 100644
--- a/mesonbuild/modules/python.py
+++ b/mesonbuild/modules/python.py
@@ -338,11 +338,13 @@ variables.update({'base_prefix': getattr(sys, 'base_prefix', sys.prefix)})
print(json.dumps({
'variables': variables,
'paths': paths,
+ 'sysconfig_paths': sysconfig.get_paths(),
'install_paths': install_paths,
'sys_paths': sys.path,
'version': sysconfig.get_python_version(),
'platform': sysconfig.get_platform(),
'is_pypy': '__pypy__' in sys.builtin_module_names,
+ 'is_venv': sys.prefix != variables['base_prefix'],
'link_libpython': links_against_libpython(),
}))
'''
@@ -352,7 +354,9 @@ if T.TYPE_CHECKING:
install_paths: T.Dict[str, str]
is_pypy: bool
+ is_venv: bool
link_libpython: bool
+ sysconfig_paths: T.Dict[str, str]
paths: T.Dict[str, str]
platform: str
suffix: str
@@ -377,7 +381,9 @@ class PythonExternalProgram(ExternalProgram):
self.info: 'PythonIntrospectionDict' = {
'install_paths': {},
'is_pypy': False,
+ 'is_venv': False,
'link_libpython': False,
+ 'sysconfig_paths': {},
'paths': {},
'platform': 'sentinal',
'variables': {},
@@ -422,7 +428,22 @@ class PythonExternalProgram(ExternalProgram):
return rel_path
value = state.get_option(f'{key}dir', module='python')
if value:
+ if state.is_user_defined_option('install_env', module='python'):
+ raise mesonlib.MesonException(f'python.{key}dir and python.install_env are mutually exclusive')
return value
+
+ install_env = state.get_option('install_env', module='python')
+ if install_env == 'auto':
+ install_env = 'venv' if self.info['is_venv'] else 'system'
+
+ if install_env == 'system':
+ rel_path = os.path.join(self.info['variables']['prefix'], rel_path)
+ elif install_env == 'venv':
+ if not self.info['is_venv']:
+ raise mesonlib.MesonException('python.install_env cannot be set to "venv" unless you are in a venv!')
+ # inside a venv, deb_system is *never* active hence info['paths'] may be wrong
+ rel_path = self.info['sysconfig_paths'][key]
+
# Use python's path relative to prefix, and warn if that's not a location
# python will lookup for modules.
abs_path = Path(state.get_option('prefix'), rel_path)