|
1 | | -OpenTitan `//third_party` |
2 | | -========== |
3 | | - |
4 | | -OpenTitan depends on a number of third party components. This directory consists of: |
5 | | -- Bazel files describing how to acquire them from the Internet, and incorporate them |
6 | | - into the OpenTitan workspace. |
7 | | -- Glue code for plugging dependencies into first-party software. |
8 | | - |
9 | | -Every dependency lives in a subdirectory; each subdirectory consists of at least three |
10 | | -files: |
11 | | -1. A (usually empty) `BUILD` file to specify that file as a Bazel package. |
12 | | -2. A `repos.bzl`, which exports a macro called `blah_repos()` that can be called in the |
13 | | - `WORKSPACE` to declare the remote repositories required for the dependency. |
14 | | -3. A `deps.bzl`, which exports a macro called `blah_deps()` that uses the repositories |
15 | | - created by `blah_repos()` to set up any other requirements of the dependency. It must |
16 | | - be called in the `WORKSPACE` file after `blah_repos()` is called. Some dependencies |
17 | | - can skip this step. |
18 | | - |
19 | | -Thus, for each third party dependency, a stanza like the following should appear in the |
20 | | -`WORKSPACE`: |
21 | | - |
22 | | -```bazel |
23 | | -load("//third_party/<dep>/repos.bzl", "<dep>_repos") |
24 | | -<dep>_repos() |
25 | | -load("//third_party/<dep>/deps.bzl", "<dep>_deps") |
26 | | -<dep>_deps() |
| 1 | +# OpenTitan external dependencies |
| 2 | + |
| 3 | +OpenTitan depends on a number of third-party components. |
| 4 | + |
| 5 | +These include: |
| 6 | + |
| 7 | +* Bazel rule dependencies (e.g. `rules_rust` for building Rust code). |
| 8 | +* Package dependencies (e.g. Rust crates, Python packages, APT packages). |
| 9 | +* Source dependencies (e.g. the source for OpenOCD, test vectors). |
| 10 | +* External silicon RTL. |
| 11 | + |
| 12 | +This document describes how we manage each of these kinds of dependency. |
| 13 | + |
| 14 | +## Bazel rule dependencies |
| 15 | + |
| 16 | +This repository forms a Bazel module described by the `MODULE.bazel` file at the |
| 17 | +root. We use a feature called [Bzlmod] to depend on other modules by adding `bazel_dep` |
| 18 | +directives to the `MODULE.bazel` file. |
| 19 | + |
| 20 | +Some Bazel modules expose "extensions" for extra features such as registering |
| 21 | +toolchains and downloading package dependencies. This example uses an extension from |
| 22 | +`rules_python` to create a specific Python toolchain that we can register: |
| 23 | + |
| 24 | +```python |
| 25 | +python = use_extension("@rules_python//python/extensions:python.bzl", "python") |
| 26 | +python.toolchain( |
| 27 | + is_default = True, |
| 28 | + python_version = "3.9", |
| 29 | +) |
| 30 | +use_repo(python, "pythons_hub") |
| 31 | +register_toolchains("@pythons_hub//:all") |
27 | 32 | ``` |
28 | 33 |
|
29 | | -In some cases, the `BUILD` file for the dependency will declare rules for tests, such as |
30 | | -`rv-compliance`. As a rule of thumb, if a dependency is being pulled in specifically for |
31 | | -some kind of test suite, the test rules should live in `//third_party`, where they can depend |
32 | | -on other parts of the tree. |
| 34 | +Extensions generate Bazel repositories (`pythons_hub` in this example) that |
| 35 | +can be imported our module's namespace. |
| 36 | + |
| 37 | +If a Bazel dependency requires lots of extension calls, consider extracting them |
| 38 | +to a new `third_party/${name}/${name}.MODULE.bazel` file and `include`ing it in |
| 39 | +the main `MODULE.bazel`. |
| 40 | + |
| 41 | +[Bzlmod]: https://bazel.build/external/overview#bzlmod |
| 42 | + |
| 43 | +## Package dependencies |
| 44 | + |
| 45 | +We tend to use an ecosystem's package definition format to list our dependencies and |
| 46 | +then install them manually or within Bazel depending on how they're used. |
| 47 | + |
| 48 | +These package manifests can be found at: |
| 49 | + |
| 50 | +* Python: `pyproject.toml` in the root of the repository. |
| 51 | +* Rust: `third_party/rust/Cargo.toml` for most dependencies. |
| 52 | + |
| 53 | + * We have additional `Cargo.toml` files to allow certain projects to use |
| 54 | + different dependency versions. |
| 55 | + |
| 56 | +* Bzlmod: `MODULE.bazel` in the root of the repository. |
| 57 | +* APT: `apt-requirements.txt` in the root of the repository. |
| 58 | + |
| 59 | +Some of these manifests have lock files which ensure we're using exactly the same |
| 60 | +versions on different builds. These must be kept up to date with changes to the |
| 61 | +manifests. Use `./ci/scripts/check-lock-files.sh` to check and regenerate lock files. |
| 62 | + |
| 63 | +## Source dependencies |
| 64 | + |
| 65 | +Sometimes we need access to external source and data files. These are brought into |
| 66 | +our Bazel module using Bzlmod extensions. |
| 67 | + |
| 68 | +To add a new source dependency: |
| 69 | + |
| 70 | +1. Create a new file `third_party/my_dep/extensions.bzl` for your extension. |
| 71 | +2. Create a Starlark function to download any repositories you need: |
| 72 | + |
| 73 | + ```python |
| 74 | + def _my_repos(): |
| 75 | + http_archive( |
| 76 | + name = "my_repo", |
| 77 | + url = "...", |
| 78 | + sha256 = "...", |
| 79 | + ) |
| 80 | + ``` |
| 81 | + |
| 82 | +3. Create a Bzlmod extension for your function: |
| 83 | + |
| 84 | + ```python |
| 85 | + my_extension = module_extension( |
| 86 | + implementation = lambda _: _my_repos(), |
| 87 | + ) |
| 88 | + ``` |
| 89 | + |
| 90 | +4. Use your extension from `MODULE.bazel` like you would with external modules: |
| 91 | + |
| 92 | + ```python |
| 93 | + my_extension = use_extension("//third_party/my_dep:extensions.bzl", "my_extension") |
| 94 | + use_repo(my_extension, "my_repo") |
| 95 | + ``` |
| 96 | + |
| 97 | +You should now be able to access your repository's files from Bazel using |
| 98 | +`@my_repo//:path/to/file`. |
33 | 99 |
|
34 | 100 | ## Third-party Silicon IP |
35 | 101 |
|
36 | | -Currently, silicon uses a separate vendoring mechanism: `util/vendor.py`. There are no |
37 | | -concrete plans to migrate off of this script for hardware. This script should not be |
38 | | -used for new software dependencies; instead, use the `//third_party` directory and Bazel |
39 | | -repositories instead. |
| 102 | +Currently, silicon uses a separate vendoring mechanism: `util/vendor.py`. |
| 103 | +There are no concrete plans to migrate off of this script for hardware. This |
| 104 | +script should not be used for new software dependencies; instead, use the |
| 105 | +`//third_party` directory and Bzlmod extensions instead. |
0 commit comments