Re: [PATCH 15/19] Kbuild: add Rust support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



"(/.On Mon, Dec 6, 2021 at 6:07 AM Miguel Ojeda <ojeda@xxxxxxxxxx> 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



[Index of Archives]     [Linux&nblp;USB Development]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite Secrets]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux