xref: /aosp_15_r20/external/bazelbuild-rules_python/python/private/local_runtime_repo_setup.bzl (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1# Copyright 2024 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Setup code called by the code generated by `local_runtime_repo`."""
16
17load("@bazel_skylib//lib:selects.bzl", "selects")
18load("@rules_cc//cc:defs.bzl", "cc_library")
19load("@rules_python//python:py_runtime.bzl", "py_runtime")
20load("@rules_python//python:py_runtime_pair.bzl", "py_runtime_pair")
21load("@rules_python//python/cc:py_cc_toolchain.bzl", "py_cc_toolchain")
22load("@rules_python//python/private:py_exec_tools_toolchain.bzl", "py_exec_tools_toolchain")
23
24_PYTHON_VERSION_FLAG = Label("@rules_python//python/config_settings:python_version")
25
26def define_local_runtime_toolchain_impl(
27        name,
28        lib_ext,
29        major,
30        minor,
31        micro,
32        interpreter_path,
33        implementation_name,
34        os):
35    """Defines a toolchain implementation for a local Python runtime.
36
37    Generates public targets:
38    * `python_runtimes`: The target toolchain type implementation
39    * `py_exec_tools_toolchain`: The exec tools toolchain type implementation
40    * `py_cc_toolchain`: The py cc toolchain type implementation
41    * `os`: A constraint (or alias to one) for the `target_compatible_with` this
42      toolchain is compatible with.
43    * `is_matching_python_version`: A `config_setting` for `target_settings`
44      this toolchain is compatible with.
45
46    Args:
47        name: `str` Only present to satisfy tooling
48        lib_ext: `str` The file extension for the `libpython` shared libraries
49        major: `str` The major Python version, e.g. `3` of `3.9.1`.
50        minor: `str` The minor Python version, e.g. `9` of `3.9.1`.
51        micro: `str` The micro Python version, e.g. "1" of `3.9.1`.
52        interpreter_path: `str` Absolute path to the interpreter.
53        implementation_name: `str` The implementation name, as returned by
54            `sys.implementation.name`.
55        os: `str` A label to the OS constraint (e.g. `@platforms//os:linux`) for
56            this runtime.
57    """
58    major_minor = "{}.{}".format(major, minor)
59    major_minor_micro = "{}.{}".format(major_minor, micro)
60
61    cc_library(
62        name = "_python_headers",
63        # NOTE: Keep in sync with watch_tree() called in local_runtime_repo
64        srcs = native.glob(["include/**/*.h"]),
65        includes = ["include"],
66    )
67
68    cc_library(
69        name = "_libpython",
70        # Don't use a recursive glob because the lib/ directory usually contains
71        # a subdirectory of the stdlib -- lots of unrelated files
72        srcs = native.glob([
73            "lib/*{}".format(lib_ext),  # Match libpython*.so
74            "lib/*{}*".format(lib_ext),  # Also match libpython*.so.1.0
75        ]),
76        hdrs = [":_python_headers"],
77    )
78
79    py_runtime(
80        name = "_py3_runtime",
81        interpreter_path = interpreter_path,
82        python_version = "PY3",
83        interpreter_version_info = {
84            "major": major,
85            "micro": micro,
86            "minor": minor,
87        },
88        implementation_name = implementation_name,
89    )
90
91    py_runtime_pair(
92        name = "python_runtimes",
93        py2_runtime = None,
94        py3_runtime = ":_py3_runtime",
95        visibility = ["//visibility:public"],
96    )
97
98    py_exec_tools_toolchain(
99        name = "py_exec_tools_toolchain",
100        visibility = ["//visibility:public"],
101        precompiler = "@rules_python//tools/precompiler:precompiler",
102    )
103
104    py_cc_toolchain(
105        name = "py_cc_toolchain",
106        headers = ":_python_headers",
107        libs = ":_libpython",
108        python_version = major_minor_micro,
109        visibility = ["//visibility:public"],
110    )
111
112    native.alias(
113        name = "os",
114        # Call Label() to force the string to evaluate in the context of
115        # rules_python, not the calling BUILD-file code. This is because
116        # the value is an `@platforms//foo` string, which @rules_python has
117        # visibility to, but the calling repo may not.
118        actual = Label(os),
119        visibility = ["//visibility:public"],
120    )
121
122    native.config_setting(
123        name = "_is_major_minor",
124        flag_values = {
125            _PYTHON_VERSION_FLAG: major_minor,
126        },
127    )
128    native.config_setting(
129        name = "_is_major_minor_micro",
130        flag_values = {
131            _PYTHON_VERSION_FLAG: major_minor_micro,
132        },
133    )
134    selects.config_setting_group(
135        name = "is_matching_python_version",
136        match_any = [
137            ":_is_major_minor",
138            ":_is_major_minor_micro",
139        ],
140        visibility = ["//visibility:public"],
141    )
142