Skip to content

Commit d60cee2

Browse files
authored
feat: allow custom platform when overriding (#2880)
This basically allows using any python-build-standalone archive and using it if custom flags are set. This is done through the `single_version_platform_override()` API, because such archives are inherently version and platform specific. Key changes: * The `platform` arg can be any value (mostly; it ends up in repo names) * Added `target_compatible_with` and `target_settings` args, which become the settings used on the generated toolchain() definition. The platform settings are version specific, i.e. the key `(python_version, platform)` is what maps to the TCW/TS values. If an existing platform is used, it'll override the defaults that normally come from the PLATFORMS global for the particular version. If a new platform is used, it creates a new platform entry with those settings. Along the way: * Added various docs about internal variables so they're easier to grok at a glance. Work towards #2081
1 parent bbf3ab8 commit d60cee2

20 files changed

+609
-141
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ END_UNRELEASED_TEMPLATE
107107
Set the `RULES_PYTHON_ENABLE_PIPSTAR=1` environment variable to enable it.
108108
* (utils) Add a way to run a REPL for any `rules_python` target that returns
109109
a `PyInfo` provider.
110+
* (toolchains) Arbitrary python-build-standalone runtimes can be registered
111+
and activated with custom flags. See the [Registering custom runtimes]
112+
docs and {obj}`single_version_platform_override()` API docs for more
113+
information.
110114

111115
{#v0-0-0-removed}
112116
### Removed

MODULE.bazel

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,22 @@ dev_python.override(
125125
register_all_versions = True,
126126
)
127127

128+
# For testing an arbitrary runtime triggered by a custom flag.
129+
# See //tests/toolchains:custom_platform_toolchain_test
130+
dev_python.single_version_platform_override(
131+
platform = "linux-x86-install-only-stripped",
132+
python_version = "3.13.1",
133+
sha256 = "56817aa976e4886bec1677699c136cb01c1cdfe0495104c0d8ef546541864bbb",
134+
target_compatible_with = [
135+
"@platforms//os:linux",
136+
"@platforms//cpu:x86_64",
137+
],
138+
target_settings = [
139+
"@@//tests/support:is_custom_runtime_linux-x86-install-only-stripped",
140+
],
141+
urls = ["https://github.com/astral-sh/python-build-standalone/releases/download/20250115/cpython-3.13.1+20250115-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"],
142+
)
143+
128144
dev_pip = use_extension(
129145
"//python/extensions:pip.bzl",
130146
"pip",

docs/toolchains.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,73 @@ existing attributes:
243243
* Adding additional Python versions via {bzl:obj}`python.single_version_override` or
244244
{bzl:obj}`python.single_version_platform_override`.
245245

246+
### Registering custom runtimes
247+
248+
Because the python-build-standalone project has _thousands_ of prebuilt runtimes
249+
available, rules_python only includes popular runtimes in its built in
250+
configurations. If you want to use a runtime that isn't already known to
251+
rules_python then {obj}`single_version_platform_override()` can be used to do
252+
so. In short, it allows specifying an arbitrary URL and using custom flags
253+
to control when a runtime is used.
254+
255+
In the example below, we register a particular python-build-standalone runtime
256+
that is activated for Linux x86 builds when the custom flag
257+
`--//:runtime=my-custom-runtime` is set.
258+
259+
```
260+
# File: MODULE.bazel
261+
bazel_dep(name = "bazel_skylib", version = "1.7.1.")
262+
bazel_dep(name = "rules_python", version = "1.5.0")
263+
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
264+
python.single_version_platform_override(
265+
platform = "my-platform",
266+
python_version = "3.13.3",
267+
sha256 = "01d08b9bc8a96698b9d64c2fc26da4ecc4fa9e708ce0a34fb88f11ab7e552cbd",
268+
os_name = "linux",
269+
arch = "x86_64",
270+
target_settings = [
271+
"@@//:runtime=my-custom-runtime",
272+
],
273+
urls = ["https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-3.13.3+20250409-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz"],
274+
)
275+
# File: //:BUILD.bazel
276+
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
277+
string_flag(
278+
name = "custom_runtime",
279+
build_setting_default = "",
280+
)
281+
config_setting(
282+
name = "is_custom_runtime_linux-x86-install-only-stripped",
283+
flag_values = {
284+
":custom_runtime": "linux-x86-install-only-stripped",
285+
},
286+
)
287+
```
288+
289+
Notes:
290+
- While any URL and archive can be used, it's assumed their content looks how
291+
a python-build-standalone archive looks.
292+
- A "version aware" toolchain is registered, which means the Python version flag
293+
must also match (e.g. `--@rules_python//python/config_settings:python_version=3.13.3`
294+
must be set -- see `minor_mapping` and `is_default` for controls and docs
295+
about version matching and selection).
296+
- The `target_compatible_with` attribute can be used to entirely specify the
297+
arg of the same name the toolchain uses.
298+
- The labels in `target_settings` must be absolute; `@@` refers to the main repo.
299+
- The `target_settings` are `config_setting` targets, which means you can
300+
customize how matching occurs.
301+
302+
:::{seealso}
303+
See {obj}`//python/config_settings` for flags rules_python already defines
304+
that can be used with `target_settings`. Some particular ones of note are:
305+
{flag}`--py_linux_libc` and {flag}`--py_freethreaded`, among others.
306+
:::
307+
308+
:::{versionadded} VERSION_NEXT_FEATURE
309+
Added support for custom platform names, `target_compatible_with`, and
310+
`target_settings` with `single_version_platform_override`.
311+
:::
312+
246313
### Using defined toolchains from WORKSPACE
247314

248315
It is possible to use toolchains defined in `MODULE.bazel` in `WORKSPACE`. For example

internal_dev_setup.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def rules_python_internal_setup():
4242
toolchain_platform_keys = {},
4343
toolchain_python_versions = {},
4444
toolchain_set_python_version_constraints = {},
45-
base_toolchain_repo_names = [],
45+
host_compatible_repo_names = [],
4646
)
4747

4848
runtime_env_repo(name = "rules_python_runtime_env_tc_info")

python/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ bzl_library(
247247
name = "versions_bzl",
248248
srcs = ["versions.bzl"],
249249
visibility = ["//:__subpackages__"],
250+
deps = ["//python/private:platform_info_bzl"],
250251
)
251252

252253
# NOTE: Remember to add bzl_library targets to //tests:bzl_libraries

python/private/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,17 @@ bzl_library(
241241
],
242242
)
243243

244+
bzl_library(
245+
name = "platform_info_bzl",
246+
srcs = ["platform_info.bzl"],
247+
)
248+
244249
bzl_library(
245250
name = "python_bzl",
246251
srcs = ["python.bzl"],
247252
deps = [
248253
":full_version_bzl",
254+
":platform_info_bzl",
249255
":python_register_toolchains_bzl",
250256
":pythons_hub_bzl",
251257
":repo_utils_bzl",

python/private/platform_info.bzl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""Helper to define a struct used to define platform metadata."""
2+
3+
def platform_info(
4+
*,
5+
compatible_with = [],
6+
flag_values = {},
7+
target_settings = [],
8+
os_name,
9+
arch):
10+
"""Creates a struct of platform metadata.
11+
12+
This is just a helper to ensure structs are created the same and
13+
the meaning/values are documented.
14+
15+
Args:
16+
compatible_with: list[str], where the values are string labels. These
17+
are the target_compatible_with values to use with the toolchain
18+
flag_values: dict[str|Label, Any] of config_setting.flag_values
19+
compatible values. DEPRECATED -- use target_settings instead
20+
target_settings: list[str], where the values are string labels. These
21+
are the target_settings values to use with the toolchain.
22+
os_name: str, the os name; must match the name used in `@platfroms//os`
23+
arch: str, the cpu name; must match the name used in `@platforms//cpu`
24+
25+
Returns:
26+
A struct with attributes and values matching the args.
27+
"""
28+
return struct(
29+
compatible_with = compatible_with,
30+
flag_values = flag_values,
31+
target_settings = target_settings,
32+
os_name = os_name,
33+
arch = arch,
34+
)

python/private/py_repositories.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def py_repositories():
4747
toolchain_platform_keys = {},
4848
toolchain_python_versions = {},
4949
toolchain_set_python_version_constraints = {},
50-
base_toolchain_repo_names = [],
50+
host_compatible_repo_names = [],
5151
)
5252
http_archive(
5353
name = "bazel_skylib",

0 commit comments

Comments
 (0)