• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Utilities for declaring Rust toolchains that are compatible with Arm gcc."""
15
16load("@rules_rust//rust:toolchain.bzl", "rust_analyzer_toolchain", "rust_toolchain")
17load("//pw_env_setup/bazel/cipd_setup:cipd_rules.bzl", "cipd_repository")
18
19HOSTS = [
20    {
21        "cipd_arch": "arm64",
22        "cpu": "aarch64",
23        "dylib_ext": ".so",
24        "os": "linux",
25        "triple": "aarch64-unknown-linux-gnu",
26    },
27    {
28        "cipd_arch": "amd64",
29        "cpu": "x86_64",
30        "dylib_ext": ".so",
31        "os": "linux",
32        "triple": "x86_64-unknown-linux-gnu",
33    },
34    {
35        "cipd_arch": "arm64",
36        "cpu": "aarch64",
37        "dylib_ext": ".dylib",
38        "os": "macos",
39        "triple": "aarch64-apple-darwin",
40    },
41    {
42        "cipd_arch": "amd64",
43        "cpu": "x86_64",
44        "dylib_ext": ".dylib",
45        "os": "macos",
46        "triple": "x86_64-apple-darwin",
47    },
48]
49
50EXTRA_TARGETS = [
51    {
52        "cpu": "armv6-m",
53        "triple": "thumbv6m-none-eabi",
54    },
55    {
56        "cpu": "armv7-m",
57        "triple": "thumbv7m-none-eabi",
58    },
59    {
60        "cpu": "armv7e-m",
61        "triple": "thumbv7m-none-eabi",
62    },
63]
64
65CHANNELS = [
66    {
67        "extra_rustc_flags": ["-Dwarnings", "-Zmacro-backtrace"],
68        "name": "nightly",
69        "target_settings": ["@rules_rust//rust/toolchain/channel:nightly"],
70    },
71    {
72        # In order to approximate a stable toolchain with our nightly one, we
73        # disable experimental features with the exception of `proc_macro_span`
74        # because the `proc-marcro2` automatically detects the toolchain
75        # as nightly and dynamically uses this feature.
76        "extra_rustc_flags": ["-Dwarnings", "-Zallow-features=proc_macro_span"],
77        "name": "stable",
78        "target_settings": ["@rules_rust//rust/toolchain/channel:stable"],
79    },
80]
81
82# buildifier: disable=unnamed-macro
83def pw_rust_register_toolchain_and_target_repos(cipd_tag, pigweed_repo_name = "@pigweed"):
84    """Declare and register CIPD repos for Rust toolchain and target rupport.
85
86    Args:
87      cipd_tag: Tag with which to select specific package versions.
88      pigweed_repo_name: The name of the pigweed used to reference build files
89        for the registered repositories.  Defaults to "@pigweed".
90    """
91    for host in HOSTS:
92        cipd_os = host["os"]
93        if cipd_os == "macos":
94            cipd_os = "mac"
95
96        cipd_repository(
97            name = "rust_toolchain_host_{}_{}".format(host["os"], host["cpu"]),
98            build_file = "{}//pw_toolchain/rust:rust_toolchain.BUILD".format(pigweed_repo_name),
99            path = "fuchsia/third_party/rust/host/{}-{}".format(cipd_os, host["cipd_arch"]),
100            tag = cipd_tag,
101        )
102
103        cipd_repository(
104            name = "rust_toolchain_target_{}".format(host["triple"]),
105            build_file = "{}//pw_toolchain/rust:rust_stdlib.BUILD".format(pigweed_repo_name),
106            path = "fuchsia/third_party/rust/target/{}".format(host["triple"]),
107            tag = cipd_tag,
108        )
109
110    for target in EXTRA_TARGETS:
111        cipd_repository(
112            name = "rust_toolchain_target_{}".format(target["triple"]),
113            build_file = "{}//pw_toolchain/rust:rust_stdlib.BUILD".format(pigweed_repo_name),
114            path = "fuchsia/third_party/rust/target/{}".format(target["triple"]),
115            tag = cipd_tag,
116        )
117
118# buildifier: disable=unnamed-macro
119def pw_rust_register_toolchains():
120    """Register Rust Toolchains
121
122    For this registration to be valid one must
123    1. Call `pw_rust_register_toolchain_and_target_repos(tag)` pervisouly in the
124       WORKSPACE file.
125    2. Call `pw_rust_declare_toolchain_targets()` from
126       `//pw_toolchain/rust/BUILD.bazel`.
127    """
128    for channel in CHANNELS:
129        for host in HOSTS:
130            native.register_toolchains(
131                "//pw_toolchain/rust:host_rust_toolchain_{}_{}_{}".format(host["os"], host["cpu"], channel["name"]),
132                "//pw_toolchain/rust:host_rust_analyzer_toolchain_{}_{}_{}".format(host["os"], host["cpu"], channel["name"]),
133            )
134            for target in EXTRA_TARGETS:
135                native.register_toolchains(
136                    "//pw_toolchain/rust:{}_{}_rust_toolchain_{}_{}_{}".format(host["os"], host["cpu"], target["triple"], target["cpu"], channel["name"]),
137                )
138
139# buildifier: disable=unnamed-macro
140def pw_rust_declare_toolchain_targets():
141    """Declare rust toolchain targets"""
142    for channel in CHANNELS:
143        for host in HOSTS:
144            _pw_rust_host_toolchain(
145                name = "host_rust_toolchain_{}_{}_{}".format(host["os"], host["cpu"], channel["name"]),
146                analyzer_toolchain_name = "host_rust_analyzer_toolchain_{}_{}_{}".format(host["os"], host["cpu"], channel["name"]),
147                compatible_with = [
148                    "@platforms//cpu:{}".format(host["cpu"]),
149                    "@platforms//os:{}".format(host["os"]),
150                ],
151                target_settings = channel["target_settings"],
152                dylib_ext = host["dylib_ext"],
153                target_repo = "@rust_toolchain_target_{}".format(host["triple"]),
154                toolchain_repo = "@rust_toolchain_host_{}_{}".format(host["os"], host["cpu"]),
155                triple = host["triple"],
156                extra_rustc_flags = channel["extra_rustc_flags"],
157            )
158            for target in EXTRA_TARGETS:
159                _pw_rust_toolchain(
160                    name = "{}_{}_rust_toolchain_{}_{}_{}".format(host["os"], host["cpu"], target["triple"], target["cpu"], channel["name"]),
161                    exec_triple = host["triple"],
162                    target_triple = target["triple"],
163                    target_repo = "@rust_toolchain_target_{}".format(target["triple"]),
164                    toolchain_repo = "@rust_toolchain_host_{}_{}".format(host["os"], host["cpu"]),
165                    dylib_ext = "*.so",
166                    exec_compatible_with = [
167                        "@platforms//cpu:{}".format(host["cpu"]),
168                        "@platforms//os:{}".format(host["os"]),
169                    ],
170                    target_compatible_with = [
171                        "@platforms//cpu:{}".format(target["cpu"]),
172                    ],
173                    target_settings = channel["target_settings"],
174                    extra_rustc_flags = channel["extra_rustc_flags"],
175                )
176
177def _pw_rust_toolchain(
178        name,
179        exec_triple,
180        target_triple,
181        toolchain_repo,
182        target_repo,
183        dylib_ext,
184        exec_compatible_with,
185        target_compatible_with,
186        target_settings,
187        extra_rustc_flags):
188    rust_toolchain(
189        name = "{}_rust_toolchain".format(name),
190        binary_ext = "",
191        default_edition = "2021",
192        dylib_ext = dylib_ext,
193        exec_compatible_with = exec_compatible_with,
194        exec_triple = exec_triple,
195        rust_doc = "{}//:bin/rustdoc".format(toolchain_repo),
196        rust_std = "{}//:rust_std".format(target_repo),
197        rustc = "{}//:bin/rustc".format(toolchain_repo),
198        rustc_lib = "{}//:rustc_lib".format(toolchain_repo),
199        staticlib_ext = ".a",
200        stdlib_linkflags = [],
201        target_compatible_with = target_compatible_with,
202        target_triple = target_triple,
203        extra_rustc_flags = extra_rustc_flags,
204        extra_exec_rustc_flags = extra_rustc_flags,
205        # TODO: https://pwbug.dev/342695883 - Works around confusing
206        # target_compatible_with semantics in rust_toolchain. Figure out how to
207        # do better.
208        tags = ["manual"],
209    )
210    native.toolchain(
211        name = name,
212        exec_compatible_with = exec_compatible_with,
213        target_compatible_with = target_compatible_with,
214        target_settings = target_settings,
215        toolchain = ":{}_rust_toolchain".format(name),
216        toolchain_type = "@rules_rust//rust:toolchain",
217    )
218
219def _pw_rust_host_toolchain(
220        name,
221        analyzer_toolchain_name,
222        triple,
223        toolchain_repo,
224        target_repo,
225        dylib_ext,
226        compatible_with,
227        target_settings,
228        extra_rustc_flags):
229    _pw_rust_toolchain(
230        name = name,
231        exec_triple = triple,
232        target_triple = triple,
233        toolchain_repo = toolchain_repo,
234        target_repo = target_repo,
235        dylib_ext = dylib_ext,
236        exec_compatible_with = compatible_with,
237        target_compatible_with = compatible_with,
238        target_settings = target_settings,
239        extra_rustc_flags = extra_rustc_flags,
240    )
241
242    rust_analyzer_toolchain(
243        name = "{}_rust_analyzer_toolchain".format(analyzer_toolchain_name),
244        exec_compatible_with = compatible_with,
245        proc_macro_srv = "{}//:libexec/rust-analyzer-proc-macro-srv".format(toolchain_repo),
246        rustc = "{}//:bin/rustc".format(toolchain_repo),
247        rustc_srcs = "{}//:rustc_srcs".format(toolchain_repo),
248        target_compatible_with = compatible_with,
249        visibility = ["//visibility:public"],
250    )
251
252    native.toolchain(
253        name = analyzer_toolchain_name,
254        exec_compatible_with = compatible_with,
255        target_compatible_with = compatible_with,
256        target_settings = target_settings,
257        toolchain = ":{}_rust_analyzer_toolchain".format(analyzer_toolchain_name),
258        toolchain_type = "@rules_rust//rust/rust_analyzer:toolchain_type",
259    )
260