From 8584c7831e862ecbaa0c289eeabe2b8cc1a3cc16 Mon Sep 17 00:00:00 2001 From: Miguel Ojeda Date: Thu, 18 Feb 2021 04:26:41 +0100 Subject: [PATCH] Documentation support Requires nightly 2021-02-20 due to added support for argument files, see https://github.com/rust-lang/rust/pull/82261. Signed-off-by: Miguel Ojeda --- .github/workflows/ci.yaml | 11 ++- Documentation/doc-guide/kernel-doc.rst | 3 + Documentation/process/changes.rst | 7 ++ Documentation/rust/coding.rst | 5 ++ Documentation/rust/docs.rst | 109 +++++++++++++++++++++++++ Documentation/rust/index.rst | 1 + Documentation/rust/quick-start.rst | 18 +++- Makefile | 13 +++ rust/.gitignore | 1 + rust/Makefile | 24 ++++++ rust/kernel/lib.rs | 3 + 11 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 Documentation/rust/docs.rst diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f0ce044d63d0a8..89fbd854c3f55f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,7 +13,7 @@ jobs: arch: [x86_64, arm64] toolchain: [gcc, clang, llvm] config: [debug, release] - rustc: [2021-01-24] + rustc: [2021-02-20] output: [src] # [src, build] install: [rustup] # [rustup, standalone] sysroot: [common] # [common, custom] @@ -27,7 +27,7 @@ jobs: - arch: x86_64 toolchain: gcc config: debug - rustc: 2021-01-31 + rustc: 2021-02-20 output: build install: rustup sysroot: custom @@ -35,7 +35,7 @@ jobs: - arch: arm64 toolchain: clang config: release - rustc: 2021-02-07 + rustc: 2021-02-20 output: build install: standalone sysroot: common @@ -43,7 +43,7 @@ jobs: - arch: x86_64 toolchain: llvm config: debug - rustc: 2021-02-11 + rustc: 2021-02-20 output: build install: standalone sysroot: custom @@ -177,3 +177,6 @@ jobs: # Report - run: ls -l ${{ env.BUILD_DIR }}drivers/char/rust_example.o ${{ env.BUILD_DIR }}drivers/char/rust_example_3.ko ${{ env.BUILD_DIR }}rust/*.o ${{ env.BUILD_DIR }}vmlinux ${{ env.BUILD_DIR }}${{ env.IMAGE_PATH }} - run: size ${{ env.BUILD_DIR }}drivers/char/rust_example.o ${{ env.BUILD_DIR }}drivers/char/rust_example_3.ko ${{ env.BUILD_DIR }}rust/*.o ${{ env.BUILD_DIR }}vmlinux + + # Docs + - run: make ${{ env.MAKE_ARCH }} ${{ env.MAKE_CROSS_COMPILE }} ${{ env.MAKE_TOOLCHAIN }} ${{ env.MAKE_OUTPUT }} ${{ env.MAKE_SYSROOT }} -j3 rustdoc diff --git a/Documentation/doc-guide/kernel-doc.rst b/Documentation/doc-guide/kernel-doc.rst index 79aaa55d6bcf2b..c655fdb9c04276 100644 --- a/Documentation/doc-guide/kernel-doc.rst +++ b/Documentation/doc-guide/kernel-doc.rst @@ -11,6 +11,9 @@ when it is embedded in source files. reasons. The kernel source contains tens of thousands of kernel-doc comments. Please stick to the style described here. +.. note:: kernel-doc does not cover Rust code: please see + :ref:`Documentation/rust/docs.rst ` instead. + The kernel-doc structure is extracted from the comments, and proper `Sphinx C Domain`_ function and type descriptions with anchors are generated from them. The descriptions are filtered for special kernel-doc diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index 61a1152b20be52..4b6ba5458706ac 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -58,6 +58,7 @@ iptables 1.4.2 iptables -V openssl & libcrypto 1.0.0 openssl version bc 1.06.95 bc --version Sphinx\ [#f1]_ 1.3 sphinx-build --version +rustdoc (optional) nightly rustdoc --version ====================== =============== ======================================== .. [#f1] Sphinx is needed only to build the Kernel documentation @@ -332,6 +333,12 @@ Sphinx Please see :ref:`sphinx_install` in :ref:`Documentation/doc-guide/sphinx.rst ` for details about Sphinx requirements. +rustdoc +------- + +``rustdoc`` is used to generate Rust documentation. Please see +:ref:`Documentation/rust/docs.rst ` for more information. + Getting updated software ======================== diff --git a/Documentation/rust/coding.rst b/Documentation/rust/coding.rst index d0d73bfa66436b..13586b4cfff76c 100644 --- a/Documentation/rust/coding.rst +++ b/Documentation/rust/coding.rst @@ -39,3 +39,8 @@ configuration: #[cfg(CONFIG_X="m")] // `CONFIG_X` is enabled as a module (`m`) #[cfg(not(CONFIG_X))] // `CONFIG_X` is disabled + +Documentation +------------- + +Please see :ref:`Documentation/rust/docs.rst `. diff --git a/Documentation/rust/docs.rst b/Documentation/rust/docs.rst new file mode 100644 index 00000000000000..58c5f98ccb3538 --- /dev/null +++ b/Documentation/rust/docs.rst @@ -0,0 +1,109 @@ +.. _rust_docs: + +Docs +==== + +Rust kernel code is not documented like C kernel code (i.e. via kernel-doc). +Instead, we use the usual system for documenting Rust code: the ``rustdoc`` +tool, which uses Markdown (a *very* lightweight markup language). + +This document describes how to make the most out of the kernel documentation +for Rust. + + +Reading the docs +---------------- + +An advantage of using Markdown is that it attempts to make text look almost as +you would have written it in plain text. This makes the documentation quite +pleasant to read even in its source form. + +However, the generated HTML docs produced by ``rustdoc`` provide a *very* nice +experience, including integrated instant search, clickable items (types, +functions, constants, etc. -- including to all the standard Rust library ones +that we use in the kernel, e.g. ``core``), categorization, links to the source +code, etc. + +Like for the rest of the kernel documentation, pregenerated HTML docs for +the libraries (crates) inside ``rust/`` that are used by the rest of the kernel +are available at `kernel.org`_. + +// TODO: link when ready + +.. _kernel.org: http://kernel.org/ + +Otherwise, you can generate them locally. This is quite fast (same order as +compiling the code itself) and you do not need any special tools or environment. +This has the added advantage that they will be tailored to your particular +kernel configuration. To generate them, simply use the ``rustdoc`` target with +the same invocation you use for compilation, e.g.:: + + make ARCH=... CROSS_COMPILE=... CC=... -j... rustdoc + + +Writing the docs +---------------- + +If you already know Markdown, learning how to write Rust documentation will be +a breeze. If not, understanding the basics is a matter of minutes reading other +code. There are also many guides available out there, a particularly nice one +is at `GitHub`_. + +.. _GitHub: https://guides.github.com/features/mastering-markdown/#syntax + +This is how a well-documented Rust function may look like (derived from the Rust +standard library):: + + /// 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 common conventions +(that we also follow 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 the preconditions needed for a call to be + safe 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. + +* If providing examples of usage would help readers, they must be written in + a section called ``Examples``. + +* Rust items (functions, types, constants...) will be automatically linked + (``rustdoc`` will find out the URL for you). + +* Following the Rust standard library conventions, 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 also 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`_. + +.. _book: https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html diff --git a/Documentation/rust/index.rst b/Documentation/rust/index.rst index fbb1938663ad83..257cf2b200b8ae 100644 --- a/Documentation/rust/index.rst +++ b/Documentation/rust/index.rst @@ -9,6 +9,7 @@ read the :ref:`Documentation/rust/quick-start.rst ` guide. quick-start coding + docs arch-support .. only:: subproject and html diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst index c513ea3380a4b5..7a44d2577d5631 100644 --- a/Documentation/rust/quick-start.rst +++ b/Documentation/rust/quick-start.rst @@ -21,7 +21,7 @@ rustc ***** A recent *nightly* Rust toolchain (with, at least, ``rustc``) is required, -e.g. ``nightly-2021-01-24``. Our goal is to use a stable toolchain as soon +e.g. ``nightly-2021-02-20``. Our goal is to use a stable toolchain as soon as possible, but for the moment we depend on a handful of nightly features. If you are using ``rustup``, run:: @@ -80,6 +80,22 @@ the component manually:: The standalone installers also come with ``rustfmt``. +rustdoc +******* + +Optionally, if you install the ``rustdoc`` tool, then you will be able +to generate HTML documentation for Rust code, including for the libraries +(crates) inside ``rust/`` that are used by the rest of the kernel. + +If you are using ``rustup``, its ``default`` profile already installs the tool, +so you should be good to go. If you are using another profile, you can install +the component manually:: + + rustup component add rustdoc + +The standalone installers also come with ``rustdoc``. + + Configuration ------------- diff --git a/Makefile b/Makefile index d0b6521128f4e6..199103e26449bc 100644 --- a/Makefile +++ b/Makefile @@ -1669,6 +1669,9 @@ help: @echo 'Documentation targets:' @$(MAKE) -f $(srctree)/Documentation/Makefile dochelp @echo '' + @echo ' rustdoc - Generate Rust documentation' + @echo ' (requires kernel .config)' + @echo '' @echo 'Architecture specific targets ($(SRCARCH)):' @$(if $(archhelp),$(archhelp),\ echo ' No architecture specific help defined for $(SRCARCH)') @@ -1722,6 +1725,16 @@ PHONY += $(DOC_TARGETS) $(DOC_TARGETS): $(Q)$(MAKE) $(build)=Documentation $@ + +# Rust documentation target +# --------------------------------------------------------------------------- + +# Using the singular to avoid running afoul of `no-dot-config-targets`. +PHONY += rustdoc +rustdoc: prepare0 + $(Q)$(MAKE) $(build)=rust $@ + + # Misc # --------------------------------------------------------------------------- diff --git a/rust/.gitignore b/rust/.gitignore index 554ba815dfc75a..8875e08ed0b17e 100644 --- a/rust/.gitignore +++ b/rust/.gitignore @@ -2,3 +2,4 @@ bindings_generated.rs exports_*_generated.h +doc/ \ No newline at end of file diff --git a/rust/Makefile b/rust/Makefile index 5726bc10e5ac43..fb52c15389fbf5 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -6,6 +6,30 @@ extra-$(CONFIG_RUST) += bindings_generated.rs libmodule.so extra-$(CONFIG_RUST) += exports_core_generated.h exports_alloc_generated.h extra-$(CONFIG_RUST) += exports_kernel_generated.h +RUSTDOC = rustdoc + +rustdoc_flags = $(filter-out --emit=% --out-dir=%, $(rustc_flags)) + +quiet_cmd_rustdoc = RUSTDOC $< + cmd_rustdoc = \ + RUST_BINDINGS_FILE=$(abspath $(objtree)/rust/bindings_generated.rs) \ + $(RUSTDOC) $(rustdoc_flags) $(rustdoc_target_flags) -L $(objtree)/rust/ \ + --output $(objtree)/rust/doc --crate-name $(subst rustdoc-,,$@) \ + -Wmissing-docs @$(objtree)/include/generated/rustc_cfg $< + +rustdoc: rustdoc-module rustdoc-kernel + +rustdoc-module: rustdoc_target_flags = --crate-type proc-macro \ + --extern proc_macro +rustdoc-module: $(srctree)/rust/module.rs FORCE + $(call if_changed,rustdoc) + +rustdoc-kernel: rustdoc_target_flags = --extern alloc \ + --extern module=$(objtree)/rust/libmodule.so +rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-module \ + $(objtree)/rust/libmodule.so $(objtree)/rust/bindings_generated.rs FORCE + $(call if_changed,rustdoc) + ifdef CONFIG_CC_IS_CLANG bindgen_c_flags = $(c_flags) else diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 972c7ad8a1a8c2..64e1e124710e15 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -13,7 +13,10 @@ compile_error!("Missing kernel configuration for conditional compilation"); use core::panic::PanicInfo; mod allocator; + +#[doc(hidden)] pub mod bindings; + pub mod c_types; pub mod chrdev; mod error;