From da7bf41e0e3941862bb8b9de7fc83cb4ae09f8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 20 Mar 2025 16:53:38 +0100 Subject: [PATCH 01/23] Support specifying variants for wheel builds Accept a `variant-name` config setting that specifies variant metadata for the built wheel. When provided, the variants will be written into wheel metadata, and the variant hash will be appended to the filename. Example usage: python -m build -w -Cvariant-name=x86_64::baseline::v3 -Cvariant-name=blas::impl::mkl --- mesonpy/__init__.py | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index 51c6f0fb..0b29635c 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -44,6 +44,8 @@ import packaging.version import pyproject_metadata +from variantlib.meta import VariantMeta, VariantDescription + import mesonpy._compat import mesonpy._rpath import mesonpy._tags @@ -310,11 +312,13 @@ def __init__( manifest: Dict[str, List[Tuple[pathlib.Path, str]]], limited_api: bool, allow_windows_shared_libs: bool, + variant: Optional[VariantDescriptor], ) -> None: self._metadata = metadata self._manifest = manifest self._limited_api = limited_api self._allow_windows_shared_libs = allow_windows_shared_libs + self._variant = variant @property def _has_internal_libs(self) -> bool: @@ -348,10 +352,16 @@ def tag(self) -> mesonpy._tags.Tag: return mesonpy._tags.Tag('py3', 'none', None) return mesonpy._tags.Tag(None, self._stable_abi, None) + @property + def _variant_suffix(self) -> str: + if self._variant is not None: + return f"-{self._variant.hexdigest}" + return "" + @property def name(self) -> str: """Wheel name, this includes the basename and tag.""" - return f'{self._metadata.distribution_name}-{self._metadata.version}-{self.tag}' + return f'{self._metadata.distribution_name}-{self._metadata.version}-{self.tag}{self._variant_suffix}' @property def _distinfo_dir(self) -> str: @@ -448,7 +458,20 @@ def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path, def _wheel_write_metadata(self, whl: mesonpy._wheelfile.WheelFile) -> None: # add metadata - whl.writestr(f'{self._distinfo_dir}/METADATA', bytes(self._metadata.as_rfc822())) + metadata = self._metadata.as_rfc822() + + # inject variant metadata + if self._variant is not None: + # hack to avoid forking pyproject-metadata + import pyproject_metadata.constants + pyproject_metadata.constants.KNOWN_METADATA_FIELDS.add('variant') + pyproject_metadata.constants.KNOWN_METADATA_FIELDS.add('variant-hash') + + metadata['Variant-Hash'] = self._variant.hexdigest + for meta in self._variant: + metadata['Variant'] = meta.to_str() + + whl.writestr(f'{self._distinfo_dir}/METADATA', bytes(metadata)) whl.writestr(f'{self._distinfo_dir}/WHEEL', self.wheel) if self.entrypoints_txt: whl.writestr(f'{self._distinfo_dir}/entry_points.txt', self.entrypoints_txt) @@ -599,6 +622,11 @@ def _bool(value: Any, name: str) -> bool: def _string_or_strings(value: Any, name: str) -> List[str]: return list([value,] if isinstance(value, str) else value) + def _variant_names(value: Any, name: str) -> VariantDescription: + if isinstance(value, str): + value = [value] + return VariantDescription([VariantMeta.from_str(x) for x in value]) + options = { 'builddir': _string, 'build-dir': _string, @@ -607,6 +635,7 @@ def _string_or_strings(value: Any, name: str) -> List[str]: 'setup-args': _string_or_strings, 'compile-args': _string_or_strings, 'install-args': _string_or_strings, + 'variant-name': _variant_names, } assert all(f'{name}-args' in options for name in _MESON_ARGS_KEYS) @@ -644,10 +673,12 @@ def __init__( build_dir: Path, meson_args: Optional[MesonArgs] = None, editable_verbose: bool = False, + variant: Optional[VariantDescription] = None, ) -> None: self._source_dir = pathlib.Path(source_dir).absolute() self._build_dir = pathlib.Path(build_dir).absolute() self._editable_verbose = editable_verbose + self._variant = variant self._meson_native_file = self._build_dir / 'meson-python-native-file.ini' self._meson_cross_file = self._build_dir / 'meson-python-cross-file.ini' self._meson_args: MesonArgs = collections.defaultdict(list) @@ -1001,13 +1032,13 @@ def sdist(self, directory: Path) -> pathlib.Path: def wheel(self, directory: Path) -> pathlib.Path: """Generates a wheel in the specified directory.""" self.build() - builder = _WheelBuilder(self._metadata, self._manifest, self._limited_api, self._allow_windows_shared_libs) + builder = _WheelBuilder(self._metadata, self._manifest, self._limited_api, self._allow_windows_shared_libs, self._variant) return builder.build(directory) def editable(self, directory: Path) -> pathlib.Path: """Generates an editable wheel in the specified directory.""" self.build() - builder = _EditableWheelBuilder(self._metadata, self._manifest, self._limited_api, self._allow_windows_shared_libs) + builder = _EditableWheelBuilder(self._metadata, self._manifest, self._limited_api, self._allow_windows_shared_libs, self._variant) return builder.build(directory, self._source_dir, self._build_dir, self._build_command, self._editable_verbose) @@ -1020,11 +1051,12 @@ def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Proje source_dir = os.path.curdir build_dir = settings.get('build-dir') editable_verbose = bool(settings.get('editable-verbose')) + variant = settings.get('variant-name') with contextlib.ExitStack() as ctx: if build_dir is None: build_dir = ctx.enter_context(tempfile.TemporaryDirectory(prefix='.mesonpy-', dir=source_dir)) - yield Project(source_dir, build_dir, meson_args, editable_verbose) + yield Project(source_dir, build_dir, meson_args, editable_verbose, variant) def _parse_version_string(string: str) -> Tuple[int, ...]: From 2cd858a2cd2258e26b6d4b116f8b54d1628670b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 20 Mar 2025 17:07:54 +0100 Subject: [PATCH 02/23] Fix breakage without variants --- mesonpy/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index 0b29635c..873c39c7 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -463,9 +463,9 @@ def _wheel_write_metadata(self, whl: mesonpy._wheelfile.WheelFile) -> None: # inject variant metadata if self._variant is not None: # hack to avoid forking pyproject-metadata - import pyproject_metadata.constants - pyproject_metadata.constants.KNOWN_METADATA_FIELDS.add('variant') - pyproject_metadata.constants.KNOWN_METADATA_FIELDS.add('variant-hash') + import pyproject_metadata.constants as c + c.KNOWN_METADATA_FIELDS.add('variant') + c.KNOWN_METADATA_FIELDS.add('variant-hash') metadata['Variant-Hash'] = self._variant.hexdigest for meta in self._variant: From 3bd701e97e427f1444f2d5d04d633747c3b2f0d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 20 Mar 2025 17:35:57 +0100 Subject: [PATCH 03/23] Include a variantlib dependency --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a64a26d1..4f679537 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', + 'git+https://github.com/wheelnext/variantlib@variant-json', ] [project] @@ -39,6 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', + 'git+https://github.com/wheelnext/variantlib@variant-json', ] [project.optional-dependencies] From b87c47931d1104759fdb0de37c09a597f813a7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 20 Mar 2025 17:42:22 +0100 Subject: [PATCH 04/23] Try via URL instead --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4f679537..6547847c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'git+https://github.com/wheelnext/variantlib@variant-json', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/variant-json.tar.gz', ] [project] @@ -40,7 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'git+https://github.com/wheelnext/variantlib@variant-json', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/variant-json.tar.gz', ] [project.optional-dependencies] From 071775019c7d65b91d3a4ed32cd4f9cf51558cef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Fri, 21 Mar 2025 19:43:19 +0100 Subject: [PATCH 05/23] Support `-Dvariant` that gets passed through to meson --- mesonpy/__init__.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index 873c39c7..ac81bb66 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -622,10 +622,10 @@ def _bool(value: Any, name: str) -> bool: def _string_or_strings(value: Any, name: str) -> List[str]: return list([value,] if isinstance(value, str) else value) - def _variant_names(value: Any, name: str) -> VariantDescription: + def _variant_names(value: Any, name: str) -> list[VariantMeta]: if isinstance(value, str): value = [value] - return VariantDescription([VariantMeta.from_str(x) for x in value]) + return [VariantMeta.from_str(x) for x in value] options = { 'builddir': _string, @@ -635,6 +635,7 @@ def _variant_names(value: Any, name: str) -> VariantDescription: 'setup-args': _string_or_strings, 'compile-args': _string_or_strings, 'install-args': _string_or_strings, + 'variant': _variant_names, 'variant-name': _variant_names, } assert all(f'{name}-args' in options for name in _MESON_ARGS_KEYS) @@ -1051,12 +1052,19 @@ def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Proje source_dir = os.path.curdir build_dir = settings.get('build-dir') editable_verbose = bool(settings.get('editable-verbose')) - variant = settings.get('variant-name') + variants = settings.get('variant', []) + variant_names = settings.get('variant-name', []) + variants + + variant_desc = None + if variants: + variant_desc = VariantDescription(variant_names) + meson_args.setdefault('setup', []) + meson_args['setup'].append(f'-Dvariant={[x.to_str() for x in variants]!r}') with contextlib.ExitStack() as ctx: if build_dir is None: build_dir = ctx.enter_context(tempfile.TemporaryDirectory(prefix='.mesonpy-', dir=source_dir)) - yield Project(source_dir, build_dir, meson_args, editable_verbose, variant) + yield Project(source_dir, build_dir, meson_args, editable_verbose, variant_desc) def _parse_version_string(string: str) -> Tuple[int, ...]: From baff058da92abd4daaa85ec3ef2675bc75aa4c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 26 Mar 2025 16:18:05 +0100 Subject: [PATCH 06/23] Fix handling variant-name without variant --- mesonpy/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index ac81bb66..21696afc 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -45,6 +45,7 @@ import pyproject_metadata from variantlib.meta import VariantMeta, VariantDescription +from variantlib.plugins import PluginLoader import mesonpy._compat import mesonpy._rpath @@ -1055,9 +1056,8 @@ def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Proje variants = settings.get('variant', []) variant_names = settings.get('variant-name', []) + variants - variant_desc = None + variant_desc = VariantDescription(variant_names) if variant_names else None if variants: - variant_desc = VariantDescription(variant_names) meson_args.setdefault('setup', []) meson_args['setup'].append(f'-Dvariant={[x.to_str() for x in variants]!r}') From 8c752d5c8b936e66aed4ccad7c00904a5e205168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 26 Mar 2025 17:45:38 +0100 Subject: [PATCH 07/23] Support appending plugin labels to wheel names --- demo-plugins/blas_plugin.py | 0 demo-plugins/demo_plugins.py | 29 +++++++++++++++++++++++++++++ demo-plugins/pyproject.toml | 13 +++++++++++++ mesonpy/__init__.py | 18 +++++++++++------- 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 demo-plugins/blas_plugin.py create mode 100644 demo-plugins/demo_plugins.py create mode 100644 demo-plugins/pyproject.toml diff --git a/demo-plugins/blas_plugin.py b/demo-plugins/blas_plugin.py new file mode 100644 index 00000000..e69de29b diff --git a/demo-plugins/demo_plugins.py b/demo-plugins/demo_plugins.py new file mode 100644 index 00000000..3cc33fac --- /dev/null +++ b/demo-plugins/demo_plugins.py @@ -0,0 +1,29 @@ +from variantlib.base import PluginBase +from variantlib.config import ProviderConfig +from variantlib.meta import VariantDescription + + +class BlasPlugin(PluginBase): + namespace = "blas" + + def get_supported_configs(self) -> ProviderConfig: + return None + + def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: + for meta in variant_desc: + if meta.namespace == "blas" and meta.key == "variant": + return [meta.value] + return [] + + +class X8664Plugin(PluginBase): + namespace = "x86_64" + + def get_supported_configs(self) -> ProviderConfig: + return None + + def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: + for meta in variant_desc: + if meta.namespace == "x86_64" and meta.key == "baseline": + return [f"x86_64_{meta.value}"] + return [] diff --git a/demo-plugins/pyproject.toml b/demo-plugins/pyproject.toml new file mode 100644 index 00000000..d1f88311 --- /dev/null +++ b/demo-plugins/pyproject.toml @@ -0,0 +1,13 @@ +[build-system] +requires = ["flit_core>=3.2,<4"] +build-backend = "flit_core.buildapi" + +[project] +name = "demo-plugins" +version = "0" +description = "Demo plugins for meson-python/numpy variants" +dependencies = ["variantlib"] + +[project.entry-points."variantlib.plugins"] +blas = "demo_plugins:BlasPlugin" +x86_64 = "demo_plugins:X8664Plugin" diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index 21696afc..ffe9a61a 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -353,16 +353,20 @@ def tag(self) -> mesonpy._tags.Tag: return mesonpy._tags.Tag('py3', 'none', None) return mesonpy._tags.Tag(None, self._stable_abi, None) - @property - def _variant_suffix(self) -> str: - if self._variant is not None: - return f"-{self._variant.hexdigest}" - return "" - @property def name(self) -> str: """Wheel name, this includes the basename and tag.""" - return f'{self._metadata.distribution_name}-{self._metadata.version}-{self.tag}{self._variant_suffix}' + name = f'{self._metadata.distribution_name}-{self._metadata.version}-{self.tag}' + if self._variant is not None: + name += f'-{self._variant.hexdigest}' + labels = PluginLoader().get_variant_labels(self._variant) + for numlabels in range(len(labels), 0, -1): + long_name = "+".join((name, *labels[:numlabels])) + # if labels would give us filename that's longer than 128 + # characters (124 + .whl), strip them + if len(long_name) < 124: + return long_name + return name @property def _distinfo_dir(self) -> str: From 88645e24b00d01d443e1fdccca00a24e36bfcb2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 26 Mar 2025 20:16:49 +0100 Subject: [PATCH 08/23] variantlib changes were merged to main --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6547847c..61f075a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/wheelnext/variantlib/archive/variant-json.tar.gz', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', ] [project] From 5b8429c218a49fec72669526dcceeabd10d1630b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 26 Mar 2025 21:05:28 +0100 Subject: [PATCH 09/23] Fix other variantlib reference --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 61f075a6..47a27a28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/wheelnext/variantlib/archive/variant-json.tar.gz', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', ] [project.optional-dependencies] From c2df8976f61317c671a7ec2d833ddfaf66ce9d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 26 Mar 2025 21:09:29 +0100 Subject: [PATCH 10/23] Actually, we need variant-labels branch --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 47a27a28..c913a63a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/variant-labels.tar.gz', ] [project] @@ -40,7 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/variant-labels.tar.gz', ] [project.optional-dependencies] From d6ddb8c3d09a9088a5887c10937e91e12575ee1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 26 Mar 2025 21:11:55 +0100 Subject: [PATCH 11/23] On my fork --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c913a63a..2d71bc03 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/wheelnext/variantlib/archive/variant-labels.tar.gz', + 'variantlib @ https://github.com/mgorny/variantlib/archive/variant-labels.tar.gz', ] [project] @@ -40,7 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/wheelnext/variantlib/archive/variant-labels.tar.gz', + 'variantlib @ https://github.com/mgorny/variantlib/archive/variant-labels.tar.gz', ] [project.optional-dependencies] From c93f2be7d7a703cabaf61731cd89b5a75c69acba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 27 Mar 2025 12:17:22 +0100 Subject: [PATCH 12/23] Install demo_plugins as part of meson-python --- demo-plugins/pyproject.toml | 13 ------------- meson.build | 4 ++++ pyproject.toml | 4 ++++ 3 files changed, 8 insertions(+), 13 deletions(-) delete mode 100644 demo-plugins/pyproject.toml diff --git a/demo-plugins/pyproject.toml b/demo-plugins/pyproject.toml deleted file mode 100644 index d1f88311..00000000 --- a/demo-plugins/pyproject.toml +++ /dev/null @@ -1,13 +0,0 @@ -[build-system] -requires = ["flit_core>=3.2,<4"] -build-backend = "flit_core.buildapi" - -[project] -name = "demo-plugins" -version = "0" -description = "Demo plugins for meson-python/numpy variants" -dependencies = ["variantlib"] - -[project.entry-points."variantlib.plugins"] -blas = "demo_plugins:BlasPlugin" -x86_64 = "demo_plugins:X8664Plugin" diff --git a/meson.build b/meson.build index e48cdb4e..fe835435 100644 --- a/meson.build +++ b/meson.build @@ -16,3 +16,7 @@ py.install_sources( 'mesonpy/_wheelfile.py', subdir: 'mesonpy', ) + +py.install_sources( + 'demo-plugins/demo_plugins.py' +) diff --git a/pyproject.toml b/pyproject.toml index 2d71bc03..07621026 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,10 @@ repository = 'https://github.com/mesonbuild/meson-python' documentation = 'https://mesonbuild.com/meson-python/' changelog = 'https://mesonbuild.com/meson-python/changelog.html' +[project.entry-points."variantlib.plugins"] +blas = "demo_plugins:BlasPlugin" +x86_64 = "demo_plugins:X8664Plugin" + [tool.mypy] show_error_codes = true From 9ba73d3ba25bcd70412c3bad6c0068a5e8b48f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 7 Apr 2025 14:55:01 +0200 Subject: [PATCH 13/23] Update to follow variantlib API changes Update for current variantlib API. Disable label code for the time being, as the feature has been blocked. --- mesonpy/__init__.py | 31 +++++++++++++++++-------------- pyproject.toml | 4 ++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index ffe9a61a..9e08ecc8 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -44,8 +44,8 @@ import packaging.version import pyproject_metadata -from variantlib.meta import VariantMeta, VariantDescription -from variantlib.plugins import PluginLoader +from variantlib.models.variant import VariantProperty, VariantDescription +from variantlib.loader import PluginLoader import mesonpy._compat import mesonpy._rpath @@ -313,7 +313,7 @@ def __init__( manifest: Dict[str, List[Tuple[pathlib.Path, str]]], limited_api: bool, allow_windows_shared_libs: bool, - variant: Optional[VariantDescriptor], + variant: Optional[VariantDescription], ) -> None: self._metadata = metadata self._manifest = manifest @@ -359,13 +359,16 @@ def name(self) -> str: name = f'{self._metadata.distribution_name}-{self._metadata.version}-{self.tag}' if self._variant is not None: name += f'-{self._variant.hexdigest}' - labels = PluginLoader().get_variant_labels(self._variant) - for numlabels in range(len(labels), 0, -1): - long_name = "+".join((name, *labels[:numlabels])) - # if labels would give us filename that's longer than 128 - # characters (124 + .whl), strip them - if len(long_name) < 124: - return long_name + # variant label API on hold, see: + # https://github.com/wheelnext/variantlib/pull/12#issuecomment-2781618773 + if False: + labels = PluginLoader().get_variant_labels(self._variant) + for numlabels in range(len(labels), 0, -1): + long_name = "+".join((name, *labels[:numlabels])) + # if labels would give us filename that's longer than 128 + # characters (124 + .whl), strip them + if len(long_name) < 124: + return long_name return name @property @@ -473,8 +476,8 @@ def _wheel_write_metadata(self, whl: mesonpy._wheelfile.WheelFile) -> None: c.KNOWN_METADATA_FIELDS.add('variant-hash') metadata['Variant-Hash'] = self._variant.hexdigest - for meta in self._variant: - metadata['Variant'] = meta.to_str() + for vprop in self._variant.properties: + metadata['Variant'] = vprop.to_str() whl.writestr(f'{self._distinfo_dir}/METADATA', bytes(metadata)) whl.writestr(f'{self._distinfo_dir}/WHEEL', self.wheel) @@ -627,10 +630,10 @@ def _bool(value: Any, name: str) -> bool: def _string_or_strings(value: Any, name: str) -> List[str]: return list([value,] if isinstance(value, str) else value) - def _variant_names(value: Any, name: str) -> list[VariantMeta]: + def _variant_names(value: Any, name: str) -> list[VariantProperty]: if isinstance(value, str): value = [value] - return [VariantMeta.from_str(x) for x in value] + return [VariantProperty.from_str(x) for x in value] options = { 'builddir': _string, diff --git a/pyproject.toml b/pyproject.toml index 07621026..a27f9144 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/mgorny/variantlib/archive/variant-labels.tar.gz', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', ] [project] @@ -40,7 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/mgorny/variantlib/archive/variant-labels.tar.gz', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', ] [project.optional-dependencies] From b2e9b806ba7f0c684a658ca32c147dbbb3493501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 7 Apr 2025 18:51:03 +0200 Subject: [PATCH 14/23] Update the demo plugin API --- demo-plugins/blas_plugin.py | 0 demo-plugins/demo_plugins.py | 28 +++++++++++++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) delete mode 100644 demo-plugins/blas_plugin.py diff --git a/demo-plugins/blas_plugin.py b/demo-plugins/blas_plugin.py deleted file mode 100644 index e69de29b..00000000 diff --git a/demo-plugins/demo_plugins.py b/demo-plugins/demo_plugins.py index 3cc33fac..835ce613 100644 --- a/demo-plugins/demo_plugins.py +++ b/demo-plugins/demo_plugins.py @@ -1,13 +1,18 @@ -from variantlib.base import PluginBase -from variantlib.config import ProviderConfig -from variantlib.meta import VariantDescription +from variantlib.base import PluginType +from variantlib.models.provider import VariantFeatureConfig +from variantlib.models.variant import VariantDescription -class BlasPlugin(PluginBase): +class BlasPlugin(PluginType): namespace = "blas" - def get_supported_configs(self) -> ProviderConfig: - return None + def get_all_configs(self) -> list[VariantFeatureConfig]: + return [ + VariantFeatureConfig("variant", ["mkl", "openblas"]) + ] + + def get_supported_configs(self) -> list[VariantFeatureConfig]: + return [] def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: for meta in variant_desc: @@ -16,11 +21,16 @@ def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: return [] -class X8664Plugin(PluginBase): +class X8664Plugin(PluginType): namespace = "x86_64" - def get_supported_configs(self) -> ProviderConfig: - return None + def get_all_configs(self) -> list[VariantFeatureConfig]: + return [ + VariantFeatureConfig("baseline", ["v1", "v2", "v3", "v4"]) + ] + + def get_supported_configs(self) -> list[VariantFeatureConfig]: + return [] def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: for meta in variant_desc: From 7a71cc5fbf9e16384dacc456df1c2fc81eef1518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Tue, 8 Apr 2025 12:44:22 +0200 Subject: [PATCH 15/23] Add variant validation --- mesonpy/__init__.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index 9e08ecc8..db2dc0ea 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -44,6 +44,7 @@ import packaging.version import pyproject_metadata +from variantlib.api import validate_variant from variantlib.models.variant import VariantProperty, VariantDescription from variantlib.loader import PluginLoader @@ -1064,6 +1065,24 @@ def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Proje variant_names = settings.get('variant-name', []) + variants variant_desc = VariantDescription(variant_names) if variant_names else None + if variant_desc is not None: + variant_valid = validate_variant(variant_desc) + + invalid_variants = sorted(x for x, y in variant_valid.results.items() + if y is False) + if invalid_variants: + raise ConfigError( + "The following variant properties are invalid: " + f"{' '.join(x.to_str() for x in invalid_variants)}") + + unknown_variants = sorted(x for x, y in variant_valid.results.items() + if y is None) + if unknown_variants: + raise ConfigError( + "The following variant properties are unknown (no installed " + "plugin claims the namespace): " + f"{' '.join(x.to_str() for x in unknown_variants)}") + if variants: meson_args.setdefault('setup', []) meson_args['setup'].append(f'-Dvariant={[x.to_str() for x in variants]!r}') From 5886b42fe778b9340c8342cc7752966f736912a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 9 Apr 2025 19:33:09 +0200 Subject: [PATCH 16/23] Use newer variant validation API --- mesonpy/__init__.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index db2dc0ea..cb3e5616 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -1067,21 +1067,15 @@ def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Proje variant_desc = VariantDescription(variant_names) if variant_names else None if variant_desc is not None: variant_valid = validate_variant(variant_desc) - - invalid_variants = sorted(x for x, y in variant_valid.results.items() - if y is False) - if invalid_variants: + if variant_valid.invalid_properties: raise ConfigError( "The following variant properties are invalid: " - f"{' '.join(x.to_str() for x in invalid_variants)}") - - unknown_variants = sorted(x for x, y in variant_valid.results.items() - if y is None) - if unknown_variants: + f"{' '.join(sorted(x.to_str() for x in variant_valid.invalid_properties))}") + if variant_valid.unknown_properties: raise ConfigError( "The following variant properties are unknown (no installed " "plugin claims the namespace): " - f"{' '.join(x.to_str() for x in unknown_variants)}") + f"{' '.join(sorted(x.to_str() for x in variant_valid.unknown_properties))}") if variants: meson_args.setdefault('setup', []) From c100caa638159a618a0e0990f2f5409c99b1c4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 10 Apr 2025 13:56:48 +0200 Subject: [PATCH 17/23] Set CFLAGS/CXXFLAGS via get_build_setup() --- demo-plugins/demo_plugins.py | 13 +++++++++++++ mesonpy/__init__.py | 6 ++++++ pyproject.toml | 4 ++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/demo-plugins/demo_plugins.py b/demo-plugins/demo_plugins.py index 835ce613..fde601b5 100644 --- a/demo-plugins/demo_plugins.py +++ b/demo-plugins/demo_plugins.py @@ -1,4 +1,5 @@ from variantlib.base import PluginType +from variantlib.base import VariantPropertyType from variantlib.models.provider import VariantFeatureConfig from variantlib.models.variant import VariantDescription @@ -37,3 +38,15 @@ def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: if meta.namespace == "x86_64" and meta.key == "baseline": return [f"x86_64_{meta.value}"] return [] + + def get_build_setup( + self, properties: list[VariantPropertyType] + ) -> dict[str, list[str]]: + for prop in properties: + assert prop.namespace == self.namespace + if prop.feature == "baseline": + return { + "cflags": [f"-march=x86-64-{prop.value}"], + "cxxflags": [f"-march=x86-64-{prop.value}"], + } + return {} diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index cb3e5616..c8fe3582 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -1077,6 +1077,12 @@ def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Proje "plugin claims the namespace): " f"{' '.join(sorted(x.to_str() for x in variant_valid.unknown_properties))}") + build_setup = PluginLoader.get_build_setup(variant_desc) + if "cflags" in build_setup: + os.environ["CFLAGS"] = " ".join((os.environ.get("CFLAGS", ""), *build_setup["cflags"])) + if "cxxflags" in build_setup: + os.environ["CXXFLAGS"] = " ".join((os.environ.get("CXXFLAGS", ""), *build_setup["cxxflags"])) + if variants: meson_args.setdefault('setup', []) meson_args['setup'].append(f'-Dvariant={[x.to_str() for x in variants]!r}') diff --git a/pyproject.toml b/pyproject.toml index a27f9144..5c890f0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', + 'variantlib @ https://github.com/mgorny/variantlib/archive/build-setup.tar.gz', ] [project] @@ -40,7 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', + 'variantlib @ https://github.com/mgorny/variantlib/archive/build-setup.tar.gz', ] [project.optional-dependencies] From 61d95a0f5b33adeafe9e62ff10e08131129fb091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 10 Apr 2025 17:34:05 +0200 Subject: [PATCH 18/23] Remove demo-plugins (they are being moved to a separate package) --- demo-plugins/demo_plugins.py | 52 ------------------------------------ meson.build | 4 --- pyproject.toml | 4 --- 3 files changed, 60 deletions(-) delete mode 100644 demo-plugins/demo_plugins.py diff --git a/demo-plugins/demo_plugins.py b/demo-plugins/demo_plugins.py deleted file mode 100644 index fde601b5..00000000 --- a/demo-plugins/demo_plugins.py +++ /dev/null @@ -1,52 +0,0 @@ -from variantlib.base import PluginType -from variantlib.base import VariantPropertyType -from variantlib.models.provider import VariantFeatureConfig -from variantlib.models.variant import VariantDescription - - -class BlasPlugin(PluginType): - namespace = "blas" - - def get_all_configs(self) -> list[VariantFeatureConfig]: - return [ - VariantFeatureConfig("variant", ["mkl", "openblas"]) - ] - - def get_supported_configs(self) -> list[VariantFeatureConfig]: - return [] - - def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: - for meta in variant_desc: - if meta.namespace == "blas" and meta.key == "variant": - return [meta.value] - return [] - - -class X8664Plugin(PluginType): - namespace = "x86_64" - - def get_all_configs(self) -> list[VariantFeatureConfig]: - return [ - VariantFeatureConfig("baseline", ["v1", "v2", "v3", "v4"]) - ] - - def get_supported_configs(self) -> list[VariantFeatureConfig]: - return [] - - def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: - for meta in variant_desc: - if meta.namespace == "x86_64" and meta.key == "baseline": - return [f"x86_64_{meta.value}"] - return [] - - def get_build_setup( - self, properties: list[VariantPropertyType] - ) -> dict[str, list[str]]: - for prop in properties: - assert prop.namespace == self.namespace - if prop.feature == "baseline": - return { - "cflags": [f"-march=x86-64-{prop.value}"], - "cxxflags": [f"-march=x86-64-{prop.value}"], - } - return {} diff --git a/meson.build b/meson.build index fe835435..e48cdb4e 100644 --- a/meson.build +++ b/meson.build @@ -16,7 +16,3 @@ py.install_sources( 'mesonpy/_wheelfile.py', subdir: 'mesonpy', ) - -py.install_sources( - 'demo-plugins/demo_plugins.py' -) diff --git a/pyproject.toml b/pyproject.toml index 5c890f0c..39ff6a47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,10 +68,6 @@ repository = 'https://github.com/mesonbuild/meson-python' documentation = 'https://mesonbuild.com/meson-python/' changelog = 'https://mesonbuild.com/meson-python/changelog.html' -[project.entry-points."variantlib.plugins"] -blas = "demo_plugins:BlasPlugin" -x86_64 = "demo_plugins:X8664Plugin" - [tool.mypy] show_error_codes = true From 4c73d71224c870172f77a16e5d2729b75cd21161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 14 Apr 2025 08:07:52 +0200 Subject: [PATCH 19/23] Restore blas demo plugin --- demo-plugins/demo_plugins.py | 22 ++++++++++++++++++++++ meson.build | 4 ++++ pyproject.toml | 3 +++ 3 files changed, 29 insertions(+) create mode 100644 demo-plugins/demo_plugins.py diff --git a/demo-plugins/demo_plugins.py b/demo-plugins/demo_plugins.py new file mode 100644 index 00000000..0de0e113 --- /dev/null +++ b/demo-plugins/demo_plugins.py @@ -0,0 +1,22 @@ +from variantlib.base import PluginType +from variantlib.base import VariantPropertyType +from variantlib.models.provider import VariantFeatureConfig +from variantlib.models.variant import VariantDescription + + +class BlasPlugin(PluginType): + namespace = "blas" + + def get_all_configs(self) -> list[VariantFeatureConfig]: + return [ + VariantFeatureConfig("variant", ["mkl", "openblas"]) + ] + + def get_supported_configs(self) -> list[VariantFeatureConfig]: + return [] + + def get_variant_labels(self, variant_desc: VariantDescription) -> list[str]: + for meta in variant_desc: + if meta.namespace == "blas" and meta.key == "variant": + return [meta.value] + return [] diff --git a/meson.build b/meson.build index e48cdb4e..fe835435 100644 --- a/meson.build +++ b/meson.build @@ -16,3 +16,7 @@ py.install_sources( 'mesonpy/_wheelfile.py', subdir: 'mesonpy', ) + +py.install_sources( + 'demo-plugins/demo_plugins.py' +) diff --git a/pyproject.toml b/pyproject.toml index 39ff6a47..9265421a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,9 @@ repository = 'https://github.com/mesonbuild/meson-python' documentation = 'https://mesonbuild.com/meson-python/' changelog = 'https://mesonbuild.com/meson-python/changelog.html' +[project.entry-points."variantlib.plugins"] +blas = "demo_plugins:BlasPlugin" + [tool.mypy] show_error_codes = true From 3035504539e8bb3b70782187f64db4b2071222ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Mon, 14 Apr 2025 19:13:01 +0200 Subject: [PATCH 20/23] Use numpy-demo branch of variantlib --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9265421a..60b71826 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/mgorny/variantlib/archive/build-setup.tar.gz', + 'variantlib @ https://github.com/mgorny/variantlib/archive/numpy-demo.tar.gz', ] [project] @@ -40,7 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/mgorny/variantlib/archive/build-setup.tar.gz', + 'variantlib @ https://github.com/mgorny/variantlib/archive/numpy-demo.tar.gz', ] [project.optional-dependencies] From dc3d9059c91e89b94afebff968a4670f1b1354e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 16 Apr 2025 16:01:23 +0200 Subject: [PATCH 21/23] Support other meson environment variables via get_build_setup --- mesonpy/__init__.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index c8fe3582..5e81476b 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -1078,10 +1078,13 @@ def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Proje f"{' '.join(sorted(x.to_str() for x in variant_valid.unknown_properties))}") build_setup = PluginLoader.get_build_setup(variant_desc) - if "cflags" in build_setup: - os.environ["CFLAGS"] = " ".join((os.environ.get("CFLAGS", ""), *build_setup["cflags"])) - if "cxxflags" in build_setup: - os.environ["CXXFLAGS"] = " ".join((os.environ.get("CXXFLAGS", ""), *build_setup["cxxflags"])) + for build_var in ("cflags", "cxxflags", "cuflags", "objcflags", "fflags", "dflags", + "valaflags", "rustflags", "cythonflags", "ldflags"): + if build_var in build_setup: + os.environ[build_var.upper()] = ( + " ".join((os.environ.get(build_var.upper(), ""), + *build_setup[build_var])) + ) if variants: meson_args.setdefault('setup', []) From d0fb02e6328b9627890e5d0306bed8f3562387f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 17 Apr 2025 14:25:00 +0200 Subject: [PATCH 22/23] Use variantlib from main branch --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 60b71826..cd25ab7b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ requires = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/mgorny/variantlib/archive/numpy-demo.tar.gz', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', ] [project] @@ -40,7 +40,7 @@ dependencies = [ 'packaging >= 19.0', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', - 'variantlib @ https://github.com/mgorny/variantlib/archive/numpy-demo.tar.gz', + 'variantlib @ https://github.com/wheelnext/variantlib/archive/main.tar.gz', ] [project.optional-dependencies] From 6809ddb86b0fb7e62d27b71299377685e42b037d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Thu, 17 Apr 2025 14:25:13 +0200 Subject: [PATCH 23/23] Update for new metadata API, support Variant-Provider metadata --- mesonpy/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mesonpy/__init__.py b/mesonpy/__init__.py index 5e81476b..71c2680a 100644 --- a/mesonpy/__init__.py +++ b/mesonpy/__init__.py @@ -44,7 +44,7 @@ import packaging.version import pyproject_metadata -from variantlib.api import validate_variant +from variantlib.api import set_variant_metadata, validate_variant from variantlib.models.variant import VariantProperty, VariantDescription from variantlib.loader import PluginLoader @@ -475,10 +475,9 @@ def _wheel_write_metadata(self, whl: mesonpy._wheelfile.WheelFile) -> None: import pyproject_metadata.constants as c c.KNOWN_METADATA_FIELDS.add('variant') c.KNOWN_METADATA_FIELDS.add('variant-hash') + c.KNOWN_METADATA_FIELDS.add('variant-provider') - metadata['Variant-Hash'] = self._variant.hexdigest - for vprop in self._variant.properties: - metadata['Variant'] = vprop.to_str() + set_variant_metadata(metadata, self._variant) whl.writestr(f'{self._distinfo_dir}/METADATA', bytes(metadata)) whl.writestr(f'{self._distinfo_dir}/WHEEL', self.wheel)