From c10ea4d9c01f31ce7fe049f7f29f8ddad590b79b Mon Sep 17 00:00:00 2001 From: Richard Levasseur Date: Fri, 23 Oct 2026 01:25:47 -0700 Subject: [PATCH] fix(toolchains): use target Python version for exec tools on Bazel 10 Bazel 10 resets Starlark flags in exec configurations unless they have universal scope, so exec tools such as the precompiler used the default Python version instead of the target's. Give the python_version flag universal scope, and run the integration tests with Bazel 10.0.0rc2. Fixes #3566 Fixes #3613 Work towards #3581 --- MODULE.bazel | 2 ++ gazelle/.bazelrc | 7 +++++++ news/3566.fixed.md | 3 +++ python/private/config_settings.bzl | 15 ++++++++++++++- .../integration/toolchain_target_settings_test.py | 3 ++- 5 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 news/3566.fixed.md diff --git a/MODULE.bazel b/MODULE.bazel index 8e7e9b649e..a03eb49a01 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -433,12 +433,14 @@ bazel_binaries.local( bazel_binaries.download(version = "7.7.0") bazel_binaries.download(version = "8.5.1") bazel_binaries.download(version = "9.1.0") +bazel_binaries.download(version = "10.0.0rc2") use_repo( bazel_binaries, "bazel_binaries", # These don't appear necessary, but are reported as direct dependencies # that should be use_repo()'d, so we add them as requested "bazel_binaries_bazelisk", + "build_bazel_bazel_10_0_0rc2", "build_bazel_bazel_7_7_0", "build_bazel_bazel_8_5_1", "build_bazel_bazel_9_1_0", diff --git a/gazelle/.bazelrc b/gazelle/.bazelrc index e30216814a..c098d0c392 100644 --- a/gazelle/.bazelrc +++ b/gazelle/.bazelrc @@ -19,4 +19,11 @@ build --@rules_python//python/config_settings:incompatible_default_to_explicit_i # Windows makes use of runfiles for some rules build --enable_runfiles +# Bazel 10 enables --incompatible_no_implicit_file_export by default, which +# breaks @io_bazel_rules_go//go/private:context: its bzl_library depends on +# @bazel_tools//tools/cpp:toolchain_utils.bzl, which bazel_tools doesn't +# export. rules_go v0.61.0+ drops that dep; remove this once rules_go is +# upgraded. +common --noincompatible_no_implicit_file_export + common:bazel7.x --incompatible_python_disallow_native_rules diff --git a/news/3566.fixed.md b/news/3566.fixed.md new file mode 100644 index 0000000000..301765b62b --- /dev/null +++ b/news/3566.fixed.md @@ -0,0 +1,3 @@ +(toolchains) Fixed build tools, such as the precompiler, running with the +default Python version instead of the target's Python version under Bazel 10 +([#3566](https://github.com/bazel-contrib/rules_python/issues/3566)). diff --git a/python/private/config_settings.bzl b/python/private/config_settings.bzl index e4f2cac9b5..8711f204eb 100644 --- a/python/private/config_settings.bzl +++ b/python/private/config_settings.bzl @@ -60,6 +60,14 @@ def construct_config_settings( _python_version_flag( name = _PYTHON_VERSION_FLAG.name, build_setting_default = default_version, + # Propagate the flag into exec configurations so exec tools (e.g. the + # precompiler) use the target's Python version. Bazel 10 resets + # Starlark flags in exec configurations unless they have universal + # scope (https://github.com/bazelbuild/bazel/issues/26909). It's set + # here, not as an attr default, because Bazel ignores scope attr + # defaults for flags set on the command line + # (https://github.com/bazelbuild/bazel/issues/31806). + scope = "universal", visibility = ["//visibility:public"], ) @@ -206,7 +214,12 @@ def _python_version_flag_impl(ctx): _python_version_flag = rule( implementation = _python_version_flag_impl, build_setting = config.string(flag = True), - attrs = {}, + attrs = { + # Read by Bazel, not the implementation, to decide whether the flag + # propagates into exec configurations. No default because Bazel only + # honors an explicitly set value; see construct_config_settings. + "scope": attr.string(), + }, ) def _python_version_major_minor_flag_impl(ctx): diff --git a/tests/integration/toolchain_target_settings_test.py b/tests/integration/toolchain_target_settings_test.py index a0c9d42fc3..4be7d54290 100644 --- a/tests/integration/toolchain_target_settings_test.py +++ b/tests/integration/toolchain_target_settings_test.py @@ -29,9 +29,10 @@ def test_custom_family_without_toolchain_fails(self): """ result = self.run_bazel("build", "//:custom_no_toolchain_test", check=False) self.assertNotEqual(result.exit_code, 0, "Expected build to fail") + # Bazel 10 reworded "found for types" to "found for target platform". self.assert_result_matches( result, - r"No matching toolchains found for types", + r"No matching toolchains found for (types|target platform)", )