1# Copyright (C) 2023 The Android Open Source Project
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"""
16This file contains rule and transition for building rust toolchain for device
17"""
18
19# Flags common to builds of the standard library.
20_EXTRA_FLAGS_FOR_STDLIB_BUILDS = [
21    # Even though --cap-lints=allow is set at the toolchain level (b/301466790),
22    # setting it again here is needed to disble linting in all upstream deps
23    "--cap-lints=allow",
24]
25
26_TRANSITION_OUTPUTS = [
27    "//command_line_option:compilation_mode",
28    "//build/bazel/toolchains/rust/bootstrap:enable_base_toolchain",
29    "@rules_rust//:extra_rustc_flags",
30    "@rules_rust//:extra_exec_rustc_flags",
31    "@rules_rust//rust/settings:use_real_import_macro",
32    "@rules_rust//rust/settings:pipelined_compilation",
33    "//command_line_option:cpu",
34]
35
36def _base_transition_impl(_, __):
37    return {
38        "//build/bazel/toolchains/rust/bootstrap:enable_base_toolchain": True,
39        "//command_line_option:compilation_mode": "opt",
40        "//command_line_option:cpu": "k8",
41        "@rules_rust//:extra_rustc_flags": _EXTRA_FLAGS_FOR_STDLIB_BUILDS,
42        "@rules_rust//:extra_exec_rustc_flags": _EXTRA_FLAGS_FOR_STDLIB_BUILDS,
43        "@rules_rust//rust/settings:use_real_import_macro": False,
44        "@rules_rust//rust/settings:pipelined_compilation": True,
45    }
46
47_base_transition = transition(
48    inputs = [],
49    outputs = _TRANSITION_OUTPUTS,
50    implementation = _base_transition_impl,
51)
52
53# Re-exports libs passed in `srcs` attribute. Used together with
54# transitions to build stdlibs at various stages.
55def _with_base_transition_impl(ctx):
56    return [DefaultInfo(files = depset(ctx.files.srcs))]
57
58# For each os + arch configuration, there is a pair of
59# 1. `<os_arch>_base_rust_toolchain`
60# 2. `<os_arch>_rust_toolchain`
61# registered in WORKSPACE. The base toolchains are only enabled when
62# `base_toolchain_enabled` `config_setting` is enabled.
63# Because `base_toolchain_enabled` is False by default, only <os_arch>_rust_toolchain
64# is enabled for a particular os + arch configuration and hence is resolved to build
65# a normal downstream rust target.
66#
67# with_base_transition attachs an incoming transition to `enable_base_toolchain`
68# which enable the base toolchains. When building for a particular configuration,
69# 1. `<os_arch>_base_rust_toolchain`
70# 2. `<os_arch>_rust_toolchain`
71# are enabled.
72# Because the base toolchain is registered before the non-base one, Bazel resolves
73# to the base toolchain. This mechanism allows building rust stdlibs using the base toolchain
74with_base_transition = rule(
75    implementation = _with_base_transition_impl,
76    attrs = {
77        "srcs": attr.label_list(
78            allow_files = True,
79        ),
80        "_allowlist_function_transition": attr.label(
81            default = Label("@bazel_tools//tools/allowlists/function_transition_allowlist"),
82        ),
83    },
84    cfg = _base_transition,
85)
86
87def _toolchain_sysroot_impl(ctx):
88    sysroot = ctx.attr.dirname
89    outputs = []
90
91    rustlibdir = "{}/lib/rustlib/{}/lib".format(sysroot, ctx.attr.target_triple)
92    rustbindir = "{}/bin".format(sysroot)
93
94    for inp in ctx.files.srcs:
95        if inp.short_path in ctx.attr.tools:
96            out = ctx.actions.declare_file(rustbindir + "/" + ctx.attr.tools[inp.short_path])
97        else:
98            out = ctx.actions.declare_file(rustlibdir + "/" + inp.basename)
99
100        outputs.append(out)
101        ctx.actions.symlink(output = out, target_file = inp)
102
103    return [DefaultInfo(
104        files = depset(outputs),
105        runfiles = ctx.runfiles(files = outputs),
106    )]
107
108toolchain_sysroot = rule(
109    implementation = _toolchain_sysroot_impl,
110    doc = """Creates a directory tree with copies of the passed Rust libraries
111    and tools, suitable to use in a rust_stdlib_filegroup.
112
113    The `srcs` attribute should enumerate the libraries and tools. Tools are
114    distinguished from libraries via the `tools` attribute, which should
115    contain an entry from the tool short_path to its final name under
116    dirname/bin/
117
118    The libraries are processed by creating symlinks to them in a local
119    directory rooted at `dirname`, e.g.,
120    dirname/lib/rustlib/x86_64-unknown-linux-gnu/lib/
121
122    The output under `dirname` is intended to constitute a valid sysroot, per
123    https://rustc-dev-guide.rust-lang.org/building/bootstrapping.html#what-is-a-sysroot
124    """,
125    attrs = {
126        "dirname": attr.string(
127            mandatory = True,
128        ),
129        "target_triple": attr.string(
130            doc = "The target triple for the rlibs.",
131            default = "x86_64-unknown-linux-gnu",
132        ),
133        "srcs": attr.label_list(
134            allow_files = True,
135        ),
136        "tools": attr.string_dict(
137            doc = "A map from tool's short_path to its final name under bin/",
138        ),
139    },
140)
141