From 863bd2e4f2031fd8a57bb7bc932b359955dfa947 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 10 May 2021 21:27:43 +0100 Subject: [PATCH] rust: Rename libmodule to libmacros Renaming to libmacros allows us to potentially have more procedural macros in the future without introducing additional crates. Having all our proc macros in a single crate allows potential code sharing between macros, and it simplifies the build process compared to multiple crates. Multiple crate does allow parallel compilation, but given the limited number of proc macros at this stage, the compilation time difference is negligible. Even when we have a big `macros` crate we can still use multiple codegen units while keep them in a single crate. Signed-off-by: Gary Guo --- rust/Makefile | 24 +++--- rust/kernel/module_param.rs | 4 +- rust/kernel/prelude.rs | 2 +- rust/macros/lib.rs | 132 ++++++++++++++++++++++++++++++ rust/{ => macros}/module.rs | 117 -------------------------- scripts/generate_rust_analyzer.py | 8 +- 6 files changed, 151 insertions(+), 136 deletions(-) create mode 100644 rust/macros/lib.rs rename rust/{ => macros}/module.rs (86%) diff --git a/rust/Makefile b/rust/Makefile index 7621e92b3dc70f..9e94e687007217 100644 --- a/rust/Makefile +++ b/rust/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_RUST) += core.o compiler_builtins.o helpers.o extra-$(CONFIG_RUST) += exports_core_generated.h -extra-$(CONFIG_RUST) += libmodule.so +extra-$(CONFIG_RUST) += libmacros.so extra-$(CONFIG_RUST) += bindings_generated.rs obj-$(CONFIG_RUST) += alloc.o kernel.o @@ -35,11 +35,11 @@ quiet_cmd_rustdoc = RUSTDOC $< --output $(objtree)/rust/doc --crate-name $(subst rustdoc-,,$@) \ -Fmissing-docs @$(objtree)/include/generated/rustc_cfg $< -rustdoc: rustdoc-module rustdoc-compiler_builtins rustdoc-kernel +rustdoc: rustdoc-macros rustdoc-compiler_builtins rustdoc-kernel -rustdoc-module: private rustdoc_target_flags = --crate-type proc-macro \ +rustdoc-macros: private rustdoc_target_flags = --crate-type proc-macro \ --extern proc_macro -rustdoc-module: $(srctree)/rust/module.rs FORCE +rustdoc-macros: $(srctree)/rust/macros/lib.rs FORCE $(call if_changed,rustdoc_host) rustdoc-compiler_builtins: $(srctree)/rust/compiler_builtins.rs FORCE @@ -47,9 +47,9 @@ rustdoc-compiler_builtins: $(srctree)/rust/compiler_builtins.rs FORCE rustdoc-kernel: private rustdoc_target_flags = --extern alloc \ --extern build_error \ - --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 + --extern macros=$(objtree)/rust/libmacros.so +rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-macros \ + $(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE $(call if_changed,rustdoc) ifdef CONFIG_CC_IS_CLANG @@ -126,9 +126,9 @@ quiet_cmd_rustc_procmacro = $(RUSTC_OR_CLIPPY_QUIET) P $@ sed -i '/^\#/d' $(depfile) # Procedural macros can only be used with the `rustc` that compiled it. -# Therefore, to get `libmodule.so` automatically recompiled when the compiler +# Therefore, to get `libmacros.so` automatically recompiled when the compiler # version changes, we add `core.o` as a dependency (even if it is not needed). -$(objtree)/rust/libmodule.so: $(srctree)/rust/module.rs \ +$(objtree)/rust/libmacros.so: $(srctree)/rust/macros/lib.rs \ $(objtree)/rust/core.o FORCE $(call if_changed_dep,rustc_procmacro) @@ -169,11 +169,11 @@ $(objtree)/rust/build_error.o: $(srctree)/rust/build_error.rs \ $(objtree)/rust/compiler_builtins.o FORCE $(call if_changed_dep,rustc_library) -# ICE on `--extern module`: https://github.com/rust-lang/rust/issues/56935 +# ICE on `--extern macros`: https://github.com/rust-lang/rust/issues/56935 $(objtree)/rust/kernel.o: private rustc_target_flags = --extern alloc \ --extern build_error \ - --extern module=$(objtree)/rust/libmodule.so + --extern macros=$(objtree)/rust/libmacros.so $(objtree)/rust/kernel.o: $(srctree)/rust/kernel/lib.rs $(objtree)/rust/alloc.o \ $(objtree)/rust/build_error.o \ - $(objtree)/rust/libmodule.so $(objtree)/rust/bindings_generated.rs FORCE + $(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs FORCE $(call if_changed_dep,rustc_library) diff --git a/rust/kernel/module_param.rs b/rust/kernel/module_param.rs index c70f61367347f3..fc6a6b01c588db 100644 --- a/rust/kernel/module_param.rs +++ b/rust/kernel/module_param.rs @@ -52,7 +52,7 @@ pub trait ModuleParam: core::fmt::Display + core::marker::Sized { /// Get the current value of the parameter for use in the kernel module. /// /// This function should not be used directly. Instead use the wrapper - /// `read` which will be generated by [`module::module`]. + /// `read` which will be generated by [`macros::module`]. fn value(&self) -> &Self::Value; /// Set the module parameter from a string. @@ -428,7 +428,7 @@ impl ModuleParam /// A C-style string parameter. /// /// The Rust version of the [`charp`] parameter. This type is meant to be -/// used by the [`module::module`] macro, not handled directly. Instead use the +/// used by the [`macros::module`] macro, not handled directly. Instead use the /// `read` method generated by that macro. /// /// [`charp`]: ../../../include/linux/moduleparam.h diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index f0835fb19b2f7b..8a6161e2b0e262 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -15,7 +15,7 @@ pub use alloc::{borrow::ToOwned, string::String}; pub use super::build_assert; -pub use module::{module, module_misc_device}; +pub use macros::{module, module_misc_device}; pub use super::{pr_alert, pr_cont, pr_crit, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs new file mode 100644 index 00000000000000..07f1015157f913 --- /dev/null +++ b/rust/macros/lib.rs @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Crate for all kernel procedural macros. + +#![deny(clippy::complexity)] +#![deny(clippy::correctness)] +#![deny(clippy::perf)] +#![deny(clippy::style)] + +mod module; + +use proc_macro::TokenStream; + +/// Declares a kernel module. +/// +/// The `type` argument should be a type which implements the [`KernelModule`] +/// trait. Also accepts various forms of kernel metadata. +/// +/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h) +/// +/// [`KernelModule`]: ../kernel/trait.KernelModule.html +/// +/// # Examples +/// +/// ```rust,no_run +/// use kernel::prelude::*; +/// +/// module!{ +/// type: MyKernelModule, +/// name: b"my_kernel_module", +/// author: b"Rust for Linux Contributors", +/// description: b"My very own kernel module!", +/// license: b"GPL v2", +/// params: { +/// my_i32: i32 { +/// default: 42, +/// permissions: 0o000, +/// description: b"Example of i32", +/// }, +/// writeable_i32: i32 { +/// default: 42, +/// permissions: 0o644, +/// description: b"Example of i32", +/// }, +/// }, +/// } +/// +/// struct MyKernelModule; +/// +/// impl KernelModule for MyKernelModule { +/// fn init() -> Result { +/// // If the parameter is writeable, then the kparam lock must be +/// // taken to read the parameter: +/// { +/// let lock = THIS_MODULE.kernel_param_lock(); +/// pr_info!("i32 param is: {}\n", writeable_i32.read(&lock)); +/// } +/// // If the parameter is read only, it can be read without locking +/// // the kernel parameters: +/// pr_info!("i32 param is: {}\n", my_i32.read()); +/// Ok(MyKernelModule) +/// } +/// } +/// ``` +/// +/// # Supported argument types +/// - `type`: type which implements the [`KernelModule`] trait (required). +/// - `name`: byte array of the name of the kernel module (required). +/// - `author`: byte array of the author of the kernel module. +/// - `description`: byte array of the description of the kernel module. +/// - `license`: byte array of the license of the kernel module (required). +/// - `alias`: byte array of alias name of the kernel module. +/// - `alias_rtnl_link`: byte array of the `rtnl_link_alias` of the kernel module (mutually exclusive with `alias`). +/// - `params`: parameters for the kernel module, as described below. +/// +/// # Supported parameter types +/// +/// - `bool`: Corresponds to C `bool` param type. +/// - `i8`: No equivalent C param type. +/// - `u8`: Corresponds to C `char` param type. +/// - `i16`: Corresponds to C `short` param type. +/// - `u16`: Corresponds to C `ushort` param type. +/// - `i32`: Corresponds to C `int` param type. +/// - `u32`: Corresponds to C `uint` param type. +/// - `i64`: No equivalent C param type. +/// - `u64`: Corresponds to C `ullong` param type. +/// - `isize`: No equivalent C param type. +/// - `usize`: No equivalent C param type. +/// - `str`: Corresponds to C `charp` param type. Reading returns a byte slice. +/// - `ArrayParam`: Corresponds to C parameters created using `module_param_array`. An array +/// of `T`'s of length at **most** `N`. +/// +/// `invbool` is unsupported: it was only ever used in a few modules. +/// Consider using a `bool` and inverting the logic instead. +#[proc_macro] +pub fn module(ts: TokenStream) -> TokenStream { + module::module(ts) +} + +/// Declares a kernel module that exposes a single misc device. +/// +/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts +/// various forms of kernel metadata. +/// +/// C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h) +/// +/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html +/// +/// # Examples +/// +/// ```rust,no_run +/// use kernel::prelude::*; +/// +/// module_misc_device! { +/// type: MyFile, +/// name: b"my_miscdev_kernel_module", +/// author: b"Rust for Linux Contributors", +/// description: b"My very own misc device kernel module!", +/// license: b"GPL v2", +/// } +/// +/// #[derive(Default)] +/// struct MyFile; +/// +/// impl kernel::file_operations::FileOperations for MyFile { +/// kernel::declare_file_operations!(); +/// } +/// ``` +#[proc_macro] +pub fn module_misc_device(ts: TokenStream) -> TokenStream { + module::module_misc_device(ts) +} diff --git a/rust/module.rs b/rust/macros/module.rs similarity index 86% rename from rust/module.rs rename to rust/macros/module.rs index 9a7009644d3cd7..c950e758354f0e 100644 --- a/rust/module.rs +++ b/rust/macros/module.rs @@ -1,14 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -//! Proc macro crate implementing the [`module!`] magic. -//! -//! C header: [`include/linux/moduleparam.h`](../../../include/linux/moduleparam.h) - -#![deny(clippy::complexity)] -#![deny(clippy::correctness)] -#![deny(clippy::perf)] -#![deny(clippy::style)] - use proc_macro::{token_stream, Delimiter, Group, TokenStream, TokenTree}; fn try_ident(it: &mut token_stream::IntoIter) -> Option { @@ -399,86 +390,6 @@ impl ModuleInfo { } } -/// Declares a kernel module. -/// -/// The `type` argument should be a type which implements the [`KernelModule`] -/// trait. Also accepts various forms of kernel metadata. -/// -/// [`KernelModule`]: ../kernel/trait.KernelModule.html -/// -/// # Examples -/// -/// ```rust,no_run -/// use kernel::prelude::*; -/// -/// module!{ -/// type: MyKernelModule, -/// name: b"my_kernel_module", -/// author: b"Rust for Linux Contributors", -/// description: b"My very own kernel module!", -/// license: b"GPL v2", -/// params: { -/// my_i32: i32 { -/// default: 42, -/// permissions: 0o000, -/// description: b"Example of i32", -/// }, -/// writeable_i32: i32 { -/// default: 42, -/// permissions: 0o644, -/// description: b"Example of i32", -/// }, -/// }, -/// } -/// -/// struct MyKernelModule; -/// -/// impl KernelModule for MyKernelModule { -/// fn init() -> Result { -/// // If the parameter is writeable, then the kparam lock must be -/// // taken to read the parameter: -/// { -/// let lock = THIS_MODULE.kernel_param_lock(); -/// pr_info!("i32 param is: {}\n", writeable_i32.read(&lock)); -/// } -/// // If the parameter is read only, it can be read without locking -/// // the kernel parameters: -/// pr_info!("i32 param is: {}\n", my_i32.read()); -/// Ok(MyKernelModule) -/// } -/// } -/// ``` -/// -/// # Supported argument types -/// - `type`: type which implements the [`KernelModule`] trait (required). -/// - `name`: byte array of the name of the kernel module (required). -/// - `author`: byte array of the author of the kernel module. -/// - `description`: byte array of the description of the kernel module. -/// - `license`: byte array of the license of the kernel module (required). -/// - `alias`: byte array of alias name of the kernel module. -/// - `alias_rtnl_link`: byte array of the `rtnl_link_alias` of the kernel module (mutually exclusive with `alias`). -/// - `params`: parameters for the kernel module, as described below. -/// -/// # Supported parameter types -/// -/// - `bool`: Corresponds to C `bool` param type. -/// - `i8`: No equivalent C param type. -/// - `u8`: Corresponds to C `char` param type. -/// - `i16`: Corresponds to C `short` param type. -/// - `u16`: Corresponds to C `ushort` param type. -/// - `i32`: Corresponds to C `int` param type. -/// - `u32`: Corresponds to C `uint` param type. -/// - `i64`: No equivalent C param type. -/// - `u64`: Corresponds to C `ullong` param type. -/// - `isize`: No equivalent C param type. -/// - `usize`: No equivalent C param type. -/// - `str`: Corresponds to C `charp` param type. Reading returns a byte slice. -/// - `ArrayParam`: Corresponds to C parameters created using `module_param_array`. An array -/// of `T`'s of length at **most** `N`. -/// -/// `invbool` is unsupported: it was only ever used in a few modules. -/// Consider using a `bool` and inverting the logic instead. -#[proc_macro] pub fn module(ts: TokenStream) -> TokenStream { let mut it = ts.into_iter(); @@ -775,34 +686,6 @@ pub fn module(ts: TokenStream) -> TokenStream { ).parse().expect("Error parsing formatted string into token stream.") } -/// Declares a kernel module that exposes a single misc device. -/// -/// The `type` argument should be a type which implements the [`FileOpener`] trait. Also accepts -/// various forms of kernel metadata. -/// -/// [`FileOpener`]: ../kernel/file_operations/trait.FileOpener.html -/// -/// # Examples -/// -/// ```rust,no_run -/// use kernel::prelude::*; -/// -/// module_misc_device! { -/// type: MyFile, -/// name: b"my_miscdev_kernel_module", -/// author: b"Rust for Linux Contributors", -/// description: b"My very own misc device kernel module!", -/// license: b"GPL v2", -/// } -/// -/// #[derive(Default)] -/// struct MyFile; -/// -/// impl kernel::file_operations::FileOperations for MyFile { -/// kernel::declare_file_operations!(); -/// } -/// ``` -#[proc_macro] pub fn module_misc_device(ts: TokenStream) -> TokenStream { let mut it = ts.into_iter(); diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py index e88d4fc9eb3000..2a7b22be642bbe 100755 --- a/scripts/generate_rust_analyzer.py +++ b/scripts/generate_rust_analyzer.py @@ -63,13 +63,13 @@ def append_crate(display_name, root_module, is_workspace_member, deps, cfg): ) append_crate( - "module", - srctree / "rust" / "module.rs", + "macros", + srctree / "rust" / "macros" / "lib.rs", True, [], [], ) - crates[-1]["proc_macro_dylib_path"] = "rust/libmodule.so" + crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so" append_crate( "build_error", @@ -83,7 +83,7 @@ def append_crate(display_name, root_module, is_workspace_member, deps, cfg): "kernel", srctree / "rust" / "kernel" / "lib.rs", True, - ["core", "alloc", "module", "build_error"], + ["core", "alloc", "macros", "build_error"], cfg, ) crates[-1]["env"]["RUST_BINDINGS_FILE"] = str(bindings_file.resolve(True))