All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nick Desaulniers <ndesaulniers@google.com>
To: Miguel Ojeda <ojeda@kernel.org>,
	Masahiro Yamada <masahiroy@kernel.org>,
	linux-kbuild@vger.kernel.org
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	rust-for-linux@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, Alex Gaynor <alex.gaynor@gmail.com>,
	Finn Behrens <me@kloenk.de>,
	Adam Bratschi-Kaye <ark.email@gmail.com>,
	Wedson Almeida Filho <wedsonaf@google.com>,
	Michael Ellerman <mpe@ellerman.id.au>,
	Sven Van Asbroeck <thesven73@gmail.com>,
	Gary Guo <gary@garyguo.net>,
	Boris-Chengbiao Zhou <bobo1239@web.de>,
	Boqun Feng <boqun.feng@gmail.com>,
	Douglas Su <d0u9.su@outlook.com>,
	Dariusz Sosnowski <dsosnowski@dsosnowski.pl>,
	Antonio Terceiro <antonio.terceiro@linaro.org>,
	Daniel Xu <dxu@dxuuu.xyz>
Subject: Re: [PATCH 15/19] Kbuild: add Rust support
Date: Tue, 7 Dec 2021 14:45:03 -0800	[thread overview]
Message-ID: <CAKwvOd=7QTUH69+ZbT7e8einvgcosTbDkyohmPaUBv6_y8RfrQ@mail.gmail.com> (raw)
In-Reply-To: <20211206140313.5653-16-ojeda@kernel.org>

"(/.On Mon, Dec 6, 2021 at 6:07 AM Miguel Ojeda <ojeda@kernel.org> wrote:
>

... snip ...

Miguel and team,
I'm happy to see progress here! Just some quick notes after a first pass.

Testing this series applied on mainline, I see:
$ make LLVM=1 -j72 defconfig
$ grep RUST .config
CONFIG_HAS_RUST=y
CONFIG_RUSTC_VERSION=14000
# CONFIG_RUST is not set
...
$ make LLVM=1 -j72 menuconfig
# enable CONFIG_RUST
$ make LLVM=1
...
  CALL    scripts/checksyscalls.sh
error: @path is unstable - use -Z unstable-options to enable its use

error: @path is unstable - use -Z unstable-options to enable its use
$ rustc --version
rustc 1.40.0 (73528e339 2019-12-16)

Can we update some Kconfig checks to fix that?

> --- a/Makefile
> +++ b/Makefile
> @@ -120,6 +120,13 @@ endif
>
>  export KBUILD_CHECKSRC
>
> +# Enable "clippy" (a linter) as part of the Rust compilation.
> +#
> +# Use 'make CLIPPY=1' to enable it.
> +ifeq ("$(origin CLIPPY)", "command line")
> +  KBUILD_CLIPPY := $(CLIPPY)
> +endif
> +

KBUILD_CLIPPY isn't used until ...

>  # Use make M=dir or set the environment variable KBUILD_EXTMOD to specify the
>  # directory of external module to build. Setting M= takes precedence.
>  ifeq ("$(origin M)", "command line")
> @@ -267,7 +274,7 @@ no-dot-config-targets := $(clean-targets) \
>                          cscope gtags TAGS tags help% %docs check% coccicheck \
>                          $(version_h) headers headers_% archheaders archscripts \
>                          %asm-generic kernelversion %src-pkg dt_binding_check \
> -                        outputmakefile
> +                        outputmakefile rustfmt rustfmtcheck
>  # Installation targets should not require compiler. Unfortunately, vdso_install
>  # is an exception where build artifacts may be updated. This must be fixed.
>  no-compiler-targets := $(no-dot-config-targets) install dtbs_install \
> @@ -461,6 +468,12 @@ OBJDUMP            = $(CROSS_COMPILE)objdump
>  READELF                = $(CROSS_COMPILE)readelf
>  STRIP          = $(CROSS_COMPILE)strip
>  endif
> +RUSTC          = rustc
> +RUSTDOC                = rustdoc
> +RUSTFMT                = rustfmt
> +CLIPPY_DRIVER  = clippy-driver
> +BINDGEN                = bindgen
> +CARGO          = cargo
>  PAHOLE         = pahole
>  RESOLVE_BTFIDS = $(objtree)/tools/bpf/resolve_btfids/resolve_btfids
>  LEX            = flex
> @@ -486,9 +499,11 @@ CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
>                   -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF)
>  NOSTDINC_FLAGS :=
>  CFLAGS_MODULE   =
> +RUSTFLAGS_MODULE =
>  AFLAGS_MODULE   =
>  LDFLAGS_MODULE  =
>  CFLAGS_KERNEL  =
> +RUSTFLAGS_KERNEL =
>  AFLAGS_KERNEL  =
>  LDFLAGS_vmlinux =
>
> @@ -517,15 +532,46 @@ KBUILD_CFLAGS   := -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs \
>                    -Werror=return-type -Wno-format-security \
>                    -std=gnu89
>  KBUILD_CPPFLAGS := -D__KERNEL__
> +KBUILD_RUST_TARGET := $(srctree)/arch/$(SRCARCH)/rust/target.json
> +KBUILD_RUSTFLAGS := --emit=dep-info,obj,metadata --edition=2021 \
> +                    -Cpanic=abort -Cembed-bitcode=n -Clto=n -Crpath=n \
> +                    -Cforce-unwind-tables=n -Ccodegen-units=1 \
> +                    -Zbinary_dep_depinfo=y -Zsymbol-mangling-version=v0 \
> +                    -Dunsafe_op_in_unsafe_fn -Drust_2018_idioms \
> +                    -Dunreachable_pub -Dnon_ascii_idents \
> +                    -Wmissing_docs \
> +                    -Drustdoc::missing_crate_level_docs \
> +                    -Dclippy::correctness -Dclippy::style -Dclippy::suspicious \
> +                    -Dclippy::complexity -Dclippy::perf -Dclippy::float_arithmetic \
> +                    -Dclippy::let_unit_value -Dclippy::mut_mut \
> +                    -Dclippy::needless_bitwise_bool -Dclippy::needless_continue \
> +                    -Wclippy::dbg_macro

Consider putting clippy specific flags in their own variable, and/or
just adding them to KBUILD_RUSTFLAGS only when clippy is actually
being used.

>  KBUILD_AFLAGS_KERNEL :=
>  KBUILD_CFLAGS_KERNEL :=
> +KBUILD_RUSTFLAGS_KERNEL :=
>  KBUILD_AFLAGS_MODULE  := -DMODULE
>  KBUILD_CFLAGS_MODULE  := -DMODULE
> +KBUILD_RUSTFLAGS_MODULE := --cfg MODULE
>  KBUILD_LDFLAGS_MODULE :=
>  KBUILD_LDFLAGS :=
>  CLANG_FLAGS :=
>
> +ifeq ($(KBUILD_CLIPPY),1)
> +       RUSTC_OR_CLIPPY_QUIET := CLIPPY
> +       RUSTC_OR_CLIPPY = $(CLIPPY_DRIVER)
> +else
> +       RUSTC_OR_CLIPPY_QUIET := RUSTC
> +       RUSTC_OR_CLIPPY = $(RUSTC)
> +endif

... here. Should we sink the check for origin CLIPPY? Can we also
match how we check for LLVM=1 rather than checking the variables
origin?  Especially since KBUILD_CLIPPY isn't exported, it seems it's
not used outside of this file, IIUC?

> +
> +ifdef RUST_LIB_SRC
> +       export RUST_LIB_SRC
> +endif
> +
> +export RUSTC_BOOTSTRAP := 1

Is this used in a different patch in the series? ^

> +
>  export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC
> +export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN CARGO
>  export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL
>  export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
>  export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD
> @@ -533,9 +579,10 @@ export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
>
>  export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDFLAGS
>  export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
> +export KBUILD_RUST_TARGET KBUILD_RUSTFLAGS RUSTFLAGS_KERNEL RUSTFLAGS_MODULE
>  export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
> -export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
> -export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
> +export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_RUSTFLAGS_MODULE KBUILD_LDFLAGS_MODULE
> +export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTFLAGS_KERNEL
>  export PAHOLE_FLAGS
>
>  # Files to ignore in find ... statements
> @@ -727,7 +774,7 @@ $(KCONFIG_CONFIG):
>  #
>  # Do not use $(call cmd,...) here. That would suppress prompts from syncconfig,
>  # so you cannot notice that Kconfig is waiting for the user input.
> -%/config/auto.conf %/config/auto.conf.cmd %/generated/autoconf.h: $(KCONFIG_CONFIG)
> +%/config/auto.conf %/config/auto.conf.cmd %/generated/autoconf.h %/generated/rustc_cfg: $(KCONFIG_CONFIG)
>         $(Q)$(kecho) "  SYNC    $@"
>         $(Q)$(MAKE) -f $(srctree)/Makefile syncconfig
>  else # !may-sync-config
> @@ -756,11 +803,27 @@ KBUILD_CFLAGS     += $(call cc-disable-warning, address-of-packed-member)
>
>  ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
>  KBUILD_CFLAGS += -O2
> +KBUILD_RUSTFLAGS_OPT_LEVEL_MAP := 2
>  else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
>  KBUILD_CFLAGS += -O3
> +KBUILD_RUSTFLAGS_OPT_LEVEL_MAP := 3
>  else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
>  KBUILD_CFLAGS += -Os
> -endif
> +KBUILD_RUSTFLAGS_OPT_LEVEL_MAP := z

If z and s are distinct opt levels, then rustc should really be using
s rather than z.  IME, z has created larger images than s due to LLVM
aggressively emitting libcalls, regardless of the cost of call setup.
See also commit a75bb4eb9e56 ("Revert "kbuild: use -Oz instead of -Os
when using clang")

> +endif
> +
> +# Always set `debug-assertions` and `overflow-checks` because their default
> +# depends on `opt-level` and `debug-assertions`, respectively.
> +KBUILD_RUSTFLAGS += -Cdebug-assertions=$(if $(CONFIG_RUST_DEBUG_ASSERTIONS),y,n)
> +KBUILD_RUSTFLAGS += -Coverflow-checks=$(if $(CONFIG_RUST_OVERFLOW_CHECKS),y,n)
> +KBUILD_RUSTFLAGS += -Copt-level=$\
> +       $(if $(CONFIG_RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C),$(KBUILD_RUSTFLAGS_OPT_LEVEL_MAP))$\
> +       $(if $(CONFIG_RUST_OPT_LEVEL_0),0)$\
> +       $(if $(CONFIG_RUST_OPT_LEVEL_1),1)$\
> +       $(if $(CONFIG_RUST_OPT_LEVEL_2),2)$\
> +       $(if $(CONFIG_RUST_OPT_LEVEL_3),3)$\
> +       $(if $(CONFIG_RUST_OPT_LEVEL_S),s)$\
> +       $(if $(CONFIG_RUST_OPT_LEVEL_Z),z)

I'm still not a fan of this separate configurability for optimization
level differing from C.

>
>  # Tell gcc to never replace conditional load with a non-conditional one
>  ifdef CONFIG_CC_IS_GCC
> @@ -791,6 +854,9 @@ KBUILD_CFLAGS += $(stackp-flags-y)
>  KBUILD_CFLAGS-$(CONFIG_WERROR) += -Werror
>  KBUILD_CFLAGS += $(KBUILD_CFLAGS-y) $(CONFIG_CC_IMPLICIT_FALLTHROUGH)
>
> +KBUILD_RUSTFLAGS-$(CONFIG_WERROR) += -Dwarnings
> +KBUILD_RUSTFLAGS += $(KBUILD_RUSTFLAGS-y)
> +
>  ifdef CONFIG_CC_IS_CLANG
>  KBUILD_CPPFLAGS += -Qunused-arguments
>  # The kernel builds with '-std=gnu89' so use of GNU extensions is acceptable.
> @@ -812,6 +878,7 @@ KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable)
>
>  ifdef CONFIG_FRAME_POINTER
>  KBUILD_CFLAGS  += -fno-omit-frame-pointer -fno-optimize-sibling-calls
> +KBUILD_RUSTFLAGS += -Cforce-frame-pointers=y
>  else
>  # Some targets (ARM with Thumb2, for example), can't be built with frame
>  # pointers.  For those, we don't have FUNCTION_TRACER automatically
> @@ -1022,10 +1089,11 @@ include $(addprefix $(srctree)/, $(include-y))
>  # Do not add $(call cc-option,...) below this line. When you build the kernel
>  # from the clean source tree, the GCC plugins do not exist at this point.
>
> -# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
> +# Add user supplied CPPFLAGS, AFLAGS, CFLAGS and RUSTFLAGS as the last assignments
>  KBUILD_CPPFLAGS += $(KCPPFLAGS)
>  KBUILD_AFLAGS   += $(KAFLAGS)
>  KBUILD_CFLAGS   += $(KCFLAGS)
> +KBUILD_RUSTFLAGS += $(KRUSTFLAGS)
>
>  KBUILD_LDFLAGS_MODULE += --build-id=sha1
>  LDFLAGS_vmlinux += --build-id=sha1
> @@ -1095,6 +1163,11 @@ ifeq ($(KBUILD_EXTMOD),)
>  core-y                 += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/
>  core-$(CONFIG_BLOCK)   += block/
>
> +# Keep this one as an `ifdef` block since its `Makefile` runs `rustc`.
> +ifdef CONFIG_RUST
> +core-y                 += rust/
> +endif
> +
>  vmlinux-dirs   := $(patsubst %/,%,$(filter %/, \
>                      $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
>                      $(libs-y) $(libs-m)))
> @@ -1195,6 +1268,9 @@ archprepare: outputmakefile archheaders archscripts scripts include/config/kerne
>  prepare0: archprepare
>         $(Q)$(MAKE) $(build)=scripts/mod
>         $(Q)$(MAKE) $(build)=.
> +ifdef CONFIG_RUST
> +       $(Q)$(MAKE) $(build)=rust
> +endif
>
>  # All the preparing..
>  prepare: prepare0
> @@ -1495,7 +1571,7 @@ endif # CONFIG_MODULES
>  # Directories & files removed with 'make clean'
>  CLEAN_FILES += include/ksym vmlinux.symvers modules-only.symvers \
>                modules.builtin modules.builtin.modinfo modules.nsdeps \
> -              compile_commands.json .thinlto-cache
> +              compile_commands.json .thinlto-cache rust/test rust/doc
>
>  # Directories & files removed with 'make mrproper'
>  MRPROPER_FILES += include/config include/generated          \
> @@ -1506,7 +1582,8 @@ MRPROPER_FILES += include/config include/generated          \
>                   certs/signing_key.pem certs/signing_key.x509 \
>                   certs/x509.genkey \
>                   vmlinux-gdb.py \
> -                 *.spec
> +                 *.spec \
> +                 rust/*_generated.h rust/*_generated.rs rust/libmacros.so
>
>  # clean - Delete most, but leave enough to build external modules
>  #
> @@ -1618,6 +1695,17 @@ help:
>         @echo  '  kselftest-merge   - Merge all the config dependencies of'
>         @echo  '                      kselftest to existing .config.'
>         @echo  ''
> +       @echo  'Rust targets:'
> +       @echo  '  rustfmt         - Reformat all the Rust code in the kernel'
> +       @echo  '  rustfmtcheck    - Checks if all the Rust code in the kernel'
> +       @echo  '                    is formatted, printing a diff otherwise.'
> +       @echo  '  rustdoc         - Generate Rust documentation'
> +       @echo  '                    (requires kernel .config)'
> +       @echo  '  rusttest        - Runs the Rust tests'
> +       @echo  '                    (requires kernel .config; downloads external repos)'
> +       @echo  '  rust-analyzer   - Generate rust-project.json rust-analyzer support file'
> +       @echo  '                    (requires kernel .config)'
> +       @echo  ''
>         @$(if $(dtstree), \
>                 echo 'Devicetree:'; \
>                 echo '* dtbs             - Build device tree blobs for enabled boards'; \
> @@ -1689,6 +1777,47 @@ PHONY += $(DOC_TARGETS)
>  $(DOC_TARGETS):
>         $(Q)$(MAKE) $(build)=Documentation $@
>
> +
> +# Rust targets
> +# ---------------------------------------------------------------------------
> +
> +# Documentation target
> +#
> +# Using the singular to avoid running afoul of `no-dot-config-targets`.
> +PHONY += rustdoc
> +rustdoc: prepare0
> +       $(Q)$(MAKE) $(build)=rust $@
> +
> +# Testing target
> +PHONY += rusttest
> +rusttest: prepare0
> +       $(Q)$(MAKE) $(build)=rust $@
> +
> +# Formatting targets
> +PHONY += rustfmt rustfmtcheck
> +
> +# We skip `rust/alloc` since we want to minimize the diff w.r.t. upstream.
> +#
> +# We match using absolute paths since `find` does not resolve them
> +# when matching, which is a problem when e.g. `srctree` is `..`.
> +# We `grep` afterwards in order to remove the directory entry itself.
> +rustfmt:
> +       $(Q)find $(abs_srctree) -type f -name '*.rs' \
> +               -o -path $(abs_srctree)/rust/alloc -prune \
> +               -o -path $(abs_objtree)/rust/test -prune \
> +               | grep -Fv $(abs_srctree)/rust/alloc \
> +               | grep -Fv $(abs_objtree)/rust/test \
> +               | grep -Fv generated \
> +               | xargs $(RUSTFMT) $(rustfmt_flags)
> +
> +rustfmtcheck: rustfmt_flags = --check
> +rustfmtcheck: rustfmt
> +
> +# IDE support targets
> +PHONY += rust-analyzer
> +rust-analyzer: prepare0
> +       $(Q)$(MAKE) $(build)=rust $@
> +
>  # Misc
>  # ---------------------------------------------------------------------------
>
> @@ -1856,6 +1985,7 @@ clean: $(clean-dirs)
>         $(call cmd,rmfiles)
>         @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
>                 \( -name '*.[aios]' -o -name '*.ko' -o -name '.*.cmd' \
> +               -o -name '*.rmeta' \
>                 -o -name '*.ko.*' \
>                 -o -name '*.dtb' -o -name '*.dtbo' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
>                 -o -name '*.dwo' -o -name '*.lst' \
> diff --git a/arch/arm/rust/target.json b/arch/arm/rust/target.json
> new file mode 100644
> index 000000000000..3f845b8221dc
> --- /dev/null
> +++ b/arch/arm/rust/target.json
> @@ -0,0 +1,27 @@
> +{
> +  "arch": "arm",
> +  "crt-static-respected": true,
> +  "data-layout": "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64",
> +  "dynamic-linking": true,
> +  "env": "gnu",
> +  "executables": true,
> +  "features": "+strict-align,+v6",
> +  "function-sections": false,
> +  "has-elf-tls": true,
> +  "has-rpath": true,
> +  "linker-is-gnu": true,
> +  "llvm-target": "arm-unknown-linux-gnueabi",
> +  "max-atomic-width": 64,
> +  "os": "linux",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "target-family": "unix",
> +  "target-mcount": "\u0001__gnu_mcount_nc",
> +  "target-pointer-width": "32"
> +}

oh boy. I wonder which configs change the above values? ;) Can rustc
still override these via command line flags?

> diff --git a/arch/arm64/rust/target.json b/arch/arm64/rust/target.json
> new file mode 100644
> index 000000000000..09a264df26c7
> --- /dev/null
> +++ b/arch/arm64/rust/target.json
> @@ -0,0 +1,34 @@
> +{
> +  "arch": "aarch64",
> +  "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
> +  "disable-redzone": true,
> +  "emit-debug-gdb-scripts": false,
> +  "env": "gnu",
> +  "features": "+strict-align,+neon,+fp-armv8",
> +  "frame-pointer": "always",
> +  "function-sections": false,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "aarch64-unknown-none",
> +  "max-atomic-width": 128,
> +  "needs-plt": true,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m64"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "stack-probes": {
> +    "kind": "none"
> +  },
> +  "target-c-int-width": "32",
> +  "target-endian": "little",
> +  "target-pointer-width": "64",
> +  "vendor": ""
> +}
> diff --git a/arch/powerpc/rust/target.json b/arch/powerpc/rust/target.json
> new file mode 100644
> index 000000000000..2420c8e6a520
> --- /dev/null
> +++ b/arch/powerpc/rust/target.json
> @@ -0,0 +1,29 @@
> +{
> +  "arch": "powerpc64",
> +  "code-model": "large",
> +  "cpu": "ppc64le",
> +  "data-layout": "e-m:e-i64:64-n32:64",
> +  "env": "gnu",
> +  "features": "-altivec,-vsx,-hard-float",
> +  "function-sections": false,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "powerpc64le-elf",
> +  "max-atomic-width": 64,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m64"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "target-family": "unix",
> +  "target-mcount": "_mcount",
> +  "target-endian": "little",
> +  "target-pointer-width": "64"
> +}
> diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
> index 8a107ed18b0d..0487db1e54c6 100644
> --- a/arch/riscv/Makefile
> +++ b/arch/riscv/Makefile
> @@ -52,6 +52,7 @@ riscv-march-$(CONFIG_FPU)             := $(riscv-march-y)fd
>  riscv-march-$(CONFIG_RISCV_ISA_C)      := $(riscv-march-y)c
>  KBUILD_CFLAGS += -march=$(subst fd,,$(riscv-march-y))
>  KBUILD_AFLAGS += -march=$(riscv-march-y)
> +KBUILD_RUST_TARGET := $(srctree)/arch/riscv/rust/$(subst fd,,$(riscv-march-y)).json
>
>  KBUILD_CFLAGS += -mno-save-restore
>  KBUILD_CFLAGS += -DCONFIG_PAGE_OFFSET=$(CONFIG_PAGE_OFFSET)
> diff --git a/arch/riscv/rust/rv32ima.json b/arch/riscv/rust/rv32ima.json
> new file mode 100644
> index 000000000000..bcdda88c1604
> --- /dev/null
> +++ b/arch/riscv/rust/rv32ima.json
> @@ -0,0 +1,36 @@
> +{
> +  "arch": "riscv32",
> +  "code-model": "medium",
> +  "cpu": "generic-rv32",
> +  "data-layout": "e-m:e-p:32:32-i64:64-n32-S128",
> +  "disable-redzone": true,
> +  "emit-debug-gdb-scripts": false,
> +  "env": "gnu",
> +  "features": "+m,+a",
> +  "frame-pointer": "always",
> +  "function-sections": false,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "riscv32",
> +  "max-atomic-width": 32,
> +  "needs-plt": true,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m32"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "stack-probes": {
> +    "kind": "none"
> +  },
> +  "target-c-int-width": "32",
> +  "target-endian": "little",
> +  "target-pointer-width": "32",
> +  "vendor": ""
> +}
> diff --git a/arch/riscv/rust/rv32imac.json b/arch/riscv/rust/rv32imac.json
> new file mode 100644
> index 000000000000..45873c10a5c3
> --- /dev/null
> +++ b/arch/riscv/rust/rv32imac.json
> @@ -0,0 +1,36 @@
> +{
> +  "arch": "riscv32",
> +  "code-model": "medium",
> +  "cpu": "generic-rv32",
> +  "data-layout": "e-m:e-p:32:32-i64:64-n32-S128",
> +  "disable-redzone": true,
> +  "emit-debug-gdb-scripts": false,
> +  "env": "gnu",
> +  "features": "+m,+a,+c",
> +  "frame-pointer": "always",
> +  "function-sections": false,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "riscv32",
> +  "max-atomic-width": 32,
> +  "needs-plt": true,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m32"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "stack-probes": {
> +    "kind": "none"
> +  },
> +  "target-c-int-width": "32",
> +  "target-endian": "little",
> +  "target-pointer-width": "32",
> +  "vendor": ""
> +}
> diff --git a/arch/riscv/rust/rv64ima.json b/arch/riscv/rust/rv64ima.json
> new file mode 100644
> index 000000000000..853d758c5461
> --- /dev/null
> +++ b/arch/riscv/rust/rv64ima.json
> @@ -0,0 +1,36 @@
> +{
> +  "arch": "riscv64",
> +  "code-model": "medium",
> +  "cpu": "generic-rv64",
> +  "data-layout": "e-m:e-p:64:64-i64:64-i128:128-n64-S128",
> +  "disable-redzone": true,
> +  "emit-debug-gdb-scripts": false,
> +  "env": "gnu",
> +  "features": "+m,+a",
> +  "frame-pointer": "always",
> +  "function-sections": false,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "riscv64",
> +  "max-atomic-width": 64,
> +  "needs-plt": true,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m64"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "stack-probes": {
> +    "kind": "none"
> +  },
> +  "target-c-int-width": "32",
> +  "target-endian": "little",
> +  "target-pointer-width": "64",
> +  "vendor": ""
> +}
> diff --git a/arch/riscv/rust/rv64imac.json b/arch/riscv/rust/rv64imac.json
> new file mode 100644
> index 000000000000..ce50ee8e8c93
> --- /dev/null
> +++ b/arch/riscv/rust/rv64imac.json
> @@ -0,0 +1,36 @@
> +{
> +  "arch": "riscv64",
> +  "code-model": "medium",
> +  "cpu": "generic-rv64",
> +  "data-layout": "e-m:e-p:64:64-i64:64-i128:128-n64-S128",
> +  "disable-redzone": true,
> +  "emit-debug-gdb-scripts": false,
> +  "env": "gnu",
> +  "features": "+m,+a,+c",
> +  "frame-pointer": "always",
> +  "function-sections": false,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "riscv64",
> +  "max-atomic-width": 64,
> +  "needs-plt": true,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m64"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "stack-probes": {
> +    "kind": "none"
> +  },
> +  "target-c-int-width": "32",
> +  "target-endian": "little",
> +  "target-pointer-width": "64",
> +  "vendor": ""
> +}
> diff --git a/arch/x86/rust/target.json b/arch/x86/rust/target.json
> new file mode 100644
> index 000000000000..379cf39e8941
> --- /dev/null
> +++ b/arch/x86/rust/target.json
> @@ -0,0 +1,36 @@
> +{
> +  "arch": "x86_64",
> +  "code-model": "kernel",
> +  "cpu": "x86-64",
> +  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
> +  "disable-redzone": true,
> +  "emit-debug-gdb-scripts": false,
> +  "env": "gnu",
> +  "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float",
> +  "frame-pointer": "always",
> +  "function-sections": false,
> +  "linker-flavor": "gcc",
> +  "linker-is-gnu": true,
> +  "llvm-target": "x86_64-elf",
> +  "max-atomic-width": 64,
> +  "needs-plt": true,
> +  "os": "none",
> +  "panic-strategy": "abort",
> +  "position-independent-executables": true,
> +  "pre-link-args": {
> +    "gcc": [
> +      "-Wl,--as-needed",
> +      "-Wl,-z,noexecstack",
> +      "-m64"
> +    ]
> +  },
> +  "relocation-model": "static",
> +  "relro-level": "full",
> +  "stack-probes": {
> +    "kind": "none"
> +  },
> +  "target-c-int-width": "32",
> +  "target-endian": "little",
> +  "target-pointer-width": "64",
> +  "vendor": "unknown"
> +}
> diff --git a/init/Kconfig b/init/Kconfig
> index 4b7bac10c72d..03d3c21e28a3 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -60,6 +60,15 @@ config LLD_VERSION
>         default $(ld-version) if LD_IS_LLD
>         default 0
>
> +config HAS_RUST
> +       depends on ARM64 || CPU_32v6 || CPU_32v6K || (PPC64 && CPU_LITTLE_ENDIAN) || X86_64 || RISCV
> +       def_bool $(success,$(RUSTC) --version)
> +
> +config RUSTC_VERSION
> +       depends on HAS_RUST
> +       int
> +       default $(shell,$(srctree)/scripts/rust-version.sh $(RUSTC))
> +
>  config CC_CAN_LINK
>         bool
>         default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(m64-flag)) if 64BIT
> @@ -142,7 +151,8 @@ config WERROR
>         default COMPILE_TEST
>         help
>           A kernel build should not cause any compiler warnings, and this
> -         enables the '-Werror' flag to enforce that rule by default.
> +         enables the '-Werror' (for C) and '-Dwarnings' (for Rust) flags
> +         to enforce that rule by default.
>
>           However, if you have a new (or very old) compiler with odd and
>           unusual warnings, or you have some architecture with problems,
> @@ -2044,6 +2054,25 @@ config PROFILING
>           Say Y here to enable the extended profiling support mechanisms used
>           by profilers.
>
> +config RUST
> +       bool "Rust support"
> +       depends on HAS_RUST
> +       depends on !COMPILE_TEST
> +       depends on !MODVERSIONS
> +       default n
> +       help
> +         Enables Rust support in the kernel.
> +
> +         This allows other Rust-related options, like drivers written in Rust,
> +         to be selected.
> +
> +         It is also required to be able to load external kernel modules
> +         written in Rust.
> +
> +         See Documentation/rust/ for more information.
> +
> +         If unsure, say N.
> +
>  #
>  # Place an empty function call at each tracepoint site. Can be
>  # dynamically changed for a probe function.
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 5c12bde10996..361379695f18 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2650,6 +2650,150 @@ config HYPERV_TESTING
>
>  endmenu # "Kernel Testing and Coverage"
>
> +menu "Rust hacking"
> +
> +config RUST_DEBUG_ASSERTIONS
> +       bool "Debug assertions"
> +       default n
> +       depends on RUST
> +       help
> +         Enables rustc's `-Cdebug-assertions` codegen option.
> +
> +         This flag lets you turn `cfg(debug_assertions)` conditional
> +         compilation on or off. This can be used to enable extra debugging
> +         code in development but not in production. For example, it controls
> +         the behavior of the standard library's `debug_assert!` macro.
> +
> +         Note that this will apply to all Rust code, including `core`.
> +
> +         If unsure, say N.
> +
> +config RUST_OVERFLOW_CHECKS
> +       bool "Overflow checks"
> +       default y

So this is like turning on -fsanitize=signed-integer-overflow and
-fsanitize=unsigned-integer-overflow by default?

> +       depends on RUST
> +       help
> +         Enables rustc's `-Coverflow-checks` codegen option.
> +
> +         This flag allows you to control the behavior of runtime integer
> +         overflow. When overflow-checks are enabled, a panic will occur
> +         on overflow.

A rust panic or a kernel panic?

> +
> +         Note that this will apply to all Rust code, including `core`.
> +
> +         If unsure, say Y.
> +
> +choice
> +       prompt "Optimization level"
> +       default RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C
> +       depends on RUST
> +       help
> +         Controls rustc's `-Copt-level` codegen option.
> +
> +         This flag controls the optimization level.
> +
> +         If unsure, say "Similar as chosen for C".
> +
> +config RUST_OPT_LEVEL_SIMILAR_AS_CHOSEN_FOR_C
> +       bool "Similar as chosen for C"
> +       help
> +         This choice will pick a similar optimization level as chosen in
> +         the "Compiler optimization level" for C:
> +
> +             -O2 is currently mapped to -Copt-level=2
> +             -O3 is currently mapped to -Copt-level=3
> +             -Os is currently mapped to -Copt-level=z
> +
> +         The mapping may change over time to follow the intended semantics
> +         of the choice for C as sensibly as possible.
> +
> +         This is the default.

This should really be the only option here. I still don't see the
point of allowing wacky combinations of configs where we differ from C
code.  The more combinations will just frustrate randconfig builds.

> +
> +config RUST_OPT_LEVEL_0
> +       bool "No optimizations (-Copt-level=0)"
> +       help
> +         Not recommended for most purposes. It may come in handy for debugging
> +         suspected optimizer bugs, unexpected undefined behavior, etc.
> +
> +         Note that this level will *not* enable debug assertions nor overflow
> +         checks on its own (like it happens when interacting with rustc
> +         directly). Use the corresponding configuration options to control
> +         that instead, orthogonally.
> +
> +         Note this level may cause excessive stack usage, which can lead to stack
> +         overflow and subsequent crashes.
> +
> +config RUST_OPT_LEVEL_1
> +       bool "Basic optimizations (-Copt-level=1)"
> +       help
> +         Useful for debugging without getting too lost, but without
> +         the overhead and boilerplate of no optimizations at all.
> +
> +         Note this level may cause excessive stack usage, which can lead to stack
> +         overflow and subsequent crashes.
> +
> +config RUST_OPT_LEVEL_2
> +       bool "Some optimizations (-Copt-level=2)"
> +       help
> +         The sensible choice in most cases.
> +
> +config RUST_OPT_LEVEL_3
> +       bool "All optimizations (-Copt-level=3)"
> +       help
> +         Yet more performance (hopefully).
> +
> +config RUST_OPT_LEVEL_S
> +       bool "Optimize for size (-Copt-level=s)"
> +       help
> +         Smaller kernel, ideally without too much performance loss.
> +
> +config RUST_OPT_LEVEL_Z
> +       bool "Optimize for size, no loop vectorization (-Copt-level=z)"
> +       help
> +         Like the previous level, but also turn off loop vectorization.
> +
> +endchoice
> +
> +choice
> +       prompt "Build-time assertions"
> +       default RUST_BUILD_ASSERT_ALLOW if RUST_OPT_LEVEL_0
> +       default RUST_BUILD_ASSERT_DENY if !RUST_OPT_LEVEL_0
> +       depends on RUST
> +       help
> +         Controls how are `build_error!` and `build_assert!` handled during build.
> +
> +         If calls to them exist in the binary, it may indicate a violated invariant
> +         or that the optimizer failed to verify the invariant during compilation.
> +         You can choose to abort compilation or ignore them during build and let the
> +         check be carried to runtime.
> +
> +         If optimizations are turned off, you cannot select "Deny".
> +
> +         If unsure, say "Deny".
> +
> +config RUST_BUILD_ASSERT_ALLOW
> +       bool "Allow"
> +       help
> +         Unoptimized calls to `build_error!` will be converted to `panic!`
> +         and checked at runtime.
> +
> +config RUST_BUILD_ASSERT_WARN
> +       bool "Warn"
> +       help
> +         Unoptimized calls to `build_error!` will be converted to `panic!`
> +         and checked at runtime, but warnings will be generated when building.
> +
> +config RUST_BUILD_ASSERT_DENY
> +       bool "Deny"
> +       depends on !RUST_OPT_LEVEL_0
> +       help
> +         Unoptimized calls to `build_error!` will abort compilation.
> +
> +endchoice
> +
> +
> +endmenu # "Rust"
> +
>  source "Documentation/Kconfig"
>
>  endmenu # Kernel hacking
> diff --git a/rust/.gitignore b/rust/.gitignore
> new file mode 100644
> index 000000000000..168cb26a31b9
> --- /dev/null
> +++ b/rust/.gitignore
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +bindings_generated.rs
> +bindings_helpers_generated.rs
> +exports_*_generated.h
> +doc/
> +test/
> diff --git a/rust/Makefile b/rust/Makefile
> new file mode 100644
> index 000000000000..2d08314e7031
> --- /dev/null
> +++ b/rust/Makefile
> @@ -0,0 +1,353 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-$(CONFIG_RUST) += core.o compiler_builtins.o helpers.o
> +extra-$(CONFIG_RUST) += exports_core_generated.h
> +
> +extra-$(CONFIG_RUST) += libmacros.so
> +
> +extra-$(CONFIG_RUST) += bindings_generated.rs bindings_helpers_generated.rs
> +obj-$(CONFIG_RUST) += alloc.o kernel.o
> +extra-$(CONFIG_RUST) += exports_alloc_generated.h exports_kernel_generated.h
> +
> +ifdef CONFIG_RUST_BUILD_ASSERT_DENY
> +extra-$(CONFIG_RUST) += build_error.o
> +else
> +obj-$(CONFIG_RUST) += build_error.o
> +endif
> +
> +obj-$(CONFIG_RUST) += exports.o
> +
> +ifeq ($(quiet),silent_)
> +cargo_quiet=-q
> +rust_test_quiet=-q
> +rustdoc_test_quiet=--test-args -q
> +else ifeq ($(quiet),quiet_)
> +rust_test_quiet=-q
> +rustdoc_test_quiet=--test-args -q
> +else
> +cargo_quiet=--verbose
> +endif
> +
> +core-cfgs = \
> +    --cfg no_fp_fmt_parse
> +
> +alloc-cfgs = \
> +    --cfg no_global_oom_handling \
> +    --cfg no_rc \
> +    --cfg no_sync
> +
> +quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
> +      cmd_rustdoc = \
> +       OBJTREE=$(abspath $(objtree)) \
> +       $(RUSTDOC) $(if $(rustdoc_host),,$(rust_cross_flags)) \
> +               $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rust_flags))) \
> +               $(rustc_target_flags) -L $(objtree)/rust \
> +               --output $(objtree)/rust/doc --crate-name $(subst rustdoc-,,$@) \
> +               @$(objtree)/include/generated/rustc_cfg $<
> +
> +rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins rustdoc-alloc rustdoc-kernel
> +       $(Q)cp $(srctree)/Documentation/rust/assets/* $(objtree)/rust/doc
> +
> +rustdoc-macros: private rustdoc_host = yes
> +rustdoc-macros: private rustc_target_flags = --crate-type proc-macro \
> +    --extern proc_macro
> +rustdoc-macros: $(srctree)/rust/macros/lib.rs FORCE
> +       $(call if_changed,rustdoc)
> +
> +rustdoc-compiler_builtins: $(srctree)/rust/compiler_builtins.rs rustdoc-core FORCE
> +       $(call if_changed,rustdoc)
> +
> +# We need to allow `rustdoc::broken_intra_doc_links` because some
> +# `no_global_oom_handling` functions refer to non-`no_global_oom_handling`
> +# functions. Ideally `rustdoc` would have a way to distinguish broken links
> +# due to things that are "configured out" vs. entirely non-existing ones.
> +rustdoc-alloc: private rustc_target_flags = $(alloc-cfgs) \
> +    -Arustdoc::broken_intra_doc_links
> +rustdoc-alloc: $(srctree)/rust/alloc/lib.rs rustdoc-core \
> +    rustdoc-compiler_builtins FORCE
> +       $(call if_changed,rustdoc)
> +
> +rustdoc-kernel: private rustc_target_flags = --extern alloc \
> +    --extern build_error \
> +    --extern macros=$(objtree)/rust/libmacros.so
> +rustdoc-kernel: $(srctree)/rust/kernel/lib.rs rustdoc-core \
> +    rustdoc-macros rustdoc-compiler_builtins rustdoc-alloc \
> +    $(objtree)/rust/libmacros.so $(objtree)/rust/bindings_generated.rs \
> +    $(objtree)/rust/bindings_helpers_generated.rs FORCE
> +       $(call if_changed,rustdoc)
> +
> +quiet_cmd_rustc_test_library = RUSTC TL $<
> +      cmd_rustc_test_library = \
> +       OBJTREE=$(abspath $(objtree)) \
> +       $(RUSTC) $(filter-out --sysroot=%, $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rust_flags)))) \
> +               $(rustc_target_flags) --crate-type $(if $(rustc_test_library_proc),proc-macro,rlib) \
> +               --out-dir $(objtree)/rust/test/ --cfg testlib \
> +               --sysroot $(objtree)/rust/test/sysroot \
> +               -L $(objtree)/rust/test/ --crate-name $(subst rusttest-,,$(subst rusttestlib-,,$@)) $<
> +
> +rusttestlib-build_error: $(srctree)/rust/build_error.rs rusttest-prepare FORCE
> +       $(call if_changed,rustc_test_library)
> +
> +rusttestlib-macros: private rustc_target_flags = --extern proc_macro
> +rusttestlib-macros: private rustc_test_library_proc = yes
> +rusttestlib-macros: $(srctree)/rust/macros/lib.rs rusttest-prepare FORCE
> +       $(call if_changed,rustc_test_library)
> +
> +quiet_cmd_rustdoc_test = RUSTDOC T $<
> +      cmd_rustdoc_test = \
> +       OBJTREE=$(abspath $(objtree)) \
> +       $(RUSTDOC) --test $(filter-out --sysroot=%, $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rust_flags)))) \

Seeing repeated filter-out rules makes me wonder if we could DRY up
some of these rules with function definitions?

> +               $(rustc_target_flags) $(rustdoc_test_target_flags) \
> +               --sysroot $(objtree)/rust/test/sysroot $(rustdoc_test_quiet) \
> +               -L $(objtree)/rust/test \
> +               --output $(objtree)/rust/doc --crate-name $(subst rusttest-,,$@) \
> +               @$(objtree)/include/generated/rustc_cfg $<
> +
> +# We cannot use `-Zpanic-abort-tests` because some tests are dynamic,
> +# so for the moment we skip `-Cpanic=abort`.
> +quiet_cmd_rustc_test = RUSTC T  $<
> +      cmd_rustc_test = \
> +       OBJTREE=$(abspath $(objtree)) \
> +       $(RUSTC) --test $(filter-out --sysroot=%, $(filter-out -Cpanic=abort, $(filter-out --emit=%, $(rust_flags)))) \
> +               $(rustc_target_flags) --out-dir $(objtree)/rust/test \
> +               --sysroot $(objtree)/rust/test/sysroot \
> +               -L $(objtree)/rust/test/ --crate-name $(subst rusttest-,,$@) $<; \
> +       $(objtree)/rust/test/$(subst rusttest-,,$@) $(rust_test_quiet) \
> +               $(rustc_test_run_flags)
> +
> +rusttest: rusttest-macros rusttest-kernel
> +
> +# This prepares a custom sysroot with our custom `alloc` instead of
> +# the standard one.
> +#
> +# This requires several hacks:
> +#   - Unlike `core` and `alloc`, `std` depends on more than a dozen crates,
> +#     including third-party crates that need to be downloaded, plus custom
> +#     `build.rs` steps. Thus hardcoding things here is not maintainable.
> +#   - `cargo` knows how to build the standard library, but it is an unstable
> +#     feature so far (`-Zbuild-std`).
> +#   - `cargo` only considers the use case of building the standard library
> +#     to use it in a given package. Thus we need to create a dummy package
> +#     and pick the generated libraries from there.
> +#   - Since we only keep a subset of upstream `alloc` in-tree, we need
> +#     to recreate it on the fly by putting our sources on top.
> +#   - The usual ways of modifying the dependency graph in `cargo` do not seem
> +#     to apply for the `-Zbuild-std` steps, thus we have to mislead it
> +#     by modifying the sources in the sysroot.
> +#   - To avoid messing with the user's Rust installation, we create a clone
> +#     of the sysroot. However, `cargo` ignores `RUSTFLAGS` in the `-Zbuild-std`
> +#     steps, thus we use a wrapper binary passed via `RUSTC` to pass the flag.

Are there links to corresponding feature requests upstream so that one
day we can drop technical debt here?  In particular, having to create
a custom sysroot as is done here isn't particularly pretty.

I'd be curious if we could remove the dependency on cargo for rust tests.

> +#
> +# In the future, we hope to avoid the whole ordeal by either:
> +#   - Making the `test` crate not depend on `std` (either improving upstream
> +#     or having our own custom crate).
> +#   - Making the tests run in kernel space (requires the previous point).
> +#   - Making `std` and friends be more like a "normal" crate, so that
> +#     `-Zbuild-std` and related hacks are not needed.
> +quiet_cmd_rustsysroot = RUSTSYSROOT
> +      cmd_rustsysroot = \
> +       rm -rf $(objtree)/rust/test; \
> +       mkdir -p $(objtree)/rust/test; \
> +       cp -a $(rustc_sysroot) $(objtree)/rust/test/sysroot; \
> +       cp -r $(srctree)/rust/alloc/* \
> +               $(objtree)/rust/test/sysroot/lib/rustlib/src/rust/library/alloc/src; \
> +       echo '\#!/bin/sh' > $(objtree)/rust/test/rustc_sysroot; \
> +       echo "$(RUSTC) --sysroot=$(abspath $(objtree)/rust/test/sysroot) \"\$$@\"" \
> +               >> $(objtree)/rust/test/rustc_sysroot; \
> +       chmod u+x $(objtree)/rust/test/rustc_sysroot; \
> +       $(CARGO) -q new $(objtree)/rust/test/dummy; \
> +       RUSTC=$(objtree)/rust/test/rustc_sysroot $(CARGO) $(cargo_quiet) \
> +               test -Zbuild-std --target $(rustc_host_target) \
> +               --manifest-path $(objtree)/rust/test/dummy/Cargo.toml; \
> +       rm $(objtree)/rust/test/sysroot/lib/rustlib/$(rustc_host_target)/lib/*; \
> +       cp $(objtree)/rust/test/dummy/target/$(rustc_host_target)/debug/deps/* \
> +               $(objtree)/rust/test/sysroot/lib/rustlib/$(rustc_host_target)/lib
> +
> +rusttest-prepare: FORCE
> +       $(call if_changed,rustsysroot)
> +
> +rusttest-macros: private rustc_target_flags = --extern proc_macro
> +rusttest-macros: private rustdoc_test_target_flags = --crate-type proc-macro
> +rusttest-macros: $(srctree)/rust/macros/lib.rs rusttest-prepare FORCE
> +       $(call if_changed,rustc_test)
> +       $(call if_changed,rustdoc_test)
> +
> +rusttest-kernel: private rustc_target_flags = --extern alloc \
> +    --extern build_error --extern macros
> +rusttest-kernel: private rustc_test_run_flags = \
> +    --skip bindgen_test_layout_
> +rusttest-kernel: $(srctree)/rust/kernel/lib.rs rusttest-prepare \
> +    rusttestlib-build_error rusttestlib-macros FORCE
> +       $(call if_changed,rustc_test)
> +       $(call if_changed,rustc_test_library)
> +       $(call if_changed,rustdoc_test)
> +
> +ifdef CONFIG_CC_IS_CLANG
> +bindgen_c_flags = $(c_flags)
> +else
> +# bindgen relies on libclang to parse C. Ideally, bindgen would support a GCC
> +# plugin backend and/or the Clang driver would be perfectly compatible with GCC.
> +#
> +# For the moment, here we are tweaking the flags on the fly. Some config
> +# options may not work (e.g. `GCC_PLUGIN_RANDSTRUCT` if we end up using one

Do we denote the conflict in KCONFIG?

> +# of those structs).
> +bindgen_skip_c_flags := -mno-fp-ret-in-387 -mpreferred-stack-boundary=% \
> +       -mskip-rax-setup -mgeneral-regs-only -msign-return-address=% \
> +       -mindirect-branch=thunk-extern -mindirect-branch-register -mrecord-mcount \
> +       -mabi=lp64 -mstack-protector-guard% -fconserve-stack -falign-jumps=% \
> +       -falign-loops=% -femit-struct-debug-baseonly \
> +       -fno-ipa-cp-clone -fno-ipa-sra -fno-partial-inlining \
> +       -fplugin-arg-arm_ssp_per_task_plugin-% \
> +       -fno-reorder-blocks -fno-allow-store-data-races -fasan-shadow-offset=% \
> +       -Wno-packed-not-aligned -Wno-format-truncation -Wno-format-overflow \
> +       -Wno-stringop-truncation -Wno-unused-but-set-variable \
> +       -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized \
> +       -Werror=designated-init -Wno-zero-length-bounds \
> +       -Wno-alloc-size-larger-than --param=% --param asan-%

Why do we need to strip out all these warning flags when running
bindgen?  Should be just be using -w to silence all warnings from
clang when invoking bindgen?

> +
> +# We need to keep the quotes for this one -- it comes from a `Kconfig`
> +bindgen_skip_c_flags += "-Wimplicit-fallthrough=%"
> +
> +# PowerPC
> +bindgen_skip_c_flags += -mtraceback=no -mno-pointers-to-nested-functions \
> +       -mno-string -mno-strict-align

I don't understand why the PowerPC specific flags are pulled out, but
the x86 specific ones (like most of the -m flags in the initial
defiition of bindgen_skip_c_flags) are not.

> +
> +# Derived from `scripts/Makefile.clang`
> +BINDGEN_TARGET_arm     := arm-linux-gnueabi
> +BINDGEN_TARGET_arm64   := aarch64-linux-gnu
> +BINDGEN_TARGET_powerpc := powerpc64le-linux-gnu
> +BINDGEN_TARGET_riscv   := riscv64-linux-gnu
> +BINDGEN_TARGET_x86     := x86_64-linux-gnu
> +BINDGEN_TARGET         := $(BINDGEN_TARGET_$(SRCARCH))
> +
> +bindgen_extra_c_flags = --target=$(BINDGEN_TARGET) \
> +       -Wno-address-of-packed-member \
> +       -Wno-gnu-variable-sized-type-not-at-end
> +bindgen_c_flags = $(filter-out $(bindgen_skip_c_flags), $(c_flags)) \
> +       $(bindgen_extra_c_flags)
> +endif
> +
> +ifdef CONFIG_LTO
> +bindgen_c_flags_lto = $(filter-out $(CC_FLAGS_LTO), $(bindgen_c_flags))
> +else
> +bindgen_c_flags_lto = $(bindgen_c_flags)
> +endif
> +
> +# To avoid several recompilations in PowerPC, which inserts `-D_TASK_CPU`
> +bindgen_c_flags_final = $(filter-out -D_TASK_CPU=%, $(bindgen_c_flags_lto))
> +
> +quiet_cmd_bindgen = BINDGEN $@
> +      cmd_bindgen = \
> +       $(BINDGEN) $< $(shell grep -v '^\#\|^$$' $(srctree)/rust/bindgen_parameters) \
> +               --use-core --with-derive-default --ctypes-prefix c_types \
> +               --no-debug '.*' \
> +               --size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE
> +
> +$(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h \
> +       $(srctree)/rust/bindgen_parameters FORCE
> +       $(call if_changed_dep,bindgen)
> +
> +quiet_cmd_bindgen_helper = BINDGEN $@
> +      cmd_bindgen_helper = \
> +       $(BINDGEN) $< --blacklist-type '.*' --whitelist-var '' \
> +               --whitelist-function 'rust_helper_.*' \
> +               --use-core --with-derive-default --ctypes-prefix c_types \
> +               --no-debug '.*' \
> +               --size_t-is-usize -o $@ -- $(bindgen_c_flags_final) \
> +               -I$(objtree)/rust/ -DMODULE; \
> +       sed -Ei 's/pub fn rust_helper_([a-zA-Z0-9_]*)/\#[link_name="rust_helper_\1"]\n    pub fn \1/g' $@
> +
> +$(objtree)/rust/bindings_helpers_generated.rs: $(srctree)/rust/helpers.c FORCE
> +       $(call if_changed_dep,bindgen_helper)
> +
> +quiet_cmd_exports = EXPORTS $@
> +      cmd_exports = \
> +       $(NM) -p --defined-only $< \
> +               | grep -E ' (T|R|D) ' | cut -d ' ' -f 3 \
> +               | xargs -Isymbol \
> +               echo 'EXPORT_SYMBOL_RUST_GPL(symbol);' > $@

This doesn't accidentally export non-GPL symbols as GPL does it?

... snip ...

--
Thanks,
~Nick Desaulniers

  reply	other threads:[~2021-12-07 22:45 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-06 14:02 [PATCH 00/19] Rust support Miguel Ojeda
2021-12-06 14:02 ` [PATCH 01/19] kallsyms: support "big" kernel symbols Miguel Ojeda
2021-12-06 14:18   ` Matthew Wilcox
2021-12-06 17:00     ` Miguel Ojeda
2021-12-06 14:02 ` [PATCH 02/19] kallsyms: increase maximum kernel symbol length to 512 Miguel Ojeda
2021-12-06 14:02 ` [PATCH 03/19] kallsyms: use the correct buffer size for symbols Miguel Ojeda
2021-12-06 14:02 ` [PATCH 04/19] rust: add C helpers Miguel Ojeda
2021-12-06 14:02 ` [PATCH 05/19] rust: add `compiler_builtins` crate Miguel Ojeda
2021-12-07 23:01   ` Nick Desaulniers
2021-12-09 19:34     ` Miguel Ojeda
2021-12-06 14:03 ` [PATCH 06/19] rust: add `alloc` crate Miguel Ojeda
2021-12-06 14:03 ` [PATCH 07/19] rust: add `build_error` crate Miguel Ojeda
2021-12-06 14:03 ` [PATCH 08/19] rust: add `macros` crate Miguel Ojeda
2021-12-06 14:03 ` [PATCH 09/19] rust: add `kernel` crate Miguel Ojeda
2021-12-06 14:03 ` [PATCH 10/19] rust: export generated symbols Miguel Ojeda
2021-12-06 14:03 ` [PATCH 11/19] vsprintf: add new `%pA` format specifier Miguel Ojeda
2021-12-06 15:02   ` Greg Kroah-Hartman
2021-12-06 15:56     ` Miguel Ojeda
2021-12-06 16:02       ` Greg Kroah-Hartman
2021-12-06 19:52         ` Nick Desaulniers
2021-12-06 19:55           ` Matthew Wilcox
2021-12-06 20:02             ` Nick Desaulniers
2021-12-06 14:03 ` [PATCH 12/19] scripts: add `generate_rust_analyzer.py` Miguel Ojeda
2021-12-06 14:03 ` [PATCH 13/19] scripts: decode_stacktrace: demangle Rust symbols Miguel Ojeda
2021-12-06 14:03 ` [PATCH 14/19] docs: add Rust documentation Miguel Ojeda
2021-12-08  1:29   ` Nick Desaulniers
2021-12-08 23:07     ` Miguel Ojeda
2021-12-06 14:03 ` [PATCH 15/19] Kbuild: add Rust support Miguel Ojeda
2021-12-07 22:45   ` Nick Desaulniers [this message]
2021-12-07 23:21     ` Nick Desaulniers
2021-12-07 23:25       ` Wedson Almeida Filho
2021-12-08  0:05         ` Nick Desaulniers
2021-12-08 22:52     ` Miguel Ojeda
2021-12-11 15:53   ` Masahiro Yamada
2022-01-17  4:45     ` Miguel Ojeda
2021-12-06 14:03 ` [PATCH 16/19] samples: add Rust examples Miguel Ojeda
2021-12-06 14:03 ` [PATCH 17/19] MAINTAINERS: Rust Miguel Ojeda
2021-12-06 14:03 ` [RFC PATCH 18/19] drivers: gpio: PrimeCell PL061 in Rust Miguel Ojeda
2021-12-06 14:03 ` [RFC PATCH 19/19] drivers: android: Binder IPC " Miguel Ojeda
2021-12-06 15:01   ` Greg Kroah-Hartman
2021-12-06 15:59     ` Wedson Almeida Filho
2021-12-06 16:02       ` Greg Kroah-Hartman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAKwvOd=7QTUH69+ZbT7e8einvgcosTbDkyohmPaUBv6_y8RfrQ@mail.gmail.com' \
    --to=ndesaulniers@google.com \
    --cc=alex.gaynor@gmail.com \
    --cc=antonio.terceiro@linaro.org \
    --cc=ark.email@gmail.com \
    --cc=bobo1239@web.de \
    --cc=boqun.feng@gmail.com \
    --cc=d0u9.su@outlook.com \
    --cc=dsosnowski@dsosnowski.pl \
    --cc=dxu@dxuuu.xyz \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=masahiroy@kernel.org \
    --cc=me@kloenk.de \
    --cc=mpe@ellerman.id.au \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=thesven73@gmail.com \
    --cc=torvalds@linux-foundation.org \
    --cc=wedsonaf@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.