1*60517a1eSAndroid Build Coastguard Worker# Copyright 2022 The Bazel Authors. All rights reserved. 2*60517a1eSAndroid Build Coastguard Worker# 3*60517a1eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*60517a1eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*60517a1eSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*60517a1eSAndroid Build Coastguard Worker# 7*60517a1eSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*60517a1eSAndroid Build Coastguard Worker# 9*60517a1eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*60517a1eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*60517a1eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*60517a1eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*60517a1eSAndroid Build Coastguard Worker# limitations under the License. 14*60517a1eSAndroid Build Coastguard Worker 15*60517a1eSAndroid Build Coastguard Worker"""Create a repository to hold the toolchains. 16*60517a1eSAndroid Build Coastguard Worker 17*60517a1eSAndroid Build Coastguard WorkerThis follows guidance here: 18*60517a1eSAndroid Build Coastguard Workerhttps://docs.bazel.build/versions/main/skylark/deploying.html#registering-toolchains 19*60517a1eSAndroid Build Coastguard Worker 20*60517a1eSAndroid Build Coastguard WorkerThe "complex computation" in our case is simply downloading large artifacts. 21*60517a1eSAndroid Build Coastguard WorkerThis guidance tells us how to avoid that: we put the toolchain targets in the 22*60517a1eSAndroid Build Coastguard Workeralias repository with only the toolchain attribute pointing into the 23*60517a1eSAndroid Build Coastguard Workerplatform-specific repositories. 24*60517a1eSAndroid Build Coastguard Worker""" 25*60517a1eSAndroid Build Coastguard Worker 26*60517a1eSAndroid Build Coastguard Workerload( 27*60517a1eSAndroid Build Coastguard Worker "//python:versions.bzl", 28*60517a1eSAndroid Build Coastguard Worker "LINUX_NAME", 29*60517a1eSAndroid Build Coastguard Worker "MACOS_NAME", 30*60517a1eSAndroid Build Coastguard Worker "PLATFORMS", 31*60517a1eSAndroid Build Coastguard Worker "WINDOWS_NAME", 32*60517a1eSAndroid Build Coastguard Worker) 33*60517a1eSAndroid Build Coastguard Workerload("//python/private:repo_utils.bzl", "REPO_DEBUG_ENV_VAR", "repo_utils") 34*60517a1eSAndroid Build Coastguard Workerload("//python/private:text_util.bzl", "render") 35*60517a1eSAndroid Build Coastguard Worker 36*60517a1eSAndroid Build Coastguard Workerdef get_repository_name(repository_workspace): 37*60517a1eSAndroid Build Coastguard Worker dummy_label = "//:_" 38*60517a1eSAndroid Build Coastguard Worker return str(repository_workspace.relative(dummy_label))[:-len(dummy_label)] or "@" 39*60517a1eSAndroid Build Coastguard Worker 40*60517a1eSAndroid Build Coastguard Workerdef python_toolchain_build_file_content( 41*60517a1eSAndroid Build Coastguard Worker prefix, 42*60517a1eSAndroid Build Coastguard Worker python_version, 43*60517a1eSAndroid Build Coastguard Worker set_python_version_constraint, 44*60517a1eSAndroid Build Coastguard Worker user_repository_name): 45*60517a1eSAndroid Build Coastguard Worker """Creates the content for toolchain definitions for a build file. 46*60517a1eSAndroid Build Coastguard Worker 47*60517a1eSAndroid Build Coastguard Worker Args: 48*60517a1eSAndroid Build Coastguard Worker prefix: Python toolchain name prefixes 49*60517a1eSAndroid Build Coastguard Worker python_version: Python versions for the toolchains 50*60517a1eSAndroid Build Coastguard Worker set_python_version_constraint: string, "True" if the toolchain should 51*60517a1eSAndroid Build Coastguard Worker have the Python version constraint added as a requirement for 52*60517a1eSAndroid Build Coastguard Worker matching the toolchain, "False" if not. 53*60517a1eSAndroid Build Coastguard Worker user_repository_name: names for the user repos 54*60517a1eSAndroid Build Coastguard Worker 55*60517a1eSAndroid Build Coastguard Worker Returns: 56*60517a1eSAndroid Build Coastguard Worker build_content: Text containing toolchain definitions 57*60517a1eSAndroid Build Coastguard Worker """ 58*60517a1eSAndroid Build Coastguard Worker 59*60517a1eSAndroid Build Coastguard Worker return "\n\n".join([ 60*60517a1eSAndroid Build Coastguard Worker """\ 61*60517a1eSAndroid Build Coastguard Workerpy_toolchain_suite( 62*60517a1eSAndroid Build Coastguard Worker user_repository_name = "{user_repository_name}_{platform}", 63*60517a1eSAndroid Build Coastguard Worker prefix = "{prefix}{platform}", 64*60517a1eSAndroid Build Coastguard Worker target_compatible_with = {compatible_with}, 65*60517a1eSAndroid Build Coastguard Worker flag_values = {flag_values}, 66*60517a1eSAndroid Build Coastguard Worker python_version = "{python_version}", 67*60517a1eSAndroid Build Coastguard Worker set_python_version_constraint = "{set_python_version_constraint}", 68*60517a1eSAndroid Build Coastguard Worker)""".format( 69*60517a1eSAndroid Build Coastguard Worker compatible_with = render.indent(render.list(meta.compatible_with)).lstrip(), 70*60517a1eSAndroid Build Coastguard Worker flag_values = render.indent(render.dict( 71*60517a1eSAndroid Build Coastguard Worker meta.flag_values, 72*60517a1eSAndroid Build Coastguard Worker key_repr = lambda x: repr(str(x)), # this is to correctly display labels 73*60517a1eSAndroid Build Coastguard Worker )).lstrip(), 74*60517a1eSAndroid Build Coastguard Worker platform = platform, 75*60517a1eSAndroid Build Coastguard Worker set_python_version_constraint = set_python_version_constraint, 76*60517a1eSAndroid Build Coastguard Worker user_repository_name = user_repository_name, 77*60517a1eSAndroid Build Coastguard Worker prefix = prefix, 78*60517a1eSAndroid Build Coastguard Worker python_version = python_version, 79*60517a1eSAndroid Build Coastguard Worker ) 80*60517a1eSAndroid Build Coastguard Worker for platform, meta in PLATFORMS.items() 81*60517a1eSAndroid Build Coastguard Worker ]) 82*60517a1eSAndroid Build Coastguard Worker 83*60517a1eSAndroid Build Coastguard Workerdef _toolchains_repo_impl(rctx): 84*60517a1eSAndroid Build Coastguard Worker build_content = """\ 85*60517a1eSAndroid Build Coastguard Worker# Generated by python/private/toolchains_repo.bzl 86*60517a1eSAndroid Build Coastguard Worker# 87*60517a1eSAndroid Build Coastguard Worker# These can be registered in the workspace file or passed to --extra_toolchains 88*60517a1eSAndroid Build Coastguard Worker# flag. By default all these toolchains are registered by the 89*60517a1eSAndroid Build Coastguard Worker# python_register_toolchains macro so you don't normally need to interact with 90*60517a1eSAndroid Build Coastguard Worker# these targets. 91*60517a1eSAndroid Build Coastguard Worker 92*60517a1eSAndroid Build Coastguard Workerload("@{rules_python}//python/private:py_toolchain_suite.bzl", "py_toolchain_suite") 93*60517a1eSAndroid Build Coastguard Worker 94*60517a1eSAndroid Build Coastguard Worker""".format( 95*60517a1eSAndroid Build Coastguard Worker rules_python = rctx.attr._rules_python_workspace.workspace_name, 96*60517a1eSAndroid Build Coastguard Worker ) 97*60517a1eSAndroid Build Coastguard Worker 98*60517a1eSAndroid Build Coastguard Worker toolchains = python_toolchain_build_file_content( 99*60517a1eSAndroid Build Coastguard Worker prefix = "", 100*60517a1eSAndroid Build Coastguard Worker python_version = rctx.attr.python_version, 101*60517a1eSAndroid Build Coastguard Worker set_python_version_constraint = str(rctx.attr.set_python_version_constraint), 102*60517a1eSAndroid Build Coastguard Worker user_repository_name = rctx.attr.user_repository_name, 103*60517a1eSAndroid Build Coastguard Worker ) 104*60517a1eSAndroid Build Coastguard Worker 105*60517a1eSAndroid Build Coastguard Worker rctx.file("BUILD.bazel", build_content + toolchains) 106*60517a1eSAndroid Build Coastguard Worker 107*60517a1eSAndroid Build Coastguard Workertoolchains_repo = repository_rule( 108*60517a1eSAndroid Build Coastguard Worker _toolchains_repo_impl, 109*60517a1eSAndroid Build Coastguard Worker doc = "Creates a repository with toolchain definitions for all known platforms " + 110*60517a1eSAndroid Build Coastguard Worker "which can be registered or selected.", 111*60517a1eSAndroid Build Coastguard Worker attrs = { 112*60517a1eSAndroid Build Coastguard Worker "python_version": attr.string(doc = "The Python version."), 113*60517a1eSAndroid Build Coastguard Worker "set_python_version_constraint": attr.bool(doc = "if target_compatible_with for the toolchain should set the version constraint"), 114*60517a1eSAndroid Build Coastguard Worker "user_repository_name": attr.string(doc = "what the user chose for the base name"), 115*60517a1eSAndroid Build Coastguard Worker "_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")), 116*60517a1eSAndroid Build Coastguard Worker }, 117*60517a1eSAndroid Build Coastguard Worker) 118*60517a1eSAndroid Build Coastguard Worker 119*60517a1eSAndroid Build Coastguard Workerdef _toolchain_aliases_impl(rctx): 120*60517a1eSAndroid Build Coastguard Worker logger = repo_utils.logger(rctx) 121*60517a1eSAndroid Build Coastguard Worker (os_name, arch) = _get_host_os_arch(rctx, logger) 122*60517a1eSAndroid Build Coastguard Worker 123*60517a1eSAndroid Build Coastguard Worker host_platform = _get_host_platform(os_name, arch) 124*60517a1eSAndroid Build Coastguard Worker 125*60517a1eSAndroid Build Coastguard Worker is_windows = (os_name == WINDOWS_NAME) 126*60517a1eSAndroid Build Coastguard Worker python3_binary_path = "python.exe" if is_windows else "bin/python3" 127*60517a1eSAndroid Build Coastguard Worker 128*60517a1eSAndroid Build Coastguard Worker # Base BUILD file for this repository. 129*60517a1eSAndroid Build Coastguard Worker build_contents = """\ 130*60517a1eSAndroid Build Coastguard Worker# Generated by python/private/toolchains_repo.bzl 131*60517a1eSAndroid Build Coastguard Workerpackage(default_visibility = ["//visibility:public"]) 132*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:versions.bzl", "gen_python_config_settings") 133*60517a1eSAndroid Build Coastguard Workergen_python_config_settings() 134*60517a1eSAndroid Build Coastguard Workerexports_files(["defs.bzl"]) 135*60517a1eSAndroid Build Coastguard Worker 136*60517a1eSAndroid Build Coastguard WorkerPLATFORMS = [ 137*60517a1eSAndroid Build Coastguard Worker{loaded_platforms} 138*60517a1eSAndroid Build Coastguard Worker] 139*60517a1eSAndroid Build Coastguard Workeralias(name = "files", actual = select({{":" + item: "@{py_repository}_" + item + "//:files" for item in PLATFORMS}})) 140*60517a1eSAndroid Build Coastguard Workeralias(name = "includes", actual = select({{":" + item: "@{py_repository}_" + item + "//:includes" for item in PLATFORMS}})) 141*60517a1eSAndroid Build Coastguard Workeralias(name = "libpython", actual = select({{":" + item: "@{py_repository}_" + item + "//:libpython" for item in PLATFORMS}})) 142*60517a1eSAndroid Build Coastguard Workeralias(name = "py3_runtime", actual = select({{":" + item: "@{py_repository}_" + item + "//:py3_runtime" for item in PLATFORMS}})) 143*60517a1eSAndroid Build Coastguard Workeralias(name = "python_headers", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_headers" for item in PLATFORMS}})) 144*60517a1eSAndroid Build Coastguard Workeralias(name = "python_runtimes", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_runtimes" for item in PLATFORMS}})) 145*60517a1eSAndroid Build Coastguard Workeralias(name = "python3", actual = select({{":" + item: "@{py_repository}_" + item + "//:" + ("python.exe" if "windows" in item else "bin/python3") for item in PLATFORMS}})) 146*60517a1eSAndroid Build Coastguard Worker""".format( 147*60517a1eSAndroid Build Coastguard Worker py_repository = rctx.attr.user_repository_name, 148*60517a1eSAndroid Build Coastguard Worker loaded_platforms = "\n".join([" \"{}\",".format(p) for p in rctx.attr.platforms]), 149*60517a1eSAndroid Build Coastguard Worker ) 150*60517a1eSAndroid Build Coastguard Worker if not is_windows: 151*60517a1eSAndroid Build Coastguard Worker build_contents += """\ 152*60517a1eSAndroid Build Coastguard Workeralias(name = "pip", actual = select({{":" + item: "@{py_repository}_" + item + "//:python_runtimes" for item in PLATFORMS if "windows" not in item}})) 153*60517a1eSAndroid Build Coastguard Worker""".format( 154*60517a1eSAndroid Build Coastguard Worker py_repository = rctx.attr.user_repository_name, 155*60517a1eSAndroid Build Coastguard Worker host_platform = host_platform, 156*60517a1eSAndroid Build Coastguard Worker ) 157*60517a1eSAndroid Build Coastguard Worker rctx.file("BUILD.bazel", build_contents) 158*60517a1eSAndroid Build Coastguard Worker 159*60517a1eSAndroid Build Coastguard Worker # Expose a Starlark file so rules can know what host platform we used and where to find an interpreter 160*60517a1eSAndroid Build Coastguard Worker # when using repository_ctx.path, which doesn't understand aliases. 161*60517a1eSAndroid Build Coastguard Worker rctx.file("defs.bzl", content = """\ 162*60517a1eSAndroid Build Coastguard Worker# Generated by python/private/toolchains_repo.bzl 163*60517a1eSAndroid Build Coastguard Worker 164*60517a1eSAndroid Build Coastguard Workerload( 165*60517a1eSAndroid Build Coastguard Worker "{rules_python}//python/config_settings:transition.bzl", 166*60517a1eSAndroid Build Coastguard Worker _py_binary = "py_binary", 167*60517a1eSAndroid Build Coastguard Worker _py_test = "py_test", 168*60517a1eSAndroid Build Coastguard Worker) 169*60517a1eSAndroid Build Coastguard Workerload( 170*60517a1eSAndroid Build Coastguard Worker "{rules_python}//python/entry_points:py_console_script_binary.bzl", 171*60517a1eSAndroid Build Coastguard Worker _py_console_script_binary = "py_console_script_binary", 172*60517a1eSAndroid Build Coastguard Worker) 173*60517a1eSAndroid Build Coastguard Workerload("{rules_python}//python:pip.bzl", _compile_pip_requirements = "compile_pip_requirements") 174*60517a1eSAndroid Build Coastguard Worker 175*60517a1eSAndroid Build Coastguard Workerhost_platform = "{host_platform}" 176*60517a1eSAndroid Build Coastguard Workerinterpreter = "@{py_repository}_{host_platform}//:{python3_binary_path}" 177*60517a1eSAndroid Build Coastguard Worker 178*60517a1eSAndroid Build Coastguard Workerdef py_binary(name, **kwargs): 179*60517a1eSAndroid Build Coastguard Worker return _py_binary( 180*60517a1eSAndroid Build Coastguard Worker name = name, 181*60517a1eSAndroid Build Coastguard Worker python_version = "{python_version}", 182*60517a1eSAndroid Build Coastguard Worker **kwargs 183*60517a1eSAndroid Build Coastguard Worker ) 184*60517a1eSAndroid Build Coastguard Worker 185*60517a1eSAndroid Build Coastguard Workerdef py_console_script_binary(name, **kwargs): 186*60517a1eSAndroid Build Coastguard Worker return _py_console_script_binary( 187*60517a1eSAndroid Build Coastguard Worker name = name, 188*60517a1eSAndroid Build Coastguard Worker binary_rule = py_binary, 189*60517a1eSAndroid Build Coastguard Worker **kwargs 190*60517a1eSAndroid Build Coastguard Worker ) 191*60517a1eSAndroid Build Coastguard Worker 192*60517a1eSAndroid Build Coastguard Workerdef py_test(name, **kwargs): 193*60517a1eSAndroid Build Coastguard Worker return _py_test( 194*60517a1eSAndroid Build Coastguard Worker name = name, 195*60517a1eSAndroid Build Coastguard Worker python_version = "{python_version}", 196*60517a1eSAndroid Build Coastguard Worker **kwargs 197*60517a1eSAndroid Build Coastguard Worker ) 198*60517a1eSAndroid Build Coastguard Worker 199*60517a1eSAndroid Build Coastguard Workerdef compile_pip_requirements(name, **kwargs): 200*60517a1eSAndroid Build Coastguard Worker return _compile_pip_requirements( 201*60517a1eSAndroid Build Coastguard Worker name = name, 202*60517a1eSAndroid Build Coastguard Worker py_binary = py_binary, 203*60517a1eSAndroid Build Coastguard Worker py_test = py_test, 204*60517a1eSAndroid Build Coastguard Worker **kwargs 205*60517a1eSAndroid Build Coastguard Worker ) 206*60517a1eSAndroid Build Coastguard Worker 207*60517a1eSAndroid Build Coastguard Worker""".format( 208*60517a1eSAndroid Build Coastguard Worker host_platform = host_platform, 209*60517a1eSAndroid Build Coastguard Worker py_repository = rctx.attr.user_repository_name, 210*60517a1eSAndroid Build Coastguard Worker python_version = rctx.attr.python_version, 211*60517a1eSAndroid Build Coastguard Worker python3_binary_path = python3_binary_path, 212*60517a1eSAndroid Build Coastguard Worker rules_python = get_repository_name(rctx.attr._rules_python_workspace), 213*60517a1eSAndroid Build Coastguard Worker )) 214*60517a1eSAndroid Build Coastguard Worker 215*60517a1eSAndroid Build Coastguard Workertoolchain_aliases = repository_rule( 216*60517a1eSAndroid Build Coastguard Worker _toolchain_aliases_impl, 217*60517a1eSAndroid Build Coastguard Worker doc = """\ 218*60517a1eSAndroid Build Coastguard WorkerCreates a repository with a shorter name only referencing the python version, 219*60517a1eSAndroid Build Coastguard Workerit contains a BUILD.bazel file declaring aliases to the host platform's targets 220*60517a1eSAndroid Build Coastguard Workerand is a great fit for any usage related to setting up toolchains for build 221*60517a1eSAndroid Build Coastguard Workeractions.""", 222*60517a1eSAndroid Build Coastguard Worker attrs = { 223*60517a1eSAndroid Build Coastguard Worker "platforms": attr.string_list( 224*60517a1eSAndroid Build Coastguard Worker doc = "List of platforms for which aliases shall be created", 225*60517a1eSAndroid Build Coastguard Worker ), 226*60517a1eSAndroid Build Coastguard Worker "python_version": attr.string(doc = "The Python version."), 227*60517a1eSAndroid Build Coastguard Worker "user_repository_name": attr.string( 228*60517a1eSAndroid Build Coastguard Worker mandatory = True, 229*60517a1eSAndroid Build Coastguard Worker doc = "The base name for all created repositories, like 'python38'.", 230*60517a1eSAndroid Build Coastguard Worker ), 231*60517a1eSAndroid Build Coastguard Worker "_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")), 232*60517a1eSAndroid Build Coastguard Worker }, 233*60517a1eSAndroid Build Coastguard Worker environ = [REPO_DEBUG_ENV_VAR], 234*60517a1eSAndroid Build Coastguard Worker) 235*60517a1eSAndroid Build Coastguard Worker 236*60517a1eSAndroid Build Coastguard Workerdef _host_toolchain_impl(rctx): 237*60517a1eSAndroid Build Coastguard Worker logger = repo_utils.logger(rctx) 238*60517a1eSAndroid Build Coastguard Worker rctx.file("BUILD.bazel", """\ 239*60517a1eSAndroid Build Coastguard Worker# Generated by python/private/toolchains_repo.bzl 240*60517a1eSAndroid Build Coastguard Worker 241*60517a1eSAndroid Build Coastguard Workerexports_files(["python"], visibility = ["//visibility:public"]) 242*60517a1eSAndroid Build Coastguard Worker""") 243*60517a1eSAndroid Build Coastguard Worker 244*60517a1eSAndroid Build Coastguard Worker (os_name, arch) = _get_host_os_arch(rctx, logger) 245*60517a1eSAndroid Build Coastguard Worker host_platform = _get_host_platform(os_name, arch) 246*60517a1eSAndroid Build Coastguard Worker repo = "@@{py_repository}_{host_platform}".format( 247*60517a1eSAndroid Build Coastguard Worker py_repository = rctx.attr.name[:-len("_host")], 248*60517a1eSAndroid Build Coastguard Worker host_platform = host_platform, 249*60517a1eSAndroid Build Coastguard Worker ) 250*60517a1eSAndroid Build Coastguard Worker 251*60517a1eSAndroid Build Coastguard Worker rctx.report_progress("Symlinking interpreter files to the target platform") 252*60517a1eSAndroid Build Coastguard Worker host_python_repo = rctx.path(Label("{repo}//:BUILD.bazel".format(repo = repo))) 253*60517a1eSAndroid Build Coastguard Worker 254*60517a1eSAndroid Build Coastguard Worker # The interpreter might not work on platfroms that don't have symlink support if 255*60517a1eSAndroid Build Coastguard Worker # we just symlink the interpreter itself. rctx.symlink does a copy in such cases 256*60517a1eSAndroid Build Coastguard Worker # so we can just attempt to symlink all of the directories in the host interpreter 257*60517a1eSAndroid Build Coastguard Worker # repo, which should be faster than re-downloading it. 258*60517a1eSAndroid Build Coastguard Worker for p in host_python_repo.dirname.readdir(): 259*60517a1eSAndroid Build Coastguard Worker if p.basename in [ 260*60517a1eSAndroid Build Coastguard Worker # ignore special files created by the repo rule automatically 261*60517a1eSAndroid Build Coastguard Worker "BUILD.bazel", 262*60517a1eSAndroid Build Coastguard Worker "MODULE.bazel", 263*60517a1eSAndroid Build Coastguard Worker "REPO.bazel", 264*60517a1eSAndroid Build Coastguard Worker "WORKSPACE", 265*60517a1eSAndroid Build Coastguard Worker "WORKSPACE.bazel", 266*60517a1eSAndroid Build Coastguard Worker "WORKSPACE.bzlmod", 267*60517a1eSAndroid Build Coastguard Worker ]: 268*60517a1eSAndroid Build Coastguard Worker continue 269*60517a1eSAndroid Build Coastguard Worker 270*60517a1eSAndroid Build Coastguard Worker # symlink works on all platforms that bazel supports, so it should work on 271*60517a1eSAndroid Build Coastguard Worker # UNIX and Windows with and without symlink support. For better performance 272*60517a1eSAndroid Build Coastguard Worker # users should enable the symlink startup option, however that requires admin 273*60517a1eSAndroid Build Coastguard Worker # privileges. 274*60517a1eSAndroid Build Coastguard Worker rctx.symlink(p, p.basename) 275*60517a1eSAndroid Build Coastguard Worker 276*60517a1eSAndroid Build Coastguard Worker is_windows = (os_name == WINDOWS_NAME) 277*60517a1eSAndroid Build Coastguard Worker python_binary = "python.exe" if is_windows else "python" 278*60517a1eSAndroid Build Coastguard Worker 279*60517a1eSAndroid Build Coastguard Worker # Ensure that we can run the interpreter and check that we are not 280*60517a1eSAndroid Build Coastguard Worker # using the host interpreter. 281*60517a1eSAndroid Build Coastguard Worker python_tester_contents = """\ 282*60517a1eSAndroid Build Coastguard Workerfrom pathlib import Path 283*60517a1eSAndroid Build Coastguard Workerimport sys 284*60517a1eSAndroid Build Coastguard Worker 285*60517a1eSAndroid Build Coastguard Workerpython = Path(sys.executable) 286*60517a1eSAndroid Build Coastguard Workerwant_python = str(Path("{python}").resolve()) 287*60517a1eSAndroid Build Coastguard Workergot_python = str(Path(sys.executable).resolve()) 288*60517a1eSAndroid Build Coastguard Worker 289*60517a1eSAndroid Build Coastguard Workerassert want_python == got_python, \ 290*60517a1eSAndroid Build Coastguard Worker "Expected to use a different interpreter:\\nwant: '{{}}'\\n got: '{{}}'".format( 291*60517a1eSAndroid Build Coastguard Worker want_python, 292*60517a1eSAndroid Build Coastguard Worker got_python, 293*60517a1eSAndroid Build Coastguard Worker ) 294*60517a1eSAndroid Build Coastguard Worker""".format(repo = repo.strip("@"), python = python_binary) 295*60517a1eSAndroid Build Coastguard Worker python_tester = rctx.path("python_tester.py") 296*60517a1eSAndroid Build Coastguard Worker rctx.file(python_tester, python_tester_contents) 297*60517a1eSAndroid Build Coastguard Worker repo_utils.execute_checked( 298*60517a1eSAndroid Build Coastguard Worker rctx, 299*60517a1eSAndroid Build Coastguard Worker op = "CheckHostInterpreter", 300*60517a1eSAndroid Build Coastguard Worker arguments = [rctx.path(python_binary), python_tester], 301*60517a1eSAndroid Build Coastguard Worker ) 302*60517a1eSAndroid Build Coastguard Worker if not rctx.delete(python_tester): 303*60517a1eSAndroid Build Coastguard Worker fail("Failed to delete the python tester") 304*60517a1eSAndroid Build Coastguard Worker 305*60517a1eSAndroid Build Coastguard Workerhost_toolchain = repository_rule( 306*60517a1eSAndroid Build Coastguard Worker _host_toolchain_impl, 307*60517a1eSAndroid Build Coastguard Worker doc = """\ 308*60517a1eSAndroid Build Coastguard WorkerCreates a repository with a shorter name meant to be used in the repository_ctx, 309*60517a1eSAndroid Build Coastguard Workerwhich needs to have `symlinks` for the interpreter. This is separate from the 310*60517a1eSAndroid Build Coastguard Workertoolchain_aliases repo because referencing the `python` interpreter target from 311*60517a1eSAndroid Build Coastguard Workerthis repo causes an eager fetch of the toolchain for the host platform. 312*60517a1eSAndroid Build Coastguard Worker """, 313*60517a1eSAndroid Build Coastguard Worker attrs = { 314*60517a1eSAndroid Build Coastguard Worker "_rule_name": attr.string(default = "host_toolchain"), 315*60517a1eSAndroid Build Coastguard Worker "_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")), 316*60517a1eSAndroid Build Coastguard Worker }, 317*60517a1eSAndroid Build Coastguard Worker) 318*60517a1eSAndroid Build Coastguard Worker 319*60517a1eSAndroid Build Coastguard Workerdef _multi_toolchain_aliases_impl(rctx): 320*60517a1eSAndroid Build Coastguard Worker rules_python = rctx.attr._rules_python_workspace.workspace_name 321*60517a1eSAndroid Build Coastguard Worker 322*60517a1eSAndroid Build Coastguard Worker for python_version, repository_name in rctx.attr.python_versions.items(): 323*60517a1eSAndroid Build Coastguard Worker file = "{}/defs.bzl".format(python_version) 324*60517a1eSAndroid Build Coastguard Worker rctx.file(file, content = """\ 325*60517a1eSAndroid Build Coastguard Worker# Generated by python/private/toolchains_repo.bzl 326*60517a1eSAndroid Build Coastguard Worker 327*60517a1eSAndroid Build Coastguard Workerload( 328*60517a1eSAndroid Build Coastguard Worker "@{repository_name}//:defs.bzl", 329*60517a1eSAndroid Build Coastguard Worker _compile_pip_requirements = "compile_pip_requirements", 330*60517a1eSAndroid Build Coastguard Worker _host_platform = "host_platform", 331*60517a1eSAndroid Build Coastguard Worker _interpreter = "interpreter", 332*60517a1eSAndroid Build Coastguard Worker _py_binary = "py_binary", 333*60517a1eSAndroid Build Coastguard Worker _py_console_script_binary = "py_console_script_binary", 334*60517a1eSAndroid Build Coastguard Worker _py_test = "py_test", 335*60517a1eSAndroid Build Coastguard Worker) 336*60517a1eSAndroid Build Coastguard Worker 337*60517a1eSAndroid Build Coastguard Workercompile_pip_requirements = _compile_pip_requirements 338*60517a1eSAndroid Build Coastguard Workerhost_platform = _host_platform 339*60517a1eSAndroid Build Coastguard Workerinterpreter = _interpreter 340*60517a1eSAndroid Build Coastguard Workerpy_binary = _py_binary 341*60517a1eSAndroid Build Coastguard Workerpy_console_script_binary = _py_console_script_binary 342*60517a1eSAndroid Build Coastguard Workerpy_test = _py_test 343*60517a1eSAndroid Build Coastguard Worker""".format( 344*60517a1eSAndroid Build Coastguard Worker repository_name = repository_name, 345*60517a1eSAndroid Build Coastguard Worker )) 346*60517a1eSAndroid Build Coastguard Worker rctx.file("{}/BUILD.bazel".format(python_version), "") 347*60517a1eSAndroid Build Coastguard Worker 348*60517a1eSAndroid Build Coastguard Worker pip_bzl = """\ 349*60517a1eSAndroid Build Coastguard Worker# Generated by python/private/toolchains_repo.bzl 350*60517a1eSAndroid Build Coastguard Worker 351*60517a1eSAndroid Build Coastguard Workerload("@{rules_python}//python:pip.bzl", "pip_parse", _multi_pip_parse = "multi_pip_parse") 352*60517a1eSAndroid Build Coastguard Worker 353*60517a1eSAndroid Build Coastguard Workerdef multi_pip_parse(name, requirements_lock, **kwargs): 354*60517a1eSAndroid Build Coastguard Worker return _multi_pip_parse( 355*60517a1eSAndroid Build Coastguard Worker name = name, 356*60517a1eSAndroid Build Coastguard Worker python_versions = {python_versions}, 357*60517a1eSAndroid Build Coastguard Worker requirements_lock = requirements_lock, 358*60517a1eSAndroid Build Coastguard Worker minor_mapping = {minor_mapping}, 359*60517a1eSAndroid Build Coastguard Worker **kwargs 360*60517a1eSAndroid Build Coastguard Worker ) 361*60517a1eSAndroid Build Coastguard Worker 362*60517a1eSAndroid Build Coastguard Worker""".format( 363*60517a1eSAndroid Build Coastguard Worker python_versions = rctx.attr.python_versions.keys(), 364*60517a1eSAndroid Build Coastguard Worker minor_mapping = render.indent(render.dict(rctx.attr.minor_mapping), indent = " " * 8).lstrip(), 365*60517a1eSAndroid Build Coastguard Worker rules_python = rules_python, 366*60517a1eSAndroid Build Coastguard Worker ) 367*60517a1eSAndroid Build Coastguard Worker rctx.file("pip.bzl", content = pip_bzl) 368*60517a1eSAndroid Build Coastguard Worker rctx.file("BUILD.bazel", "") 369*60517a1eSAndroid Build Coastguard Worker 370*60517a1eSAndroid Build Coastguard Workermulti_toolchain_aliases = repository_rule( 371*60517a1eSAndroid Build Coastguard Worker _multi_toolchain_aliases_impl, 372*60517a1eSAndroid Build Coastguard Worker attrs = { 373*60517a1eSAndroid Build Coastguard Worker "minor_mapping": attr.string_dict(doc = "The mapping between `X.Y` and `X.Y.Z` python version values"), 374*60517a1eSAndroid Build Coastguard Worker "python_versions": attr.string_dict(doc = "The Python versions."), 375*60517a1eSAndroid Build Coastguard Worker "_rules_python_workspace": attr.label(default = Label("//:WORKSPACE")), 376*60517a1eSAndroid Build Coastguard Worker }, 377*60517a1eSAndroid Build Coastguard Worker) 378*60517a1eSAndroid Build Coastguard Worker 379*60517a1eSAndroid Build Coastguard Workerdef sanitize_platform_name(platform): 380*60517a1eSAndroid Build Coastguard Worker return platform.replace("-", "_") 381*60517a1eSAndroid Build Coastguard Worker 382*60517a1eSAndroid Build Coastguard Workerdef _get_host_platform(os_name, arch): 383*60517a1eSAndroid Build Coastguard Worker """Gets the host platform. 384*60517a1eSAndroid Build Coastguard Worker 385*60517a1eSAndroid Build Coastguard Worker Args: 386*60517a1eSAndroid Build Coastguard Worker os_name: the host OS name. 387*60517a1eSAndroid Build Coastguard Worker arch: the host arch. 388*60517a1eSAndroid Build Coastguard Worker Returns: 389*60517a1eSAndroid Build Coastguard Worker The host platform. 390*60517a1eSAndroid Build Coastguard Worker """ 391*60517a1eSAndroid Build Coastguard Worker host_platform = None 392*60517a1eSAndroid Build Coastguard Worker for platform, meta in PLATFORMS.items(): 393*60517a1eSAndroid Build Coastguard Worker if meta.os_name == os_name and meta.arch == arch: 394*60517a1eSAndroid Build Coastguard Worker host_platform = platform 395*60517a1eSAndroid Build Coastguard Worker if not host_platform: 396*60517a1eSAndroid Build Coastguard Worker fail("No platform declared for host OS {} on arch {}".format(os_name, arch)) 397*60517a1eSAndroid Build Coastguard Worker return host_platform 398*60517a1eSAndroid Build Coastguard Worker 399*60517a1eSAndroid Build Coastguard Workerdef _get_host_os_arch(rctx, logger): 400*60517a1eSAndroid Build Coastguard Worker """Infer the host OS name and arch from a repository context. 401*60517a1eSAndroid Build Coastguard Worker 402*60517a1eSAndroid Build Coastguard Worker Args: 403*60517a1eSAndroid Build Coastguard Worker rctx: Bazel's repository_ctx. 404*60517a1eSAndroid Build Coastguard Worker logger: Logger to use for operations. 405*60517a1eSAndroid Build Coastguard Worker 406*60517a1eSAndroid Build Coastguard Worker Returns: 407*60517a1eSAndroid Build Coastguard Worker A tuple with the host OS name and arch. 408*60517a1eSAndroid Build Coastguard Worker """ 409*60517a1eSAndroid Build Coastguard Worker os_name = rctx.os.name 410*60517a1eSAndroid Build Coastguard Worker 411*60517a1eSAndroid Build Coastguard Worker # We assume the arch for Windows is always x86_64. 412*60517a1eSAndroid Build Coastguard Worker if "windows" in os_name.lower(): 413*60517a1eSAndroid Build Coastguard Worker arch = "x86_64" 414*60517a1eSAndroid Build Coastguard Worker 415*60517a1eSAndroid Build Coastguard Worker # Normalize the os_name. E.g. os_name could be "OS windows server 2019". 416*60517a1eSAndroid Build Coastguard Worker os_name = WINDOWS_NAME 417*60517a1eSAndroid Build Coastguard Worker else: 418*60517a1eSAndroid Build Coastguard Worker # This is not ideal, but bazel doesn't directly expose arch. 419*60517a1eSAndroid Build Coastguard Worker arch = repo_utils.execute_unchecked( 420*60517a1eSAndroid Build Coastguard Worker rctx, 421*60517a1eSAndroid Build Coastguard Worker op = "GetUname", 422*60517a1eSAndroid Build Coastguard Worker arguments = [repo_utils.which_checked(rctx, "uname"), "-m"], 423*60517a1eSAndroid Build Coastguard Worker logger = logger, 424*60517a1eSAndroid Build Coastguard Worker ).stdout.strip() 425*60517a1eSAndroid Build Coastguard Worker 426*60517a1eSAndroid Build Coastguard Worker # Normalize the os_name. 427*60517a1eSAndroid Build Coastguard Worker if "mac" in os_name.lower(): 428*60517a1eSAndroid Build Coastguard Worker os_name = MACOS_NAME 429*60517a1eSAndroid Build Coastguard Worker elif "linux" in os_name.lower(): 430*60517a1eSAndroid Build Coastguard Worker os_name = LINUX_NAME 431*60517a1eSAndroid Build Coastguard Worker 432*60517a1eSAndroid Build Coastguard Worker return (os_name, arch) 433