Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation for Rust support #83715

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/workflows/doc-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
tests/
**/Kconfig*
west.yml
submanifests/optional.yaml
scripts/dts/
doc/requirements.txt
.github/workflows/doc-build.yml
Expand Down Expand Up @@ -255,13 +256,93 @@ jobs:
doc/_build/latex/zephyr.pdf
doc/_build/latex/zephyr.log

rust-doc-build-html:
name: "Rust Documentation Build (HTML)"
needs: [doc-file-check]
if: >
github.repository_owner == 'zephyrproject-rtos' &&
( needs.doc-file-check.outputs.file_check == 'true' || github.event_name != 'pull_request' )
runs-on: ubuntu-22.04

steps:
- name: Checkout
uses: actions/checkout@v4
with:
path: zephyr
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.11

- name: Setup Zephyr Project
uses: zephyrproject-rtos/action-zephyr-setup@v1
with:
app-path: zephyr
manifest-file-name: west.yml
toolchains: arm-zephyr-eabi

- name: Bring in docs
shell: bash
run: |
set -x
cd zephyr
# Show a git log to make sure we got the upstream version and west didn't "fix" it for us.
git log -3

# Add the rust module to the manifest.
west config manifest.project-filter +zephyr-lang-rust
west update zephyr-lang-rust

echo Rust support
ls -l ../modules/lang/rust

- name: Install Rust Target
shell: bash
run: |
rustup target add thumbv7em-none-eabi
rustup target add thumbv7m-none-eabi

- name: Build Rust docs
shell: bash
run: |
cargo --version
cd zephyr
west build -t rustdoc -b nrf52840dk/nrf52840 ../modules/lang/rust/docgen
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is west really needed to build rust docs? Also, why is a board required? I'm a bit surprised that rust docs are not generated on its own repo.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do generate rust docs in that repo, but they aren't correlated with any particular Zephyr release. This builds the rust docs that are specifically the version brought in.

As far as why west and a board are needed:

  • The rust code uses bindgen to generate bindings to the Zephyr API. In order to parse headers, the generated header files are needed, this requires much of the build tools to get that far.
  • The rust docs will be generated based on specific Kconfig values. The docgen app is intended to enable as many as possible in order to get the fullest docs.
  • Picking a specific board will make the contents of the docs, specifically for zephyr::raw also specific to that board. I intend to have instructions in the docs for Rust explain how to generate and view the docs locally, so developers can have those be accurate for their configuration and board. But, we need something so that we can reference the docs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit surprised that rust docs are not generated on its own repo.

They are. But, using them in the main docs would be a bit complicated logistically. Namely, we currently generate docs for each PR in the rust repo. These will stick around for I think two weeks. We also generate docs for main (well, we will, there is a small issue to fix that), but these are replaced each time a change is merged. If we wanted to directly use that artifact from here, we'd need to also generate them for specific shas, and somehow know to only retire those when a manifest doesn't refer to them. It would have to check every possible branch's manifest (there will be backport branches after the first release containing this).

It seems just easier to regenerate them in the Zephyr repo for the correct version, that way they'll persist according to the rules here (for each PR, the two weeks, and latest getting updated).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do generate rust docs in that repo, but they aren't correlated with any particular Zephyr release. This builds the rust docs that are specifically the version brought in.

As far as why west and a board are needed:

  • The rust code uses bindgen to generate bindings to the Zephyr API. In order to parse headers, the generated header files are needed, this requires much of the build tools to get that far.

I understand you need a build target, but picking a nordic board feels weird unless explained. I'd rather choose some vendor-agnostic target.

  • The rust docs will be generated based on specific Kconfig values. The docgen app is intended to enable as many as possible in order to get the fullest docs.

Is it using https://github.com/zephyrproject-rtos/zephyr/blob/main/doc/_extensions/zephyr/kconfig/__init__.py#L133 ?

  • Picking a specific board will make the contents of the docs, specifically for zephyr::raw also specific to that board. I intend to have instructions in the docs for Rust explain how to generate and view the docs locally, so developers can have those be accurate for their configuration and board. But, we need something so that we can reference the docs.

Maybe you should instead create a "rustdoc" board as a build target that enables as much zephyr raw as possible for docs purposes. In general, I don't think rust users should really bother about the APIs exposed depending on the board... And zephyr::raw should likely be kept as something internal people should not rely on their apps.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand you need a build target, but picking a nordic board feels weird unless explained. I'd rather choose some vendor-agnostic target.

I could do one of the qemu targets. I think this will be reasonably complete, as most shouldn't depend on the particular devices that are present. Someone wanting to navigate the rust version of their devicetree really needs to be generating docs locally for their specific build anyway.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I don't think rust users should really bother about the APIs exposed depending on the board

Where this really matters is with the generated modules representing their current device tree. The user will need to use this to be able to get instances of the devices on their platform. And, this doesn't make sense to have it be generic.

cd ..
mkdir rustdocs
mv zephyr/build/rust/target/thumbv7em-none-eabi/doc rustdocs/nostd
cp modules/lang/rust/docs/top-index.html rustdocs/index.html

# TODO: Build the std-based docs as well
- name: Build Rust Build-time docs
shell: bash
run: |
cd modules/lang/rust/zephyr-build
cargo doc
mv target/doc ../../../../rustdocs/std

cd ../../../..
du -hs rustdocs
ls -l rustdocs

- name: compress-rust-docs
run: |
tar --use-compress-program="xz -T0" -cf rustdocs-output.tar.xz rustdocs

- name: Upload docs artifact
uses: actions/upload-artifact@v4
with:
name: rustdocs
path: rustdocs-output.tar.xz

doc-build-status-check:
if: always()
name: "Documentation Build Status"
needs:
- doc-build-pdf
- doc-file-check
- doc-build-html
- rust-doc-build-html
uses: ./.github/workflows/ready-to-merge.yml
with:
needs_context: ${{ toJson(needs) }}
8 changes: 8 additions & 0 deletions .github/workflows/doc-publish-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ jobs:
if [ -f api-coverage/api-coverage.tar.xz ]; then
tar xf api-coverage/api-coverage.tar.xz -C api-coverage
fi
if [ -f rustdocs/rustdocs-output.tar.xz ]; then
tar xf rustdocs/rustdocs-output.tar.xz -C rustdocs
fi

- name: Configure AWS Credentials
if: steps.download-artifacts.outputs.found_artifact == 'true'
Expand All @@ -82,3 +85,8 @@ jobs:
s3://builds.zephyrproject.org/${{ github.event.repository.name }}/pr/${PR_NUM}/api-coverage \
--delete
fi
if [ -d rustdocs/rustdocs ]; then
aws s3 sync --quiet rustdocs/rustdocs/ \
s3://builds.zephyrproject.org/${{ github.event.repository.name }}/pr/${PR_NUM}/rustdocs \
--delete
fi
6 changes: 6 additions & 0 deletions .github/workflows/doc-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ jobs:
if [ -f api-coverage/api-coverage.tar.xz ]; then
tar xf api-coverage/api-coverage.tar.xz -C api-coverage
fi
if [ -f rustdocs/rustdocs-output.tar.xz ]; then
tar xf rustdocs/rustdocs-output.tar.xz -C rustdocs
fi

- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
Expand All @@ -58,4 +61,7 @@ jobs:
if [ -d api-coverage/coverage-report ]; then
aws s3 sync --quiet api-coverage/coverage-report/ s3://docs.zephyrproject.org/api-coverage/${VERSION} --delete
fi
if [ -d rustdocs/rustdocs ]; then
aws s3 sync --quiet rustdocs/rustdocs/ s3://docs.zephyrproject.org/rustdocs/${VERSION} --delete
fi
aws s3 cp --quiet pdf-output/zephyr.pdf s3://docs.zephyrproject.org/${VERSION}/zephyr.pdf
1 change: 1 addition & 0 deletions doc/develop/languages/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ Language Support

c/index.rst
cpp/index.rst
rust/index.rst
88 changes: 88 additions & 0 deletions doc/develop/languages/rust/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
.. _language_rust:

Rust Language Support
#####################

Rust is a modern systems programming language focused on safety, speed, and concurrency. Unlike
traditional systems programming languages such as C and C++, Rust ensures memory safety without
relying on garbage colleciton, thanks to its ownership model and borrow checker. Rust also offers a
rich type system, expressive syntax, and support for zero-cost abstractions, making it well-suited
for embedded development.

Rust’s emphasis on reliability and performance aligns well with Zephyr. By combining Rust’s
guarantees with Zephyr’s robust ecosystem, developers can create efficient and maintainable embedded
applications. The integration of Rust with Zephyr allows developers to leverage Rust’s language
features while benefiting from Zephyr’s drivers, APIs, and multi-threading capabilities.

At this point, Rust support in Zephyr is entirely for those wishing to write applications in Rust
that run *on* Zephyr. Any efforts to add code *to* Zephyr, written in Rust (such as device drivers)
would be an independent effort.

Enabling Rust Support
*********************

Both Rust and Zephyr have their own build systems, along with an ecosystem around this. For Rust,
this is the "crate" system of managing external dependencies. Because this support is for
applications written in Rust, Zephyr's rust support leverages crates, and the cargo tool to build
the Rust part of the application.

Enabling the module
-------------------

Before getting very far, it is important to make sure that the Rust support module is included. By
default, rust support is listed in the project manifest, but is marked as optional. It is easy to
enable the module using ``west``:

.. code-block:: console

west config manifest.project-filter +zephyr-lang-rust
west update

This should enable the module, and then sync modules, which will add the module to your modules
directory.

Setting up the environment
--------------------------

Before starting with Rust, make sure you are able to build a simple Zephyr application, such as
"blinky". It is easier to debug Zephyr build issues before introducing Rust.

After this, you will need to have a recent Rust toolchain install, as well as target support for
your desired target. It is generally easiest to use `Rustup`_ to install an maintain a rust
installation. After following these instructions, you will need to install target support for your
target.

Because Zephyr and LLVM use different naming conventions for targets, and can be a little
challenging to determine the right target to install. Sometimes, it is easiest to proceed with
building a Rust sample with your desired target, and the toolchain will emit an error message giving
the appropriate command to run. The target needed will depend both on the board/soc selected, as
well as certain configuration choices (such as whether floating point is enabled). Please see the
function ``_rust_map_target`` in :module_file:`zephyr-lang-rust:CMakeLists.txt` for details on how
this is computed. As an example, a particular Cortex-M target may need the following command:

.. code-block:: console

rustup target add thumbv7m-none-eabi

.. _`Rustup`: https://rustup.rs/

Building a sample
-----------------

.. This file (a directory in samples) and the above CMakeLists.txt should be done with the
module_file reference. However, the current doc build doesn't seem to be including modules, so
for now, just make these regular file references.

The directory :file:`zephyr-lang-rust:samples` contains some samples that can be useful for
testing. Hello world is a good basic test, although blinky may also be useful if your target has an
LED defined. Please make sure that :file:`samples/basic/blink` works with your board,
however, before trying it with Rust.

Following from the getting-started guide, you can build the hello world sample in rust with:

.. code-block: console

cd ~/zephyrproject/modules/lang/rust
west build -p always -b <your-board-name> samples/blinky

Provided this is successful, the image can be flashed and tested as per the getting started guide.
Loading