public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-dev] [PATCH 0/4] linux-mod-r1.eclass: new eclass, rewrite of -r0
@ 2023-05-26  4:02 Ionen Wolkens
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 1/4] profiles/use.desc: create USE=strip global USE flag Ionen Wolkens
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Ionen Wolkens @ 2023-05-26  4:02 UTC (permalink / raw
  To: gentoo-dev

Posting here for early general feedback / review, see also the PR[1].

Please try to migrate some ebuilds using it, small issues / nitpicks
can be resolved anytime but usage changes could be messy after merge.

Refer to eclass docs for usage and migration instructions. Commit
message for linux-mod-r1 gives an overview of feature differences
with -r0.

Including a simple migrated ebuild (ryzen_smu) to show what it
looks like. PR[1] has additional ones, currently: nvidia-drivers,
virtualbox-modules, xpadneo, and zfs-kmod.

[1] https://github.com/gentoo/gentoo/pull/31154

Ionen Wolkens (4):
  profiles/use.desc: create USE=strip global USE flag
  profiles/use.desc: create USE=modules-sign global USE flag
  linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass
  app-admin/ryzen_smu: migrate to linux-mod-r1

 .../ryzen_smu-0.1.2_p20211205-r1.ebuild       |   28 +
 eclass/linux-mod-r1.eclass                    | 1199 +++++++++++++++++
 profiles/use.desc                             |    2 +
 3 files changed, 1229 insertions(+)
 create mode 100644 app-admin/ryzen_smu/ryzen_smu-0.1.2_p20211205-r1.ebuild
 create mode 100644 eclass/linux-mod-r1.eclass

-- 
2.40.1



^ permalink raw reply	[flat|nested] 9+ messages in thread

* [gentoo-dev] [PATCH 1/4] profiles/use.desc: create USE=strip global USE flag
  2023-05-26  4:02 [gentoo-dev] [PATCH 0/4] linux-mod-r1.eclass: new eclass, rewrite of -r0 Ionen Wolkens
@ 2023-05-26  4:02 ` Ionen Wolkens
  2023-05-26  5:06   ` Sam James
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 2/4] profiles/use.desc: create USE=modules-sign " Ionen Wolkens
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Ionen Wolkens @ 2023-05-26  4:02 UTC (permalink / raw
  To: gentoo-dev

Primarily intended for use by linux-mod-r1.eclass, which needs
a global IUSE to control stripping of kernel modules *before*
signatures and compression (alternative would be to simply never
strip, but that seem sub-optimal).

Originally meant to be USE=modules-strip or similar, but this can
have a more general use case when portage does not know how to
strip special files properly while the ebuild does.

Notable is mingw ebuilds (wine-*, dxvk, vkd3d-proton, mingw64-*).
If portage uses x86_64-pc-linux-strip on, e.g. mingw64-toolchain's
runtime libraries, then at least the 32bit toolchain ends up broken
and cannot compile anything anymore. But then dostrip -x results in
unstripped files while we can use x86_64-w64-mingw32-strip in the
ebuild potentially saving 60MB+. Currently this is done through
USE=debug, but does not feel fully fitting given this isn't about
adding debugging paths (or even symbols, or anything) and is merely
"do not strip".

No USE in ::gentoo currently contain the word "strip" and defining
it should not conflict.

Signed-off-by: Ionen Wolkens <ionen@gentoo.org>
---
 profiles/use.desc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/profiles/use.desc b/profiles/use.desc
index 47438c839071..aa5d16dd652e 100644
--- a/profiles/use.desc
+++ b/profiles/use.desc
@@ -301,6 +301,7 @@ ssl - Add support for SSL/TLS connections (Secure Socket Layer / Transport Layer
 startup-notification - Enable application startup event feedback mechanism
 static - !!do not set this during bootstrap!! Causes binaries to be statically linked instead of dynamically
 static-libs - Build static versions of dynamic libraries as well
+strip - Allow symbol stripping to be performed by the ebuild for special files
 subversion - Enable subversion (version control system) support
 suid - Enable setuid root program(s)
 svg - Add support for SVG (Scalable Vector Graphics)
-- 
2.40.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [gentoo-dev] [PATCH 2/4] profiles/use.desc: create USE=modules-sign global USE flag
  2023-05-26  4:02 [gentoo-dev] [PATCH 0/4] linux-mod-r1.eclass: new eclass, rewrite of -r0 Ionen Wolkens
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 1/4] profiles/use.desc: create USE=strip global USE flag Ionen Wolkens
@ 2023-05-26  4:02 ` Ionen Wolkens
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 3/4] linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass Ionen Wolkens
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 4/4] app-admin/ryzen_smu: migrate to linux-mod-r1 Ionen Wolkens
  3 siblings, 0 replies; 9+ messages in thread
From: Ionen Wolkens @ 2023-05-26  4:02 UTC (permalink / raw
  To: gentoo-dev

Similarly to gyakovlev's proposition for signing back in 2018 (with
a module-sign IUSE), linux-mod-r1.eclass will make use of this to
enable/disable signing and it would be inconvenient if consumers
had to define it.

An alternative could be to automagic enable when the kernel has
"sign by default" a bit like compression is handled -- albeit this
can sometime need more configuration and may be unexpected (i.e.
permissions for keys, if keys were moved to a different locations,
passphrases, and dist-kernels unsurprisingly don't install the
private key and would result in failure out-of-the-box).

Having a USE also makes it more obvious that support exists,
and attempting to enable will give bit of explanations if anything
is amiss.

Name-wise, debated between this and 'sign-modules' but fwiw former
sorts better with the already existing 'modules'.

Signed-off-by: Ionen Wolkens <ionen@gentoo.org>
---
 profiles/use.desc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/profiles/use.desc b/profiles/use.desc
index aa5d16dd652e..bd8cb7031ab8 100644
--- a/profiles/use.desc
+++ b/profiles/use.desc
@@ -192,6 +192,7 @@ mms - Support for Microsoft Media Server (MMS) streams
 mng - Add support for libmng (MNG images)
 modplug - Add libmodplug support for playing SoundTracker-style music files
 modules - Build the kernel modules
+modules-sign - Cryptographically sign installed kernel modules (requires CONFIG_MODULE_SIG=y in the kernel)
 mono - Build Mono bindings to support dotnet type stuff
 motif - Add support for the Motif toolkit
 mp3 - Add support for reading mp3 files
-- 
2.40.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [gentoo-dev] [PATCH 3/4] linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass
  2023-05-26  4:02 [gentoo-dev] [PATCH 0/4] linux-mod-r1.eclass: new eclass, rewrite of -r0 Ionen Wolkens
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 1/4] profiles/use.desc: create USE=strip global USE flag Ionen Wolkens
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 2/4] profiles/use.desc: create USE=modules-sign " Ionen Wolkens
@ 2023-05-26  4:02 ` Ionen Wolkens
  2023-05-28 12:41   ` [gentoo-dev] [PATCH v2] " Ionen Wolkens
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 4/4] app-admin/ryzen_smu: migrate to linux-mod-r1 Ionen Wolkens
  3 siblings, 1 reply; 9+ messages in thread
From: Ionen Wolkens @ 2023-05-26  4:02 UTC (permalink / raw
  To: gentoo-dev

Here's a rough overview of -r0 -> -r1 differences with occasional
rationale behind them if felt relevant (for migrating, refer to
the eclassdocs instead as this does not really document usage
changes):

Features that did not exist in previous eclass (not exhaustive):
* automatic modules signing support, been often requested and
  users would instead use messy bashrc hacks to accomplish this
 (enabled with USE=modules-sign)
* modules (manual) stripping support to allow stripping *before*
  signing and compression
 (can be disabled with USE=-strip)
* can auto-select toolchain to match kernel, e.g. if built with
  clang-15 then it won't use gcc nor clang-16 if possible
 (will warn if the matching compiler went missing)
* helper functions to profit from the above 3 even if not using
  linux-mod-r1_src_compile+install (e.g. for zfs-kmod)
* generic supported kernel version checks (min/max) which comes with
  an encouragement to use LTS kernels for out-of-tree modules
 (but max is not enforced, just makes a strong suggestion)
* linux-mod-r1_src_install now does einstalldocs
* can guess some common build targets rather than just 'module',
  largely removing the need for BUILD_TARGETS
* user-oriented MODULES_EXTRA_EMAKE among other few variables
* various additional sanity checks hopefully making issues
  clearer for users and ebuilds a bit harder to write wrong

"Features" that existed but were not kept (not exhaustive):
* support for <kernel-2.6(!) modules, eclass only tested with >=4.14.x
* allowing doing all in global scope using variables ran through `eval`
 (this often led to all sort of variable misuse in global scope)
* MODULESD_* support, originally meant to keep but it is used by only
  5 packages and holds very little meaning that I can see even in these
 (when needed, packages should write their own .conf)
* moduledb, was being updated for nothing in postinst/postrm
  despite the tool that can use this (sys-kernel/module-rebuild)
  being gone from the tree since Feb 2014
* convert_to_m(), only 1 in-tree ebuild uses this right now (svgalib)
* various other functions with no consumers were dropped, some
  were likely meant to be @INTERNAL, get-KERNEL_CC was never used
  either and now there's ${KERNEL_CC}
* running 'clean' by default, this sometime led to race conditions by
  attempting to clean and build at same time in e.g. nvidia-drivers
 (if an ebuild truly need this, it can be specified manually)
* BUILD_FIXES support, this is set by linux-info.eclass but has no
  real relevance that I can see (ebuilds have sometime wrongly used it)
* undocumented feature CONFIG_CHECK="@CONFIG:modname" (or so?) meant
  for automagic based on kernel config is no longer supported, this
  also removes the also undocumented MODULE_IGNORE used by it (found
  0 ebuilds using these in the tree, can be done manually if needed)
* converting CONFIG_CHECK to non-fatal for running again on binary
  merge when (while *possible*) it's rather unlikely would build
  modules for a different kernel than the one that will be used
* having preinst and postrm exports, removed
  -> originally wanted to remove pkg_setup too but it complicated
     things with linux-info's own pkg_setup and made the eclass
     feel less convenient and error-prone with environment handling

Dependency changes:
* virtual/libelf DEPEND removed, building objtool (which uses this) is
  not handled by the eclass and does not seem auto-built by make if
  missing, as such the dependency is not used *here* but rather by
  dist-kernels and source packages which both already request it.
* sys-apps/kmod[tools] BDEPEND+IDEPEND added, and removed from DEPEND
  (linux-mod-r0 uses it similarly but lacks the eapi7+8 adjustment)
* modules-sign? ( dev-libs/openssl virtual/pkgconfig ) BDEPEND for
  building sign-file, unlike objtool it may need rebuilds for openssl
  and is handled here
* dependencies are no longer guarded by "kernel_linux? ( )", it only
  served to silence pkgcheck and then give build failures (linux-only
  ebuilds should be masked on non-Linux profiles or, if mixed, use a
  masked MODULES_OPTIONAL_IUSE which *can* be kernel_linux).

Tentative changes:
* drop KERNEL_ABI support, (nowadays) kernel seems to append its own
  -m32/-m64 and should be no need for multilib.eclass complications
 (tested to work *at least* with x32[userland]+64bit[kernel])
* ^ but add hppa2.0->64 kgcc64 switching like kernel-build.eclass
* drop addpredict wrt bug #653286, assuming no longer relevant given
  unable to reproduce even with kernel-4.14.315+split-debug+some misc
  modules, perhaps would with spl but that (removed) ebuild is too
  broken to try

Misc changes:
* misc -> extra default install dir, to match the kernel's defaults
 (this is also where zfs-kmod already installs due to that default)

Three bugs were addressed, but not closing given -r0 remains affected:
* bug #447352: modules signing is supported
* bug #759238: arguably not an issue anymore in -r0 either due to
  CHECKCONFIG_DONOTHING=1 (bug #862315) now existing, but -r1
  additionally makes it non-fatal if a whitelist exists in the kernel
* bug #816024: trying to select toolchain better is a -r1 highlight

Bug: https://bugs.gentoo.org/447352
Bug: https://bugs.gentoo.org/759238
Bug: https://bugs.gentoo.org/816024
Signed-off-by: Ionen Wolkens <ionen@gentoo.org>
---
 eclass/linux-mod-r1.eclass | 1199 ++++++++++++++++++++++++++++++++++++
 1 file changed, 1199 insertions(+)
 create mode 100644 eclass/linux-mod-r1.eclass

diff --git a/eclass/linux-mod-r1.eclass b/eclass/linux-mod-r1.eclass
new file mode 100644
index 000000000000..27f4ceeb2d85
--- /dev/null
+++ b/eclass/linux-mod-r1.eclass
@@ -0,0 +1,1199 @@
+# Copyright 2023 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: linux-mod-r1.eclass
+# @MAINTAINER:
+# Ionen Wolkens <ionen@gentoo.org>
+# Gentoo Kernel project <kernel@gentoo.org>
+# @AUTHOR:
+# Ionen Wolkens <ionen@gentoo.org>
+# @SUPPORTED_EAPIS: 8
+# @PROVIDES: linux-info
+# @BLURB: Functions for installing out-of-tree Linux kernel modules
+# @DESCRIPTION:
+# See the linux-mod-r1_src_compile function documentation for in-depth
+# usage, and see the example further down for a quick overview.
+#
+# @SUBSECTION linux-mod -> linux-mod-r1 migration overview
+#  0. Define a src_compile if missing, local variables below go there.
+#  1. MODULE_NAMES="name(libdir:srcdir:objdir)"
+#     BUILD_TARGETS="target"
+#       -> local modlist=( name=libdir:srcdir:objdir:target(s) )
+#     - try without :target first, it is now almost always unnecessary
+#     - srcdir defaults to the current directory, and note that paths
+#       can be relative to that (should typically *not* pass ${S})
+#     - "name(misc)" or "(extra)" are fine just as modlist=( name )
+#  2. BUILD_PARAMS and/or BUILD_FIXES
+#       -> local modargs=( VAR="${KV_OUT_DIR}" ... )
+#     - CC/LD and similar are unneeded, always passed (V=1 too)
+#     - eval (aka eval "${BUILD_PARAMS}") is /not/ used for this anymore
+#  3. s/linux-mod_/linux-mod-r1/g
+#  4. _preinst+_postrm can be dropped, keep linux-mod-r1_pkg_postinst
+#  5. linux-mod-r1_src_install now runs einstalldocs, adjust as needed
+#  6. if *not* using linux-mod-r1_src_compile/install, should look at:
+#     modules_makeargs_to_array + linux_domodule + modules_post_process
+#  7. If any, clang<->gcc switching custom workarounds can be dropped
+#  8. See MODULES_KERNEL_MAX/_MIN if had or need kernel version checks.
+#
+# Not an exhaustive list, verify that no installed files are missing
+# after.  Look for "command not found" errors in the build log too.
+#
+# @EXAMPLE:
+#
+# If source directory S had a layout such as:
+#  - Makefile (builds a gentoo.ko in current directory)
+#  - gamepad/Makefile (want to install to kernel/drivers/hid)
+#  - gamepad/obj/ (the built gamepad.ko ends up here)
+#
+# then:
+#
+# @CODE
+# CONFIG_CHECK="INPUT_FF_MEMLESS" # gamepad needs it to rumble
+# MODULES_KERNEL_MIN=5.4 # needs features introduced in 5.4
+#
+# src_compile() {
+#     local modlist=(
+#         # module-name=install-dir:source-dir:build-dir:make-target(s)
+#         gentoo
+#         gamepad=kernel/drivers/hid:gamepad:gamepad/obj
+#     )
+#     local modargs=(
+#         # Makefile *here* uses this, should inspect Makefiles for the
+#         # right source variable (about KV_, see linux-info eclass).
+#         NIH_KERNEL_SOURCE_VARIABLE="${KV_OUT_DIR}"
+#     )
+#
+#     linux-mod-r1_src_compile
+# }
+# @CODE
+#
+# Or if using the package's build system directly is more convenient:
+#
+# @CODE
+# src_compile() {
+#     local emakeargs=(
+#         KDIR="${KV_OUT_DIR}"
+#         KSRC="${KV_DIR}"
+#     )
+#     modules_makeargs_to_array emakeargs # adds ARCH, CC, etc..
+#
+#     emake "${emakeargs[@]}"
+# }
+#
+# src_install() {
+#     emake ... install # or linux_domodule ...
+#
+#     modules_post_process # strip->sign->compress
+# }
+# @CODE
+#
+# (please ensure linux-mod-r1_pkg_postinst is ran in either methods)
+
+case ${EAPI} in
+	8) ;;
+	*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
+esac
+
+if [[ ! ${_LINUX_MOD_R1_ECLASS} ]]; then
+_LINUX_MOD_R1_ECLASS=1
+
+inherit edo linux-info multiprocessing toolchain-funcs
+
+IUSE="dist-kernel modules-sign +strip ${MODULES_OPTIONAL_IUSE}"
+
+RDEPEND="
+	sys-apps/kmod[tools]
+	dist-kernel? ( virtual/dist-kernel:= )
+"
+DEPEND="
+	virtual/linux-sources
+"
+BDEPEND="
+	sys-apps/kmod[tools]
+	modules-sign? (
+		dev-libs/openssl
+		virtual/pkgconfig
+	)
+"
+IDEPEND="
+	sys-apps/kmod[tools]
+"
+
+if [[ -n ${MODULES_OPTIONAL_IUSE} ]]; then
+	: "${MODULES_OPTIONAL_IUSE#+}? ( | )"
+	RDEPEND=${_/|/${RDEPEND}} DEPEND=${_/|/${DEPEND}} \
+		BDEPEND=${_/|/${BDEPEND}} IDEPEND=${_/|/${IDEPEND}}
+fi
+
+# @ECLASS_VARIABLE: KERNEL_CHOST
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Can be set to the CHOST value to use when selecting the toolchain
+# for building kernel modules.  This is similar to setting the kernel
+# build system's CROSS_COMPILE variable minus the trailing dash.
+#
+# If this does not auto-select the desired toolchain, finer control
+# can be achieved by setting the not directly documented (but valid)
+# variables:
+#
+# KERNEL_{CC,CXX,LD,AR,NM,OBJCOPY,OBJDUMP,READELF,STRIP}
+#
+# If in doubt, do not set any of this.
+#
+# Default if unset: auto-detection, typically same as the current CHOST
+
+# @ECLASS_VARIABLE: MODULES_EXTRA_EMAKE
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Extra arguments to pass to emake when building modules.
+# Can contain arguments with quoted spaces, e.g.
+# @CODE
+# ..._EMAKE="KCFLAGS='-fzomg-optimize -fsuper-strict-aliasing' ..."
+# @CODE
+
+# @ECLASS_VARIABLE: MODULES_I_WANT_FULL_CONTROL
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# When set to a non-empty value, disables passing most of the eclass'
+# defaults to emake when building modules.  Users' MODULES_EXTRA_EMAKE
+# and ebuilds' modargs will still be used if set.  Primarily
+# intended for expert users with modified kernel Makefiles.
+#
+# May want to look at KERNEL_CHOST before considering this.
+
+# @ECLASS_VARIABLE: MODULES_SIGN_HASH
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Used with USE=modules-sign.  Can be set to hash algorithm to use
+# during signature generation.
+#
+# Rather than set this, it is recommended to select using the kernel's
+# configuration to ensure proper support (e.g. CONFIG_MODULE_SIG_SHA256),
+# and then it will be auto-detected here.
+#
+# Valid values: sha512,sha384,sha256,sha224,sha1
+#
+# Default if unset: kernel CONFIG_MODULE_SIG_HASH's value
+
+# @ECLASS_VARIABLE: MODULES_SIGN_KEY
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Used with USE=modules-sign.  Can be set to the path of the private
+# key in PEM format to use, or a PKCS#11 URI.
+#
+# If path is relative (e.g. "certs/name.pem"), it is assumed to be
+# relative to the kernel build directory being used.
+#
+# If the key requires a passphrase or PIN, the used kernel sign-file
+# utility recognizes the KBUILD_SIGN_PIN environment variable.  Be
+# warned that the package manager may store this value in binary
+# packages, database files, temporary files, and possibly logs.  This
+# eclass unsets the variable after use to mitigate the issue (notably
+# for shared binary packages), but use this with care.
+#
+# Default if unset: kernel CONFIG_MODULE_SIG_KEY's value which itself
+# defaults to certs/signing_key.pem
+
+# @ECLASS_VARIABLE: MODULES_SIGN_CERT
+# @USER_VARIABLE
+# @DESCRIPTION:
+# Used with USE=modules-sign.  Can be set to the path of the X.509
+# public key certificate to use.
+#
+# If path is relative (e.g. "certs/name.x509"), it is assumed to be
+# relative to the kernel build directory being used.
+: "${MODULES_SIGN_CERT:=certs/signing_key.x509}"
+
+# @ECLASS_VARIABLE: INSTALL_MOD_PATH
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Prefix to install modules to, i.e. <modpath>/lib/modules.
+# Recognized to mimic the kernel's own ``make modules_install``.
+#
+# If in doubt, do not set this.
+
+# @ECLASS_VARIABLE: MODULES_KERNEL_MAX
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a kernel version (format: 1, 1.2, or 1.2.3), will print a
+# warning if the used version is greater than (ver_test -gt) to this
+# value using the same amount of version components (i.e. MAX=1.2
+# allows 1.2.3, but MAX=1.2.2 does not).
+#
+# This should *only* be used for modules that are known to break
+# frequently on upgrades.  If setting this to a non-LTS kernel, then
+# should also take care to test and update this value regularly with
+# new major kernel releases not to let the warning become stale and
+# ignored by users.
+#
+# Not fatal to allow users to try or self-patch easily, but the (large)
+# warning is difficult to miss.  If need a fatal check for more serious
+# issues (e.g. filesystem corruption), please do it manually.
+#
+# This is intended to reduce the amount of bug reports for recurring
+# expected issues that can be easily mitigated by using LTS kernels
+# and waiting for new releases.
+#
+# If used, must be set before linux-mod-r1_pkg_setup is called.
+
+# @ECLASS_VARIABLE: MODULES_KERNEL_MIN
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a kernel version (format: 1, 1.2, or 1.2.3), will abort if
+# the used version is less than (ver_test -lt) this value.
+#
+# Should only be used if known broken, or if upstream recommends a sane
+# minimum.  Not particularly necessary for kernels that are no longer
+# in the tree.
+#
+# If used, must be set before linux-mod-r1_pkg_setup is called.
+
+# @ECLASS_VARIABLE: MODULES_OPTIONAL_IUSE
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# May contain a single flag to be added to IUSE optionally prefixed
+# with a + sign to enable it by default.  Doing so makes *all* of
+# linux-mod-r1's functions and dependencies a no-op unless the flag
+# is enabled.  This includes phases, e.g. linux-mod-r1_pkg_setup will
+# not process CONFIG_CHECK unless the flag is set.
+#
+# The typical recommended value is "+modules".
+#
+# Note that modules being optional can be useful even if user space
+# tools require them (e.g. installing in a chroot or prefix when the
+# modules are loaded on the host, saves setting up linux sources).
+# However, if tools are non-trivial to build, it may be preferable
+# to split into two packages than use this variable due to requiring
+# rebuilds every kernel upgrades.
+
+# @FUNCTION: linux-mod-r1_pkg_setup
+# @DESCRIPTION:
+# Required before using other functions from this eclass, and will:
+#  1. run linux-info_pkg_setup (see linux-info.eclass)
+#  -> implies processing CONFIG_CHECK, and providing KV_* variables
+#    (MODULES and TRIM_UNUSED_KSYMS are checked by default)
+#  2. prepare toolchain to match the kernel
+#  -> sets KERNEL_{CHOST,CC,CXX,LD,AR,NM,OBJCOPY,OBJDUMP,READELF,STRIP}
+#  3. perform various sanity check to fail early on issues
+linux-mod-r1_pkg_setup() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	[[ ${MERGE_TYPE} != binary ]] || return 0
+	_MODULES_GLOBAL[ran:pkg_setup]=1
+	_modules_check_function ${#} 0 0 || return 0
+	_modules_check_migration
+
+	_modules_prepare_kernel
+
+	# note: modules-specific check_modules_supported could probably be
+	# removed from linux-info in the future as this is a sufficient check
+	local CONFIG_CHECK="${CONFIG_CHECK} MODULES"
+
+	# kernel will not typically know about symbols we use (bug #591832),
+	# but stay non-fatal if kernel has an exception list set (bug #759238)
+	# note: possible to bypass either way with CHECKCONFIG_DONOTHING=1
+	if [[ $(linux_chkconfig_string UNUSED_KSYMS_WHITELIST) == \"+(?)\" ]]; then
+		CONFIG_CHECK+=" ~!TRIM_UNUSED_KSYMS"
+	else
+		CONFIG_CHECK+=" !TRIM_UNUSED_KSYMS"
+	fi
+
+	linux-info_pkg_setup
+
+	_modules_prepare_sign
+	_modules_prepare_toolchain
+}
+
+# @FUNCTION: linux-mod-r1_src_compile
+# @DESCRIPTION:
+# Builds modules, see the eclass' example for a quick overview.
+# Uses the variables modlist and modargs as described below:
+#
+# * local modlist=( ... ) - list of modules to build, set as:
+#
+#     module-name=install-dir:source-dir:build-dir:make-target
+#
+# > module-name: Resulting name, aka <module-name>.ko (required).
+#
+# > install-dir: Kernel modules sub-directory to install the module
+# to (/lib/modules/version/<install-dir>/name.ko).  Will be used when
+# run linux-mod-r1_src_install.  May want to consider the values of
+# INSTALL_MOD_DIR(Makefile) or DEST_MODULE_LOCATION(dkms.conf) if it
+# exists, but it can be anything.
+#  -> Default: extra
+#
+# > source-dir: Directory containing the Makefile to build the module,
+# path can be relative to the current directory or absolute.
+#  -> Default: current directory
+#
+# > build-dir: Directory that will hold the built module-name.ko.
+#  -> Default: same as source-dir's value
+#
+# > make-target: Almost always unneeded but, if defaults are not right,
+# then can specify the Makefile's target(s) to build the module/extras.
+# Multiple targets can be used with spaces, e.g. :"first second".
+#  -> Default: specially tries modules, module, <name>.ko, <name>,
+# default, all, empty target, and runs the first found usable
+#
+# Missing elements results in defaults being used, e.g. this is valid:
+#   modlist=( name1 name2=:source name3=install::build )
+#
+# Tip: If all modules need the same arguments, they can be repeated by:
+#   modlist=( {mod1,mod2,mod3}=arguments )
+#
+# * local modargs=( ... ) - extra arguments to pass to emake
+#
+# Makefile should notably be inspected for which variable it uses
+# to find the kernel's build directory then, e.g. KDIR="${KV_OUT_DIR}"
+# as appropriate.  Note that typically want to pass KV_OUT_DIR(build)
+# rather than KV_DIR(sources) if not both.  This allows users to do
+# out-of-source kernel builds and still build modules.
+#
+# Passing common toolchain variables such as CC or LD is not needed
+# here as they are passed by default.
+#
+# ---
+#
+# Allowed to be called multiple times with a different modlist if need
+# different make arguments per modules or intermediate steps -- albeit,
+# if atypical, may want to build manually (see eclass' example).
+linux-mod-r1_src_compile() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 0 0 || return 0
+
+	[[ ${modlist@a} == *a* && ${#modlist[@]} -gt 0 ]] ||
+		die "${FUNCNAME[0]} was called without a 'modlist' array"
+
+	# run this again to verify built files access with src_compile's user
+	_modules_sanity_kernelbuilt
+
+	local -a emakeargs
+	modules_makeargs_to_array emakeargs
+
+	[[ ${modargs@a} == *a* ]] && emakeargs+=( "${modargs[@]}" )
+
+	local -A built=()
+	local build mod name target
+	for mod in "${modlist[@]}"; do
+		# note modlist was not made a [name]= associative array to preserve
+		# ordering, but is still using = to improve readability
+		name=${mod%%=*}
+		[[ -n ${name} && ${name} != *:* ]] || die "invalid mod entry '${mod}'"
+
+		# 0:install-dir 1:source-dir 2:build-dir 3:make-target(s)
+		mod=${mod#"${name}"}
+		IFS=: read -ra mod <<<"${mod#=}"
+		[[ ${#mod[@]} -le 4 ]] || die "too many ':' in ${name}'s modlist"
+
+		[[ ${mod[1]:=${PWD}} != /* ]] && mod[1]=${PWD}/${mod[1]}
+		[[ ${mod[2]:=${mod[1]}} != /* ]] && mod[2]=${PWD}/${mod[2]}
+		_MODULES_INSTALL[${mod[2]}/${name}.ko]=${mod[0]:-extra}
+
+		pushd "${mod[1]}" >/dev/null || die
+
+		if [[ -z ${mod[3]} ]]; then
+			# guess between commonly used targets if none given, fallback to
+			# an empty target without trying to see the error output
+			for target in module{s,} "${name}"{.ko,} default all; do
+				nonfatal emake "${emakeargs[@]}" -q "${target}" &>/dev/null
+				if [[ ${?} -eq 1 ]]; then
+					mod[3]=${target}
+					break
+				fi
+			done
+		fi
+
+		# sometime modules are all from same source dir and built all at once,
+		# make will not rebuild either way but can skip the unnecessary noise
+		build=
+		for target in ${mod[3]:-&}; do
+			if ! has "${target}" ${built[${mod[1]}]}; then
+				build=1
+				built[${mod[1]}]+=" ${target} "
+			fi
+		done
+
+		if [[ ${build} ]]; then
+			einfo "Building ${name} module in ${mod[1]} ..."
+
+			# allow word splitting for rare cases of multiple targets
+			emake "${emakeargs[@]}" ${mod[3]}
+		else
+			einfo "Building ${name} module in ${mod[1]} ... already done."
+		fi
+
+		popd >/dev/null || die
+	done
+}
+
+# @FUNCTION: linux-mod-r1_src_install
+# @DESCRIPTION:
+# Installs modules built by linux-mod-r1_src_compile using
+# linux_domodule, then runs modules_post_process and einstalldocs.
+linux-mod-r1_src_install() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 0 0 || return 0
+
+	(( ${#_MODULES_INSTALL[@]} )) ||
+		die "${FUNCNAME[0]} was called without running linux-mod-r1_src_compile"
+
+	(
+		for mod in "${!_MODULES_INSTALL[@]}"; do
+			linux_moduleinto "${_MODULES_INSTALL[${mod}]}"
+			linux_domodule "${mod}"
+		done
+	)
+
+	modules_post_process
+
+	einstalldocs
+}
+
+# @FUNCTION: linux-mod-r1_pkg_postinst
+# @DESCRIPTION:
+# Updates module dependencies using depmod.
+linux-mod-r1_pkg_postinst() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 0 0 || return 0
+
+	_modules_update_depmod
+
+	# post_process ensures modules were installed and that the eclass' USE
+	# are likely not no-ops (unfortunately postinst itself may be missed)
+	[[ -v _MODULES_GLOBAL[ran:post_process] ]] ||
+		eqawarn "QA Notice: neither linux-mod-r1_src_install nor modules_post_process were used"
+}
+
+# @FUNCTION: linux_domodule
+# @USAGE: <module>...
+# @DESCRIPTION:
+# Installs Linux modules (.ko files).
+#
+# See linux_moduleinto for more information and changing directories.
+linux_domodule() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 1 '' "<module>..." || return 0
+	(
+		# bug #642240: questionable how used/useful this is through ebuilds,
+		# but old linux-mod-r0, kernel, and some other module-related build
+		# systems recognize it leaving us the odd one out
+		insinto "${INSTALL_MOD_PATH}/lib/modules/${KV_FULL}/${_MODULES_GLOBAL[moduleinto]:-extra}"
+		doins "${@}"
+	)
+}
+
+# @FUNCTION: linux_moduleinto
+# @USAGE: <install-dir>
+# @DESCRIPTION:
+# Directory to install modules into when calling linux_domodule.
+# Relative to kernel modules path as in:
+# ${ED}${INSTALL_MOD_PATH}/lib/modules/${KV_FULL}/<install-dir>
+#
+# Can contain subdiretories, e.g. kernel/fs.
+#
+# If not called, defaults to "extra".  On the kernel build system,
+# this is like setting INSTALL_MOD_DIR which has the same default.
+linux_moduleinto() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 1 1 "<install-dir>" || return 0
+	_MODULES_GLOBAL[moduleinto]=${1}
+}
+
+# @FUNCTION: modules_makeargs_to_array
+# @USAGE: <array-name>
+# @DESCRIPTION:
+# Convenience function to append eclass' default modules make args such
+# as CC="${KERNEL_CC}" and ARCH="$(tc-arch-kernel)" to an array that can
+# be used to, e.g. `emake "${array-name[@]}"`.
+#
+# Primarily intended for when not relying on linux-mod-r1_src_compile.
+modules_makeargs_to_array() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 1 1 "<array-name>" || return 0
+
+	local -n _modules_args=${1}
+
+	_modules_args+=( ARCH="$(tc-arch-kernel)" )
+
+	if [[ ${MODULES_I_WANT_FULL_CONTROL} ]]; then
+		# keep ARCH given it is otherwise very broken in ebuilds, but users
+		# can still override the value through this MODULES_EXTRA_EMAKE
+		# (eval is to handle quoted spaces, die is for syntax errors)
+		eval "_modules_args+=( ${MODULES_EXTRA_EMAKE} )" || die
+	else
+		# many of these are unlikely to be useful here, but still trying to be
+		# complete given never know what out-of-tree modules may use
+		_modules_args+=(
+			V=1
+			# redundant with V, but needed sometimes (e.g. virtualbox-modules)
+			KBUILD_VERBOSE=1
+
+			# wrt bug #550428, given most toolchain variables are being passed to
+			# make, setting CROSS in the environment would change very little
+			# (instead set KERNEL_CHOST which will affect other variables,
+			# or MODULES_I_WANT_FULL_CONTROL if do not want any of this)
+			CROSS_COMPILE="${KERNEL_CHOST}-"
+
+			HOSTCC="$(tc-getBUILD_CC)"
+			HOSTCXX="$(tc-getBUILD_CXX)"
+
+			# fwiw this function is not meant to pollute the environment
+			HOSTCFLAGS="$(tc-export_build_env; echo "${BUILD_CFLAGS}")"
+			HOSTCXXFLAGS="$(tc-export_build_env; echo "${BUILD_CXXFLAGS}")"
+			HOSTLDFLAGS="$(tc-export_build_env; echo "${BUILD_LDFLAGS}")"
+
+			HOSTPKG_CONFIG="$(tc-getBUILD_PKG_CONFIG)"
+
+			CC="${KERNEL_CC}"
+			CXX="${KERNEL_CXX}"
+			LD="${KERNEL_LD}"
+			AR="${KERNEL_AR}"
+			NM="${KERNEL_NM}"
+			OBJCOPY="${KERNEL_OBJCOPY}"
+			OBJDUMP="${KERNEL_OBJDUMP}"
+			READELF="${KERNEL_READELF}"
+			STRIP=:
+		)
+
+		eval "_modules_args+=( ${MODULES_EXTRA_EMAKE} )" || die
+	fi
+}
+
+# @FUNCTION: modules_post_process
+# @USAGE: [<path>]
+# @DESCRIPTION:
+# Strip, sign, verify, and compress all .ko modules found under
+# <path>.  Should typically *not* be called directly as it will
+# be run by linux-mod-r1_src_install.
+#
+# <path> should exist under ${ED}${INSTALL_MOD_PATH}.
+# If unspecified it defaults to /lib/modules/${KV_FULL}
+#
+# Filenames may change due to compression, so any operations on
+# these should be performed prior.
+#
+# This is intended for use when modules were installed some other way.
+#
+# If installing through modules_install rather than linux_domodule,
+# could need to manually disable related features by doing, e.g.:
+# @CODE
+# local makeargs=(
+#     ...
+#     CONFIG_MODULE_{SIG_ALL,COMPRESS_{GZIP,XZ,ZSTD}}=
+#     DEPMOD=:
+# )
+# emake "${makeargs[@]}" modules_install
+# modules_post_process
+# @CODE
+#
+# Warning: If this finds no modules it will abort, which can happen if
+# modules were unexpectedly pre-compressed (likely due to the kernel
+# config) as it only looks at .ko filenames.
+modules_post_process() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 0 1 '[<path>]' || return 0
+	[[ ${EBUILD_PHASE} == install ]] ||
+		die "${FUNCNAME[0]} can only be called in the src_install phase"
+
+	local path=${ED}${INSTALL_MOD_PATH}${1-/lib/modules/${KV_FULL}}
+	local -a mods
+	[[ -d ${path} ]] && mapfile -td '' mods < <(
+		find "${path}" -type f -name '*.ko' -print0 || die
+	)
+	(( ${#mods[@]} )) ||
+		die "${FUNCNAME[0]} was called with no installed modules to process"
+
+	_modules_process_strip "${mods[@]}"
+	_modules_process_sign "${mods[@]}"
+	_modules_sanity_modversion "${mods[@]}" # after strip/sign in case broke it
+	_modules_process_compress "${mods[@]}"
+
+	_MODULES_GLOBAL[ran:post_process]=1
+}
+
+# @ECLASS_VARIABLE: _MODULES_GLOBAL
+# @INTERNAL
+# @DESCRIPTION:
+# General use associative array to avoid defining separate globals.
+declare -gA _MODULES_GLOBAL=()
+
+# @ECLASS_VARIABLE: _MODULES_INSTALL
+# @INTERNAL
+# @DESCRIPTION:
+# List of modules from linux-mod-r1_src_compile to be installed.
+declare -gA _MODULES_INSTALL=()
+
+# @FUNCTION: _modules_check_function
+# @USAGE: [<args-count> <args-min> <args-max> [<usage-string>]]
+# @RETURN: 0 or 1 if caller should do nothing
+# @INTERNAL
+# @DESCRIPTION:
+# Checks for MODULES_OPTIONAL_IUSE, and aborts if amount of arguments
+# does not add up or if it was called before linux-mod-r1_pkg_setup.
+_modules_check_function() {
+	[[ -z ${MODULES_OPTIONAL_IUSE} ]] ||
+		use "${MODULES_OPTIONAL_IUSE#+}" || return 1
+
+	[[ ${#} == 0 || ${1} -ge ${2} && ( ! ${3} || ${1} -le ${3} ) ]] ||
+		die "Usage: ${FUNCNAME[1]} ${4-(no arguments)}"
+
+	[[ -v _MODULES_GLOBAL[ran:pkg_setup] ]] ||
+		die "${FUNCNAME[1]} was called without running linux-mod-r1_pkg_setup"
+}
+
+# @FUNCTION: _modules_check_migration
+# @INTERNAL
+# @DESCRIPTION:
+# Dies if see obsolete variables from the linux-mod-r0 eclass being
+# used likely due to an incomplete migration.  This function should be
+# removed after linux-mod-r0 is @DEAD not to fail for nothing if users
+# happen to have these in their environment given the naming for some
+# is a bit generic.
+_modules_check_migration() {
+	_modules_check_var() {
+		[[ -z ${!1} ]] ||
+			die "${1} is obsolete, see ${2} in linux-mod-r1 eclassdocs"
+	}
+	# the 'I' on this one is notably sneaky and could silently be ignored
+	_modules_check_var MODULES_OPTIONAL_USE MODULES_OPTIONAL_IUSE
+	_modules_check_var MODULES_OPTIONAL_USE_IUSE_DEFAULT MODULES_OPTIONAL_IUSE
+	_modules_check_var BUILD_PARAMS modargs
+	_modules_check_var BUILD_TARGETS modlist
+	_modules_check_var MODULE_NAMES modlist
+	[[ -z ${!MODULESD_*} ]] ||
+		die "MODULESD_* variables are no longer supported, replace by handcrafted .conf files if needed"
+
+	# Ignored variables:
+	# - BUILD_FIXES: seen in some ebuilds but was undocumented and linux-info
+	#   still sets it preventing from blocking it entirely
+	# - ECONF_PARAMS: documented but was a no-op in linux-mod too
+}
+
+# @FUNCTION: _modules_prepare_kernel
+# @INTERNAL
+# @DESCRIPTION:
+# Uses linux-info to find kernel sources (sets KV_ variables), then
+# performs sanity checks to see if usable to build modules and abort
+# otherwise.
+_modules_prepare_kernel() {
+	get_version
+
+	# linux-info allows skipping checks if SKIP_KERNEL_CHECK is set and
+	# then require_configured_kernel will not abort, but no sources means
+	# 100% failure for building modules and so just abort now (the proper
+	# way to allow skipping sources here is MODULES_OPTIONAL_IUSE)
+	[[ -n ${KV_FULL} ]] ||
+		die "kernel sources are required to build kernel modules"
+
+	require_configured_kernel
+
+	_modules_sanity_kernelbuilt
+	_modules_sanity_kernelversion
+}
+
+# @FUNCTION: _modules_prepare_sign
+# @INTERNAL
+# @DESCRIPTION:
+# Determines arguments to pass to sign-file (hash/keys), and performs
+# basic sanity checks to abort early if signing does not look possible.
+_modules_prepare_sign() {
+	use modules-sign || return 0
+
+	_modules_sign_die() {
+		eerror "USE=modules-sign requires additional configuration, please see the"
+		eerror "kernel[1] documentation and the linux-mod-r1 eclass[2] user variables."
+		eerror "[1] https://www.kernel.org/doc/html/v${KV_MAJOR}.${KV_MINOR}/admin-guide/module-signing.html"
+		eerror "[2] https://devmanual.gentoo.org/eclass-reference/linux-mod-r1.eclass/index.html"
+		die "USE=modules-sign is set but ${*}"
+	}
+
+	linux_chkconfig_present MODULE_SIG ||
+		_modules_sign_die "CONFIG_MODULE_SIG is not set in the kernel"
+
+	if [[ -z ${MODULES_SIGN_HASH} ]]; then
+		: "$(linux_chkconfig_string MODULE_SIG_HASH)"
+		MODULES_SIGN_HASH=${_//\"}
+		[[ -n ${MODULES_SIGN_HASH} ]] ||
+			_modules_sign_die "CONFIG_MODULE_SIG_HASH is not set in the kernel"
+	fi
+
+	if [[ -z ${MODULES_SIGN_KEY} ]]; then
+		: "$(linux_chkconfig_string MODULE_SIG_KEY)"
+		MODULES_SIGN_KEY=${_//\"}
+		[[ -n ${MODULES_SIGN_KEY} ]] ||
+			_modules_sign_die "CONFIG_MODULE_SIG_KEY is not set in the kernel"
+	fi
+
+	[[ ${MODULES_SIGN_KEY} != @(/|pkcs11:)* ]] &&
+		MODULES_SIGN_KEY=${KV_OUT_DIR}/${MODULES_SIGN_KEY}
+	[[ ${MODULES_SIGN_CERT} != /* ]] &&
+		MODULES_SIGN_CERT=${KV_OUT_DIR}/${MODULES_SIGN_CERT}
+
+	# assumes users know what they are doing if using a pkcs11 URI
+	[[ ${MODULES_SIGN_KEY} == pkcs11:* || -f ${MODULES_SIGN_KEY} ]] ||
+		_modules_sign_die "the private key '${MODULES_SIGN_KEY}' was not found"
+	[[ -f ${MODULES_SIGN_CERT} ]] ||
+		_modules_sign_die "the public key certificate '${MODULES_SIGN_CERT}' was not found"
+}
+
+# @FUNCTION: _modules_prepare_toolchain
+# @INTERNAL
+# @DESCRIPTION:
+# Sets KERNEL_{CC,CXX,LD,AR,NM,OBJCOPY,OBJDUMP,READELF,STRIP} based on
+# the kernel configuration and KERNEL_CHOST (also set if missing) that
+# *should* be usable to build modules.
+#
+# Tries to match compiler type (gcc or clang), and major version.
+# Users can set KERNEL_ variables themselves to override.
+#
+# Also performs some sanity checks and informs about possible issues.
+#
+# These variables are normally manipulated by the kernel's LLVM=1 with
+# the exception of CXX that is included anyway given *some* out-of-tree
+# modules use it, e.g. nvidia-drivers[kernel-open].
+_modules_prepare_toolchain() {
+	# note that the kernel adds -m32/-m64 by default (for e.g. x32), but
+	# may need automagic here if want a different toolchain (e.g. kgcc64)
+	[[ -z ${KERNEL_CHOST} ]] && linux_chkconfig_present 64BIT &&
+		case ${CHOST} in
+			# matching kernel-build.eclass, see for details
+			hppa2.0-*) KERNEL_CHOST=${CHOST/2.0/64};;
+		esac
+
+	# recognizing KERNEL_CHOST given CROSS_COMPILE seems too generic here,
+	# but should rarely be necessary unless different userland and kernel
+	: "${KERNEL_CHOST:=${CHOST}}"
+
+	einfo "Preparing ${KERNEL_CHOST} toolchain for kernel modules (override with KERNEL_CHOST) ..."
+
+	_modules_tc_best() {
+		[[ -z ${!1} ]] && read -r ${1} < <(type -P -- "${@:2}")
+	}
+
+	local gccv clangv tool
+	if linux_chkconfig_present CC_IS_GCC; then
+		gccv=$(linux_chkconfig_string GCC_VERSION)
+		gccv=${gccv::2} # major version, will break on gcc-100...
+		# chost-gcc-ver > chost-gcc > gcc-ver > gcc
+		_modules_tc_best KERNEL_CC {"${KERNEL_CHOST}-",}gcc{"-${gccv}",}
+		_modules_tc_best KERNEL_CXX {"${KERNEL_CHOST}-",}g++{"-${gccv}",}
+		# unknown what was used exactly here, but prefer non-llvm with gcc
+		for tool in AR NM OBJCOPY OBJDUMP READELF STRIP; do
+			_modules_tc_best KERNEL_${tool} \
+				{"${KERNEL_CHOST}-",}{gcc-,}${tool,,}
+		done
+	elif linux_chkconfig_present CC_IS_CLANG; then
+		clangv=$(linux_chkconfig_string CLANG_VERSION)
+		clangv=${clangv::2}
+		# like gcc, but try directories to get same version on all tools
+		# (not using get_llvm_prefix to avoid conflicts with ebuilds using
+		# llvm slots for non-modules reasons, e.g. sets llvm_check_deps)
+		_modules_tc_best KERNEL_CC \
+			{"${BROOT}/usr/lib/llvm/${clangv}/bin/",}{"${KERNEL_CHOST}-",}clang{"-${clangv}",}
+		_modules_tc_best KERNEL_CXX \
+			{"${BROOT}/usr/lib/llvm/${clangv}/bin/",}{"${KERNEL_CHOST}-",}clang++{"-${clangv}",}
+		for tool in AR NM OBJCOPY OBJDUMP READELF STRIP; do
+			_modules_tc_best KERNEL_${tool} \
+				{"${BROOT}/usr/lib/llvm/${clangv}/bin/",}{"${KERNEL_CHOST}-",}{llvm-,}${tool,,}
+		done
+	fi
+
+	if linux_chkconfig_present LD_IS_BFD; then
+		_modules_tc_best KERNEL_LD {"${KERNEL_CHOST}-",}ld.bfd
+	elif linux_chkconfig_present LD_IS_LLD; then
+		# also match with clang if it was used
+		_modules_tc_best KERNEL_LD \
+			{${clangv+"${BROOT}/usr/lib/llvm/${clangv}/bin/"},}{"${KERNEL_CHOST}-",}ld.lld
+	fi
+
+	# if any variables are still empty, fallback to normal defaults
+	local CHOST=${KERNEL_CHOST}
+	: "${KERNEL_CC:=$(tc-getCC)}"
+	: "${KERNEL_CXX:=$(tc-getCXX)}"
+	: "${KERNEL_LD:=$(tc-getLD)}"
+	: "${KERNEL_AR:=$(tc-getAR)}"
+	: "${KERNEL_NM:=$(tc-getNM)}"
+	: "${KERNEL_OBJCOPY:=$(tc-getOBJCOPY)}"
+	: "${KERNEL_OBJDUMP:=$(tc-getOBJDUMP)}"
+	: "${KERNEL_READELF:=$(tc-getREADELF)}"
+	: "${KERNEL_STRIP:=$(tc-getSTRIP)}"
+
+	# for toolchain-funcs, uses CPP > CC but set both not to make assumptions
+	local CC=${KERNEL_CC} CPP="${KERNEL_CC} -E" LD=${KERNEL_LD}
+
+	# show results, skip line wrap to avoid standing out too much
+	einfo "Toolchain picked for kernel modules (override with KERNEL_CC, _LD, ...):"\
+		"'${KERNEL_CC}' '${KERNEL_CXX}' '${KERNEL_LD}' '${KERNEL_AR}'"\
+		"'${KERNEL_NM}' '${KERNEL_OBJCOPY}' '${KERNEL_OBJDUMP}'"\
+		"'${KERNEL_READELF}' '${KERNEL_STRIP}'"
+
+	# hack: kernel adds --thinlto-cache-dir to KBUILD_LDFLAGS with ThinLTO
+	# resulting in sandbox violations and we cannot safely override that
+	# variable, using *both* {LDFLAGS_MODULE,ldflags-y}=--thinlto-cache-dir=
+	# can work but raises concerns about breaking packages that may use these
+	if linux_chkconfig_present LTO_CLANG_THIN && tc-ld-is-lld; then
+		KERNEL_LD=${T}/linux-mod-r1_ld.lld
+		printf '#!/usr/bin/env sh\nexec %s "${@}" --thinlto-cache-dir=\n' \
+			"${LD}" > "${KERNEL_LD}" || die
+		chmod +x -- "${KERNEL_LD}" || die
+	fi
+
+	# perform a (fatal) check for gcc plugins mismatch
+	_modules_sanity_gccplugins
+
+	# warn if final picked CC type or major version is mismatching, arguably
+	# should be fatal too but not forcing without being sure it is broken
+	local warn
+	if [[ -v gccv ]]; then
+		if ! tc-is-gcc; then
+			warn="gcc-${gccv} but '${KERNEL_CC}' is not gcc"
+		elif [[ $(gcc-major-version) -ne "${gccv}" ]]; then
+			warn="gcc-${gccv} but '${KERNEL_CC}' is gcc-$(gcc-major-version)"
+		fi
+	elif [[ -v clangv ]]; then
+		if ! tc-is-clang; then
+			warn="clang-${clangv} but '${KERNEL_CC}' is not clang"
+		elif [[ $(clang-major-version) -ne "${clangv}" ]]; then
+			warn="clang-${clangv} but '${KERNEL_CC}' is clang-$(clang-major-version)"
+		fi
+	fi
+
+	if [[ -v warn ]]; then
+		ewarn "Warning: kernel ${KV_FULL} is built with ${warn}"
+		ewarn "This could result in modules build failure, it is recommended to either"
+		ewarn "\`make clean\` and rebuild the kernel with the current toolchain, or set"
+		ewarn "the KERNEL_CC variable to point to the same compiler."
+	fi
+}
+
+# @FUNCTION: _modules_process_compress
+# @USAGE: <module>...
+# @INTERNAL
+# @DESCRIPTION:
+# If enabled in the kernel configuration, this compresses the given
+# modules using the same format.
+_modules_process_compress() {
+	local -a compress
+	if linux_chkconfig_present MODULE_COMPRESS_XZ; then
+		compress=(xz -qT"$(makeopts_jobs)" --memlimit-compress=50%)
+	elif linux_chkconfig_present MODULE_COMPRESS_GZIP; then
+		if type -P pigz &>/dev/null; then
+			compress=(pigz -p"$(makeopts_jobs)")
+		else
+			compress=(gzip)
+		fi
+	elif linux_chkconfig_present MODULE_COMPRESS_ZSTD; then
+		compress=(zstd -qT"$(makeopts_jobs)" --rm)
+	fi
+
+	if [[ -v compress ]]; then
+		# could fail, assumes have commands that were needed for the kernel
+		einfo "Compressing modules (matching the kernel configuration) ..."
+		edob "${compress[@]}" -- "${@}"
+	fi
+}
+
+# @FUNCTION: _modules_process_sign
+# @USAGE: <module>...
+# @INTERNAL
+# @DESCRIPTION:
+# Cryptographically signs the given modules when USE=modules-sign is
+# enabled.
+_modules_process_sign() {
+	use modules-sign || return 0
+
+	# scripts/sign-file used to be a perl script but is now written in C,
+	# and it could either be missing or broken given it links with openssl
+	# (no subslot rebuilds on kernel sources), trivial to compile regardless
+	local sign=
+	if [[ -f ${KV_DIR}/scripts/sign-file.c ]]; then
+		sign=${T}/linux-mod-r1_sign-file
+		(
+			# unfortunately using the kernel's Makefile is inconvenient (no
+			# simple build target for this), may need revisiting on changes
+			einfo "Compiling sign-file ..."
+			tc-export_build_env
+			nonfatal edob $(tc-getBUILD_CC) ${BUILD_CFLAGS} ${BUILD_CPPFLAGS} \
+				$($(tc-getBUILD_PKG_CONFIG) --cflags libcrypto) \
+				${BUILD_LDFLAGS} -o "${sign}" "${KV_DIR}"/scripts/sign-file.c \
+				$($(tc-getBUILD_PKG_CONFIG) --libs libcrypto || echo -lcrypto)
+		) || {
+			einfo "Trying fallback ..."
+			sign=
+		}
+	fi
+
+	if [[ -z ${sign} ]]; then
+		if [[ -x ${KV_OUT_DIR}/scripts/sign-file ]]; then
+			sign=${KV_OUT_DIR}/scripts/sign-file # try if built
+		elif [[ -x ${KV_DIR}/scripts/sign-file ]]; then
+			sign=${KV_DIR}/scripts/sign-file # old kernel (<linux-4.4)
+		else
+			die "USE=modules-sign is set but '${KV_DIR}/scripts/sign-file.c' is not usable"
+		fi
+	fi
+
+	einfo "Signing modules ..."
+
+	# good odds the private key has limited access, and with the kernel's
+	# automated method it is likely to be -rw------- root:root (but is rarely
+	# an issue given portage's src_install used here normally runs as root)
+	[[ ${MODULES_SIGN_KEY} == pkcs11:* || -r ${MODULES_SIGN_KEY} ]] ||
+		die "USE=modules-sign is set but lacking read access to the signing key at '${MODULES_SIGN_KEY}'"
+
+	local mod
+	for mod; do
+		edob "${sign}" "${MODULES_SIGN_HASH}" "${MODULES_SIGN_KEY}" \
+			"${MODULES_SIGN_CERT}" "${mod}"
+	done
+
+	# unset to at least be out of the environment file in, e.g. shared binpkgs
+	unset KBUILD_SIGN_PIN
+}
+
+# @FUNCTION: _modules_process_strip
+# @USAGE: <module>...
+# @INTERNAL
+# @DESCRIPTION:
+# Strips the given modules of unneeded symbols when USE=strip is
+# enabled, and informs the package manager not to regardless.
+_modules_process_strip() {
+	# letting the package manager handle this complicates scenarios
+	# where we want to either compress the pre-stripped module, or
+	# sign the module without its signature becoming invalid on merge
+	dostrip -x "${@#"${ED}"}"
+
+	if use strip; then
+		einfo "Stripping modules ..."
+		edob "${KERNEL_STRIP}" --strip-unneeded -- "${@}"
+	fi
+}
+
+# @FUNCTION: _modules_sanity_gccplugins
+# @INTERNAL
+# @DESCRIPTION:
+# Performs a basic build test to detect gcc plugins mismatch issues
+# and, if so, dies with a clearer error given it often confuses users.
+#
+# Note: may need occasional review to ensure the test still works,
+# albeit issue is mitigated by _modules_prepare_toolchain's version
+# checks and is not critical.  To test, should be sufficient to enable
+# a gcc plugin in the kernel, build with a old gcc, then build a module
+# by setting KERNEL_CC=gcc-<major-version+1>.
+_modules_sanity_gccplugins() {
+	linux_chkconfig_present GCC_PLUGINS || return 0
+
+	local tmp=${T}/linux-mod-r1_gccplugins
+	mkdir -p -- "${tmp}" || die
+
+	echo "obj-m += test.o" > "${tmp}"/Kbuild || die
+	:> "${tmp}"/test.c || die
+
+	local -a emakeargs=( M="${tmp}" )
+	modules_makeargs_to_array emakeargs
+
+	# always fails, but interested in the stderr messages
+	local output=$(
+		cd -- "${KV_OUT_DIR}" && # fwiw skip non-POSIX -C in eclasses
+			LC_ALL=C nonfatal emake "${emakeargs[@]}" 2>&1 >/dev/null
+	)
+
+	if [[ ${output} == *"error: incompatible gcc/plugin version"* ]]; then
+		eerror "Detected kernel was built with a different gcc/plugin version, and"
+		eerror "this will prevent building modules. Please \`make clean\` and rebuild"
+		eerror "the kernel using the current toolchain."
+		die "kernel ${KV_FULL} needs to be rebuilt"
+	fi
+}
+
+# @FUNCTION: _modules_sanity_kernelbuilt
+# @INTERNAL
+# @DESCRIPTION:
+# Checks if the kernel seems fully built by having a Module.symvers
+# that is also readable, abort otherwise.
+#
+# About readability, occasionally users build their kernel as root with
+# umask 0077 and then the package manager's user cannot read built files
+# leaving them confused.
+#
+# Given user and access can very between phases (notably src_compile),
+# it makes sense to run this check more than once.
+#
+# Note:
+# This is an alternate version of linux-info's check_kernel_built
+# which probably will not need to exist there if linux-mod-r0 is
+# gone, error it gives is also modules-specific and fits better here.
+#
+# The old check_kernel_built checks version.h and suggests running
+# modules_prepare if missing, but that does not create Module.symvers.
+# Nowadays the kernel makes unresolved symbols fatal by default
+# meaning that all modules will fail unless KBUILD_MODPOST_WARN=1
+# which seem questionable to support.  So rather than version.h, this
+# checks and require Module.symvers, and suggests a full build if
+# missing (if really must, users can bypass by touching the file).
+# nvidia-drivers (for one) further checks this file directly to do
+# configure tests that will break badly without.
+_modules_sanity_kernelbuilt() {
+	local symvers=${KV_OUT_DIR}/Module.symvers
+
+	if [[ ! -f ${symvers} ]]; then
+		eerror "'${symvers}' was not found implying that the"
+		eerror "linux-${KV_FULL} tree at that location has not been built."
+		eerror
+		eerror "Please verify that this is the intended kernel version, then perform"
+		eerror "a full build[1] (i.e. make && make modules_install && make install)."
+		eerror
+		eerror "Alternatively, consider a distribution kernel[2] that does not need"
+		eerror "these manual steps (e.g. sys-kernel/gentoo-kernel or gentoo-kernel-bin)."
+		eerror
+		eerror "[1] https://wiki.gentoo.org/wiki/Kernel/Configuration#Build"
+		eerror "[2] https://wiki.gentoo.org/wiki/Project:Distribution_Kernel"
+		die "built kernel sources are required to build kernel modules"
+	fi
+
+	if [[ ! -r ${symvers} ]]; then
+		eerror "'${symvers}' exists but cannot be read by the"
+		eerror "user id(${EUID}) of the package manager, likely implying no world"
+		eerror "read access permissions:"
+		eerror
+		eerror "    $(ls -l -- "${symvers}")"
+		eerror
+		eerror "Causes may vary, but a common one is building the kernel with a umask"
+		eerror "value of '0077' rather than the more typical '0022' (run the \`umask\`"
+		eerror "command to confirm, as root if was building the kernel using it)."
+		eerror
+		eerror "Many other files are likely affected and will lead to build failures."
+		eerror "It is recommended to clean the sources and rebuild with \`umask 0022\`"
+		eerror "rather than attempt to fix the permissions manually."
+		die "no read access permission to the generated kernel files"
+	fi
+}
+
+# @FUNCTION: _modules_sanity_kernelversion
+# @INTERNAL
+# @DESCRIPTION:
+# Prints a warning if the kernel version is greater than to
+# MODULES_KERNEL_MAX (while only considering same amount of version
+# components), or aborts if it is less than MODULES_KERNEL_MIN
+_modules_sanity_kernelversion() {
+	local kv=${KV_MAJOR}.${KV_MINOR}.${KV_PATCH}
+
+	if [[ -n ${MODULES_KERNEL_MIN} ]] &&
+		ver_test "${kv}" -lt "${MODULES_KERNEL_MIN}"
+	then
+		eerror "${P} requires a kernel version of at least >=${MODULES_KERNEL_MIN},"
+		eerror "but the current kernel is ${KV_FULL}. Please update."
+		die "kernel ${KV_FULL} is too old"
+	fi
+
+	if [[ -n ${MODULES_KERNEL_MAX} ]]; then
+		: "${MODULES_KERNEL_MAX//[^.]/}"
+		local -i count=${#_}
+
+		if ver_test "$(ver_cut 1-$((count+1)) "${kv}")" \
+			-gt "${MODULES_KERNEL_MAX}"
+		then
+			# add .x to 1 missing component to make, e.g. <=1.2.x more natural,
+			# not <1.3 given users sometimes see it as 1.3 support at a glance
+			local max=${MODULES_KERNEL_MAX}
+			[[ ${count} -lt 2 ]] && max+=.x
+
+			ewarn
+			ewarn " *** WARNING *** "
+			ewarn
+			ewarn "${PN} is known to break easily with new kernel versions and,"
+			ewarn "with the current kernel (${KV_FULL}), it was either hardly"
+			ewarn "tested or is known broken. It is recommended to use one of:"
+			ewarn
+			ewarn "    <=sys-kernel/gentoo-kernel-${max}"
+			ewarn "    <=sys-kernel/gentoo-sources-${max}"
+			ewarn
+			ewarn "or equivalent rather than file downstream bug reports if run into"
+			ewarn "issues, then wait for upstream fixes and a new release. Ideally,"
+			ewarn "with out-of-tree modules, use an LTS (Long Term Support) kernel"
+			ewarn "branch[1]. If in doubt, Gentoo's stable kernels are always LTS"
+			ewarn "and can be easily used even on ~testing systems."
+			ewarn
+			ewarn "[1] https://www.kernel.org/category/releases.html"
+			ewarn
+		fi
+	fi
+}
+
+# @FUNCTION: _modules_sanity_modversion
+# @USAGE: <module>...
+# @INTERNAL
+# @DESCRIPTION:
+# Checks if the passed module(s) do not seem obviously broken and the
+# builtin versions match ${KV_FULL}, otherwise die with an explanation.
+#
+# If receive a bug with a version error, an easy way to reproduce is to
+# set KERNEL_DIR with the sources of a different kernel version than
+# both the ones pointed by /usr/src/linux and `uname -r`.
+_modules_sanity_modversion() {
+	local mod ver
+	for mod; do
+		# modinfo can read different-arch modules, being fatal *should* be safe
+		# and serve as a basic sanity check to ensure the module is valid
+		read -rd ' ' ver < <(
+			LC_ALL=C modinfo -F vermagic -- "${mod}" ||
+				die "modinfo failed to read module '${mod}' (broken module?)"
+		)
+		[[ -n ${ver} ]] ||
+				die "modinfo found no kernel version in '${mod}' (broken module?)"
+
+		if [[ ${ver} != "${KV_FULL}" ]]; then
+			eerror "A module seem to have been built for kernel version '${ver}'"
+			eerror "while it was meant for '${KV_FULL}'. This may indicate an"
+			eerror "ebuild issue (e.g. used runtime \`uname -r\` kernel rather than"
+			eerror "the chosen sources). Please report this to the ebuild's maintainer."
+			die "module and source version mismatch in '${mod}'"
+		fi
+	done
+}
+
+# @FUNCTION: _modules_update_depmod
+# @INTERNAL
+# @DESCRIPTION:
+# If possible, update module dependencies using depmod and System.map,
+# otherwise prompt user to handle it.  System.map may notably no longer
+# be available on binary merges.
+_modules_update_depmod() {
+	# prefer /lib/modules' path given it is what depmod operates on,
+	# and is mostly foolproof when it comes to ROOT (relative symlink)
+	local map=${EROOT}/lib/modules/${KV_FULL}/build/System.map
+
+	if [[ ! -f ${map} ]]; then
+		# KV_OUT_DIR may still be right even on a different system, but state
+		# of (E)ROOT is unknown, e.g. could be from KERNEL_DIR=${OLDROOT}/...
+		map=${KV_OUT_DIR}/System.map
+
+		# last resort, typical but may not be mounted/readable/installed
+		[[ ! -f ${map} ]] &&
+			map=${EROOT}/boot/System.map-${KV_FULL}
+	fi
+
+	einfo "Updating module dependencies for kernel ${KV_FULL} ..."
+	if [[ -f ${map} ]]; then
+		nonfatal edob depmod -ae -F "${map}" -b "${EROOT:-/}" "${KV_FULL}" &&
+			return 0
+	else
+		eerror
+		eerror "System.map for kernel ${KV_FULL} was not found, may be due to the"
+		eerror "built kernel sources no longer being available and lacking the fallback:"
+		eerror
+		eerror "${EROOT}/boot/System.map-${KV_FULL}"
+	fi
+	eerror
+	eerror "Some modules may not load without updating manually using depmod."
+}
+
+fi
+
+EXPORT_FUNCTIONS pkg_setup src_compile src_install pkg_postinst
-- 
2.40.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [gentoo-dev] [PATCH 4/4] app-admin/ryzen_smu: migrate to linux-mod-r1
  2023-05-26  4:02 [gentoo-dev] [PATCH 0/4] linux-mod-r1.eclass: new eclass, rewrite of -r0 Ionen Wolkens
                   ` (2 preceding siblings ...)
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 3/4] linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass Ionen Wolkens
@ 2023-05-26  4:02 ` Ionen Wolkens
  3 siblings, 0 replies; 9+ messages in thread
From: Ionen Wolkens @ 2023-05-26  4:02 UTC (permalink / raw
  To: gentoo-dev

Randomly migrating myself as a very simple migration example (don't
actually use this, no hardware). Notably makes the CC_IS_CLANG checks
from the old ebuild unnecessary.

Signed-off-by: Ionen Wolkens <ionen@gentoo.org>
---
 .../ryzen_smu-0.1.2_p20211205-r1.ebuild       | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 app-admin/ryzen_smu/ryzen_smu-0.1.2_p20211205-r1.ebuild

diff --git a/app-admin/ryzen_smu/ryzen_smu-0.1.2_p20211205-r1.ebuild b/app-admin/ryzen_smu/ryzen_smu-0.1.2_p20211205-r1.ebuild
new file mode 100644
index 000000000000..f1b8625e5b94
--- /dev/null
+++ b/app-admin/ryzen_smu/ryzen_smu-0.1.2_p20211205-r1.ebuild
@@ -0,0 +1,28 @@
+# Copyright 1999-2023 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit linux-mod-r1
+
+DESCRIPTION="Kernel driver for AMD Ryzen's System Management Unit"
+HOMEPAGE="https://github.com/leogx9r/ryzen_smu"
+SRC_URI="https://dev.gentoo.org/~slashbeast/distfiles/${PN}/${P}.tar.xz"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="~amd64 ~x86"
+
+src_compile() {
+	local modlist=( ryzen_smu )
+	local modargs=( KERNEL_BUILD="${KV_OUT_DIR}" )
+
+	linux-mod-r1_src_compile
+}
+
+src_install() {
+	linux-mod-r1_src_install
+
+	insinto /usr/lib/modules-load.d
+	doins "${FILESDIR}"/ryzen_smu.conf
+}
-- 
2.40.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [gentoo-dev] [PATCH 1/4] profiles/use.desc: create USE=strip global USE flag
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 1/4] profiles/use.desc: create USE=strip global USE flag Ionen Wolkens
@ 2023-05-26  5:06   ` Sam James
  2023-05-26  5:25     ` Ionen Wolkens
  0 siblings, 1 reply; 9+ messages in thread
From: Sam James @ 2023-05-26  5:06 UTC (permalink / raw
  To: gentoo-dev

[-- Attachment #1: Type: text/plain, Size: 1476 bytes --]


Ionen Wolkens <ionen@gentoo.org> writes:

> Primarily intended for use by linux-mod-r1.eclass, which needs
> a global IUSE to control stripping of kernel modules *before*
> signatures and compression (alternative would be to simply never
> strip, but that seem sub-optimal).
>
> Originally meant to be USE=modules-strip or similar, but this can
> have a more general use case when portage does not know how to
> strip special files properly while the ebuild does.
>
> Notable is mingw ebuilds (wine-*, dxvk, vkd3d-proton, mingw64-*).
> If portage uses x86_64-pc-linux-strip on, e.g. mingw64-toolchain's
> runtime libraries, then at least the 32bit toolchain ends up broken
> and cannot compile anything anymore. But then dostrip -x results in
> unstripped files while we can use x86_64-w64-mingw32-strip in the
> ebuild potentially saving 60MB+. Currently this is done through
> USE=debug, but does not feel fully fitting given this isn't about
> adding debugging paths (or even symbols, or anything) and is merely
> "do not strip".
>
> No USE in ::gentoo currently contain the word "strip" and defining
> it should not conflict.

This sounds fine (and a good idea), but we may want some indication
in the USE flag description (eh), a QA policy to indicate
it's only for special situations, or some note in the devmanual.

Can see people getting this wrong and trying to use it in ebuilds
which would work otherwise. But maybe the "special" in the USE
description is enough?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 377 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [gentoo-dev] [PATCH 1/4] profiles/use.desc: create USE=strip global USE flag
  2023-05-26  5:06   ` Sam James
@ 2023-05-26  5:25     ` Ionen Wolkens
  0 siblings, 0 replies; 9+ messages in thread
From: Ionen Wolkens @ 2023-05-26  5:25 UTC (permalink / raw
  To: gentoo-dev

[-- Attachment #1: Type: text/plain, Size: 1851 bytes --]

On Fri, May 26, 2023 at 06:06:46AM +0100, Sam James wrote:
> 
> Ionen Wolkens <ionen@gentoo.org> writes:
> 
> > Primarily intended for use by linux-mod-r1.eclass, which needs
> > a global IUSE to control stripping of kernel modules *before*
> > signatures and compression (alternative would be to simply never
> > strip, but that seem sub-optimal).
> >
> > Originally meant to be USE=modules-strip or similar, but this can
> > have a more general use case when portage does not know how to
> > strip special files properly while the ebuild does.
> >
> > Notable is mingw ebuilds (wine-*, dxvk, vkd3d-proton, mingw64-*).
> > If portage uses x86_64-pc-linux-strip on, e.g. mingw64-toolchain's
> > runtime libraries, then at least the 32bit toolchain ends up broken
> > and cannot compile anything anymore. But then dostrip -x results in
> > unstripped files while we can use x86_64-w64-mingw32-strip in the
> > ebuild potentially saving 60MB+. Currently this is done through
> > USE=debug, but does not feel fully fitting given this isn't about
> > adding debugging paths (or even symbols, or anything) and is merely
> > "do not strip".
> >
> > No USE in ::gentoo currently contain the word "strip" and defining
> > it should not conflict.
> 
> This sounds fine (and a good idea), but we may want some indication
> in the USE flag description (eh), a QA policy to indicate
> it's only for special situations, or some note in the devmanual.
> 
> Can see people getting this wrong and trying to use it in ebuilds
> which would work otherwise. But maybe the "special" in the USE
> description is enough?

This is what I had in mind when I used that word. Didn't want the
description to sound like it's aimed at developers more than users,
but still have something that prevents matching common strip usage.
-- 
ionen

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [gentoo-dev] [PATCH v2] linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass
  2023-05-26  4:02 ` [gentoo-dev] [PATCH 3/4] linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass Ionen Wolkens
@ 2023-05-28 12:41   ` Ionen Wolkens
  2023-05-29 13:10     ` Ionen Wolkens
  0 siblings, 1 reply; 9+ messages in thread
From: Ionen Wolkens @ 2023-05-28 12:41 UTC (permalink / raw
  To: gentoo-dev

Update notes for ML:

Likely final as far as initial merge goes.

Given been suggested that it'd be easier to have it in the tree for
testing and that without consumers it can't break anything (yet),
planning to merge tomorrow. Just posting update here as a formality.

I assume the two global USE are okay at this point.

Rough updates overview since v1 after self-review:
- adjust compiler mismatch warning for better visiblity and accuracy
- prevent passing -Werror even if CONFIG_WERROR=y which recent kernels
  enable by default (unrealistic for not-frequently-updated modules),
  the other -Werror=specific are left alone
- add DEPMOD=: and no-auto-sign/compress CONFIG_ to default makeargs,
  this should help streamline ebuilds using make install (zfs-kmod,
  dahdi, maybe others), technically useless arguments for others but
  should not be harmful
- drop INSTALL_MOD_PATH support, formerly added to mimic -r0 but upon
  further reflection I think this is bad and becomes easily inconsistent
  when ebuilds use emake install, find commands, and such (getting it
  right in zfs-kmod was also confusing)
- drop modules_makeargs_to_array and replace by MODULES_MAKEARGS,
  sounded like a good idea at first but this just added extra churn
- various typos, wording, and style adjustments/fix

----------------------
Normal commit summary:

Here's a rough overview of -r0 -> -r1 differences with occasional
rationale behind them if felt relevant (for migrating, refer to
the eclassdocs instead as this does not really document usage
changes):

Features that did not exist in previous eclass (not exhaustive):
* automatic modules signing support, been often requested and
  users would instead use messy bashrc hacks to accomplish this
 (enabled with USE=modules-sign)
* modules (manual) stripping support to allow stripping *before*
  signing and compression
 (can be disabled with USE=-strip)
* can auto-select toolchain to match kernel, e.g. if built with
  clang-15 then it won't use gcc nor clang-16 if possible
 (will warn if the matching compiler went missing)
* helper functions to profit from the above 3 even if not using
  linux-mod-r1_src_compile+install (e.g. for zfs-kmod)
* generic supported kernel version checks (min/max) which comes with
  an encouragement to use LTS kernels for out-of-tree modules
 (but max is not enforced, just makes a strong suggestion)
* linux-mod-r1_src_install now does einstalldocs
* can guess some common build targets rather than just 'module',
  largely removing the need for BUILD_TARGETS
* user-oriented MODULES_EXTRA_EMAKE among other few variables
* various additional sanity checks hopefully making issues
  clearer for users and ebuilds a bit harder to write wrong

"Features" that existed but were not kept (not exhaustive):
* support for <kernel-2.6(!) modules, eclass only tested with >=4.14.x
* allowing doing all in global scope using variables ran through `eval`
 (this often led to all sort of variable misuse in global scope)
* MODULESD_* support, originally meant to keep but it is used by only
  5 packages and holds very little meaning that I can see even in these
 (when needed, packages should write their own .conf)
* moduledb, was being updated for nothing in postinst/postrm
  despite the tool that can use this (sys-kernel/module-rebuild)
  being gone from the tree since Feb 2014
* convert_to_m(), only 1 in-tree ebuild uses this right now (svgalib)
* various other functions with no consumers were dropped, some
  were likely meant to be @INTERNAL, get-KERNEL_CC was never used
  either and now there's ${KERNEL_CC}
* running 'clean' by default, this sometime led to race conditions by
  attempting to clean and build at same time in e.g. nvidia-drivers
 (if an ebuild truly need this, it can be specified manually)
* INSTALL_MOD_PATH support, this integrates badly with ebuilds that
  use it as DESTDIR with e.g. `make INSTALL_MOD_PATH="${ED}" install`
  or find "${ED}"/lib/modules, etc... requiring extra consideration
 (also feels inconsistent with how ebuilds normally work, the few
  concerned users may be interested by setting ROOT or manually moving
  files instead -- but support was missing until 2021 so it should
  have little impact)
* BUILD_FIXES support, this is set by linux-info.eclass but has no
  real relevance that I can see (ebuilds have sometime wrongly used it)
* undocumented feature CONFIG_CHECK="@CONFIG:modname" (or so?) meant
  for automagic based on kernel config is no longer supported, this
  also removes the also undocumented MODULE_IGNORE used by it (found
  0 ebuilds using these in the tree, can be done manually if needed)
* converting CONFIG_CHECK to non-fatal for running again on binary
  merge when (while *possible*) it's rather unlikely would build
  modules for a different kernel than the one that will be used
* having preinst and postrm exports, removed
  -> originally wanted to remove pkg_setup too but it complicated
     things with linux-info's own pkg_setup and made the eclass
     feel less convenient and error-prone with environment handling

Dependency changes:
* virtual/libelf DEPEND removed, building objtool (which uses this) is
  not handled by the eclass and does not seem auto-built by make if
  missing, as such the dependency is not used *here* but rather by
  dist-kernels and source packages which both already request it.
* sys-apps/kmod[tools] BDEPEND+IDEPEND added, and removed from DEPEND
  (linux-mod-r0 uses it similarly but lacks the eapi7+8 adjustment)
* modules-sign? ( dev-libs/openssl virtual/pkgconfig ) BDEPEND for
  building sign-file, unlike objtool it may need rebuilds for openssl
  and is handled here
* dependencies are no longer guarded by "kernel_linux? ( )", it only
  served to silence pkgcheck and then give build failures (linux-only
  ebuilds should be masked on non-Linux profiles or, if mixed, use a
  masked MODULES_OPTIONAL_IUSE which *can* be kernel_linux).

Tentative changes:
* drop KERNEL_ABI support, (nowadays) kernel seems to append its own
  -m32/-m64 and should be no need for multilib.eclass complications
 (tested to work *at least* with x32[userland]+64bit[kernel])
* ^ but add hppa2.0->64 kgcc64 switching like kernel-build.eclass
* drop addpredict wrt bug #653286, assuming no longer relevant given
  unable to reproduce even with kernel-4.14.315+split-debug+some misc
  modules, perhaps would with spl but that (removed) ebuild is too
  broken to try

Misc changes:
* misc -> extra default install dir, to match the kernel's defaults
 (this is also where zfs-kmod already installs due to that default)

Three bugs were addressed, but not closing given -r0 remains affected:
* bug #447352: modules signing is supported
* bug #759238: arguably not an issue anymore in -r0 either due to
  CHECKCONFIG_DONOTHING=1 (bug #862315) now existing, but -r1
  additionally makes it non-fatal if a whitelist exists in the kernel
* bug #816024: trying to select toolchain better is a -r1 highlight

Additionally, becomes WONTFIX in this version:
* bug #642240: INSTALL_MOD_PATH support is reverted

Bug: https://bugs.gentoo.org/447352
Bug: https://bugs.gentoo.org/642240
Bug: https://bugs.gentoo.org/759238
Bug: https://bugs.gentoo.org/816024
Signed-off-by: Ionen Wolkens <ionen@gentoo.org>
---
 eclass/linux-mod-r1.eclass | 1206 ++++++++++++++++++++++++++++++++++++
 1 file changed, 1206 insertions(+)
 create mode 100644 eclass/linux-mod-r1.eclass

diff --git a/eclass/linux-mod-r1.eclass b/eclass/linux-mod-r1.eclass
new file mode 100644
index 000000000000..a27809031cb0
--- /dev/null
+++ b/eclass/linux-mod-r1.eclass
@@ -0,0 +1,1206 @@
+# Copyright 2023 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: linux-mod-r1.eclass
+# @MAINTAINER:
+# Ionen Wolkens <ionen@gentoo.org>
+# Gentoo Kernel project <kernel@gentoo.org>
+# @AUTHOR:
+# Ionen Wolkens <ionen@gentoo.org>
+# @SUPPORTED_EAPIS: 8
+# @PROVIDES: linux-info
+# @BLURB: Functions for installing out-of-tree Linux kernel modules
+# @DESCRIPTION:
+# See the linux-mod-r1_src_compile function documentation for in-depth
+# usage, and see the example further down for a quick overview.
+#
+# @SUBSECTION linux-mod -> linux-mod-r1 migration overview
+#  0. Define a src_compile if missing, local variables below go there.
+#  1. MODULE_NAMES="name(libdir:srcdir:objdir)"
+#     BUILD_TARGETS="target"
+#       -> local modlist=( name=libdir:srcdir:objdir:target(s) )
+#     - try without :target first, it is now almost always unnecessary
+#     - srcdir defaults to the current directory, and note that paths
+#       can be relative to that (should typically *not* pass ${S})
+#     - "name(misc)" or "(extra)" are fine just as modlist=( name )
+#  2. BUILD_PARAMS and/or BUILD_FIXES
+#       -> local modargs=( VAR="${KV_OUT_DIR}" ... )
+#     - CC/LD and similar are unneeded, always passed (V=1 too)
+#     - eval (aka eval "${BUILD_PARAMS}") is /not/ used for this anymore
+#  3. s/linux-mod_/linux-mod-r1/g
+#  4. _preinst+_postrm can be dropped, keep linux-mod-r1_pkg_postinst
+#  5. linux-mod-r1_src_install now runs einstalldocs, adjust as needed
+#  6. if *not* using linux-mod-r1_src_compile/install, then refer to
+#     the eclass' 2nd example and ensure using modules_post_process
+#  7. If any, clang<->gcc switching custom workarounds can be dropped
+#  8. See MODULES_KERNEL_MAX/_MIN if had or need kernel version checks.
+#
+# Not an exhaustive list, verify that no installed files are missing
+# after.  Look for "command not found" errors in the build log too.
+#
+# Revision bumps are not strictly needed to migrate unless want to
+# keep the old as fallback for regressions, kernel upgrades or new
+# IUSE=+strip will typically cause rebuilds either way.
+#
+# @EXAMPLE:
+#
+# If source directory S had a layout such as:
+#  - Makefile (builds a gentoo.ko in current directory)
+#  - gamepad/Makefile (want to install to kernel/drivers/hid)
+#  - gamepad/obj/ (the built gamepad.ko ends up here)
+#
+# ...and the Makefile uses the NIH_SOURCE variable to find where the
+# kernel build directory is (aka KV_OUT_DIR, see linux-info.eclass)
+#
+# then:
+#
+# @CODE
+# CONFIG_CHECK="INPUT_FF_MEMLESS" # gamepad needs it to rumble
+# MODULES_KERNEL_MIN=5.4 # needs features introduced in 5.4
+#
+# src_compile() {
+#     local modlist=(
+#         gentoo
+#         gamepad=kernel/drivers/hid:gamepad:gamepad/obj
+#     )
+#     local modargs=( NIH_SOURCE="${KV_OUT_DIR}" )
+#
+#     linux-mod-r1_src_compile
+# }
+# @CODE
+#
+# Alternatively, if using the package's build system directly is
+# more convenient, a typical example would be:
+#
+# @CODE
+# src_compile() {
+#     MODULES_MAKEARGS+=(
+#         KDIR="${KV_OUT_DIR}"
+#         KSRC="${KV_DIR}"
+#     )
+#
+#     emake "${MODULES_MAKEARGS[@]}"
+# }
+#
+# src_install() {
+#     emake "${MODULES_MAKEARGS[@]}" DESTDIR="${ED}" install
+#     modules_post_process # strip->sign->compress
+#
+#     einstalldocs
+# }
+# @CODE
+# Some extra make variables may be of interest:
+#  - INSTALL_MOD_PATH: sometime used instead of DESTDIR
+#  - INSTALL_MOD_DIR: equivalent to linux_moduleinto
+#
+# MODULES_MAKEARGS is set by the eclass to handle toolchain and,
+# when installing, also attempts to disable automatic stripping,
+# compression, signing, and depmod to let the eclass handle it.
+#
+# linux_domodule can alternatively be used to install a single module.
+#
+# (remember to ensure that linux-mod-r1_pkg_postinst is ran for depmod)
+
+case ${EAPI} in
+	8) ;;
+	*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
+esac
+
+if [[ ! ${_LINUX_MOD_R1_ECLASS} ]]; then
+_LINUX_MOD_R1_ECLASS=1
+
+inherit edo linux-info multiprocessing toolchain-funcs
+
+IUSE="dist-kernel modules-sign +strip ${MODULES_OPTIONAL_IUSE}"
+
+RDEPEND="
+	sys-apps/kmod[tools]
+	dist-kernel? ( virtual/dist-kernel:= )
+"
+DEPEND="
+	virtual/linux-sources
+"
+BDEPEND="
+	sys-apps/kmod[tools]
+	modules-sign? (
+		dev-libs/openssl
+		virtual/pkgconfig
+	)
+"
+IDEPEND="
+	sys-apps/kmod[tools]
+"
+
+if [[ -n ${MODULES_OPTIONAL_IUSE} ]]; then
+	: "${MODULES_OPTIONAL_IUSE#+}? ( | )"
+	RDEPEND=${_/|/${RDEPEND}} DEPEND=${_/|/${DEPEND}} \
+		BDEPEND=${_/|/${BDEPEND}} IDEPEND=${_/|/${IDEPEND}}
+fi
+
+# @ECLASS_VARIABLE: KERNEL_CHOST
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Can be set to the CHOST value to use when selecting the toolchain
+# for building kernel modules.  This is similar to setting the kernel
+# build system's CROSS_COMPILE variable minus the trailing dash.
+#
+# If this does not auto-select the desired toolchain, finer control
+# can be achieved by setting the not directly documented (but valid)
+# variables:
+#
+# KERNEL_{CC,CXX,LD,AR,NM,OBJCOPY,OBJDUMP,READELF,STRIP}
+#
+# If in doubt, do not set any of this.
+#
+# Default if unset: auto-detection, typically same as the current CHOST
+
+# @ECLASS_VARIABLE: MODULES_EXTRA_EMAKE
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Extra arguments to pass to emake when building modules.
+# Can contain arguments with quoted spaces, e.g.
+# @CODE
+# ..._EMAKE="KCFLAGS='-fzomg-optimize -fsuper-strict-aliasing' ..."
+# @CODE
+
+# @ECLASS_VARIABLE: MODULES_I_WANT_FULL_CONTROL
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# When set to a non-empty value, disables passing most of the eclass'
+# toolchain defaults to emake when building modules.  Basic eclass
+# requirements, ebuilds' modargs, and users' MODULES_EXTRA_EMAKE are
+# still used.
+#
+# Primarily intended for expert users with modified kernel Makefiles
+# that want the Makefile's values to be used by default.
+#
+# May want to look at KERNEL_CHOST before considering this.
+
+# @ECLASS_VARIABLE: MODULES_SIGN_HASH
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Used with USE=modules-sign.  Can be set to hash algorithm to use
+# during signature generation.
+#
+# Rather than set this, it is recommended to select using the kernel's
+# configuration to ensure proper support (e.g. CONFIG_MODULE_SIG_SHA256),
+# and then it will be auto-detected here.
+#
+# Valid values: sha512,sha384,sha256,sha224,sha1
+#
+# Default if unset: kernel CONFIG_MODULE_SIG_HASH's value
+
+# @ECLASS_VARIABLE: MODULES_SIGN_KEY
+# @USER_VARIABLE
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# Used with USE=modules-sign.  Can be set to the path of the private
+# key in PEM format to use, or a PKCS#11 URI.
+#
+# If path is relative (e.g. "certs/name.pem"), it is assumed to be
+# relative to the kernel build directory being used.
+#
+# If the key requires a passphrase or PIN, the used kernel sign-file
+# utility recognizes the KBUILD_SIGN_PIN environment variable.  Be
+# warned that the package manager may store this value in binary
+# packages, database files, temporary files, and possibly logs.  This
+# eclass unsets the variable after use to mitigate the issue (notably
+# for shared binary packages), but use this with care.
+#
+# Default if unset: kernel CONFIG_MODULE_SIG_KEY's value which itself
+# defaults to certs/signing_key.pem
+
+# @ECLASS_VARIABLE: MODULES_SIGN_CERT
+# @USER_VARIABLE
+# @DESCRIPTION:
+# Used with USE=modules-sign.  Can be set to the path of the X.509
+# public key certificate to use.
+#
+# If path is relative (e.g. "certs/name.x509"), it is assumed to be
+# relative to the kernel build directory being used.
+: "${MODULES_SIGN_CERT:=certs/signing_key.x509}"
+
+# @ECLASS_VARIABLE: MODULES_KERNEL_MAX
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a kernel version (format: 1, 1.2, or 1.2.3), will print a
+# warning if the used version is greater than (ver_test -gt) to this
+# value using the same amount of version components (i.e. MAX=1.2
+# allows 1.2.3, but MAX=1.2.2 does not).
+#
+# This should *only* be used for modules that are known to break
+# frequently on upgrades.  If setting this to a non-LTS kernel, then
+# should also take care to test and update this value regularly with
+# new major kernel releases not to let the warning become stale and
+# ignored by users.
+#
+# Not fatal to allow users to try or self-patch easily, but the (large)
+# warning is difficult to miss.  If need a fatal check for more serious
+# issues (e.g. filesystem corruption), please do it manually.
+#
+# This is intended to reduce the amount of bug reports for recurring
+# expected issues that can be easily mitigated by using LTS kernels
+# and waiting for new releases.
+#
+# If used, must be set before linux-mod-r1_pkg_setup is called.
+
+# @ECLASS_VARIABLE: MODULES_KERNEL_MIN
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a kernel version (format: 1, 1.2, or 1.2.3), will abort if
+# the used version is less than (ver_test -lt) this value.
+#
+# Should only be used if known broken, or if upstream recommends a sane
+# minimum.  Not particularly necessary for kernels that are no longer
+# in the tree.
+#
+# If used, must be set before linux-mod-r1_pkg_setup is called.
+
+# @ECLASS_VARIABLE: MODULES_OPTIONAL_IUSE
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# May contain a single flag to be added to IUSE optionally prefixed
+# with a + sign to enable it by default.  Doing so makes *all* of
+# linux-mod-r1's functions and dependencies a no-op unless the flag
+# is enabled.  This includes phases, e.g. linux-mod-r1_pkg_setup will
+# not process CONFIG_CHECK unless the flag is set.
+#
+# The typical recommended value is "+modules".
+#
+# Note that modules being optional can be useful even if user space
+# tools require them (e.g. installing in a chroot or prefix when the
+# modules are loaded on the host, saves setting up linux sources).
+# However, if tools are non-trivial to build, it may be preferable
+# to split into two packages than use this variable due to requiring
+# rebuilds every kernel upgrades.
+
+# @ECLASS_VARIABLE: MODULES_MAKEARGS
+# @OUTPUT_VARIABLE
+# @DESCRIPTION:
+# Will be set after linux-mod-r1_pkg_setup has been called.  Contains
+# arguments that should be passed to emake when building or installing
+# modules.
+#
+# Modifying this variable is acceptable (e.g. to add kernel source
+# arguments) but, if using linux-mod-r1_src_compile, setting modargs
+# is the intended method seen as cleaner and less error-prone.
+
+# @FUNCTION: linux-mod-r1_pkg_setup
+# @DESCRIPTION:
+# Required before using other functions from this eclass, and will:
+#  1. run linux-info_pkg_setup (see linux-info.eclass)
+#  -> implies processing CONFIG_CHECK, and providing KV_ variables
+#    (MODULES and TRIM_UNUSED_KSYMS are always checked)
+#  2. prepare toolchain to match the kernel
+#  -> sets KERNEL_{CHOST,CC,CXX,LD,AR,NM,OBJCOPY,OBJDUMP,READELF,STRIP}
+#  -> also sets MODULES_MAKEARGS array with, e.g. CC="${KERNEL_CC}"
+#    (normally these should not be used directly, for custom builds)
+#  3. perform various sanity checks to fail early on issues
+linux-mod-r1_pkg_setup() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	[[ ${MERGE_TYPE} != binary ]] || return 0
+	_MODULES_GLOBAL[ran:pkg_setup]=1
+	_modules_check_function ${#} 0 0 || return 0
+	_modules_check_migration
+
+	_modules_prepare_kernel
+	_modules_prepare_sign
+	_modules_prepare_toolchain
+
+	_modules_set_makeargs
+
+	_modules_sanity_gccplugins # needs makeargs
+}
+
+# @FUNCTION: linux-mod-r1_src_compile
+# @DESCRIPTION:
+# Builds modules, see the eclass' example for a quick overview.
+# Uses the variables modlist and modargs as described below:
+#
+# * local modlist=( ... ) - list of modules to build, set as:
+#
+#     module-name=install-dir:source-dir:build-dir:make-target
+#
+# > module-name: Resulting name, aka <module-name>.ko (required).
+#
+# > install-dir: Kernel modules sub-directory to install the module
+# to (/lib/modules/version/<install-dir>/name.ko).  Will be used when
+# run linux-mod-r1_src_install.  May want to consider the values of
+# INSTALL_MOD_DIR(Makefile) or DEST_MODULE_LOCATION(dkms.conf) if it
+# exists, but it can be anything.
+#  -> Default: extra
+#
+# > source-dir: Directory containing the Makefile to build the module,
+# path can be relative to the current directory or absolute.
+#  -> Default: current directory
+#
+# > build-dir: Directory that will hold the built module-name.ko.
+#  -> Default: same as source-dir's value
+#
+# > make-target: Almost always unneeded but, if defaults are not right,
+# then can specify the Makefile's target(s) to build the module/extras.
+# Multiple targets can be used with spaces, e.g. :"first second".
+#  -> Default: specially tries modules, module, <name>.ko, <name>,
+# default, all, empty target, and runs the first found usable
+#
+# Missing elements results in defaults being used, e.g. this is valid:
+#   modlist=( name1 name2=:source name3=install::build )
+#
+# Tip: If all modules need the same arguments, they can be repeated by:
+#   modlist=( {mod1,mod2,mod3}=arguments )
+#
+# * local modargs=( ... ) - extra arguments to pass to emake
+#
+# Makefile should notably be inspected for which variable it uses
+# to find the kernel's build directory then, e.g. KDIR="${KV_OUT_DIR}"
+# as appropriate.  Note that typically want to pass KV_OUT_DIR(build)
+# rather than KV_DIR(sources) if not both.  This allows users to do
+# out-of-source kernel builds and still build modules.
+#
+# Passing common toolchain variables such as CC or LD is not needed
+# here as they are passed by default.
+#
+# ---
+#
+# Allowed to be called multiple times with a different modlist if need
+# different make arguments per modules or intermediate steps -- albeit,
+# if atypical, may want to build manually (see eclass' example).
+linux-mod-r1_src_compile() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 0 0 || return 0
+
+	[[ ${modlist@a} == *a* && ${#modlist[@]} -gt 0 ]] ||
+		die "${FUNCNAME[0]} was called without a 'modlist' array"
+
+	# run this again to verify built files access with src_compile's user
+	_modules_sanity_kernelbuilt
+
+	local -a emakeargs=( "${MODULES_MAKEARGS[@]}" )
+	[[ ${modargs@a} == *a* ]] && emakeargs+=( "${modargs[@]}" )
+
+	local -A built=()
+	local build mod name target
+	for mod in "${modlist[@]}"; do
+		# note modlist was not made a [name]= associative array to preserve
+		# ordering, but is still using = to improve readability
+		name=${mod%%=*}
+		[[ -n ${name} && ${name} != *:* ]] || die "invalid mod entry '${mod}'"
+
+		# 0:install-dir 1:source-dir 2:build-dir 3:make-target(s)
+		mod=${mod#"${name}"}
+		IFS=: read -ra mod <<<"${mod#=}"
+		[[ ${#mod[@]} -le 4 ]] || die "too many ':' in ${name}'s modlist"
+
+		[[ ${mod[1]:=${PWD}} != /* ]] && mod[1]=${PWD}/${mod[1]}
+		[[ ${mod[2]:=${mod[1]}} != /* ]] && mod[2]=${PWD}/${mod[2]}
+		_MODULES_INSTALL[${mod[2]}/${name}.ko]=${mod[0]:-extra}
+
+		pushd "${mod[1]}" >/dev/null || die
+
+		if [[ -z ${mod[3]} ]]; then
+			# guess between commonly used targets if none given, fallback to
+			# an empty target without trying to see the error output
+			for target in module{s,} "${name}"{.ko,} default all; do
+				nonfatal emake "${emakeargs[@]}" -q "${target}" &>/dev/null
+				if [[ ${?} -eq 1 ]]; then
+					mod[3]=${target}
+					break
+				fi
+			done
+		fi
+
+		# sometime modules are all from same source dir and built all at once,
+		# make will not rebuild either way but can skip the unnecessary noise
+		build=
+		for target in ${mod[3]:-&}; do
+			if ! has "${target}" ${built[${mod[1]}]}; then
+				build=1
+				built[${mod[1]}]+=" ${target} "
+			fi
+		done
+
+		if [[ ${build} ]]; then
+			einfo "Building ${name} module in ${mod[1]} ..."
+
+			# allow word splitting for rare cases of multiple targets
+			emake "${emakeargs[@]}" ${mod[3]}
+		else
+			einfo "Building ${name} module in ${mod[1]} ... already done."
+		fi
+
+		popd >/dev/null || die
+	done
+}
+
+# @FUNCTION: linux-mod-r1_src_install
+# @DESCRIPTION:
+# Installs modules built by linux-mod-r1_src_compile using
+# linux_domodule, then runs modules_post_process and einstalldocs.
+linux-mod-r1_src_install() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 0 0 || return 0
+
+	(( ${#_MODULES_INSTALL[@]} )) ||
+		die "${FUNCNAME[0]} was called without running linux-mod-r1_src_compile"
+
+	(
+		for mod in "${!_MODULES_INSTALL[@]}"; do
+			linux_moduleinto "${_MODULES_INSTALL[${mod}]}"
+			linux_domodule "${mod}"
+		done
+	)
+
+	modules_post_process
+
+	einstalldocs
+}
+
+# @FUNCTION: linux-mod-r1_pkg_postinst
+# @DESCRIPTION:
+# Updates module dependencies using depmod.
+linux-mod-r1_pkg_postinst() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 0 0 || return 0
+
+	_modules_update_depmod
+
+	# post_process ensures modules were installed and that the eclass' USE
+	# are likely not no-ops (unfortunately postinst itself may be missed)
+	[[ -v _MODULES_GLOBAL[ran:post_process] ]] ||
+		eqawarn "QA Notice: neither linux-mod-r1_src_install nor modules_post_process were used"
+}
+
+# @FUNCTION: linux_domodule
+# @USAGE: <module>...
+# @DESCRIPTION:
+# Installs Linux modules (.ko files).
+#
+# See also linux_moduleinto.
+linux_domodule() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 1 '' "<module>..." || return 0
+	(
+		# linux-mod-r0 formerly supported INSTALL_MOD_PATH (bug #642240), but
+		# this been judged messy to integrate consistently as not everything
+		# uses this function and build systems sometime mix it with DESTDIR
+		# (try ROOT if need to install somewhere else instead)
+		insinto "/lib/modules/${KV_FULL}/${_MODULES_GLOBAL[moduleinto]:-extra}"
+		doins "${@}"
+	)
+}
+
+# @FUNCTION: linux_moduleinto
+# @USAGE: <install-dir>
+# @DESCRIPTION:
+# Directory to install modules into when calling linux_domodule.
+# Relative to kernel modules path as in:
+# ${ED}/lib/modules/${KV_FULL}/<install-dir>
+#
+# Can contain subdiretories, e.g. kernel/fs.
+#
+# If not called, defaults to "extra".  On the kernel build system,
+# this is like setting INSTALL_MOD_DIR which has the same default
+# for external modules.
+linux_moduleinto() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 1 1 "<install-dir>" || return 0
+	_MODULES_GLOBAL[moduleinto]=${1}
+}
+
+# @FUNCTION: modules_post_process
+# @USAGE: [<path>]
+# @DESCRIPTION:
+# Strip, sign, verify, and compress all .ko modules found under
+# <path>.  Should typically *not* be called directly as it will
+# be run by linux-mod-r1_src_install.
+#
+# <path> should exist under ${ED}.
+# Defaults to /lib/modules/${KV_FULL}.
+#
+# Filenames may change due to compression, so any operations on
+# these should be performed prior.
+#
+# This is intended for use when modules were installed some other way.
+#
+# Warning: This will abort if no modules are found, which can happen
+# if modules were unexpectedly pre-compressed.
+modules_post_process() {
+	debug-print-function ${FUNCNAME[0]} "${@}"
+	_modules_check_function ${#} 0 1 '[<path>]' || return 0
+	[[ ${EBUILD_PHASE} == install ]] ||
+		die "${FUNCNAME[0]} can only be called in the src_install phase"
+
+	local path=${ED}${1-/lib/modules/${KV_FULL}}
+	local -a mods
+	[[ -d ${path} ]] && mapfile -td '' mods < <(
+		find "${path}" -type f -name '*.ko' -print0 || die
+	)
+	(( ${#mods[@]} )) ||
+		die "${FUNCNAME[0]} was called with no installed modules to process"
+
+	_modules_process_strip "${mods[@]}"
+	_modules_process_sign "${mods[@]}"
+	_modules_sanity_modversion "${mods[@]}" # after strip/sign in case broke it
+	_modules_process_compress "${mods[@]}"
+
+	_MODULES_GLOBAL[ran:post_process]=1
+}
+
+# @ECLASS_VARIABLE: _MODULES_GLOBAL
+# @INTERNAL
+# @DESCRIPTION:
+# General use associative array to avoid defining separate globals.
+declare -gA _MODULES_GLOBAL=()
+
+# @ECLASS_VARIABLE: _MODULES_INSTALL
+# @INTERNAL
+# @DESCRIPTION:
+# List of modules from linux-mod-r1_src_compile to be installed.
+declare -gA _MODULES_INSTALL=()
+
+# @FUNCTION: _modules_check_function
+# @USAGE: [<args-count> <args-min> <args-max> [<usage-string>]]
+# @RETURN: 0 or 1 if caller should do nothing
+# @INTERNAL
+# @DESCRIPTION:
+# Checks for MODULES_OPTIONAL_IUSE, and aborts if amount of arguments
+# does not add up or if it was called before linux-mod-r1_pkg_setup.
+_modules_check_function() {
+	[[ -z ${MODULES_OPTIONAL_IUSE} ]] ||
+		use "${MODULES_OPTIONAL_IUSE#+}" || return 1
+
+	[[ ${#} == 0 || ${1} -ge ${2} && ( ! ${3} || ${1} -le ${3} ) ]] ||
+		die "Usage: ${FUNCNAME[1]} ${4-(no arguments)}"
+
+	[[ -v _MODULES_GLOBAL[ran:pkg_setup] ]] ||
+		die "${FUNCNAME[1]} was called without running linux-mod-r1_pkg_setup"
+}
+
+# @FUNCTION: _modules_check_migration
+# @INTERNAL
+# @DESCRIPTION:
+# Dies if see obsolete variables from the linux-mod-r0 eclass being
+# used likely due to an incomplete migration.  This function should be
+# removed after linux-mod-r0 is @DEAD not to fail for nothing if users
+# happen to have these in their environment given the naming for some
+# is a bit generic.
+_modules_check_migration() {
+	_modules_check_var() {
+		[[ -z ${!1} ]] ||
+			die "${1} is obsolete, see ${2} in linux-mod-r1 eclassdocs"
+	}
+	# the 'I' on this one is notably sneaky and could silently be ignored
+	_modules_check_var MODULES_OPTIONAL_USE MODULES_OPTIONAL_IUSE
+	_modules_check_var MODULES_OPTIONAL_USE_IUSE_DEFAULT MODULES_OPTIONAL_IUSE
+	_modules_check_var BUILD_PARAMS modargs
+	_modules_check_var BUILD_TARGETS modlist
+	_modules_check_var MODULE_NAMES modlist
+	[[ -z ${!MODULESD_*} ]] ||
+		die "MODULESD_* variables are no longer supported, replace by handcrafted .conf files if needed"
+
+	# Ignored variables:
+	# - BUILD_FIXES: seen in some ebuilds but was undocumented and linux-info
+	#   still sets it preventing from blocking it entirely
+	# - ECONF_PARAMS: documented but was a no-op in linux-mod too
+}
+
+# @FUNCTION: _modules_prepare_kernel
+# @INTERNAL
+# @DESCRIPTION:
+# Handles linux-info bits to provide usable sources, KV_ variables,
+# and CONFIG_CHECK use.
+_modules_prepare_kernel() {
+	get_version
+
+	# linux-info allows skipping checks if SKIP_KERNEL_CHECK is set and
+	# then require_configured_kernel will not abort, but no sources means
+	# 100% failure for building modules and so just abort now (the proper
+	# way to allow skipping sources here is MODULES_OPTIONAL_IUSE)
+	[[ -n ${KV_FULL} ]] ||
+		die "kernel sources are required to build kernel modules"
+
+	require_configured_kernel
+
+	_modules_sanity_kernelbuilt
+	_modules_sanity_kernelversion
+
+	# note: modules-specific check_modules_supported could probably be
+	# removed from linux-info in the future as this is a sufficient check
+	local CONFIG_CHECK="${CONFIG_CHECK} MODULES"
+
+	# kernel will not typically know about symbols we use (bug #591832),
+	# but stay non-fatal if kernel has an exception list set (bug #759238)
+	# note: possible to bypass either way with CHECKCONFIG_DONOTHING=1
+	if [[ $(linux_chkconfig_string UNUSED_KSYMS_WHITELIST) == \"+(?)\" ]]; then
+		CONFIG_CHECK+=" ~!TRIM_UNUSED_KSYMS"
+	else
+		CONFIG_CHECK+=" !TRIM_UNUSED_KSYMS"
+	fi
+
+	linux-info_pkg_setup
+}
+
+# @FUNCTION: _modules_prepare_sign
+# @INTERNAL
+# @DESCRIPTION:
+# Determines arguments to pass to sign-file (hash/keys), and performs
+# basic sanity checks to abort early if signing does not look possible.
+_modules_prepare_sign() {
+	use modules-sign || return 0
+
+	_modules_sign_die() {
+		eerror "USE=modules-sign requires additional configuration, please see the"
+		eerror "kernel[1] documentation and the linux-mod-r1 eclass[2] user variables."
+		eerror "[1] https://www.kernel.org/doc/html/v${KV_MAJOR}.${KV_MINOR}/admin-guide/module-signing.html"
+		eerror "[2] https://devmanual.gentoo.org/eclass-reference/linux-mod-r1.eclass/index.html"
+		die "USE=modules-sign is set but ${*}"
+	}
+
+	linux_chkconfig_present MODULE_SIG ||
+		_modules_sign_die "CONFIG_MODULE_SIG is not set in the kernel"
+
+	if [[ -z ${MODULES_SIGN_HASH} ]]; then
+		: "$(linux_chkconfig_string MODULE_SIG_HASH)"
+		MODULES_SIGN_HASH=${_//\"}
+		[[ -n ${MODULES_SIGN_HASH} ]] ||
+			_modules_sign_die "CONFIG_MODULE_SIG_HASH is not set in the kernel"
+	fi
+
+	if [[ -z ${MODULES_SIGN_KEY} ]]; then
+		: "$(linux_chkconfig_string MODULE_SIG_KEY)"
+		MODULES_SIGN_KEY=${_//\"}
+		[[ -n ${MODULES_SIGN_KEY} ]] ||
+			_modules_sign_die "CONFIG_MODULE_SIG_KEY is not set in the kernel"
+	fi
+
+	[[ ${MODULES_SIGN_KEY} != @(/|pkcs11:)* ]] &&
+		MODULES_SIGN_KEY=${KV_OUT_DIR}/${MODULES_SIGN_KEY}
+	[[ ${MODULES_SIGN_CERT} != /* ]] &&
+		MODULES_SIGN_CERT=${KV_OUT_DIR}/${MODULES_SIGN_CERT}
+
+	# assumes users know what they are doing if using a pkcs11 URI
+	[[ ${MODULES_SIGN_KEY} == pkcs11:* || -f ${MODULES_SIGN_KEY} ]] ||
+		_modules_sign_die "the private key '${MODULES_SIGN_KEY}' was not found"
+	[[ -f ${MODULES_SIGN_CERT} ]] ||
+		_modules_sign_die "the public key certificate '${MODULES_SIGN_CERT}' was not found"
+}
+
+# @FUNCTION: _modules_prepare_toolchain
+# @INTERNAL
+# @DESCRIPTION:
+# Sets KERNEL_{CC,CXX,LD,AR,NM,OBJCOPY,OBJDUMP,READELF,STRIP} based on
+# the kernel configuration and KERNEL_CHOST (also set if missing) that
+# *should* be usable to build modules.
+#
+# Tries to match compiler type (gcc or clang), and major version.
+# Users can set KERNEL_ variables themselves to override.
+#
+# Also performs some sanity checks and informs about possible issues.
+#
+# These variables are normally manipulated by the kernel's LLVM=1 with
+# the exception of CXX that is included anyway given *some* out-of-tree
+# modules use it, e.g. nvidia-drivers[kernel-open].
+_modules_prepare_toolchain() {
+	# note that the kernel adds -m32/-m64 by default (for e.g. x32), but
+	# may need automagic here if want a different toolchain (e.g. kgcc64)
+	[[ -z ${KERNEL_CHOST} ]] && linux_chkconfig_present 64BIT &&
+		case ${CHOST} in
+			# matching kernel-build.eclass, see for details
+			hppa2.0-*) KERNEL_CHOST=${CHOST/2.0/64};;
+		esac
+
+	# recognizing KERNEL_CHOST given CROSS_COMPILE seems too generic here,
+	# but should rarely be necessary unless different userland and kernel
+	: "${KERNEL_CHOST:=${CHOST}}"
+
+	einfo "Preparing ${KERNEL_CHOST} toolchain for kernel modules (override with KERNEL_CHOST) ..."
+
+	_modules_tc_best() {
+		[[ -z ${!1} ]] && read -r ${1} < <(type -P -- "${@:2}")
+	}
+
+	local gccv clangv tool
+	if linux_chkconfig_present CC_IS_GCC; then
+		gccv=$(linux_chkconfig_string GCC_VERSION)
+		gccv=${gccv::2} # major version, will break on gcc-100...
+		# chost-gcc-ver > chost-gcc > gcc-ver > gcc
+		_modules_tc_best KERNEL_CC {"${KERNEL_CHOST}-",}gcc{"-${gccv}",}
+		_modules_tc_best KERNEL_CXX {"${KERNEL_CHOST}-",}g++{"-${gccv}",}
+		# unknown what was used exactly here, but prefer non-llvm with gcc
+		for tool in AR NM OBJCOPY OBJDUMP READELF STRIP; do
+			_modules_tc_best KERNEL_${tool} \
+				{"${KERNEL_CHOST}-",}{gcc-,}${tool,,}
+		done
+	elif linux_chkconfig_present CC_IS_CLANG; then
+		clangv=$(linux_chkconfig_string CLANG_VERSION)
+		clangv=${clangv::2}
+		# like gcc, but try directories to get same version on all tools
+		# (not using get_llvm_prefix to avoid conflicts with ebuilds using
+		# llvm slots for non-modules reasons, e.g. sets llvm_check_deps)
+		_modules_tc_best KERNEL_CC \
+			{"${BROOT}/usr/lib/llvm/${clangv}/bin/",}{"${KERNEL_CHOST}-",}clang{"-${clangv}",}
+		_modules_tc_best KERNEL_CXX \
+			{"${BROOT}/usr/lib/llvm/${clangv}/bin/",}{"${KERNEL_CHOST}-",}clang++{"-${clangv}",}
+		for tool in AR NM OBJCOPY OBJDUMP READELF STRIP; do
+			_modules_tc_best KERNEL_${tool} \
+				{"${BROOT}/usr/lib/llvm/${clangv}/bin/",}{"${KERNEL_CHOST}-",}{llvm-,}${tool,,}
+		done
+	fi
+
+	if linux_chkconfig_present LD_IS_BFD; then
+		_modules_tc_best KERNEL_LD {"${KERNEL_CHOST}-",}ld.bfd
+	elif linux_chkconfig_present LD_IS_LLD; then
+		# also match with clang if it was used
+		_modules_tc_best KERNEL_LD \
+			{${clangv+"${BROOT}/usr/lib/llvm/${clangv}/bin/"},}{"${KERNEL_CHOST}-",}ld.lld
+	fi
+
+	# if any variables are still empty, fallback to normal defaults
+	local CHOST=${KERNEL_CHOST}
+	: "${KERNEL_CC:=$(tc-getCC)}"
+	: "${KERNEL_CXX:=$(tc-getCXX)}"
+	: "${KERNEL_LD:=$(tc-getLD)}"
+	: "${KERNEL_AR:=$(tc-getAR)}"
+	: "${KERNEL_NM:=$(tc-getNM)}"
+	: "${KERNEL_OBJCOPY:=$(tc-getOBJCOPY)}"
+	: "${KERNEL_OBJDUMP:=$(tc-getOBJDUMP)}"
+	: "${KERNEL_READELF:=$(tc-getREADELF)}"
+	: "${KERNEL_STRIP:=$(tc-getSTRIP)}"
+
+	# for toolchain-funcs, uses CPP > CC but set both not to make assumptions
+	local CC=${KERNEL_CC} CPP="${KERNEL_CC} -E" LD=${KERNEL_LD}
+
+	# show results, skip line wrap to avoid standing out too much
+	einfo "Toolchain picked for kernel modules (override with KERNEL_CC, _LD, ...):"\
+		"'${KERNEL_CC}' '${KERNEL_CXX}' '${KERNEL_LD}' '${KERNEL_AR}'"\
+		"'${KERNEL_NM}' '${KERNEL_OBJCOPY}' '${KERNEL_OBJDUMP}'"\
+		"'${KERNEL_READELF}' '${KERNEL_STRIP}'"
+
+	# hack: kernel adds --thinlto-cache-dir to KBUILD_LDFLAGS with ThinLTO
+	# resulting in sandbox violations and we cannot safely override that
+	# variable, using *both* {LDFLAGS_MODULE,ldflags-y}=--thinlto-cache-dir=
+	# can work but raises concerns about breaking packages that may use these
+	if linux_chkconfig_present LTO_CLANG_THIN && tc-ld-is-lld; then
+		KERNEL_LD=${T}/linux-mod-r1_ld.lld
+		printf '#!/usr/bin/env sh\nexec %s "${@}" --thinlto-cache-dir=\n' \
+			"${LD}" > "${KERNEL_LD}" || die
+		chmod +x -- "${KERNEL_LD}" || die
+	fi
+
+	# warn if final picked CC type or major version is mismatching, arguably
+	# should be fatal but not forcing given it is not *always* an issue
+	local warn
+	if [[ -v gccv ]]; then
+		if ! tc-is-gcc; then
+			warn="gcc-${gccv} but\n         '${KERNEL_CC}' is not gcc"
+		elif [[ $(gcc-major-version) -ne "${gccv}" ]]; then
+			warn="gcc-${gccv} but\n         '${KERNEL_CC}' is gcc-$(gcc-major-version)"
+		fi
+	elif [[ -v clangv ]]; then
+		if ! tc-is-clang; then
+			warn="clang-${clangv} but\n         '${KERNEL_CC}' is not clang"
+		elif [[ $(clang-major-version) -ne "${clangv}" ]]; then
+			warn="clang-${clangv} but\n         '${KERNEL_CC}' is clang-$(clang-major-version)"
+		fi
+	fi
+
+	if [[ -v warn ]]; then
+		ewarn
+		ewarn "Warning: kernel ${KV_FULL} is built with ${warn}"
+		ewarn "This *could* result in build issues or other incompatibilities."
+		ewarn "It is recommended to either \`make clean\` and rebuild the kernel"
+		ewarn "with the current toolchain (for distribution kernels, re-installing"
+		ewarn "will do the same), or set the KERNEL_CC variable to point to the"
+		ewarn "same compiler. Note that when it is available, auto-selection is"
+		ewarn "attempted making the latter rarely needed."
+		ewarn
+	fi
+}
+
+# @FUNCTION: _modules_process_compress
+# @USAGE: <module>...
+# @INTERNAL
+# @DESCRIPTION:
+# If enabled in the kernel configuration, this compresses the given
+# modules using the same format.
+_modules_process_compress() {
+	local -a compress
+	if linux_chkconfig_present MODULE_COMPRESS_XZ; then
+		compress=(xz -qT"$(makeopts_jobs)" --memlimit-compress=50%)
+	elif linux_chkconfig_present MODULE_COMPRESS_GZIP; then
+		if type -P pigz &>/dev/null; then
+			compress=(pigz -p"$(makeopts_jobs)")
+		else
+			compress=(gzip)
+		fi
+	elif linux_chkconfig_present MODULE_COMPRESS_ZSTD; then
+		compress=(zstd -qT"$(makeopts_jobs)" --rm)
+	fi
+
+	if [[ -v compress ]]; then
+		# could fail, assumes have commands that were needed for the kernel
+		einfo "Compressing modules (matching the kernel configuration) ..."
+		edob "${compress[@]}" -- "${@}"
+	fi
+}
+
+# @FUNCTION: _modules_process_sign
+# @USAGE: <module>...
+# @INTERNAL
+# @DESCRIPTION:
+# Cryptographically signs the given modules when USE=modules-sign is
+# enabled.
+_modules_process_sign() {
+	use modules-sign || return 0
+
+	# scripts/sign-file used to be a perl script but is now written in C,
+	# and it could either be missing or broken given it links with openssl
+	# (no subslot rebuilds on kernel sources), trivial to compile regardless
+	local sign=
+	if [[ -f ${KV_DIR}/scripts/sign-file.c ]]; then
+		sign=${T}/linux-mod-r1_sign-file
+		(
+			# unfortunately using the kernel's Makefile is inconvenient (no
+			# simple build target for this), may need revisiting on changes
+			einfo "Compiling sign-file ..."
+			tc-export_build_env
+			nonfatal edob $(tc-getBUILD_CC) ${BUILD_CFLAGS} ${BUILD_CPPFLAGS} \
+				$($(tc-getBUILD_PKG_CONFIG) --cflags libcrypto) \
+				${BUILD_LDFLAGS} -o "${sign}" "${KV_DIR}"/scripts/sign-file.c \
+				$($(tc-getBUILD_PKG_CONFIG) --libs libcrypto || echo -lcrypto)
+		) || {
+			einfo "Trying fallback ..."
+			sign=
+		}
+	fi
+
+	if [[ -z ${sign} ]]; then
+		if [[ -x ${KV_OUT_DIR}/scripts/sign-file ]]; then
+			sign=${KV_OUT_DIR}/scripts/sign-file # try if built
+		elif [[ -x ${KV_DIR}/scripts/sign-file ]]; then
+			sign=${KV_DIR}/scripts/sign-file # old kernel (<linux-4.4)
+		else
+			die "USE=modules-sign is set but '${KV_DIR}/scripts/sign-file.c' is not usable"
+		fi
+	fi
+
+	einfo "Signing modules ..."
+
+	# good odds the private key has limited access, and with the kernel's
+	# automated method it is likely to be -rw------- root:root (but is rarely
+	# an issue given portage's src_install used here normally runs as root)
+	[[ ${MODULES_SIGN_KEY} == pkcs11:* || -r ${MODULES_SIGN_KEY} ]] ||
+		die "USE=modules-sign is set but lacking read access to the signing key at '${MODULES_SIGN_KEY}'"
+
+	local mod
+	for mod; do
+		edob "${sign}" "${MODULES_SIGN_HASH}" "${MODULES_SIGN_KEY}" \
+			"${MODULES_SIGN_CERT}" "${mod}"
+	done
+
+	# unset to at least be out of the environment file in, e.g. shared binpkgs
+	unset KBUILD_SIGN_PIN
+}
+
+# @FUNCTION: _modules_process_strip
+# @USAGE: <module>...
+# @INTERNAL
+# @DESCRIPTION:
+# Strips the given modules of unneeded symbols when USE=strip is
+# enabled, and informs the package manager not to regardless.
+_modules_process_strip() {
+	# letting the package manager handle this complicates scenarios
+	# where we want to either compress the pre-stripped module, or
+	# sign the module without its signature becoming invalid on merge
+	dostrip -x "${@#"${ED}"}"
+
+	if use strip; then
+		einfo "Stripping modules ..."
+		edob "${KERNEL_STRIP}" --strip-unneeded -- "${@}"
+	fi
+}
+
+# @FUNCTION: _modules_sanity_gccplugins
+# @INTERNAL
+# @DESCRIPTION:
+# Performs a basic build test to detect GCC plugins mismatch issues
+# and, if so, aborts with explanation given it often confuses users.
+#
+# Using mismatching gcc can sometime work to build modules, but if
+# GCC plugins are enabled it will almost always be an error.
+#
+# Note: may need occasional review to ensure the test still works by:
+# enabling a GCC plugin in the kernel, building with older GCC,
+# then building a module by setting KERNEL_CC=gcc-<major-version+1>.
+_modules_sanity_gccplugins() {
+	linux_chkconfig_present GCC_PLUGINS || return 0
+
+	local tmp=${T}/linux-mod-r1_gccplugins
+	mkdir -p -- "${tmp}" || die
+
+	echo "obj-m += test.o" > "${tmp}"/Kbuild || die
+	:> "${tmp}"/test.c || die
+
+	# always fails, but interested in the stderr messages
+	local output=$(
+		cd -- "${KV_OUT_DIR}" && # fwiw skip non-POSIX -C in eclasses
+			LC_ALL=C nonfatal emake "${MODULES_MAKEARGS[@]}" M="${tmp}" \
+				2>&1 >/dev/null
+	)
+
+	if [[ ${output} == *"error: incompatible gcc/plugin version"* ]]; then
+		eerror "GCC_PLUGINS is enabled in the kernel and plugin version mismatch issues"
+		eerror "have been detected. Please \`make clean\` and rebuild the kernel using"
+		eerror "the current version of GCC (or re-install for distribution kernels)."
+		die "kernel ${KV_FULL} needs to be rebuilt"
+	fi
+}
+
+# @FUNCTION: _modules_sanity_kernelbuilt
+# @INTERNAL
+# @DESCRIPTION:
+# Checks if the kernel seems fully built by having a Module.symvers
+# that is also readable, abort otherwise.
+#
+# About readability, occasionally users build their kernel as root with
+# umask 0077 and then the package manager's user cannot read built files
+# leaving them confused.
+#
+# Given user and access can very between phases (notably src_compile),
+# it makes sense to run this check more than once.
+#
+# Note:
+# This is an alternate version of linux-info's check_kernel_built
+# which probably will not need to exist there if linux-mod-r0 is
+# gone, error it gives is also modules-specific and fits better here.
+#
+# The old check_kernel_built checks version.h and suggests running
+# modules_prepare if missing, but that does not create Module.symvers.
+# Nowadays the kernel makes unresolved symbols fatal by default
+# meaning that all modules will fail unless KBUILD_MODPOST_WARN=1
+# which seem questionable to support.  So rather than version.h, this
+# checks and require Module.symvers, and suggests a full build if
+# missing (if really must, users can bypass by touching the file).
+# nvidia-drivers (for one) further checks this file directly to do
+# configure tests that will break badly without.
+_modules_sanity_kernelbuilt() {
+	local symvers=${KV_OUT_DIR}/Module.symvers
+
+	if [[ ! -f ${symvers} ]]; then
+		eerror "'${symvers}' was not found implying that the"
+		eerror "linux-${KV_FULL} tree at that location has not been built."
+		eerror
+		eerror "Please verify that this is the intended kernel version, then perform"
+		eerror "a full build[1] (i.e. make && make modules_install && make install)."
+		eerror
+		eerror "Alternatively, consider a distribution kernel[2] that does not need"
+		eerror "these manual steps (e.g. sys-kernel/gentoo-kernel or gentoo-kernel-bin)."
+		eerror
+		eerror "[1] https://wiki.gentoo.org/wiki/Kernel/Configuration#Build"
+		eerror "[2] https://wiki.gentoo.org/wiki/Project:Distribution_Kernel"
+		die "built kernel sources are required to build kernel modules"
+	fi
+
+	if [[ ! -r ${symvers} ]]; then
+		eerror "'${symvers}' exists but cannot be read by the"
+		eerror "user id(${EUID}) of the package manager, likely implying no world"
+		eerror "read access permissions:"
+		eerror
+		eerror "    $(ls -l -- "${symvers}")"
+		eerror
+		eerror "Causes may vary, but a common one is building the kernel with a umask"
+		eerror "value of '0077' rather than the more typical '0022' (run the \`umask\`"
+		eerror "command to confirm, as root if was building the kernel using it)."
+		eerror
+		eerror "Many other files are likely affected and will lead to build failures."
+		eerror "It is recommended to clean the sources and rebuild with \`umask 0022\`"
+		eerror "rather than attempt to fix the permissions manually."
+		die "no read access permission to the generated kernel files"
+	fi
+}
+
+# @FUNCTION: _modules_sanity_kernelversion
+# @INTERNAL
+# @DESCRIPTION:
+# Prints a warning if the kernel version is greater than to
+# MODULES_KERNEL_MAX (while only considering same amount of version
+# components), or aborts if it is less than MODULES_KERNEL_MIN
+_modules_sanity_kernelversion() {
+	local kv=${KV_MAJOR}.${KV_MINOR}.${KV_PATCH}
+
+	if [[ -n ${MODULES_KERNEL_MIN} ]] &&
+		ver_test "${kv}" -lt "${MODULES_KERNEL_MIN}"
+	then
+		eerror "${P} requires a kernel version of at least >=${MODULES_KERNEL_MIN},"
+		eerror "but the current kernel is ${KV_FULL}. Please update."
+		die "kernel ${KV_FULL} is too old"
+	fi
+
+	if [[ -n ${MODULES_KERNEL_MAX} ]]; then
+		: "${MODULES_KERNEL_MAX//[^.]/}"
+		local -i count=${#_}
+
+		if ver_test "$(ver_cut 1-$((count+1)) "${kv}")" \
+			-gt "${MODULES_KERNEL_MAX}"
+		then
+			# add .x to 1 missing component to make, e.g. <=1.2.x more natural,
+			# not <1.3 given users sometimes see it as 1.3 support at a glance
+			local max=${MODULES_KERNEL_MAX}
+			[[ ${count} -lt 2 ]] && max+=.x
+
+			ewarn
+			ewarn " *** WARNING *** "
+			ewarn
+			ewarn "${PN} is known to break easily with new kernel versions and,"
+			ewarn "with the current kernel (${KV_FULL}), it was either hardly"
+			ewarn "tested or is known broken. It is recommended to use one of:"
+			ewarn
+			ewarn "    <=sys-kernel/gentoo-kernel-${max}"
+			ewarn "    <=sys-kernel/gentoo-sources-${max}"
+			ewarn
+			ewarn "or equivalent rather than file downstream bug reports if run into"
+			ewarn "issues, then wait for upstream fixes and a new release. Ideally,"
+			ewarn "with out-of-tree modules, use an LTS (Long Term Support) kernel"
+			ewarn "branch[1]. If in doubt, Gentoo's stable kernels are always LTS"
+			ewarn "and can be easily used even on ~testing systems."
+			ewarn
+			ewarn "[1] https://www.kernel.org/category/releases.html"
+			ewarn
+		fi
+	fi
+}
+
+# @FUNCTION: _modules_sanity_modversion
+# @USAGE: <module>...
+# @INTERNAL
+# @DESCRIPTION:
+# Checks if the passed module(s) do not seem obviously broken and the
+# builtin versions match ${KV_FULL}, otherwise die with an explanation.
+#
+# If receive a bug with a version error, an easy way to reproduce is to
+# set KERNEL_DIR with the sources of a different kernel version than
+# both the ones pointed by /usr/src/linux and `uname -r`.
+_modules_sanity_modversion() {
+	local mod ver
+	for mod; do
+		# modinfo can read different-arch modules, being fatal *should* be safe
+		# and serve as a basic sanity check to ensure the module is valid
+		read -rd ' ' ver < <(
+			LC_ALL=C modinfo -F vermagic -- "${mod}" ||
+				die "modinfo failed to read module '${mod}' (broken module?)"
+		)
+		[[ -n ${ver} ]] ||
+				die "modinfo found no kernel version in '${mod}' (broken module?)"
+
+		if [[ ${ver} != "${KV_FULL}" ]]; then
+			eerror "A module seem to have been built for kernel version '${ver}'"
+			eerror "while it was meant for '${KV_FULL}'. This may indicate an"
+			eerror "ebuild issue (e.g. used runtime \`uname -r\` kernel rather than"
+			eerror "the chosen sources). Please report this to the ebuild's maintainer."
+			die "module and source version mismatch in '${mod}'"
+		fi
+	done
+}
+
+# @FUNCTION: _modules_set_makeargs
+# @INTERNAL
+# @DESCRIPTION:
+# Sets the MODULES_MAKEARGS global array.
+_modules_set_makeargs() {
+	MODULES_MAKEARGS=(
+		ARCH="$(tc-arch-kernel)"
+
+		V=1
+		# redundant with V, but needed sometimes (e.g. virtualbox-modules)
+		KBUILD_VERBOSE=1
+
+		# unrealistic when building less frequently updated modules
+		CONFIG_WERROR=
+
+		# these are only needed if using these arguments for installing, lets
+		# eclass handle strip, sign, compress, and depmod (CONFIG_ should
+		# have no impact on building, only used by Makefile.modinst)
+		CONFIG_MODULE_{SIG_ALL,COMPRESS_{GZIP,XZ,ZSTD}}=
+		DEPMOD=:
+		STRIP=:
+	)
+
+	if [[ ! ${MODULES_I_WANT_FULL_CONTROL} ]]; then
+		# many of these are unlikely to be useful here, but still trying to be
+		# complete given never know what out-of-tree modules may use
+		MODULES_MAKEARGS+=(
+			# wrt bug #550428, given most toolchain variables are being passed to
+			# make, setting CROSS in the environment would change very little
+			# (instead set KERNEL_CHOST which will affect other variables,
+			# or MODULES_I_WANT_FULL_CONTROL if do not want any of this)
+			CROSS_COMPILE="${KERNEL_CHOST}-"
+
+			HOSTCC="$(tc-getBUILD_CC)"
+			HOSTCXX="$(tc-getBUILD_CXX)"
+
+			# fwiw this function is not meant to pollute the environment
+			HOSTCFLAGS="$(tc-export_build_env; echo "${BUILD_CFLAGS}")"
+			HOSTCXXFLAGS="$(tc-export_build_env; echo "${BUILD_CXXFLAGS}")"
+			HOSTLDFLAGS="$(tc-export_build_env; echo "${BUILD_LDFLAGS}")"
+
+			HOSTPKG_CONFIG="$(tc-getBUILD_PKG_CONFIG)"
+
+			CC="${KERNEL_CC}"
+			CXX="${KERNEL_CXX}"
+			LD="${KERNEL_LD}"
+			AR="${KERNEL_AR}"
+			NM="${KERNEL_NM}"
+			OBJCOPY="${KERNEL_OBJCOPY}"
+			OBJDUMP="${KERNEL_OBJDUMP}"
+			READELF="${KERNEL_READELF}"
+		)
+	fi
+
+	# eval is to handle quoted spaces, die is for syntax errors
+	eval "MODULES_MAKEARGS+=( ${MODULES_EXTRA_EMAKE} )" || die
+}
+
+# @FUNCTION: _modules_update_depmod
+# @INTERNAL
+# @DESCRIPTION:
+# If possible, update module dependencies using depmod and System.map,
+# otherwise prompt user to handle it.  System.map may notably no longer
+# be available on binary merges.
+_modules_update_depmod() {
+	# prefer /lib/modules' path given it is what depmod operates on,
+	# and is mostly foolproof when it comes to ROOT (relative symlink)
+	local map=${EROOT}/lib/modules/${KV_FULL}/build/System.map
+
+	if [[ ! -f ${map} ]]; then
+		# KV_OUT_DIR may still be right even on a different system, but state
+		# of (E)ROOT is unknown, e.g. could be from KERNEL_DIR=${OLDROOT}/...
+		map=${KV_OUT_DIR}/System.map
+
+		# last resort, typical but may not be mounted/readable/installed
+		[[ ! -f ${map} ]] &&
+			map=${EROOT}/boot/System.map-${KV_FULL}
+	fi
+
+	einfo "Updating module dependencies for kernel ${KV_FULL} ..."
+	if [[ -f ${map} ]]; then
+		nonfatal edob depmod -ae -F "${map}" -b "${EROOT:-/}" "${KV_FULL}" &&
+			return 0
+	else
+		eerror
+		eerror "System.map for kernel ${KV_FULL} was not found, may be due to the"
+		eerror "built kernel sources no longer being available and lacking the fallback:"
+		eerror
+		eerror "${EROOT}/boot/System.map-${KV_FULL}"
+	fi
+	eerror
+	eerror "Some modules may not load without updating manually using depmod."
+}
+
+fi
+
+EXPORT_FUNCTIONS pkg_setup src_compile src_install pkg_postinst
-- 
2.40.1



^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [gentoo-dev] [PATCH v2] linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass
  2023-05-28 12:41   ` [gentoo-dev] [PATCH v2] " Ionen Wolkens
@ 2023-05-29 13:10     ` Ionen Wolkens
  0 siblings, 0 replies; 9+ messages in thread
From: Ionen Wolkens @ 2023-05-29 13:10 UTC (permalink / raw
  To: gentoo-dev

[-- Attachment #1: Type: text/plain, Size: 733 bytes --]

On Sun, May 28, 2023 at 08:41:16AM -0400, Ionen Wolkens wrote:
> Likely final as far as initial merge goes.
> 
> Given been suggested that it'd be easier to have it in the tree for
> testing and that without consumers it can't break anything (yet),
> planning to merge tomorrow. Just posting update here as a formality.

It is now merged with just a few minor comment/doc adjustments on top
(no code changes).

Feel free to start using it with in-tree ebuilds (currently used
by app-admin/ryzen_smu and games-util/xpadneo). Should still be
considered experimental as it had very little reviewing and testing
so far (please report issues!).

linux-mod-r0 will likely be marked @DEPRECATED at a later date.
-- 
ionen

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2023-05-29 13:10 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-26  4:02 [gentoo-dev] [PATCH 0/4] linux-mod-r1.eclass: new eclass, rewrite of -r0 Ionen Wolkens
2023-05-26  4:02 ` [gentoo-dev] [PATCH 1/4] profiles/use.desc: create USE=strip global USE flag Ionen Wolkens
2023-05-26  5:06   ` Sam James
2023-05-26  5:25     ` Ionen Wolkens
2023-05-26  4:02 ` [gentoo-dev] [PATCH 2/4] profiles/use.desc: create USE=modules-sign " Ionen Wolkens
2023-05-26  4:02 ` [gentoo-dev] [PATCH 3/4] linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass Ionen Wolkens
2023-05-28 12:41   ` [gentoo-dev] [PATCH v2] " Ionen Wolkens
2023-05-29 13:10     ` Ionen Wolkens
2023-05-26  4:02 ` [gentoo-dev] [PATCH 4/4] app-admin/ryzen_smu: migrate to linux-mod-r1 Ionen Wolkens

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox