Skip to content

Commit e2cd548

Browse files
committed
[doc] Add documentation for external dependencies
Signed-off-by: James Wainwright <[email protected]> (cherry picked from commit 7cfcca2)
1 parent 3fb416e commit e2cd548

File tree

2 files changed

+102
-34
lines changed

2 files changed

+102
-34
lines changed

SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,9 @@
407407

408408
# Software
409409
- [Introduction](./sw/README.md)
410+
410411
- [Build Software](./sw/doc/build_software.md)
412+
- [External dependencies](./third_party/README.md)
411413

412414
- [Device Software](./sw/device/README.md)
413415
- [Build & Test Rules](./rules/opentitan/README.md)

third_party/README.md

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,105 @@
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")
2732
```
2833

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`.
3399

34100
## Third-party Silicon IP
35101

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

Comments
 (0)