diff --git a/python/config_settings/BUILD.bazel b/python/config_settings/BUILD.bazel index c31d69f20..e6f03dc84 100644 --- a/python/config_settings/BUILD.bazel +++ b/python/config_settings/BUILD.bazel @@ -169,3 +169,13 @@ string_flag( define_pypi_internal_flags( name = "define_pypi_internal_flags", ) + +string_flag( + name = "free_threading", + build_setting_default = "no", + values = [ + "yes", + "no", + ], + visibility = ["//visibility:public"], +) diff --git a/python/private/hermetic_runtime_repo_setup.bzl b/python/private/hermetic_runtime_repo_setup.bzl index 4b5a3c681..02fbf0c14 100644 --- a/python/private/hermetic_runtime_repo_setup.bzl +++ b/python/private/hermetic_runtime_repo_setup.bzl @@ -27,7 +27,8 @@ def define_hermetic_runtime_toolchain_impl( extra_files_glob_exclude, python_version, python_bin, - coverage_tool): + coverage_tool, + free_threading = False): """Define a toolchain implementation for a python-build-standalone repo. It expected this macro is called in the top-level package of an extracted @@ -44,13 +45,17 @@ def define_hermetic_runtime_toolchain_impl( python_version: {type}`str` The Python version, in `major.minor.micro` format. python_bin: {type}`str` The path to the Python binary within the - repositoroy. + repository. coverage_tool: {type}`str` optional target to the coverage tool to use. + free_threading: {type}`bool` optional free-threading support. + Default, False. """ _ = name # @unused version_info = semver(python_version) version_dict = version_info.to_dict() + version_dict["ft_postfix"] = "t" if free_threading else "" + native.filegroup( name = "files", srcs = native.glob( @@ -67,19 +72,19 @@ def define_hermetic_runtime_toolchain_impl( "**/* *", # Bazel does not support spaces in file names. # Unused shared libraries. `python` executable and the `:libpython` target # depend on `libpython{python_version}.so.1.0`. - "lib/libpython{major}.{minor}.so".format(**version_dict), + "lib/libpython{major}.{minor}{ft_postfix}.so".format(**version_dict), # static libraries "lib/**/*.a", # tests for the standard libraries. - "lib/python{major}.{minor}/**/test/**".format(**version_dict), - "lib/python{major}.{minor}/**/tests/**".format(**version_dict), + "lib/python{major}.{minor}{ft_postfix}/**/test/**".format(**version_dict), + "lib/python{major}.{minor}{ft_postfix}/**/tests/**".format(**version_dict), "**/__pycache__/*.pyc.*", # During pyc creation, temp files named *.pyc.NNN are created ] + extra_files_glob_exclude, ), ) cc_import( name = "interface", - interface_library = "libs/python{major}{minor}.lib".format(**version_dict), + interface_library = "libs/python{major}{minor}{ft_postfix}.lib".format(**version_dict), system_provided = True, ) @@ -96,7 +101,7 @@ def define_hermetic_runtime_toolchain_impl( hdrs = [":includes"], includes = [ "include", - "include/python{major}.{minor}".format(**version_dict), + "include/python{major}.{minor}{ft_postfix}".format(**version_dict), "include/python{major}.{minor}m".format(**version_dict), ], ) @@ -105,11 +110,11 @@ def define_hermetic_runtime_toolchain_impl( hdrs = [":includes"], srcs = select({ "@platforms//os:linux": [ - "lib/libpython{major}.{minor}.so".format(**version_dict), - "lib/libpython{major}.{minor}.so.1.0".format(**version_dict), + "lib/libpython{major}.{minor}{ft_postfix}.so".format(**version_dict), + "lib/libpython{major}.{minor}{ft_postfix}.so.1.0".format(**version_dict), ], - "@platforms//os:macos": ["lib/libpython{major}.{minor}.dylib".format(**version_dict)], - "@platforms//os:windows": ["python3.dll", "libs/python{major}{minor}.lib".format(**version_dict)], + "@platforms//os:macos": ["lib/libpython{major}.{minor}{ft_postfix}.dylib".format(**version_dict)], + "@platforms//os:windows": ["python3.dll", "libs/python{major}{minor}{ft_postfix}.lib".format(**version_dict)], }), ) diff --git a/python/private/python_register_toolchains.bzl b/python/private/python_register_toolchains.bzl index d20e04961..f1b2a8e56 100644 --- a/python/private/python_register_toolchains.bzl +++ b/python/private/python_register_toolchains.bzl @@ -129,6 +129,12 @@ def python_register_toolchains( )], ) + flag_values = tool_versions[python_version].get("flag_values", None) + free_threading_label = str(Label("//python/config_settings:free_threading")) + free_threading = False + if flag_values: + free_threading = flag_values.get(free_threading_label, False) == "yes" + python_repository( name = "{name}_{platform}".format( name = name, @@ -143,6 +149,7 @@ def python_register_toolchains( urls = urls, strip_prefix = strip_prefix, coverage_tool = coverage_tool, + free_threading = free_threading, **kwargs ) if register_toolchains: diff --git a/python/private/python_repository.bzl b/python/private/python_repository.bzl index e44bdd151..43c015625 100644 --- a/python/private/python_repository.bzl +++ b/python/private/python_repository.bzl @@ -67,6 +67,7 @@ def _python_repository_impl(rctx): release_filename = rctx.attr.release_filename urls = rctx.attr.urls or [rctx.attr.url] auth = get_auth(rctx, urls) + free_threading = rctx.attr.free_threading if release_filename.endswith(".zst"): rctx.download( @@ -130,7 +131,8 @@ def _python_repository_impl(rctx): if "windows" in platform: distutils_path = "Lib/distutils/distutils.cfg" else: - distutils_path = "lib/python{}/distutils/distutils.cfg".format(python_short_version) + ft_postfix = "t" if free_threading else "" + distutils_path = "lib/python{}{}/distutils/distutils.cfg".format(python_short_version, ft_postfix) if rctx.attr.distutils: rctx.file(distutils_path, rctx.read(rctx.attr.distutils)) elif rctx.attr.distutils_content: @@ -255,6 +257,7 @@ define_hermetic_runtime_toolchain_impl( python_version = {python_version}, python_bin = {python_bin}, coverage_tool = {coverage_tool}, + free_threading = {free_threading}, ) """.format( extra_files_glob_exclude = render.list(glob_exclude), @@ -262,6 +265,7 @@ define_hermetic_runtime_toolchain_impl( python_bin = render.str(python_bin), python_version = render.str(rctx.attr.python_version), coverage_tool = render.str(coverage_tool), + free_threading = free_threading, ) rctx.delete("python") rctx.symlink(python_bin, "python") @@ -321,6 +325,10 @@ For more information see {attr}`py_runtime.coverage_tool`. "Either distutils or distutils_content can be specified, but not both.", mandatory = False, ), + "free_threading": attr.bool( + doc = "TODO", + default = False, + ), "ignore_root_user_error": attr.bool( default = False, doc = "Whether the check for root should be ignored or not. This causes cache misses with .pyc files.",