aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)