From nobody Sat Apr 11 22:24:44 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7296FC6FA92 for ; Tue, 27 Sep 2022 13:21:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232829AbiI0NVC (ORCPT ); Tue, 27 Sep 2022 09:21:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36822 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232660AbiI0NTY (ORCPT ); Tue, 27 Sep 2022 09:19:24 -0400 Received: from ams.source.kernel.org (ams.source.kernel.org [IPv6:2604:1380:4601:e00::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1DFD83869D; Tue, 27 Sep 2022 06:17:47 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 60176B81BBD; Tue, 27 Sep 2022 13:17:43 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id D7A12C433D6; Tue, 27 Sep 2022 13:17:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1664284662; bh=holZV62OpOLew27O8pogZb4ZpHQQjLzNNpqzMcaS6gE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ObEb7utCm+jXhfRChyMzcqi2OY7G7yRIeE+BE4aYHbVoIf2w8vmPYWJ/0J7n98G+P Tixznozd4nKXQHcBiy6uIRqPYZ91DAJDjHCAwhapNJTWWSVQIxu46iVeFvettWiorP GDjlJpad5g395QV6KCtIOukOpPoZIWKCwx1iA2JDVs8VoAPjewQji2pZL0uVmAE77s CV2/8JHp6KtIsL6Ojvrmr33mjBIU9Rga0+9jRaqtnPvrHOmEc+y4u1EOwU2C9ncCpl q8pa6F2AQkQ7Fxx72bCegZGu+7k7p/9SJFt2iKrO7bwdXd00A0dk6nRhOOnT86fxg1 d/vT461hgiJPw== From: Miguel Ojeda To: Linus Torvalds , Greg Kroah-Hartman Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, patches@lists.linux.dev, Jarkko Sakkinen , Miguel Ojeda , Kees Cook , Nick Desaulniers , Alex Gaynor , Finn Behrens , Adam Bratschi-Kaye , Wedson Almeida Filho , Michael Ellerman , Sven Van Asbroeck , Gary Guo , Boris-Chengbiao Zhou , Boqun Feng , Douglas Su , Dariusz Sosnowski , Antonio Terceiro , Daniel Xu , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Martin Rodriguez Reboredo , Masahiro Yamada , Michal Marek , linux-kbuild@vger.kernel.org Subject: [PATCH v10 23/27] Kbuild: add Rust support Date: Tue, 27 Sep 2022 15:14:54 +0200 Message-Id: <20220927131518.30000-24-ojeda@kernel.org> In-Reply-To: <20220927131518.30000-1-ojeda@kernel.org> References: <20220927131518.30000-1-ojeda@kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Having most of the new files in place, we now enable Rust support in the build system, including `Kconfig` entries related to Rust, the Rust configuration printer and a few other bits. Reviewed-by: Kees Cook Reviewed-by: Nick Desaulniers Tested-by: Nick Desaulniers Co-developed-by: Alex Gaynor Signed-off-by: Alex Gaynor Co-developed-by: Finn Behrens Signed-off-by: Finn Behrens Co-developed-by: Adam Bratschi-Kaye Signed-off-by: Adam Bratschi-Kaye Co-developed-by: Wedson Almeida Filho Signed-off-by: Wedson Almeida Filho Co-developed-by: Michael Ellerman Signed-off-by: Michael Ellerman Co-developed-by: Sven Van Asbroeck Signed-off-by: Sven Van Asbroeck Co-developed-by: Gary Guo Signed-off-by: Gary Guo Co-developed-by: Boris-Chengbiao Zhou Signed-off-by: Boris-Chengbiao Zhou Co-developed-by: Boqun Feng Signed-off-by: Boqun Feng Co-developed-by: Douglas Su Signed-off-by: Douglas Su Co-developed-by: Dariusz Sosnowski Signed-off-by: Dariusz Sosnowski Co-developed-by: Antonio Terceiro Signed-off-by: Antonio Terceiro Co-developed-by: Daniel Xu Signed-off-by: Daniel Xu Co-developed-by: Bj=C3=B6rn Roy Baron Signed-off-by: Bj=C3=B6rn Roy Baron Co-developed-by: Martin Rodriguez Reboredo Signed-off-by: Martin Rodriguez Reboredo Signed-off-by: Miguel Ojeda Reviewed-by: Greg Kroah-Hartman Reviewed-by: Wei Liu --- .gitignore | 2 + Makefile | 172 ++++++++++++++- arch/Kconfig | 6 + include/linux/compiler_types.h | 6 +- init/Kconfig | 46 +++- kernel/configs/rust.config | 1 + lib/Kconfig.debug | 34 +++ rust/.gitignore | 8 + rust/Makefile | 381 +++++++++++++++++++++++++++++++++ rust/bindgen_parameters | 21 ++ scripts/Kconfig.include | 6 +- scripts/Makefile | 3 + scripts/Makefile.build | 60 ++++++ scripts/Makefile.debug | 8 + scripts/Makefile.host | 34 ++- scripts/Makefile.lib | 12 ++ scripts/Makefile.modfinal | 8 +- scripts/cc-version.sh | 12 +- scripts/kconfig/confdata.c | 75 +++++++ 19 files changed, 869 insertions(+), 26 deletions(-) create mode 100644 kernel/configs/rust.config create mode 100644 rust/.gitignore create mode 100644 rust/Makefile create mode 100644 rust/bindgen_parameters diff --git a/.gitignore b/.gitignore index 97e085d613a2..5da004814678 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,8 @@ *.o *.o.* *.patch +*.rmeta +*.rsi *.s *.so *.so.dbg diff --git a/Makefile b/Makefile index 647a42a1f800..c759ee315254 100644 --- a/Makefile +++ b/Makefile @@ -120,6 +120,15 @@ endif =20 export KBUILD_CHECKSRC =20 +# Enable "clippy" (a linter) as part of the Rust compilation. +# +# Use 'make CLIPPY=3D1' to enable it. +ifeq ("$(origin CLIPPY)", "command line") + KBUILD_CLIPPY :=3D $(CLIPPY) +endif + +export KBUILD_CLIPPY + # Use make M=3Ddir or set the environment variable KBUILD_EXTMOD to specif= y the # directory of external module to build. Setting M=3D takes precedence. ifeq ("$(origin M)", "command line") @@ -270,14 +279,14 @@ no-dot-config-targets :=3D $(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 rustavailable rustfmt rustfmtcheck # Installation targets should not require compiler. Unfortunately, vdso_in= stall # is an exception where build artifacts may be updated. This must be fixed. no-compiler-targets :=3D $(no-dot-config-targets) install dtbs_install \ headers_install modules_install kernelrelease image_name no-sync-config-targets :=3D $(no-dot-config-targets) %install kernelreleas= e \ image_name -single-targets :=3D %.a %.i %.ko %.lds %.ll %.lst %.mod %.o %.s %.symtypes= %/ +single-targets :=3D %.a %.i %.rsi %.ko %.lds %.ll %.lst %.mod %.o %.s %.sy= mtypes %/ =20 config-build :=3D mixed-build :=3D @@ -439,6 +448,7 @@ else HOSTCC =3D gcc HOSTCXX =3D g++ endif +HOSTRUSTC =3D rustc HOSTPKG_CONFIG =3D pkg-config =20 KBUILD_USERHOSTCFLAGS :=3D -Wall -Wmissing-prototypes -Wstrict-prototypes \ @@ -447,8 +457,26 @@ KBUILD_USERHOSTCFLAGS :=3D -Wall -Wmissing-prototypes = -Wstrict-prototypes \ KBUILD_USERCFLAGS :=3D $(KBUILD_USERHOSTCFLAGS) $(USERCFLAGS) KBUILD_USERLDFLAGS :=3D $(USERLDFLAGS) =20 +# These flags apply to all Rust code in the tree, including the kernel and +# host programs. +export rust_common_flags :=3D --edition=3D2021 \ + -Zbinary_dep_depinfo=3Dy \ + -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::let_unit_value -Dclippy::mut_mut \ + -Dclippy::needless_bitwise_bool \ + -Dclippy::needless_continue \ + -Wclippy::dbg_macro + KBUILD_HOSTCFLAGS :=3D $(KBUILD_USERHOSTCFLAGS) $(HOST_LFS_CFLAGS) $(HOS= TCFLAGS) KBUILD_HOSTCXXFLAGS :=3D -Wall -O2 $(HOST_LFS_CFLAGS) $(HOSTCXXFLAGS) +KBUILD_HOSTRUSTFLAGS :=3D $(rust_common_flags) -O -Cstrip=3Ddebuginfo \ + -Zallow-features=3D $(HOSTRUSTFLAGS) KBUILD_HOSTLDFLAGS :=3D $(HOST_LFS_LDFLAGS) $(HOSTLDFLAGS) KBUILD_HOSTLDLIBS :=3D $(HOST_LFS_LIBS) $(HOSTLDLIBS) =20 @@ -473,6 +501,12 @@ OBJDUMP =3D $(CROSS_COMPILE)objdump READELF =3D $(CROSS_COMPILE)readelf STRIP =3D $(CROSS_COMPILE)strip endif +RUSTC =3D rustc +RUSTDOC =3D rustdoc +RUSTFMT =3D rustfmt +CLIPPY_DRIVER =3D clippy-driver +BINDGEN =3D bindgen +CARGO =3D cargo PAHOLE =3D pahole RESOLVE_BTFIDS =3D $(objtree)/tools/bpf/resolve_btfids/resolve_btfids LEX =3D flex @@ -498,9 +532,11 @@ CHECKFLAGS :=3D -D__linux__ -Dlinux -D__STDC__ -Du= nix -D__unix__ \ -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF) NOSTDINC_FLAGS :=3D CFLAGS_MODULE =3D +RUSTFLAGS_MODULE =3D AFLAGS_MODULE =3D LDFLAGS_MODULE =3D CFLAGS_KERNEL =3D +RUSTFLAGS_KERNEL =3D AFLAGS_KERNEL =3D LDFLAGS_vmlinux =3D =20 @@ -529,15 +565,43 @@ KBUILD_CFLAGS :=3D -Wall -Wundef -Werror=3Dstrict-p= rototypes -Wno-trigraphs \ -Werror=3Dreturn-type -Wno-format-security \ -std=3Dgnu11 KBUILD_CPPFLAGS :=3D -D__KERNEL__ +KBUILD_RUSTFLAGS :=3D $(rust_common_flags) \ + --target=3D$(objtree)/rust/target.json \ + -Cpanic=3Dabort -Cembed-bitcode=3Dn -Clto=3Dn \ + -Cforce-unwind-tables=3Dn -Ccodegen-units=3D1 \ + -Csymbol-mangling-version=3Dv0 \ + -Crelocation-model=3Dstatic \ + -Zfunction-sections=3Dn \ + -Dclippy::float_arithmetic + KBUILD_AFLAGS_KERNEL :=3D KBUILD_CFLAGS_KERNEL :=3D +KBUILD_RUSTFLAGS_KERNEL :=3D KBUILD_AFLAGS_MODULE :=3D -DMODULE KBUILD_CFLAGS_MODULE :=3D -DMODULE +KBUILD_RUSTFLAGS_MODULE :=3D --cfg MODULE KBUILD_LDFLAGS_MODULE :=3D KBUILD_LDFLAGS :=3D CLANG_FLAGS :=3D =20 +ifeq ($(KBUILD_CLIPPY),1) + RUSTC_OR_CLIPPY_QUIET :=3D CLIPPY + RUSTC_OR_CLIPPY =3D $(CLIPPY_DRIVER) +else + RUSTC_OR_CLIPPY_QUIET :=3D RUSTC + RUSTC_OR_CLIPPY =3D $(RUSTC) +endif + +ifdef RUST_LIB_SRC + export RUST_LIB_SRC +endif + +# Allows the usage of unstable features in stable compilers. +export RUSTC_BOOTSTRAP :=3D 1 + export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPI= LE LD CC HOSTPKG_CONFIG +export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN= CARGO +export HOSTRUSTC KBUILD_HOSTRUSTFLAGS export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX Y= ACC AWK INSTALLKERNEL export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD @@ -546,9 +610,10 @@ export KBUILD_USERCFLAGS KBUILD_USERLDFLAGS =20 export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS KBUILD_LDF= LAGS export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE +export 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 K= BUILD_LDFLAGS_MODULE +export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTFLAGS_KERNEL export PAHOLE_FLAGS =20 # Files to ignore in find ... statements @@ -729,7 +794,7 @@ $(KCONFIG_CONFIG): # # Do not use $(call cmd,...) here. That would suppress prompts from syncco= nfig, # so you cannot notice that Kconfig is waiting for the user input. -%/config/auto.conf %/config/auto.conf.cmd %/generated/autoconf.h: $(KCONFI= G_CONFIG) +%/config/auto.conf %/config/auto.conf.cmd %/generated/autoconf.h %/generat= ed/rustc_cfg: $(KCONFIG_CONFIG) $(Q)$(kecho) " SYNC $@" $(Q)$(MAKE) -f $(srctree)/Makefile syncconfig else # !may-sync-config @@ -758,10 +823,17 @@ KBUILD_CFLAGS +=3D $(call cc-disable-warning, address= -of-packed-member) =20 ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE KBUILD_CFLAGS +=3D -O2 +KBUILD_RUSTFLAGS +=3D -Copt-level=3D2 else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS +=3D -Os +KBUILD_RUSTFLAGS +=3D -Copt-level=3Ds endif =20 +# Always set `debug-assertions` and `overflow-checks` because their default +# depends on `opt-level` and `debug-assertions`, respectively. +KBUILD_RUSTFLAGS +=3D -Cdebug-assertions=3D$(if $(CONFIG_RUST_DEBUG_ASSERT= IONS),y,n) +KBUILD_RUSTFLAGS +=3D -Coverflow-checks=3D$(if $(CONFIG_RUST_OVERFLOW_CHEC= KS),y,n) + # Tell gcc to never replace conditional load with a non-conditional one ifdef CONFIG_CC_IS_GCC # gcc-10 renamed --param=3Dallow-store-data-races=3D0 to @@ -792,6 +864,9 @@ KBUILD_CFLAGS-$(CONFIG_WERROR) +=3D -Werror KBUILD_CFLAGS-$(CONFIG_CC_NO_ARRAY_BOUNDS) +=3D -Wno-array-bounds KBUILD_CFLAGS +=3D $(KBUILD_CFLAGS-y) $(CONFIG_CC_IMPLICIT_FALLTHROUGH) =20 +KBUILD_RUSTFLAGS-$(CONFIG_WERROR) +=3D -Dwarnings +KBUILD_RUSTFLAGS +=3D $(KBUILD_RUSTFLAGS-y) + ifdef CONFIG_CC_IS_CLANG KBUILD_CPPFLAGS +=3D -Qunused-arguments # The kernel builds with '-std=3Dgnu11' so use of GNU extensions is accept= able. @@ -812,12 +887,15 @@ KBUILD_CFLAGS +=3D $(call cc-disable-warning, danglin= g-pointer) =20 ifdef CONFIG_FRAME_POINTER KBUILD_CFLAGS +=3D -fno-omit-frame-pointer -fno-optimize-sibling-calls +KBUILD_RUSTFLAGS +=3D -Cforce-frame-pointers=3Dy else # Some targets (ARM with Thumb2, for example), can't be built with frame # pointers. For those, we don't have FUNCTION_TRACER automatically # select FRAME_POINTER. However, FUNCTION_TRACER adds -pg, and this is # incompatible with -fomit-frame-pointer with current GCC, so we don't use # -fomit-frame-pointer with FUNCTION_TRACER. +# In the Rust target specification, "frame-pointer" is set explicitly +# to "may-omit". ifndef CONFIG_FUNCTION_TRACER KBUILD_CFLAGS +=3D -fomit-frame-pointer endif @@ -882,8 +960,10 @@ ifdef CONFIG_DEBUG_SECTION_MISMATCH KBUILD_CFLAGS +=3D -fno-inline-functions-called-once endif =20 +# `rustc`'s `-Zfunction-sections` applies to data too (as of 1.59.0). ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION KBUILD_CFLAGS_KERNEL +=3D -ffunction-sections -fdata-sections +KBUILD_RUSTFLAGS_KERNEL +=3D -Zfunction-sections=3Dy LDFLAGS_vmlinux +=3D --gc-sections endif =20 @@ -1026,10 +1106,11 @@ include $(addprefix $(srctree)/, $(include-y)) # Do not add $(call cc-option,...) below this line. When you build the ker= nel # from the clean source tree, the GCC plugins do not exist at this point. =20 -# Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments +# Add user supplied CPPFLAGS, AFLAGS, CFLAGS and RUSTFLAGS as the last ass= ignments KBUILD_CPPFLAGS +=3D $(KCPPFLAGS) KBUILD_AFLAGS +=3D $(KAFLAGS) KBUILD_CFLAGS +=3D $(KCFLAGS) +KBUILD_RUSTFLAGS +=3D $(KRUSTFLAGS) =20 KBUILD_LDFLAGS_MODULE +=3D --build-id=3Dsha1 LDFLAGS_vmlinux +=3D --build-id=3Dsha1 @@ -1104,6 +1185,7 @@ ifeq ($(KBUILD_EXTMOD),) core-y +=3D kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ core-$(CONFIG_BLOCK) +=3D block/ core-$(CONFIG_IO_URING) +=3D io_uring/ +core-$(CONFIG_RUST) +=3D rust/ =20 vmlinux-dirs :=3D $(patsubst %/,%,$(filter %/, \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ @@ -1206,6 +1288,10 @@ prepare0: archprepare =20 # All the preparing.. prepare: prepare0 +ifdef CONFIG_RUST + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh -v + $(Q)$(MAKE) $(build)=3Drust +endif =20 PHONY +=3D remove-stale-files remove-stale-files: @@ -1499,7 +1585,7 @@ endif # CONFIG_MODULES # Directories & files removed with 'make clean' CLEAN_FILES +=3D 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 =20 # Directories & files removed with 'make mrproper' MRPROPER_FILES +=3D include/config include/generated \ @@ -1510,7 +1596,8 @@ MRPROPER_FILES +=3D include/config include/generated = \ certs/signing_key.pem \ certs/x509.genkey \ vmlinux-gdb.py \ - *.spec + *.spec \ + rust/target.json rust/libmacros.so =20 # clean - Delete most, but leave enough to build external modules # @@ -1535,6 +1622,9 @@ $(mrproper-dirs): =20 mrproper: clean $(mrproper-dirs) $(call cmd,rmfiles) + @find . $(RCS_FIND_IGNORE) \ + \( -name '*.rmeta' \) \ + -type f -print | xargs rm -f =20 # distclean # @@ -1622,6 +1712,24 @@ help: @echo ' kselftest-merge - Merge all the config dependencies of' @echo ' kselftest to existing .config.' @echo '' + @echo 'Rust targets:' + @echo ' rustavailable - Checks whether the Rust toolchain is' + @echo ' available and, if not, explains why.' + @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 supp= ort file' + @echo ' (requires kernel .config)' + @echo ' dir/file.[os] - Build specified target only' + @echo ' dir/file.rsi - Build macro expanded source, similar to C pre= processing.' + @echo ' Run with RUSTFMT=3Dn to skip reformatting if = needed.' + @echo ' The output is not intended to be compilable.' + @echo ' dir/file.ll - Build the LLVM assembly file' + @echo '' @$(if $(dtstree), \ echo 'Devicetree:'; \ echo '* dtbs - Build device tree blobs for enabled boards'; \ @@ -1694,6 +1802,52 @@ PHONY +=3D $(DOC_TARGETS) $(DOC_TARGETS): $(Q)$(MAKE) $(build)=3DDocumentation $@ =20 + +# Rust targets +# ------------------------------------------------------------------------= --- + +# "Is Rust available?" target +PHONY +=3D rustavailable +rustavailable: + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/rust_is_available.sh -v && echo "R= ust is available!" + +# Documentation target +# +# Using the singular to avoid running afoul of `no-dot-config-targets`. +PHONY +=3D rustdoc +rustdoc: prepare + $(Q)$(MAKE) $(build)=3Drust $@ + +# Testing target +PHONY +=3D rusttest +rusttest: prepare + $(Q)$(MAKE) $(build)=3Drust $@ + +# Formatting targets +PHONY +=3D 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 =3D --check +rustfmtcheck: rustfmt + +# IDE support targets +PHONY +=3D rust-analyzer +rust-analyzer: + $(Q)$(MAKE) $(build)=3Drust $@ + # Misc # ------------------------------------------------------------------------= --- =20 @@ -1861,7 +2015,7 @@ $(clean-dirs): clean: $(clean-dirs) $(call cmd,rmfiles) @find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ - \( -name '*.[aios]' -o -name '*.ko' -o -name '.*.cmd' \ + \( -name '*.[aios]' -o -name '*.rsi' -o -name '*.ko' -o -name '.*.cmd' \ -o -name '*.ko.*' \ -o -name '*.dtb' -o -name '*.dtbo' -o -name '*.dtb.S' -o -name '*.dt.yam= l' \ -o -name '*.dwo' -o -name '*.lst' \ diff --git a/arch/Kconfig b/arch/Kconfig index 8b311e400ec1..d9b4ae0fc805 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -355,6 +355,12 @@ config HAVE_RSEQ This symbol should be selected by an architecture if it supports an implementation of restartable sequences. =20 +config HAVE_RUST + bool + help + This symbol should be selected by an architecture if it + supports Rust. + config HAVE_FUNCTION_ARG_ACCESS_API bool help diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 4f2a819fd60a..50b3f6b9502e 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -4,8 +4,12 @@ =20 #ifndef __ASSEMBLY__ =20 +/* + * Skipped when running bindgen due to a libclang issue; + * see https://github.com/rust-lang/rust-bindgen/issues/2244. + */ #if defined(CONFIG_DEBUG_INFO_BTF) && defined(CONFIG_PAHOLE_HAS_BTF_TAG) &= & \ - __has_attribute(btf_type_tag) + __has_attribute(btf_type_tag) && !defined(__BINDGEN__) # define BTF_TYPE_TAG(value) __attribute__((btf_type_tag(#value))) #else # define BTF_TYPE_TAG(value) /* nothing */ diff --git a/init/Kconfig b/init/Kconfig index 532362fcfe31..a078cb026523 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -60,6 +60,17 @@ config LLD_VERSION default $(ld-version) if LD_IS_LLD default 0 =20 +config RUST_IS_AVAILABLE + def_bool $(success,$(srctree)/scripts/rust_is_available.sh) + help + This shows whether a suitable Rust toolchain is available (found). + + Please see Documentation/rust/quick-start.rst for instructions on how + to satify the build requirements of Rust support. + + In particular, the Makefile target 'rustavailable' is useful to check + why the Rust toolchain is not being detected. + config CC_CAN_LINK bool default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) = $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag)) if 64BIT @@ -147,7 +158,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. =20 However, if you have a new (or very old) compiler with odd and unusual warnings, or you have some architecture with problems, @@ -1899,6 +1911,38 @@ config PROFILING Say Y here to enable the extended profiling support mechanisms used by profilers. =20 +config RUST + bool "Rust support" + depends on HAVE_RUST + depends on RUST_IS_AVAILABLE + depends on !MODVERSIONS + depends on !GCC_PLUGINS + depends on !RANDSTRUCT + depends on !DEBUG_INFO_BTF + select CONSTRUCTORS + 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. + +config RUSTC_VERSION_TEXT + string + depends on RUST + default $(shell,command -v $(RUSTC) >/dev/null 2>&1 && $(RUSTC) --version= || echo n) + +config BINDGEN_VERSION_TEXT + string + depends on RUST + default $(shell,command -v $(BINDGEN) >/dev/null 2>&1 && $(BINDGEN) --ver= sion || echo n) + # # Place an empty function call at each tracepoint site. Can be # dynamically changed for a probe function. diff --git a/kernel/configs/rust.config b/kernel/configs/rust.config new file mode 100644 index 000000000000..38a7c5362c9c --- /dev/null +++ b/kernel/configs/rust.config @@ -0,0 +1 @@ +CONFIG_RUST=3Dy diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index d3e5f36bb01e..e62271da937f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2710,6 +2710,40 @@ config HYPERV_TESTING =20 endmenu # "Kernel Testing and Coverage" =20 +menu "Rust hacking" + +config RUST_DEBUG_ASSERTIONS + bool "Debug assertions" + 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 + 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 Rust panic will occur + on overflow. + + Note that this will apply to all Rust code, including `core`. + + If unsure, say Y. + +endmenu # "Rust" + source "Documentation/Kconfig" =20 endmenu # Kernel hacking diff --git a/rust/.gitignore b/rust/.gitignore new file mode 100644 index 000000000000..9bd1af8e05a1 --- /dev/null +++ b/rust/.gitignore @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 + +target.json +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..7700d3853404 --- /dev/null +++ b/rust/Makefile @@ -0,0 +1,381 @@ +# SPDX-License-Identifier: GPL-2.0 + +always-$(CONFIG_RUST) +=3D target.json +no-clean-files +=3D target.json + +obj-$(CONFIG_RUST) +=3D core.o compiler_builtins.o +always-$(CONFIG_RUST) +=3D exports_core_generated.h + +# Missing prototypes are expected in the helpers since these are exported +# for Rust only, thus there is no header nor prototypes. +obj-$(CONFIG_RUST) +=3D helpers.o +CFLAGS_REMOVE_helpers.o =3D -Wmissing-prototypes -Wmissing-declarations + +always-$(CONFIG_RUST) +=3D libmacros.so +no-clean-files +=3D libmacros.so + +always-$(CONFIG_RUST) +=3D bindings/bindings_generated.rs bindings/binding= s_helpers_generated.rs +obj-$(CONFIG_RUST) +=3D alloc.o bindings.o kernel.o +always-$(CONFIG_RUST) +=3D exports_alloc_generated.h exports_bindings_gene= rated.h \ + exports_kernel_generated.h + +obj-$(CONFIG_RUST) +=3D exports.o + +# Avoids running `$(RUSTC)` for the sysroot when it may not be available. +ifdef CONFIG_RUST + +# `$(rust_flags)` is passed in case the user added `--sysroot`. +rustc_sysroot :=3D $(shell $(RUSTC) $(rust_flags) --print sysroot) +rustc_host_target :=3D $(shell $(RUSTC) --version --verbose | grep -F 'hos= t: ' | cut -d' ' -f2) +RUST_LIB_SRC ?=3D $(rustc_sysroot)/lib/rustlib/src/rust/library + +ifeq ($(quiet),silent_) +cargo_quiet=3D-q +rust_test_quiet=3D-q +rustdoc_test_quiet=3D--test-args -q +else ifeq ($(quiet),quiet_) +rust_test_quiet=3D-q +rustdoc_test_quiet=3D--test-args -q +else +cargo_quiet=3D--verbose +endif + +core-cfgs =3D \ + --cfg no_fp_fmt_parse + +alloc-cfgs =3D \ + --cfg no_fmt \ + --cfg no_global_oom_handling \ + --cfg no_macros \ + --cfg no_rc \ + --cfg no_str \ + --cfg no_string \ + --cfg no_sync \ + --cfg no_thin + +quiet_cmd_rustdoc =3D RUSTDOC $(if $(rustdoc_host),H, ) $< + cmd_rustdoc =3D \ + OBJTREE=3D$(abspath $(objtree)) \ + $(RUSTDOC) $(if $(rustdoc_host),$(rust_common_flags),$(rust_flags)) \ + $(rustc_target_flags) -L$(objtree)/$(obj) \ + --output $(objtree)/$(obj)/doc \ + --crate-name $(subst rustdoc-,,$@) \ + @$(objtree)/include/generated/rustc_cfg $< + +# The `html_logo_url` and `html_favicon_url` forms of the `doc` attribute +# can be used to specify a custom logo. However: +# - The given value is used as-is, thus it cannot be relative or a local= file +# (unlike the non-custom case) since the generated docs have subfolder= s. +# - It requires adding it to every crate. +# - It requires changing `core` which comes from the sysroot. +# +# Using `-Zcrate-attr` would solve the last two points, but not the first. +# The https://github.com/rust-lang/rfcs/pull/3226 RFC suggests two new +# command-like flags to solve the issue. Meanwhile, we use the non-custom = case +# and then retouch the generated files. +rustdoc: rustdoc-core rustdoc-macros rustdoc-compiler_builtins \ + rustdoc-alloc rustdoc-kernel + $(Q)cp $(srctree)/Documentation/images/logo.svg $(objtree)/$(obj)/doc + $(Q)cp $(srctree)/Documentation/images/COPYING-logo $(objtree)/$(obj)/doc + $(Q)find $(objtree)/$(obj)/doc -name '*.html' -type f -print0 | xargs -0 = sed -Ei \ + -e 's:rust-logo\.svg:logo.svg:g' \ + -e 's:rust-logo\.png:logo.svg:g' \ + -e 's:favicon\.svg:logo.svg:g' \ + -e 's:::g' + $(Q)echo '.logo-container > img { object-fit: contain; }' \ + >> $(objtree)/$(obj)/doc/rustdoc.css + +rustdoc-macros: private rustdoc_host =3D yes +rustdoc-macros: private rustc_target_flags =3D --crate-type proc-macro \ + --extern proc_macro +rustdoc-macros: $(src)/macros/lib.rs FORCE + $(call if_changed,rustdoc) + +rustdoc-core: private rustc_target_flags =3D $(core-cfgs) +rustdoc-core: $(RUST_LIB_SRC)/core/src/lib.rs FORCE + $(call if_changed,rustdoc) + +rustdoc-compiler_builtins: $(src)/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 =3D $(alloc-cfgs) \ + -Arustdoc::broken_intra_doc_links +rustdoc-alloc: $(src)/alloc/lib.rs rustdoc-core rustdoc-compiler_builtins = FORCE + $(call if_changed,rustdoc) + +rustdoc-kernel: private rustc_target_flags =3D --extern alloc \ + --extern macros=3D$(objtree)/$(obj)/libmacros.so \ + --extern bindings +rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \ + rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \ + $(obj)/bindings.o FORCE + $(call if_changed,rustdoc) + +quiet_cmd_rustc_test_library =3D RUSTC TL $< + cmd_rustc_test_library =3D \ + OBJTREE=3D$(abspath $(objtree)) \ + $(RUSTC) $(rust_common_flags) \ + @$(objtree)/include/generated/rustc_cfg $(rustc_target_flags) \ + --crate-type $(if $(rustc_test_library_proc),proc-macro,rlib) \ + --out-dir $(objtree)/$(obj)/test --cfg testlib \ + --sysroot $(objtree)/$(obj)/test/sysroot \ + -L$(objtree)/$(obj)/test \ + --crate-name $(subst rusttest-,,$(subst rusttestlib-,,$@)) $< + +rusttestlib-macros: private rustc_target_flags =3D --extern proc_macro +rusttestlib-macros: private rustc_test_library_proc =3D yes +rusttestlib-macros: $(src)/macros/lib.rs rusttest-prepare FORCE + $(call if_changed,rustc_test_library) + +rusttestlib-bindings: $(src)/bindings/lib.rs rusttest-prepare FORCE + $(call if_changed,rustc_test_library) + +quiet_cmd_rustdoc_test =3D RUSTDOC T $< + cmd_rustdoc_test =3D \ + OBJTREE=3D$(abspath $(objtree)) \ + $(RUSTDOC) --test $(rust_common_flags) \ + @$(objtree)/include/generated/rustc_cfg \ + $(rustc_target_flags) $(rustdoc_test_target_flags) \ + --sysroot $(objtree)/$(obj)/test/sysroot $(rustdoc_test_quiet) \ + -L$(objtree)/$(obj)/test --output $(objtree)/$(obj)/doc \ + --crate-name $(subst rusttest-,,$@) $< + +# We cannot use `-Zpanic-abort-tests` because some tests are dynamic, +# so for the moment we skip `-Cpanic=3Dabort`. +quiet_cmd_rustc_test =3D RUSTC T $< + cmd_rustc_test =3D \ + OBJTREE=3D$(abspath $(objtree)) \ + $(RUSTC) --test $(rust_common_flags) \ + @$(objtree)/include/generated/rustc_cfg \ + $(rustc_target_flags) --out-dir $(objtree)/$(obj)/test \ + --sysroot $(objtree)/$(obj)/test/sysroot \ + -L$(objtree)/$(obj)/test \ + --crate-name $(subst rusttest-,,$@) $<; \ + $(objtree)/$(obj)/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 unstab= le +# 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 s= eem +# 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 f= lag. +# +# In the future, we hope to avoid the whole ordeal by either: +# - Making the `test` crate not depend on `std` (either improving upstre= am +# 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 =3D RUSTSYSROOT + cmd_rustsysroot =3D \ + rm -rf $(objtree)/$(obj)/test; \ + mkdir -p $(objtree)/$(obj)/test; \ + cp -a $(rustc_sysroot) $(objtree)/$(obj)/test/sysroot; \ + cp -r $(srctree)/$(src)/alloc/* \ + $(objtree)/$(obj)/test/sysroot/lib/rustlib/src/rust/library/alloc/src; \ + echo '\#!/bin/sh' > $(objtree)/$(obj)/test/rustc_sysroot; \ + echo "$(RUSTC) --sysroot=3D$(abspath $(objtree)/$(obj)/test/sysroot) \"\$= $@\"" \ + >> $(objtree)/$(obj)/test/rustc_sysroot; \ + chmod u+x $(objtree)/$(obj)/test/rustc_sysroot; \ + $(CARGO) -q new $(objtree)/$(obj)/test/dummy; \ + RUSTC=3D$(objtree)/$(obj)/test/rustc_sysroot $(CARGO) $(cargo_quiet) \ + test -Zbuild-std --target $(rustc_host_target) \ + --manifest-path $(objtree)/$(obj)/test/dummy/Cargo.toml; \ + rm $(objtree)/$(obj)/test/sysroot/lib/rustlib/$(rustc_host_target)/lib/*;= \ + cp $(objtree)/$(obj)/test/dummy/target/$(rustc_host_target)/debug/deps/* \ + $(objtree)/$(obj)/test/sysroot/lib/rustlib/$(rustc_host_target)/lib + +rusttest-prepare: FORCE + $(call if_changed,rustsysroot) + +rusttest-macros: private rustc_target_flags =3D --extern proc_macro +rusttest-macros: private rustdoc_test_target_flags =3D --crate-type proc-m= acro +rusttest-macros: $(src)/macros/lib.rs rusttest-prepare FORCE + $(call if_changed,rustc_test) + $(call if_changed,rustdoc_test) + +rusttest-kernel: private rustc_target_flags =3D --extern alloc \ + --extern macros --extern bindings +rusttest-kernel: $(src)/kernel/lib.rs rusttest-prepare \ + rusttestlib-macros rusttestlib-bindings FORCE + $(call if_changed,rustc_test) + $(call if_changed,rustc_test_library) + +filechk_rust_target =3D $(objtree)/scripts/generate_rust_target < $< + +$(obj)/target.json: $(objtree)/include/config/auto.conf FORCE + $(call filechk,rust_target) + +ifdef CONFIG_CC_IS_CLANG +bindgen_c_flags =3D $(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 wit= h GCC. +# +# For the moment, here we are tweaking the flags on the fly. This is a hac= k, +# and some kernel configurations may not work (e.g. `GCC_PLUGIN_RANDSTRUCT` +# if we end up using one of those structs). +bindgen_skip_c_flags :=3D -mno-fp-ret-in-387 -mpreferred-stack-boundary=3D= % \ + -mskip-rax-setup -mgeneral-regs-only -msign-return-address=3D% \ + -mindirect-branch=3Dthunk-extern -mindirect-branch-register \ + -mfunction-return=3Dthunk-extern -mrecord-mcount -mabi=3Dlp64 \ + -mindirect-branch-cs-prefix -mstack-protector-guard% -mtraceback=3Dno \ + -mno-pointers-to-nested-functions -mno-string \ + -mno-strict-align -mstrict-align \ + -fconserve-stack -falign-jumps=3D% -falign-loops=3D% \ + -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=3D% \ + -fzero-call-used-regs=3D% -fno-stack-clash-protection \ + -fno-inline-functions-called-once \ + --param=3D% --param asan-% + +# Derived from `scripts/Makefile.clang`. +BINDGEN_TARGET_x86 :=3D x86_64-linux-gnu +BINDGEN_TARGET :=3D $(BINDGEN_TARGET_$(SRCARCH)) + +# All warnings are inhibited since GCC builds are very experimental, +# many GCC warnings are not supported by Clang, they may only appear in +# some configurations, with new GCC versions, etc. +bindgen_extra_c_flags =3D -w --target=3D$(BINDGEN_TARGET) + +bindgen_c_flags =3D $(filter-out $(bindgen_skip_c_flags), $(c_flags)) \ + $(bindgen_extra_c_flags) +endif + +ifdef CONFIG_LTO +bindgen_c_flags_lto =3D $(filter-out $(CC_FLAGS_LTO), $(bindgen_c_flags)) +else +bindgen_c_flags_lto =3D $(bindgen_c_flags) +endif + +bindgen_c_flags_final =3D $(bindgen_c_flags_lto) -D__BINDGEN__ + +quiet_cmd_bindgen =3D BINDGEN $@ + cmd_bindgen =3D \ + $(BINDGEN) $< $(bindgen_target_flags) \ + --use-core --with-derive-default --ctypes-prefix core::ffi --no-layout-t= ests \ + --no-debug '.*' \ + --size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE \ + $(bindgen_target_cflags) $(bindgen_target_extra) + +$(obj)/bindings/bindings_generated.rs: private bindgen_target_flags =3D \ + $(shell grep -v '^\#\|^$$' $(srctree)/$(src)/bindgen_parameters) +$(obj)/bindings/bindings_generated.rs: $(src)/bindings/bindings_helper.h \ + $(src)/bindgen_parameters FORCE + $(call if_changed_dep,bindgen) + +# See `CFLAGS_REMOVE_helpers.o` above. In addition, Clang on C does not wa= rn +# with `-Wmissing-declarations` (unlike GCC), so it is not strictly needed= here +# given it is `libclang`; but for consistency, future Clang changes and/or +# a potential future GCC backend for `bindgen`, we disable it too. +$(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_flag= s =3D \ + --blacklist-type '.*' --whitelist-var '' \ + --whitelist-function 'rust_helper_.*' +$(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_cfla= gs =3D \ + -I$(objtree)/$(obj) -Wno-missing-prototypes -Wno-missing-declarations +$(obj)/bindings/bindings_helpers_generated.rs: private bindgen_target_extr= a =3D ; \ + sed -Ei 's/pub fn rust_helper_([a-zA-Z0-9_]*)/#[link_name=3D"rust_help= er_\1"]\n pub fn \1/g' $@ +$(obj)/bindings/bindings_helpers_generated.rs: $(src)/helpers.c FORCE + $(call if_changed_dep,bindgen) + +quiet_cmd_exports =3D EXPORTS $@ + cmd_exports =3D \ + $(NM) -p --defined-only $< \ + | grep -E ' (T|R|D) ' | cut -d ' ' -f 3 \ + | xargs -Isymbol \ + echo 'EXPORT_SYMBOL_RUST_GPL(symbol);' > $@ + +$(obj)/exports_core_generated.h: $(obj)/core.o FORCE + $(call if_changed,exports) + +$(obj)/exports_alloc_generated.h: $(obj)/alloc.o FORCE + $(call if_changed,exports) + +$(obj)/exports_bindings_generated.h: $(obj)/bindings.o FORCE + $(call if_changed,exports) + +$(obj)/exports_kernel_generated.h: $(obj)/kernel.o FORCE + $(call if_changed,exports) + +quiet_cmd_rustc_procmacro =3D $(RUSTC_OR_CLIPPY_QUIET) P $@ + cmd_rustc_procmacro =3D \ + $(RUSTC_OR_CLIPPY) $(rust_common_flags) \ + --emit=3Ddep-info,link --extern proc_macro \ + --crate-type proc-macro --out-dir $(objtree)/$(obj) \ + --crate-name $(patsubst lib%.so,%,$(notdir $@)) $<; \ + mv $(objtree)/$(obj)/$(patsubst lib%.so,%,$(notdir $@)).d $(depfile); \ + sed -i '/^\#/d' $(depfile) + +# Procedural macros can only be used with the `rustc` that compiled it. +# Therefore, to get `libmacros.so` automatically recompiled when the compi= ler +# version changes, we add `core.o` as a dependency (even if it is not need= ed). +$(obj)/libmacros.so: $(src)/macros/lib.rs $(obj)/core.o FORCE + $(call if_changed_dep,rustc_procmacro) + +quiet_cmd_rustc_library =3D $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QU= IET)) L $@ + cmd_rustc_library =3D \ + OBJTREE=3D$(abspath $(objtree)) \ + $(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \ + $(filter-out $(skip_flags),$(rust_flags) $(rustc_target_flags)) \ + --emit=3Ddep-info,obj,metadata --crate-type rlib \ + --out-dir $(objtree)/$(obj) -L$(objtree)/$(obj) \ + --crate-name $(patsubst %.o,%,$(notdir $@)) $<; \ + mv $(objtree)/$(obj)/$(patsubst %.o,%,$(notdir $@)).d $(depfile); \ + sed -i '/^\#/d' $(depfile) \ + $(if $(rustc_objcopy),;$(OBJCOPY) $(rustc_objcopy) $@) + +rust-analyzer: + $(Q)$(srctree)/scripts/generate_rust_analyzer.py $(srctree) $(objtree) \ + $(RUST_LIB_SRC) > $(objtree)/rust-project.json + +$(obj)/core.o: private skip_clippy =3D 1 +$(obj)/core.o: private skip_flags =3D -Dunreachable_pub +$(obj)/core.o: private rustc_target_flags =3D $(core-cfgs) +$(obj)/core.o: $(RUST_LIB_SRC)/core/src/lib.rs $(obj)/target.json FORCE + $(call if_changed_dep,rustc_library) + +$(obj)/compiler_builtins.o: private rustc_objcopy =3D -w -W '__*' +$(obj)/compiler_builtins.o: $(src)/compiler_builtins.rs $(obj)/core.o FORCE + $(call if_changed_dep,rustc_library) + +$(obj)/alloc.o: private skip_clippy =3D 1 +$(obj)/alloc.o: private skip_flags =3D -Dunreachable_pub +$(obj)/alloc.o: private rustc_target_flags =3D $(alloc-cfgs) +$(obj)/alloc.o: $(src)/alloc/lib.rs $(obj)/compiler_builtins.o FORCE + $(call if_changed_dep,rustc_library) + +$(obj)/bindings.o: $(src)/bindings/lib.rs \ + $(obj)/compiler_builtins.o \ + $(obj)/bindings/bindings_generated.rs \ + $(obj)/bindings/bindings_helpers_generated.rs FORCE + $(call if_changed_dep,rustc_library) + +$(obj)/kernel.o: private rustc_target_flags =3D --extern alloc \ + --extern macros --extern bindings +$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o \ + $(obj)/libmacros.so $(obj)/bindings.o FORCE + $(call if_changed_dep,rustc_library) + +endif # CONFIG_RUST diff --git a/rust/bindgen_parameters b/rust/bindgen_parameters new file mode 100644 index 000000000000..be4963bf7203 --- /dev/null +++ b/rust/bindgen_parameters @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0 + +--opaque-type xregs_state +--opaque-type desc_struct +--opaque-type arch_lbr_state +--opaque-type local_apic + +# Packed type cannot transitively contain a `#[repr(align)]` type. +--opaque-type x86_msi_data +--opaque-type x86_msi_addr_lo + +# `try` is a reserved keyword since Rust 2018; solved in `bindgen` v0.59.2, +# commit 2aed6b021680 ("context: Escape the try keyword properly"). +--opaque-type kunit_try_catch + +# If SMP is disabled, `arch_spinlock_t` is defined as a ZST which triggers= a Rust +# warning. We don't need to peek into it anyway. +--opaque-type spinlock + +# `seccomp`'s comment gets understood as a doctest +--no-doc-comments diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index a0ccceb22cf8..274125307ebd 100644 --- a/scripts/Kconfig.include +++ b/scripts/Kconfig.include @@ -36,12 +36,12 @@ ld-option =3D $(success,$(LD) -v $(1)) as-instr =3D $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x a= ssembler -o /dev/null -) =20 # check if $(CC) and $(LD) exist -$(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found) +$(error-if,$(failure,command -v $(CC)),C compiler '$(CC)' not found) $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found) =20 -# Get the compiler name, version, and error out if it is not supported. +# Get the C compiler name, version, and error out if it is not supported. cc-info :=3D $(shell,$(srctree)/scripts/cc-version.sh $(CC)) -$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this compiler is = not supported.) +$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this C compiler i= s not supported.) cc-name :=3D $(shell,set -- $(cc-info) && echo $1) cc-version :=3D $(shell,set -- $(cc-info) && echo $2) =20 diff --git a/scripts/Makefile b/scripts/Makefile index f084f08ed176..1575af84d557 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -10,6 +10,9 @@ hostprogs-always-$(CONFIG_BUILDTIME_TABLE_SORT) +=3D sor= ttable hostprogs-always-$(CONFIG_ASN1) +=3D asn1_compiler hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) +=3D sign-file hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) +=3D insert-sys-cert +hostprogs-always-$(CONFIG_RUST) +=3D generate_rust_target + +generate_rust_target-rust :=3D y =20 HOSTCFLAGS_sorttable.o =3D -I$(srctree)/tools/include HOSTLDLIBS_sorttable =3D -lpthread diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 784f46d41959..27be77c0d6d8 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -26,6 +26,7 @@ EXTRA_CPPFLAGS :=3D EXTRA_LDFLAGS :=3D asflags-y :=3D ccflags-y :=3D +rustflags-y :=3D cppflags-y :=3D ldflags-y :=3D =20 @@ -271,6 +272,65 @@ quiet_cmd_cc_lst_c =3D MKLST $@ $(obj)/%.lst: $(src)/%.c FORCE $(call if_changed_dep,cc_lst_c) =20 +# Compile Rust sources (.rs) +# ------------------------------------------------------------------------= --- + +rust_allowed_features :=3D core_ffi_c + +rust_common_cmd =3D \ + RUST_MODFILE=3D$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \ + -Zallow-features=3D$(rust_allowed_features) \ + -Zcrate-attr=3Dno_std \ + -Zcrate-attr=3D'feature($(rust_allowed_features))' \ + --extern alloc --extern kernel \ + --crate-type rlib --out-dir $(obj) -L $(objtree)/rust/ \ + --crate-name $(basename $(notdir $@)) + +rust_handle_depfile =3D \ + mv $(obj)/$(basename $(notdir $@)).d $(depfile); \ + sed -i '/^\#/d' $(depfile) + +# `--emit=3Dobj`, `--emit=3Dasm` and `--emit=3Dllvm-ir` imply a single cod= egen unit +# will be used. We explicitly request `-Ccodegen-units=3D1` in any case, a= nd +# the compiler shows a warning if it is not 1. However, if we ever stop +# requesting it explicitly and we start using some other `--emit` that doe= s not +# imply it (and for which codegen is performed), then we would be out of s= ync, +# i.e. the outputs we would get for the different single targets (e.g. `.l= l`) +# would not match each other. + +quiet_cmd_rustc_o_rs =3D $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ + cmd_rustc_o_rs =3D \ + $(rust_common_cmd) --emit=3Ddep-info,obj $<; \ + $(rust_handle_depfile) + +$(obj)/%.o: $(src)/%.rs FORCE + $(call if_changed_dep,rustc_o_rs) + +quiet_cmd_rustc_rsi_rs =3D $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ + cmd_rustc_rsi_rs =3D \ + $(rust_common_cmd) --emit=3Ddep-info -Zunpretty=3Dexpanded $< >$@; \ + command -v $(RUSTFMT) >/dev/null && $(RUSTFMT) $@; \ + $(rust_handle_depfile) + +$(obj)/%.rsi: $(src)/%.rs FORCE + $(call if_changed_dep,rustc_rsi_rs) + +quiet_cmd_rustc_s_rs =3D $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ + cmd_rustc_s_rs =3D \ + $(rust_common_cmd) --emit=3Ddep-info,asm $<; \ + $(rust_handle_depfile) + +$(obj)/%.s: $(src)/%.rs FORCE + $(call if_changed_dep,rustc_s_rs) + +quiet_cmd_rustc_ll_rs =3D $(RUSTC_OR_CLIPPY_QUIET) $(quiet_modtag) $@ + cmd_rustc_ll_rs =3D \ + $(rust_common_cmd) --emit=3Ddep-info,llvm-ir $<; \ + $(rust_handle_depfile) + +$(obj)/%.ll: $(src)/%.rs FORCE + $(call if_changed_dep,rustc_ll_rs) + # Compile assembler sources (.S) # ------------------------------------------------------------------------= --- =20 diff --git a/scripts/Makefile.debug b/scripts/Makefile.debug index 8cf1cb22dd93..332c486f705f 100644 --- a/scripts/Makefile.debug +++ b/scripts/Makefile.debug @@ -1,4 +1,6 @@ DEBUG_CFLAGS :=3D +DEBUG_RUSTFLAGS :=3D + debug-flags-y :=3D -g =20 ifdef CONFIG_DEBUG_INFO_SPLIT @@ -17,9 +19,12 @@ KBUILD_AFLAGS +=3D $(debug-flags-y) =20 ifdef CONFIG_DEBUG_INFO_REDUCED DEBUG_CFLAGS +=3D -fno-var-tracking +DEBUG_RUSTFLAGS +=3D -Cdebuginfo=3D1 ifdef CONFIG_CC_IS_GCC DEBUG_CFLAGS +=3D -femit-struct-debug-baseonly endif +else +DEBUG_RUSTFLAGS +=3D -Cdebuginfo=3D2 endif =20 ifdef CONFIG_DEBUG_INFO_COMPRESSED @@ -30,3 +35,6 @@ endif =20 KBUILD_CFLAGS +=3D $(DEBUG_CFLAGS) export DEBUG_CFLAGS + +KBUILD_RUSTFLAGS +=3D $(DEBUG_RUSTFLAGS) +export DEBUG_RUSTFLAGS diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 278b4d6ac945..da133780b751 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -22,6 +22,8 @@ $(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE # to preprocess a data file. # # Both C and C++ are supported, but preferred language is C for such utili= ties. +# Rust is also supported, but it may only be used in scenarios where a Rust +# toolchain is required to be available (e.g. when `CONFIG_RUST` is enabl= ed). # # Sample syntax (see Documentation/kbuild/makefiles.rst for reference) # hostprogs :=3D bin2hex @@ -37,15 +39,20 @@ $(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE # qconf-objs :=3D menu.o # Will compile qconf as a C++ program, and menu as a C program. # They are linked as C++ code to the executable qconf +# +# hostprogs :=3D target +# target-rust :=3D y +# Will compile `target` as a Rust program, using `target.rs` as the crate = root. +# The crate may consist of several source files. =20 # C code # Executables compiled from a single .c file host-csingle :=3D $(foreach m,$(hostprogs), \ - $(if $($(m)-objs)$($(m)-cxxobjs),,$(m))) + $(if $($(m)-objs)$($(m)-cxxobjs)$($(m)-rust),,$(m))) =20 # C executables linked based on several .o files host-cmulti :=3D $(foreach m,$(hostprogs),\ - $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) + $(if $($(m)-cxxobjs)$($(m)-rust),,$(if $($(m)-objs),$(m)))) =20 # Object (.o) files compiled from .c files host-cobjs :=3D $(sort $(foreach m,$(hostprogs),$($(m)-objs))) @@ -58,11 +65,17 @@ host-cxxmulti :=3D $(foreach m,$(hostprogs),$(if $($(m)= -cxxobjs),$(m))) # C++ Object (.o) files compiled from .cc files host-cxxobjs :=3D $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs))) =20 +# Rust code +# Executables compiled from a single Rust crate (which may consist of +# one or more .rs files) +host-rust :=3D $(foreach m,$(hostprogs),$(if $($(m)-rust),$(m))) + host-csingle :=3D $(addprefix $(obj)/,$(host-csingle)) host-cmulti :=3D $(addprefix $(obj)/,$(host-cmulti)) host-cobjs :=3D $(addprefix $(obj)/,$(host-cobjs)) host-cxxmulti :=3D $(addprefix $(obj)/,$(host-cxxmulti)) host-cxxobjs :=3D $(addprefix $(obj)/,$(host-cxxobjs)) +host-rust :=3D $(addprefix $(obj)/,$(host-rust)) =20 ##### # Handle options to gcc. Support building with separate output directory @@ -71,6 +84,8 @@ _hostc_flags =3D $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFL= AGS) \ $(HOSTCFLAGS_$(target-stem).o) _hostcxx_flags =3D $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ $(HOSTCXXFLAGS_$(target-stem).o) +_hostrust_flags =3D $(KBUILD_HOSTRUSTFLAGS) $(HOST_EXTRARUSTFLAGS) \ + $(HOSTRUSTFLAGS_$(target-stem)) =20 # $(objtree)/$(obj) for including generated headers from checkin source fi= les ifeq ($(KBUILD_EXTMOD),) @@ -82,6 +97,7 @@ endif =20 hostc_flags =3D -Wp,-MMD,$(depfile) $(_hostc_flags) hostcxx_flags =3D -Wp,-MMD,$(depfile) $(_hostcxx_flags) +hostrust_flags =3D $(_hostrust_flags) =20 ##### # Compile programs on the host @@ -128,5 +144,17 @@ quiet_cmd_host-cxxobjs =3D HOSTCXX $@ $(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE $(call if_changed_dep,host-cxxobjs) =20 +# Create executable from a single Rust crate (which may consist of +# one or more `.rs` files) +# host-rust -> Executable +quiet_cmd_host-rust =3D HOSTRUSTC $@ + cmd_host-rust =3D \ + $(HOSTRUSTC) $(hostrust_flags) --emit=3Ddep-info,link \ + --out-dir=3D$(obj)/ $<; \ + mv $(obj)/$(target-stem).d $(depfile); \ + sed -i '/^\#/d' $(depfile) +$(host-rust): $(obj)/%: $(src)/%.rs FORCE + $(call if_changed_dep,host-rust) + targets +=3D $(host-csingle) $(host-cmulti) $(host-cobjs) \ - $(host-cxxmulti) $(host-cxxobjs) + $(host-cxxmulti) $(host-cxxobjs) $(host-rust) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 3fb6a99e78c4..c88b98b5dc44 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -8,6 +8,7 @@ ldflags-y +=3D $(EXTRA_LDFLAGS) # flags that take effect in current and sub directories KBUILD_AFLAGS +=3D $(subdir-asflags-y) KBUILD_CFLAGS +=3D $(subdir-ccflags-y) +KBUILD_RUSTFLAGS +=3D $(subdir-rustflags-y) =20 # Figure out what we need to build from the various variables # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D @@ -128,6 +129,10 @@ _c_flags =3D $(filter-out $(CFLAGS_REMOVE_$(targ= et-stem).o), \ $(filter-out $(ccflags-remove-y), \ $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(ccflags-y))= \ $(CFLAGS_$(target-stem).o)) +_rust_flags =3D $(filter-out $(RUSTFLAGS_REMOVE_$(target-stem).o), \ + $(filter-out $(rustflags-remove-y), \ + $(KBUILD_RUSTFLAGS) $(rustflags-y)) \ + $(RUSTFLAGS_$(target-stem).o)) _a_flags =3D $(filter-out $(AFLAGS_REMOVE_$(target-stem).o), \ $(filter-out $(asflags-remove-y), \ $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(asflags-y))= \ @@ -202,6 +207,11 @@ modkern_cflags =3D = \ $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \ $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL) $(modfile_flags)) =20 +modkern_rustflags =3D \ + $(if $(part-of-module), \ + $(KBUILD_RUSTFLAGS_MODULE) $(RUSTFLAGS_MODULE), \ + $(KBUILD_RUSTFLAGS_KERNEL) $(RUSTFLAGS_KERNEL)) + modkern_aflags =3D $(if $(part-of-module), \ $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE), \ $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)) @@ -211,6 +221,8 @@ c_flags =3D -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS= ) $(LINUXINCLUDE) \ $(_c_flags) $(modkern_cflags) \ $(basename_flags) $(modname_flags) =20 +rust_flags =3D $(_rust_flags) $(modkern_rustflags) @$(objtree)/include= /generated/rustc_cfg + a_flags =3D -Wp,-MMD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) = \ $(_a_flags) $(modkern_aflags) =20 diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 35100e981f4a..9a1fa6aa30fe 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -39,11 +39,13 @@ quiet_cmd_ld_ko_o =3D LD [M] $@ =20 quiet_cmd_btf_ko =3D BTF [M] $@ cmd_btf_ko =3D \ - if [ -f vmlinux ]; then \ + if [ ! -f vmlinux ]; then \ + printf "Skipping BTF generation for %s due to unavailability of vmlinux\= n" $@ 1>&2; \ + elif [ -n "$(CONFIG_RUST)" ] && $(srctree)/scripts/is_rust_module.sh $@; = then \ + printf "Skipping BTF generation for %s because it's a Rust module\n" $@ = 1>&2; \ + else \ LLVM_OBJCOPY=3D"$(OBJCOPY)" $(PAHOLE) -J $(PAHOLE_FLAGS) --btf_base vmli= nux $@; \ $(RESOLVE_BTFIDS) -b vmlinux $@; \ - else \ - printf "Skipping BTF generation for %s due to unavailability of vmlinux\= n" $@ 1>&2; \ fi; =20 # Same as newer-prereqs, but allows to exclude specified extra dependencies diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh index f1952c522466..2401c86fcf53 100755 --- a/scripts/cc-version.sh +++ b/scripts/cc-version.sh @@ -1,13 +1,13 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 # -# Print the compiler name and its version in a 5 or 6-digit form. +# Print the C compiler name and its version in a 5 or 6-digit form. # Also, perform the minimum version check. =20 set -e =20 -# Print the compiler name and some version components. -get_compiler_info() +# Print the C compiler name and some version components. +get_c_compiler_info() { cat <<- EOF | "$@" -E -P -x c - 2>/dev/null #if defined(__clang__) @@ -32,7 +32,7 @@ get_canonical_version() =20 # $@ instead of $1 because multiple words might be given, e.g. CC=3D"ccach= e gcc". orig_args=3D"$@" -set -- $(get_compiler_info "$@") +set -- $(get_c_compiler_info "$@") =20 name=3D$1 =20 @@ -52,7 +52,7 @@ ICC) min_version=3D$($min_tool_version icc) ;; *) - echo "$orig_args: unknown compiler" >&2 + echo "$orig_args: unknown C compiler" >&2 exit 1 ;; esac @@ -62,7 +62,7 @@ min_cversion=3D$(get_canonical_version $min_version) =20 if [ "$cversion" -lt "$min_cversion" ]; then echo >&2 "***" - echo >&2 "*** Compiler is too old." + echo >&2 "*** C compiler is too old." echo >&2 "*** Your $name version: $version" echo >&2 "*** Minimum $name version: $min_version" echo >&2 "***" diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index c4340c90e172..b7c9f1dd5e42 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -216,6 +216,13 @@ static const char *conf_get_autoheader_name(void) return name ? name : "include/generated/autoconf.h"; } =20 +static const char *conf_get_rustccfg_name(void) +{ + char *name =3D getenv("KCONFIG_RUSTCCFG"); + + return name ? name : "include/generated/rustc_cfg"; +} + static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, ch= ar *p) { char *p2; @@ -605,6 +612,9 @@ static const struct comment_style comment_style_c =3D { =20 static void conf_write_heading(FILE *fp, const struct comment_style *cs) { + if (!cs) + return; + fprintf(fp, "%s\n", cs->prefix); =20 fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n", @@ -745,6 +755,65 @@ static void print_symbol_for_c(FILE *fp, struct symbol= *sym) free(escaped); } =20 +static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym) +{ + const char *val; + const char *val_prefix =3D ""; + char *val_prefixed =3D NULL; + size_t val_prefixed_len; + char *escaped =3D NULL; + + if (sym->type =3D=3D S_UNKNOWN) + return; + + val =3D sym_get_string_value(sym); + + switch (sym->type) { + case S_BOOLEAN: + case S_TRISTATE: + /* + * We do not care about disabled ones, i.e. no need for + * what otherwise are "comments" in other printers. + */ + if (*val =3D=3D 'n') + return; + + /* + * To have similar functionality to the C macro `IS_ENABLED()` + * we provide an empty `--cfg CONFIG_X` here in both `y` + * and `m` cases. + * + * Then, the common `fprintf()` below will also give us + * a `--cfg CONFIG_X=3D"y"` or `--cfg CONFIG_X=3D"m"`, which can + * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`. + */ + fprintf(fp, "--cfg=3D%s%s\n", CONFIG_, sym->name); + break; + case S_HEX: + if (val[0] !=3D '0' || (val[1] !=3D 'x' && val[1] !=3D 'X')) + val_prefix =3D "0x"; + break; + default: + break; + } + + if (strlen(val_prefix) > 0) { + val_prefixed_len =3D strlen(val) + strlen(val_prefix) + 1; + val_prefixed =3D xmalloc(val_prefixed_len); + snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val); + val =3D val_prefixed; + } + + /* All values get escaped: the `--cfg` option only takes strings */ + escaped =3D escape_string_value(val); + val =3D escaped; + + fprintf(fp, "--cfg=3D%s%s=3D%s\n", CONFIG_, sym->name, val); + + free(escaped); + free(val_prefixed); +} + /* * Write out a minimal config. * All values that has default values are skipped as this is redundant. @@ -1132,6 +1201,12 @@ int conf_write_autoconf(int overwrite) if (ret) return ret; =20 + ret =3D __conf_write_autoconf(conf_get_rustccfg_name(), + print_symbol_for_rustccfg, + NULL); + if (ret) + return ret; + /* * Create include/config/auto.conf. This must be the last step because * Kbuild has a dependency on auto.conf and this marks the successful --=20 2.37.3