Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,26 @@
.. SPDX-License-Identifier: GPL-2.0
Arch Support
============
Currently, the Rust compiler (``rustc``) uses LLVM for code generation,
which limits the supported architectures that can be targeted. In addition,
support for building the kernel with LLVM/Clang varies (please see
Documentation/kbuild/llvm.rst). This support is needed for ``bindgen``
which uses ``libclang``.
Below is a general summary of architectures that currently work. Level of
support corresponds to ``S`` values in the ``MAINTAINERS`` file.
============= ================ ==============================================
Architecture Level of support Constraints
============= ================ ==============================================
``arm`` Maintained ARMv7 Little Endian only.
``arm64`` Maintained Little Endian only.
``loongarch`` Maintained \-
``riscv`` Maintained ``riscv64`` and LLVM/Clang only.
``s390`` Maintained ``CONFIG_EXPOLINE`` must be disabled.
``um`` Maintained \-
``x86`` Maintained ``x86_64`` only.
============= ================ ==============================================
@@ -0,0 +1,487 @@
.. SPDX-License-Identifier: GPL-2.0
Coding Guidelines
=================
This document describes how to write Rust code in the kernel.
Style & formatting
------------------
The code should be formatted using ``rustfmt``. In this way, a person
contributing from time to time to the kernel does not need to learn and
remember one more style guide. More importantly, reviewers and maintainers
do not need to spend time pointing out style issues anymore, and thus
less patch roundtrips may be needed to land a change.
.. note:: Conventions on comments and documentation are not checked by
``rustfmt``. Thus those are still needed to be taken care of.
The default settings of ``rustfmt`` are used. This means the idiomatic Rust
style is followed. For instance, 4 spaces are used for indentation rather
than tabs.
It is convenient to instruct editors/IDEs to format while typing,
when saving or at commit time. However, if for some reason reformatting
the entire kernel Rust sources is needed at some point, the following can be
run::
make LLVM=1 rustfmt
It is also possible to check if everything is formatted (printing a diff
otherwise), for instance for a CI, with::
make LLVM=1 rustfmtcheck
Like ``clang-format`` for the rest of the kernel, ``rustfmt`` works on
individual files, and does not require a kernel configuration. Sometimes it may
even work with broken code.
Imports
~~~~~~~
``rustfmt``, by default, formats imports in a way that is prone to conflicts
while merging and rebasing, since in some cases it condenses several items into
the same line. For instance:
.. code-block:: rust
// Do not use this style.
use crate::{
example1,
example2::{example3, example4, example5},
example6, example7,
example8::example9,
};
Instead, the kernel uses a vertical layout that looks like this:
.. code-block:: rust
use crate::{
example1,
example2::{
example3,
example4,
example5, //
},
example6,
example7,
example8::example9, //
};
That is, each item goes into its own line, and braces are used as soon as there
is more than one item in a list.
The trailing empty comment allows to preserve this formatting. Not only that,
``rustfmt`` will actually reformat imports vertically when the empty comment is
added. That is, it is possible to easily reformat the original example into the
expected style by running ``rustfmt`` on an input like:
.. code-block:: rust
// Do not use this style.
use crate::{
example1,
example2::{example3, example4, example5, //
},
example6, example7,
example8::example9, //
};
The trailing empty comment works for nested imports, as shown above, as well as
for single item imports -- this can be useful to minimize diffs within patch
series:
.. code-block:: rust
use crate::{
example1, //
};
The trailing empty comment works in any of the lines within the braces, but it
is preferred to keep it in the last item, since it is reminiscent of the
trailing comma in other formatters. Sometimes it may be simpler to avoid moving
the comment several times within a patch series due to changes in the list.
There may be cases where exceptions may need to be made, i.e. none of this is
a hard rule. There is also code that is not migrated to this style yet, but
please do not introduce code in other styles.
Eventually, the goal is to get ``rustfmt`` to support this formatting style (or
a similar one) automatically in a stable release without requiring the trailing
empty comment. Thus, at some point, the goal is to remove those comments.
Comments
--------
"Normal" comments (i.e. ``//``, rather than code documentation which starts
with ``///`` or ``//!``) are written in Markdown the same way as documentation
comments are, even though they will not be rendered. This improves consistency,
simplifies the rules and allows to move content between the two kinds of
comments more easily. For instance:
.. code-block:: rust
// `object` is ready to be handled now.
f(object);
Furthermore, just like documentation, comments are capitalized at the beginning
of a sentence and ended with a period (even if it is a single sentence). This
includes ``// SAFETY:``, ``// TODO:`` and other "tagged" comments, e.g.:
.. code-block:: rust
// FIXME: The error should be handled properly.
Comments should not be used for documentation purposes: comments are intended
for implementation details, not users. This distinction is useful even if the
reader of the source file is both an implementor and a user of an API. In fact,
sometimes it is useful to use both comments and documentation at the same time.
For instance, for a ``TODO`` list or to comment on the documentation itself.
For the latter case, comments can be inserted in the middle; that is, closer to
the line of documentation to be commented. For any other case, comments are
written after the documentation, e.g.:
.. code-block:: rust
/// Returns a new [`Foo`].
///
/// # Examples
///
// TODO: Find a better example.
/// ```
/// let foo = f(42);
/// ```
// FIXME: Use fallible approach.
pub fn f(x: i32) -> Foo {
// ...
}
This applies to both public and private items. This increases consistency with
public items, allows changes to visibility with less changes involved and will
allow us to potentially generate the documentation for private items as well.
In other words, if documentation is written for a private item, then ``///``
should still be used. For instance:
.. code-block:: rust
/// My private function.
// TODO: ...
fn f() {}
One special kind of comments are the ``// SAFETY:`` comments. These must appear
before every ``unsafe`` block, and they explain why the code inside the block is
correct/sound, i.e. why it cannot trigger undefined behavior in any case, e.g.:
.. code-block:: rust
// SAFETY: `p` is valid by the safety requirements.
unsafe { *p = 0; }
``// SAFETY:`` comments are not to be confused with the ``# Safety`` sections
in code documentation. ``# Safety`` sections specify the contract that callers
(for functions) or implementors (for traits) need to abide by. ``// SAFETY:``
comments show why a call (for functions) or implementation (for traits) actually
respects the preconditions stated in a ``# Safety`` section or the language
reference.
Code documentation
------------------
Rust kernel code is not documented like C kernel code (i.e. via kernel-doc).
Instead, the usual system for documenting Rust code is used: the ``rustdoc``
tool, which uses Markdown (a lightweight markup language).
To learn Markdown, there are many guides available out there. For instance,
the one at:
https://commonmark.org/help/
This is how a well-documented Rust function may look like:
.. code-block:: rust
/// Returns the contained [`Some`] value, consuming the `self` value,
/// without checking that the value is not [`None`].
///
/// # Safety
///
/// Calling this method on [`None`] is *[undefined behavior]*.
///
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
///
/// # Examples
///
/// ```
/// let x = Some("air");
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
/// ```
pub unsafe fn unwrap_unchecked(self) -> T {
match self {
Some(val) => val,
// SAFETY: The safety contract must be upheld by the caller.
None => unsafe { hint::unreachable_unchecked() },
}
}
This example showcases a few ``rustdoc`` features and some conventions followed
in the kernel:
- The first paragraph must be a single sentence briefly describing what
the documented item does. Further explanations must go in extra paragraphs.
- Unsafe functions must document their safety preconditions under
a ``# Safety`` section.
- While not shown here, if a function may panic, the conditions under which
that happens must be described under a ``# Panics`` section.
Please note that panicking should be very rare and used only with a good
reason. In almost all cases, a fallible approach should be used, typically
returning a ``Result``.
- If providing examples of usage would help readers, they must be written in
a section called ``# Examples``.
- Rust items (functions, types, constants...) must be linked appropriately
(``rustdoc`` will create a link automatically).
- Any ``unsafe`` block must be preceded by a ``// SAFETY:`` comment
describing why the code inside is sound.
While sometimes the reason might look trivial and therefore unneeded,
writing these comments is not just a good way of documenting what has been
taken into account, but most importantly, it provides a way to know that
there are no *extra* implicit constraints.
To learn more about how to write documentation for Rust and extra features,
please take a look at the ``rustdoc`` book at:
https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html
In addition, the kernel supports creating links relative to the source tree by
prefixing the link destination with ``srctree/``. For instance:
.. code-block:: rust
//! C header: [`include/linux/printk.h`](srctree/include/linux/printk.h)
or:
.. code-block:: rust
/// [`struct mutex`]: srctree/include/linux/mutex.h
C FFI types
-----------
Rust kernel code refers to C types, such as ``int``, using type aliases such as
``c_int``, which are readily available from the ``kernel`` prelude. Please do
not use the aliases from ``core::ffi`` -- they may not map to the correct types.
These aliases should generally be referred directly by their identifier, i.e.
as a single segment path. For instance:
.. code-block:: rust
fn f(p: *const c_char) -> c_int {
// ...
}
Naming
------
Rust kernel code follows the usual Rust naming conventions:
https://rust-lang.github.io/api-guidelines/naming.html
When existing C concepts (e.g. macros, functions, objects...) are wrapped into
a Rust abstraction, a name as close as reasonably possible to the C side should
be used in order to avoid confusion and to improve readability when switching
back and forth between the C and Rust sides. For instance, macros such as
``pr_info`` from C are named the same in the Rust side.
Having said that, casing should be adjusted to follow the Rust naming
conventions, and namespacing introduced by modules and types should not be
repeated in the item names. For instance, when wrapping constants like:
.. code-block:: c
#define GPIO_LINE_DIRECTION_IN 0
#define GPIO_LINE_DIRECTION_OUT 1
The equivalent in Rust may look like (ignoring documentation):
.. code-block:: rust
pub mod gpio {
pub enum LineDirection {
In = bindings::GPIO_LINE_DIRECTION_IN as _,
Out = bindings::GPIO_LINE_DIRECTION_OUT as _,
}
}
That is, the equivalent of ``GPIO_LINE_DIRECTION_IN`` would be referred to as
``gpio::LineDirection::In``. In particular, it should not be named
``gpio::gpio_line_direction::GPIO_LINE_DIRECTION_IN``.
Lints
-----
In Rust, it is possible to ``allow`` particular warnings (diagnostics, lints)
locally, making the compiler ignore instances of a given warning within a given
function, module, block, etc.
It is similar to ``#pragma GCC diagnostic push`` + ``ignored`` + ``pop`` in C
[#]_:
.. code-block:: c
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
static void f(void) {}
#pragma GCC diagnostic pop
.. [#] In this particular case, the kernel's ``__{always,maybe}_unused``
attributes (C23's ``[[maybe_unused]]``) may be used; however, the example
is meant to reflect the equivalent lint in Rust discussed afterwards.
But way less verbose:
.. code-block:: rust
#[allow(dead_code)]
fn f() {}
By that virtue, it makes it possible to comfortably enable more diagnostics by
default (i.e. outside ``W=`` levels). In particular, those that may have some
false positives but that are otherwise quite useful to keep enabled to catch
potential mistakes.
On top of that, Rust provides the ``expect`` attribute which takes this further.
It makes the compiler warn if the warning was not produced. For instance, the
following will ensure that, when ``f()`` is called somewhere, we will have to
remove the attribute:
.. code-block:: rust
#[expect(dead_code)]
fn f() {}
If we do not, we get a warning from the compiler::
warning: this lint expectation is unfulfilled
--> x.rs:3:10
|
3 | #[expect(dead_code)]
| ^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
This means that ``expect``\ s do not get forgotten when they are not needed, which
may happen in several situations, e.g.:
- Temporary attributes added while developing.
- Improvements in lints in the compiler, Clippy or custom tools which may
remove a false positive.
- When the lint is not needed anymore because it was expected that it would be
removed at some point, such as the ``dead_code`` example above.
It also increases the visibility of the remaining ``allow``\ s and reduces the
chance of misapplying one.
Thus prefer ``expect`` over ``allow`` unless:
- Conditional compilation triggers the warning in some cases but not others.
If there are only a few cases where the warning triggers (or does not
trigger) compared to the total number of cases, then one may consider using
a conditional ``expect`` (i.e. ``cfg_attr(..., expect(...))``). Otherwise,
it is likely simpler to just use ``allow``.
- Inside macros, when the different invocations may create expanded code that
triggers the warning in some cases but not in others.
- When code may trigger a warning for some architectures but not others, such
as an ``as`` cast to a C FFI type.
As a more developed example, consider for instance this program:
.. code-block:: rust
fn g() {}
fn main() {
#[cfg(CONFIG_X)]
g();
}
Here, function ``g()`` is dead code if ``CONFIG_X`` is not set. Can we use
``expect`` here?
.. code-block:: rust
#[expect(dead_code)]
fn g() {}
fn main() {
#[cfg(CONFIG_X)]
g();
}
This would emit a lint if ``CONFIG_X`` is set, since it is not dead code in that
configuration. Therefore, in cases like this, we cannot use ``expect`` as-is.
A simple possibility is using ``allow``:
.. code-block:: rust
#[allow(dead_code)]
fn g() {}
fn main() {
#[cfg(CONFIG_X)]
g();
}
An alternative would be using a conditional ``expect``:
.. code-block:: rust
#[cfg_attr(not(CONFIG_X), expect(dead_code))]
fn g() {}
fn main() {
#[cfg(CONFIG_X)]
g();
}
This would ensure that, if someone introduces another call to ``g()`` somewhere
(e.g. unconditionally), then it would be spotted that it is not dead code
anymore. However, the ``cfg_attr`` is more complex than a simple ``allow``.
Therefore, it is likely that it is not worth using conditional ``expect``\ s when
more than one or two configurations are involved or when the lint may be
triggered due to non-local changes (such as ``dead_code``).
For more information about diagnostics in Rust, please see:
https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html
Error handling
--------------
For some background and guidelines about Rust for Linux specific error handling,
please see:
https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust
@@ -0,0 +1,161 @@
.. SPDX-License-Identifier: GPL-2.0
General Information
===================
This document contains useful information to know when working with
the Rust support in the kernel.
``no_std``
----------
The Rust support in the kernel can link only `core <https://doc.rust-lang.org/core/>`_,
but not `std <https://doc.rust-lang.org/std/>`_. Crates for use in the
kernel must opt into this behavior using the ``#![no_std]`` attribute.
.. _rust_code_documentation:
Code documentation
------------------
Rust kernel code is documented using ``rustdoc``, its built-in documentation
generator.
The generated HTML docs include integrated search, linked items (e.g. types,
functions, constants), source code, etc. They may be read at:
https://rust.docs.kernel.org
For linux-next, please see:
https://rust.docs.kernel.org/next/
There are also tags for each main release, e.g.:
https://rust.docs.kernel.org/6.10/
The docs can also be easily generated and read locally. This is quite fast
(same order as compiling the code itself) and no special tools or environment
are needed. This has the added advantage that they will be tailored to
the particular kernel configuration used. To generate them, use the ``rustdoc``
target with the same invocation used for compilation, e.g.::
make LLVM=1 rustdoc
To read the docs locally in your web browser, run e.g.::
xdg-open Documentation/output/rust/rustdoc/kernel/index.html
To learn about how to write the documentation, please see coding-guidelines.rst.
Extra lints
-----------
While ``rustc`` is a very helpful compiler, some extra lints and analyses are
available via ``clippy``, a Rust linter. To enable it, pass ``CLIPPY=1`` to
the same invocation used for compilation, e.g.::
make LLVM=1 CLIPPY=1
Please note that Clippy may change code generation, thus it should not be
enabled while building a production kernel.
Abstractions vs. bindings
-------------------------
Abstractions are Rust code wrapping kernel functionality from the C side.
In order to use functions and types from the C side, bindings are created.
Bindings are the declarations for Rust of those functions and types from
the C side.
For instance, one may write a ``Mutex`` abstraction in Rust which wraps
a ``struct mutex`` from the C side and calls its functions through the bindings.
Abstractions are not available for all the kernel internal APIs and concepts,
but it is intended that coverage is expanded as time goes on. "Leaf" modules
(e.g. drivers) should not use the C bindings directly. Instead, subsystems
should provide as-safe-as-possible abstractions as needed.
.. code-block::
rust/bindings/
(rust/helpers/)
include/ -----+ <-+
| |
drivers/ rust/kernel/ +----------+ <-+ |
fs/ | bindgen | |
.../ +-------------------+ +----------+ --+ |
| Abstractions | | |
+---------+ | +------+ +------+ | +----------+ | |
| my_foo | -----> | | foo | | bar | | -------> | Bindings | <-+ |
| driver | Safe | | sub- | | sub- | | Unsafe | | |
+---------+ | |system| |system| | | bindings | <-----+
| | +------+ +------+ | | crate | |
| | kernel crate | +----------+ |
| +-------------------+ |
| |
+------------------# FORBIDDEN #--------------------------------+
The main idea is to encapsulate all direct interaction with the kernel's C APIs
into carefully reviewed and documented abstractions. Then users of these
abstractions cannot introduce undefined behavior (UB) as long as:
#. The abstractions are correct ("sound").
#. Any ``unsafe`` blocks respect the safety contract necessary to call the
operations inside the block. Similarly, any ``unsafe impl``\ s respect the
safety contract necessary to implement the trait.
Bindings
~~~~~~~~
By including a C header from ``include/`` into
``rust/bindings/bindings_helper.h``, the ``bindgen`` tool will auto-generate the
bindings for the included subsystem. After building, see the ``*_generated.rs``
output files in the ``rust/bindings/`` directory.
For parts of the C header that ``bindgen`` does not auto generate, e.g. C
``inline`` functions or non-trivial macros, it is acceptable to add a small
wrapper function to ``rust/helpers/`` to make it available for the Rust side as
well.
Abstractions
~~~~~~~~~~~~
Abstractions are the layer between the bindings and the in-kernel users. They
are located in ``rust/kernel/`` and their role is to encapsulate the unsafe
access to the bindings into an as-safe-as-possible API that they expose to their
users. Users of the abstractions include things like drivers or file systems
written in Rust.
Besides the safety aspect, the abstractions are supposed to be "ergonomic", in
the sense that they turn the C interfaces into "idiomatic" Rust code. Basic
examples are to turn the C resource acquisition and release into Rust
constructors and destructors or C integer error codes into Rust's ``Result``\ s.
Conditional compilation
-----------------------
Rust code has access to conditional compilation based on the kernel
configuration:
.. code-block:: rust
#[cfg(CONFIG_X)] // Enabled (`y` or `m`)
#[cfg(CONFIG_X="y")] // Enabled as a built-in (`y`)
#[cfg(CONFIG_X="m")] // Enabled as a module (`m`)
#[cfg(not(CONFIG_X))] // Disabled
For other predicates that Rust's ``cfg`` does not support, e.g. expressions with
numerical comparisons, one may define a new Kconfig symbol:
.. code-block:: kconfig
config RUSTC_HAS_SPAN_FILE
def_bool RUSTC_VERSION >= 108800
+42
View File
@@ -0,0 +1,42 @@
.. SPDX-License-Identifier: GPL-2.0
Rust
====
Documentation related to Rust within the kernel. To start using Rust
in the kernel, please read the quick-start.rst guide.
Code documentation
------------------
Given a kernel configuration, the kernel may generate Rust code documentation,
i.e. HTML rendered by the ``rustdoc`` tool.
.. only:: rustdoc and html
This kernel documentation was built with `Rust code documentation
<rustdoc/kernel/index.html>`_.
.. only:: not rustdoc and html
This kernel documentation was not built with Rust code documentation.
A pregenerated version is provided at:
https://rust.docs.kernel.org
Please see the :ref:`Code documentation <rust_code_documentation>` section for
more details.
.. toctree::
:maxdepth: 1
quick-start
general-information
coding-guidelines
arch-support
testing
You can also find learning materials for Rust in its section in
:doc:`../process/kernel-docs`.
@@ -0,0 +1,354 @@
.. SPDX-License-Identifier: GPL-2.0
Quick Start
===========
This document describes how to get started with kernel development in Rust.
There are a few ways to install a Rust toolchain needed for kernel development.
A simple way is to use the packages from your Linux distribution if they are
suitable -- the first section below explains this approach. An advantage of this
approach is that, typically, the distribution will match the LLVM used by Rust
and Clang.
Another way is using the prebuilt stable versions of LLVM+Rust provided on
`kernel.org <https://kernel.org/pub/tools/llvm/rust/>`_. These are the same slim
and fast LLVM toolchains from :ref:`Getting LLVM <getting_llvm>` with versions
of Rust added to them that Rust for Linux supports. Two sets are provided: the
"latest LLVM" and "matching LLVM" (please see the link for more information).
Alternatively, the next two "Requirements" sections explain each component and
how to install them through ``rustup``, the standalone installers from Rust
and/or building them.
The rest of the document explains other aspects on how to get started.
Distributions
-------------
Arch Linux
**********
Arch Linux provides recent Rust releases and thus it should generally work out
of the box, e.g.::
pacman -S rust rust-src rust-bindgen
Debian
******
Debian 13 (Trixie), as well as Testing and Debian Unstable (Sid) provide recent
Rust releases and thus they should generally work out of the box, e.g.::
apt install rustc rust-src bindgen rustfmt rust-clippy
Fedora Linux
************
Fedora Linux provides recent Rust releases and thus it should generally work out
of the box, e.g.::
dnf install rust rust-src bindgen-cli rustfmt clippy
Gentoo Linux
************
Gentoo Linux provides recent Rust releases and thus it should generally work out
of the box, e.g.::
USE='rust-src rustfmt clippy' emerge dev-lang/rust dev-util/bindgen
``LIBCLANG_PATH`` may need to be set.
Nix
***
Nix provides recent Rust releases and thus it should generally work out of the
box, e.g.::
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = with pkgs; [ rustc rust-bindgen rustfmt clippy ];
RUST_LIB_SRC = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
}
openSUSE
********
openSUSE Slowroll and openSUSE Tumbleweed provide recent Rust releases and thus
they should generally work out of the box, e.g.::
zypper install rust rust-src rust-bindgen clang
Ubuntu
******
Ubuntu 25.10 and 26.04 LTS provide recent Rust releases and thus they should
generally work out of the box, e.g.::
apt install rustc rust-src bindgen rustfmt rust-clippy
In addition, ``RUST_LIB_SRC`` needs to be set, e.g.::
RUST_LIB_SRC=/usr/src/rustc-$(rustc --version | cut -d' ' -f2)/library
For convenience, ``RUST_LIB_SRC`` can be exported to the global environment.
24.04 LTS and older
~~~~~~~~~~~~~~~~~~~
Though Ubuntu 24.04 LTS and older versions still provide recent Rust
releases, they require some additional configuration to be set, using
the versioned packages, e.g.::
apt install rustc-1.85 rust-1.85-src bindgen-0.71 rustfmt-1.85 \
rust-1.85-clippy
ln -s /usr/lib/rust-1.85/bin/rustfmt /usr/bin/rustfmt-1.85
ln -s /usr/lib/rust-1.85/bin/clippy-driver /usr/bin/clippy-driver-1.85
None of these packages set their tools as defaults; therefore they should be
specified explicitly, e.g.::
make LLVM=1 RUSTC=rustc-1.85 RUSTDOC=rustdoc-1.85 RUSTFMT=rustfmt-1.85 \
CLIPPY_DRIVER=clippy-driver-1.85 BINDGEN=bindgen-0.71
Alternatively, modify the ``PATH`` variable to place the Rust 1.85 binaries
first and set ``bindgen`` as the default, e.g.::
PATH=/usr/lib/rust-1.85/bin:$PATH
update-alternatives --install /usr/bin/bindgen bindgen \
/usr/bin/bindgen-0.71 100
update-alternatives --set bindgen /usr/bin/bindgen-0.71
``RUST_LIB_SRC`` may need to be set when using the versioned packages, e.g.::
RUST_LIB_SRC=/usr/src/rustc-$(rustc-1.85 --version | cut -d' ' -f2)/library
For convenience, ``RUST_LIB_SRC`` can be exported to the global environment.
In addition, ``bindgen-0.71`` is available in newer releases (24.04 LTS),
but it may not be available in older ones (20.04 LTS and 22.04 LTS),
thus ``bindgen`` may need to be built manually (please see below).
Requirements: Building
----------------------
This section explains how to fetch the tools needed for building.
To easily check whether the requirements are met, the following target
can be used::
make LLVM=1 rustavailable
This triggers the same logic used by Kconfig to determine whether
``RUST_IS_AVAILABLE`` should be enabled; but it also explains why not
if that is the case.
rustc
*****
A recent version of the Rust compiler is required.
If ``rustup`` is being used, enter the kernel build directory (or use
``--path=<build-dir>`` argument to the ``set`` sub-command) and run,
for instance::
rustup override set stable
This will configure your working directory to use the given version of
``rustc`` without affecting your default toolchain.
Note that the override applies to the current working directory (and its
sub-directories).
If you are not using ``rustup``, fetch a standalone installer from:
https://forge.rust-lang.org/infra/other-installation-methods.html#standalone
Rust standard library source
****************************
The Rust standard library source is required because the build system will
cross-compile ``core``.
If ``rustup`` is being used, run::
rustup component add rust-src
The components are installed per toolchain, thus upgrading the Rust compiler
version later on requires re-adding the component.
Otherwise, if a standalone installer is used, the Rust source tree may be
downloaded into the toolchain's installation folder::
curl -L "https://static.rust-lang.org/dist/rust-src-$(rustc --version | cut -d' ' -f2).tar.gz" |
tar -xzf - -C "$(rustc --print sysroot)/lib" \
"rust-src-$(rustc --version | cut -d' ' -f2)/rust-src/lib/" \
--strip-components=3
In this case, upgrading the Rust compiler version later on requires manually
updating the source tree (this can be done by removing ``$(rustc --print
sysroot)/lib/rustlib/src/rust`` then rerunning the above command).
libclang
********
``libclang`` (part of LLVM) is used by ``bindgen`` to understand the C code
in the kernel, which means LLVM needs to be installed; like when the kernel
is compiled with ``LLVM=1``.
Linux distributions are likely to have a suitable one available, so it is
best to check that first.
There are also some binaries for several systems and architectures uploaded at:
https://releases.llvm.org/download.html
Otherwise, building LLVM takes quite a while, but it is not a complex process:
https://llvm.org/docs/GettingStarted.html#getting-the-source-code-and-building-llvm
Please see Documentation/kbuild/llvm.rst for more information and further ways
to fetch pre-built releases and distribution packages.
bindgen
*******
The bindings to the C side of the kernel are generated at build time using
the ``bindgen`` tool.
Install it, for instance, via (note that this will download and build the tool
from source)::
cargo install --locked bindgen-cli
``bindgen`` uses the ``clang-sys`` crate to find a suitable ``libclang`` (which
may be linked statically, dynamically or loaded at runtime). By default, the
``cargo`` command above will produce a ``bindgen`` binary that will load
``libclang`` at runtime. If it is not found (or a different ``libclang`` than
the one found should be used), the process can be tweaked, e.g. by using the
``LIBCLANG_PATH`` environment variable. For details, please see ``clang-sys``'s
documentation at:
https://github.com/KyleMayes/clang-sys#linking
https://github.com/KyleMayes/clang-sys#environment-variables
Requirements: Developing
------------------------
This section explains how to fetch the tools needed for developing. That is,
they are not needed when just building the kernel.
rustfmt
*******
The ``rustfmt`` tool is used to automatically format all the Rust kernel code,
including the generated C bindings (for details, please see
coding-guidelines.rst).
If ``rustup`` is being used, its ``default`` profile already installs the tool,
thus nothing needs to be done. If another profile is being used, the component
can be installed manually::
rustup component add rustfmt
The standalone installers also come with ``rustfmt``.
clippy
******
``clippy`` is a Rust linter. Running it provides extra warnings for Rust code.
It can be run by passing ``CLIPPY=1`` to ``make`` (for details, please see
general-information.rst).
If ``rustup`` is being used, its ``default`` profile already installs the tool,
thus nothing needs to be done. If another profile is being used, the component
can be installed manually::
rustup component add clippy
The standalone installers also come with ``clippy``.
rustdoc
*******
``rustdoc`` is the documentation tool for Rust. It generates pretty HTML
documentation for Rust code (for details, please see
general-information.rst).
``rustdoc`` is also used to test the examples provided in documented Rust code
(called doctests or documentation tests). The ``rusttest`` Make target uses
this feature.
If ``rustup`` is being used, all the profiles already install the tool,
thus nothing needs to be done.
The standalone installers also come with ``rustdoc``.
rust-analyzer
*************
The `rust-analyzer <https://rust-analyzer.github.io/>`_ language server can
be used with many editors to enable syntax highlighting, completion, go to
definition, and other features.
``rust-analyzer`` needs a configuration file, ``rust-project.json``, which
can be generated by the ``rust-analyzer`` Make target::
make LLVM=1 rust-analyzer
Configuration
-------------
``Rust support`` (``CONFIG_RUST``) needs to be enabled in the ``General setup``
menu. The option is only shown if a suitable Rust toolchain is found (see
above), as long as the other requirements are met. In turn, this will make
visible the rest of options that depend on Rust.
Afterwards, go to::
Kernel hacking
-> Sample kernel code
-> Rust samples
And enable some sample modules either as built-in or as loadable.
Building
--------
Building a kernel with a complete LLVM toolchain is the best supported setup
at the moment. That is::
make LLVM=1
Using GCC also works for some configurations, but it is very experimental at
the moment.
Hacking
-------
To dive deeper, take a look at the source code of the samples
at ``samples/rust/``, the Rust support code under ``rust/`` and
the ``Rust hacking`` menu under ``Kernel hacking``.
+241
View File
@@ -0,0 +1,241 @@
.. SPDX-License-Identifier: GPL-2.0
Testing
=======
This document contains useful information how to test the Rust code in the
kernel.
There are three sorts of tests:
- The KUnit tests.
- The ``#[test]`` tests.
- The Kselftests.
The KUnit tests
---------------
These are the tests that come from the examples in the Rust documentation. They
get transformed into KUnit tests.
Usage
*****
These tests can be run via KUnit. For example via ``kunit_tool`` (``kunit.py``)
on the command line::
./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 --kconfig_add CONFIG_RUST=y
Alternatively, KUnit can run them as kernel built-in at boot. Refer to
Documentation/dev-tools/kunit/index.rst for the general KUnit documentation
and Documentation/dev-tools/kunit/architecture.rst for the details of kernel
built-in vs. command line testing.
To use these KUnit doctests, the following must be enabled::
CONFIG_KUNIT
Kernel hacking -> Kernel Testing and Coverage -> KUnit - Enable support for unit tests
CONFIG_RUST_KERNEL_DOCTESTS
Kernel hacking -> Rust hacking -> Doctests for the `kernel` crate
in the kernel config system.
KUnit tests are documentation tests
***********************************
These documentation tests are typically examples of usage of any item (e.g.
function, struct, module...).
They are very convenient because they are just written alongside the
documentation. For instance:
.. code-block:: rust
/// Sums two numbers.
///
/// ```
/// assert_eq!(mymod::f(10, 20), 30);
/// ```
pub fn f(a: i32, b: i32) -> i32 {
a + b
}
In userspace, the tests are collected and run via ``rustdoc``. Using the tool
as-is would be useful already, since it allows verifying that examples compile
(thus enforcing they are kept in sync with the code they document) and as well
as running those that do not depend on in-kernel APIs.
For the kernel, however, these tests get transformed into KUnit test suites.
This means that doctests get compiled as Rust kernel objects, allowing them to
run against a built kernel.
A benefit of this KUnit integration is that Rust doctests get to reuse existing
testing facilities. For instance, the kernel log would look like::
KTAP version 1
1..1
KTAP version 1
# Subtest: rust_doctests_kernel
1..59
# rust_doctest_kernel_build_assert_rs_0.location: rust/kernel/build_assert.rs:13
ok 1 rust_doctest_kernel_build_assert_rs_0
# rust_doctest_kernel_build_assert_rs_1.location: rust/kernel/build_assert.rs:56
ok 2 rust_doctest_kernel_build_assert_rs_1
# rust_doctest_kernel_init_rs_0.location: rust/kernel/init.rs:122
ok 3 rust_doctest_kernel_init_rs_0
...
# rust_doctest_kernel_types_rs_2.location: rust/kernel/types.rs:150
ok 59 rust_doctest_kernel_types_rs_2
# rust_doctests_kernel: pass:59 fail:0 skip:0 total:59
# Totals: pass:59 fail:0 skip:0 total:59
ok 1 rust_doctests_kernel
Tests using the `? <https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator>`_
operator are also supported as usual, e.g.:
.. code-block:: rust
/// ```
/// # use kernel::{spawn_work_item, workqueue};
/// spawn_work_item!(workqueue::system(), || pr_info!("x\n"))?;
/// # Ok::<(), Error>(())
/// ```
The tests are also compiled with Clippy under ``CLIPPY=1``, just like normal
code, thus also benefitting from extra linting.
In order for developers to easily see which line of doctest code caused a
failure, a KTAP diagnostic line is printed to the log. This contains the
location (file and line) of the original test (i.e. instead of the location in
the generated Rust file)::
# rust_doctest_kernel_types_rs_2.location: rust/kernel/types.rs:150
Rust tests appear to assert using the usual ``assert!`` and ``assert_eq!``
macros from the Rust standard library (``core``). We provide a custom version
that forwards the call to KUnit instead. Importantly, these macros do not
require passing context, unlike those for KUnit testing (i.e.
``struct kunit *``). This makes them easier to use, and readers of the
documentation do not need to care about which testing framework is used. In
addition, it may allow us to test third-party code more easily in the future.
A current limitation is that KUnit does not support assertions in other tasks.
Thus, we presently simply print an error to the kernel log if an assertion
actually failed. Additionally, doctests are not run for nonpublic functions.
Since these tests are examples, i.e. they are part of the documentation, they
should generally be written like "real code". Thus, for example, instead of
using ``unwrap()`` or ``expect()``, use the ``?`` operator. For more background,
please see:
https://rust.docs.kernel.org/kernel/error/type.Result.html#error-codes-in-c-and-rust
The ``#[test]`` tests
---------------------
Additionally, there are the ``#[test]`` tests. Like for documentation tests,
these are also fairly similar to what you would expect from userspace, and they
are also mapped to KUnit.
These tests are introduced by the ``kunit_tests`` procedural macro, which takes
the name of the test suite as an argument.
Each test suite should be guarded by a Kconfig option in
``rust/kernel/Kconfig.test``.
For instance, assume we want to test the function ``f`` from the documentation
tests section. We could write, in the same file where we have our function:
.. code-block:: rust
#[cfg(CONFIG_RUST_MYMOD_KUNIT_TEST)]
#[kunit_tests(rust_kernel_mymod)]
mod tests {
use super::*;
#[test]
fn test_f() {
assert_eq!(f(10, 20), 30);
}
}
And if we run it, the kernel log would look like::
KTAP version 1
# Subtest: rust_kernel_mymod
# speed: normal
1..1
# test_f.speed: normal
ok 1 test_f
ok 1 rust_kernel_mymod
Like documentation tests, the ``assert!`` and ``assert_eq!`` macros are mapped
back to KUnit and do not panic. Similarly, the
`? <https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator>`_
operator is supported, i.e. the test functions may return either nothing (i.e.
the unit type ``()``) or ``Result`` (i.e. any ``Result<T, E>``). For instance:
.. code-block:: rust
#[cfg(CONFIG_RUST_MYMOD_KUNIT_TEST)]
#[kunit_tests(rust_kernel_mymod)]
mod tests {
use super::*;
#[test]
fn test_g() -> Result {
let x = g()?;
assert_eq!(x, 30);
Ok(())
}
}
If we run the test and the call to ``g`` fails, then the kernel log would show::
KTAP version 1
# Subtest: rust_kernel_mymod
# speed: normal
1..1
# test_g: ASSERTION FAILED at rust/kernel/lib.rs:335
Expected is_test_result_ok(test_g()) to be true, but is false
# test_g.speed: normal
not ok 1 test_g
not ok 1 rust_kernel_mymod
If a ``#[test]`` test could be useful as an example for the user, then please
use a documentation test instead. Even edge cases of an API, e.g. error or
boundary cases, can be interesting to show in examples.
The ``rusttest`` host tests
---------------------------
These are userspace tests that can be built and run in the host (i.e. the one
that performs the kernel build) using the ``rusttest`` Make target::
make LLVM=1 rusttest
This requires the kernel ``.config``.
Currently, they are mostly used for testing the ``macros`` crate's examples.
The Kselftests
--------------
Kselftests are also available in the ``tools/testing/selftests/rust`` folder.
The kernel config options required for the tests are listed in the
``tools/testing/selftests/rust/config`` file and can be included with the aid
of the ``merge_config.sh`` script::
./scripts/kconfig/merge_config.sh .config tools/testing/selftests/rust/config
The kselftests are built within the kernel source tree and are intended to
be executed on a system that is running the same kernel.
Once a kernel matching the source tree has been installed and booted, the
tests can be compiled and executed using the following command::
make TARGETS="rust" kselftest
Refer to Documentation/dev-tools/kselftest.rst for the general Kselftest
documentation.