summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIonen Wolkens <ionen@gentoo.org>2023-05-23 05:25:02 -0400
committerIonen Wolkens <ionen@gentoo.org>2023-05-29 09:03:27 -0400
commitd9687a4df038382187300d6f44230661ff5bc377 (patch)
treedf30157862ed3dea643f9410e5e9d081afc77af7 /eclass/linux-mod-r1.eclass
parentprofiles/use.desc: create USE=modules-sign global USE flag (diff)
downloadgentoo-d9687a4df038382187300d6f44230661ff5bc377.tar.gz
gentoo-d9687a4df038382187300d6f44230661ff5bc377.tar.bz2
gentoo-d9687a4df038382187300d6f44230661ff5bc377.zip
linux-mod-r1.eclass: new eclass, rewrite of linux-mod.eclass
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 Closes: https://github.com/gentoo/gentoo/pull/31154 Signed-off-by: Ionen Wolkens <ionen@gentoo.org>
Diffstat (limited to 'eclass/linux-mod-r1.eclass')
-rw-r--r--eclass/linux-mod-r1.eclass1206
1 files changed, 1206 insertions, 0 deletions
diff --git a/eclass/linux-mod-r1.eclass b/eclass/linux-mod-r1.eclass
new file mode 100644
index 000000000000..595711008627
--- /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 notes
+# 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 the
+# 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 could be:
+#
+# @CODE
+# src_compile() {
+# MODULES_MAKEARGS+=(
+# NIH_KDIR="${KV_OUT_DIR}"
+# NIH_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 as 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 kernel 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. runtime 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" (global IUSE).
+#
+# 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 append 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
+}
+
+# @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 )
+#
+# * 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 an associative array ([name]=) 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 subdirectories, 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. This is intended for use
+# when modules were installed some other way.
+#
+# <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.
+#
+# Warning: This will abort if no modules are found, which can happen
+# if modules were unexpectedly pre-compressed possibly due to using
+# make install without passing MODULES_MAKEARGS to disable it.
+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 under ${path}"
+
+ _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:
+# Aborts if see obsolete variables from the linux-mod-r0 eclass being
+# used, likely due to an incomplete migration. This function should
+# eventually 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 eclass docs"
+ }
+ # 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. Will
+# inform if matching was not possible likely due to the compiler being
+# uninstalled. Users can set KERNEL_ variables themselves to override.
+#
+# 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/-m elf_x86_64/etc... for, e.g.
+ # toolchains defaulting to x32, but may need automagic here if need
+ # a different toolchain such as sys-devel/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 src_install *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`. Refer to
+# linux-mod-r1_src_compile's modargs in the eclass docs for fixing.
+_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
+ # normally redundant with V, but some custom Makefiles override it
+ KBUILD_VERBOSE=1
+
+ # unrealistic when building modules that often have slow releases,
+ # but note that the kernel will still pass some -Werror=bad-thing
+ 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