summaryrefslogtreecommitdiff
path: root/eclass/linux-mod.eclass
blob: ff2294f1e4efe4c40c17e373f0ca84d715ae3a3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
# Copyright 1999-2022 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

# @ECLASS: linux-mod.eclass
# @MAINTAINER:
# kernel@gentoo.org
# @AUTHOR:
# John Mylchreest <johnm@gentoo.org>,
# Stefan Schweizer <genstef@gentoo.org>
# @SUPPORTED_EAPIS: 6 7 8
# @PROVIDES: linux-info
# @BLURB: It provides the functionality required to install external modules against a kernel source tree.
# @DESCRIPTION:
# This eclass is used to interface with linux-info.eclass in such a way
# to provide the functionality and initial functions
# required to install external modules against a kernel source
# tree.

# A Couple of env vars are available to effect usage of this eclass
# These are as follows:

# @ECLASS_VARIABLE: MODULES_OPTIONAL_USE
# @PRE_INHERIT
# @DEFAULT_UNSET
# @DESCRIPTION:
# A string containing the USE flag to use for making this eclass optional
# The recommended non-empty value is 'modules'

# @ECLASS_VARIABLE: MODULES_OPTIONAL_USE_IUSE_DEFAULT
# @PRE_INHERIT
# @DEFAULT_UNSET
# @DESCRIPTION:
# A boolean to control the IUSE default state for the MODULES_OPTIONAL_USE USE
# flag. Default value is unset (false). True represented by 1 or 'on', other
# values including unset treated as false.

# @ECLASS_VARIABLE: KERNEL_DIR
# @DESCRIPTION:
# A string containing the directory of the target kernel sources. The default value is
# "/usr/src/linux"
: ${KERNEL_DIR:=/usr/src/linux}

# @ECLASS_VARIABLE: ECONF_PARAMS
# @DEFAULT_UNSET
# @DESCRIPTION:
# It's a string containing the parameters to pass to econf.
# If this is not set, then econf isn't run.

# @ECLASS_VARIABLE: BUILD_PARAMS
# @DEFAULT_UNSET
# @DESCRIPTION:
# It's a string with the parameters to pass to emake.

# @ECLASS_VARIABLE: BUILD_TARGETS
# @DESCRIPTION:
# It's a string with the build targets to pass to make. The default value is "clean module"
: ${BUILD_TARGETS:=clean module}

# @ECLASS_VARIABLE: MODULE_NAMES
# @DEFAULT_UNSET
# @DESCRIPTION:
# It's a string containing the modules to be built automatically using the default
# src_compile/src_install. It will only make ${BUILD_TARGETS} once in any directory.
#
# The structure of each MODULE_NAMES entry is as follows:
#
#   modulename(libdir:srcdir:objdir)
#
# where:
#
#   modulename = name of the module file excluding the .ko
#   libdir     = place in system modules directory where module is installed (by default it's misc)
#   srcdir     = place for ebuild to cd to before running make (by default it's ${S})
#   objdir     = place the .ko and objects are located after make runs (by default it's set to srcdir)
#
# To get an idea of how these variables are used, here's a few lines
# of code from around line 540 in this eclass:
#
#	einfo "Installing ${modulename} module"
#	cd ${objdir} || die "${objdir} does not exist"
#	insinto /lib/modules/${KV_FULL}/${libdir}
#	doins ${modulename}.${KV_OBJ} || die "doins ${modulename}.${KV_OBJ} failed"
#
# For example:
#   MODULE_NAMES="module_pci(pci:${S}/pci:${S}) module_usb(usb:${S}/usb:${S})"
#
# what this would do is
#
#   cd "${S}"/pci
#   make ${BUILD_PARAMS} ${BUILD_TARGETS}
#   cd "${S}"
#   insinto /lib/modules/${KV_FULL}/pci
#   doins module_pci.${KV_OBJ}
#
#   cd "${S}"/usb
#   make ${BUILD_PARAMS} ${BUILD_TARGETS}
#   cd "${S}"
#   insinto /lib/modules/${KV_FULL}/usb
#   doins module_usb.${KV_OBJ}

# There is also support for automated modprobe.d file generation.
# This can be explicitly enabled by setting any of the following variables.

# @ECLASS_VARIABLE: MODULESD_<modulename>_ENABLED
# @DEFAULT_UNSET
# @DESCRIPTION:
# This is used to disable the modprobe.d file generation otherwise the file will be
# always generated (unless no MODULESD_<modulename>_* variable is provided). Set to "no" to disable
# the generation of the file and the installation of the documentation.

# @ECLASS_VARIABLE: MODULESD_<modulename>_EXAMPLES
# @DEFAULT_UNSET
# @DESCRIPTION:
# This is a bash array containing a list of examples which should
# be used. If you want us to try and take a guess set this to "guess".
#
# For each array_component it's added an options line in the modprobe.d file
#
#   options array_component
#
# where array_component is "<modulename> options" (see modprobe.conf(5))

# @ECLASS_VARIABLE: MODULESD_<modulename>_ALIASES
# @DEFAULT_UNSET
# @DESCRIPTION:
# This is a bash array containing a list of associated aliases.
#
# For each array_component it's added an alias line in the modprobe.d file
#
#   alias array_component
#
# where array_component is "wildcard <modulename>" (see modprobe.conf(5))

# @ECLASS_VARIABLE: MODULESD_<modulename>_ADDITIONS
# @DEFAULT_UNSET
# @DESCRIPTION:
# This is a bash array containing a list of additional things to
# add to the bottom of the file. This can be absolutely anything.
# Each entry is a new line.

# @ECLASS_VARIABLE: MODULESD_<modulename>_DOCS
# @DEFAULT_UNSET
# @DESCRIPTION:
# This is a string list which contains the full path to any associated
# documents for <modulename>. These files are installed in the live tree.

# @ECLASS_VARIABLE: KV_OBJ
# @INTERNAL
# @DESCRIPTION:
# It's a read-only variable. It contains the extension of the kernel modules.

case ${EAPI:-0} in
	[67])
		inherit eutils
		;;
	8)
		;;
	*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
esac

if [[ -z ${_LINUX_MOD_ECLASS} ]] ; then
_LINUX_MOD_ECLASS=1

# TODO: When adding support for future EAPIs, please audit this list
# for unused inherits and conditionalise them.
inherit linux-info multilib multiprocessing toolchain-funcs

case ${MODULES_OPTIONAL_USE_IUSE_DEFAULT:-n} in
  [nNfF]*|[oO][fF]*|0|-) _modules_optional_use_iuse_default='' ;;
  *) _modules_optional_use_iuse_default='+' ;;
esac

[[ -n "${_modules_optional_use_iuse_default}" ]] && case ${EAPI:-0} in
	0) die "EAPI=${EAPI} is not supported with MODULES_OPTIONAL_USE_IUSE_DEFAULT due to lack of IUSE defaults" ;;
esac

IUSE="dist-kernel
	${MODULES_OPTIONAL_USE:+${_modules_optional_use_iuse_default}}${MODULES_OPTIONAL_USE}"
SLOT="0"
RDEPEND="
	${MODULES_OPTIONAL_USE}${MODULES_OPTIONAL_USE:+? (}
		kernel_linux? (
			sys-apps/kmod[tools]
			dist-kernel? ( virtual/dist-kernel:= )
		)
	${MODULES_OPTIONAL_USE:+)}"
DEPEND="${RDEPEND}
    ${MODULES_OPTIONAL_USE}${MODULES_OPTIONAL_USE:+? (}
	kernel_linux? ( virtual/linux-sources virtual/libelf )
	${MODULES_OPTIONAL_USE:+)}"

# eclass utilities
# ----------------------------------

# @FUNCTION: use_m
# @RETURN: true or false
# @DESCRIPTION:
# It checks if the kernel version is greater than 2.6.5.
use_m() {
	debug-print-function ${FUNCNAME} $*

	# if we haven't determined the version yet, we need too.
	get_version;

	# if the kernel version is greater than 2.6.6 then we should use
	# M= instead of SUBDIRS=
	[ ${KV_MAJOR} -ge 3 ] && return 0
	[ ${KV_MAJOR} -eq 2 -a ${KV_MINOR} -gt 5 -a ${KV_PATCH} -gt 5 ] && \
		return 0 || return 1
}

# @FUNCTION: convert_to_m
# @USAGE: </path/to/the/file>
# @DESCRIPTION:
# It converts a file (e.g. a makefile) to use M= instead of SUBDIRS=
convert_to_m() {
	debug-print-function ${FUNCNAME} $*

	if use_m
	then
		[ ! -f "${1}" ] && \
			die "convert_to_m() requires a filename as an argument"
		ebegin "Converting ${1/${WORKDIR}\//} to use M= instead of SUBDIRS="
		sed -i 's:SUBDIRS=:M=:g' "${1}"
		eend $?
	fi
}

# @FUNCTION: update_depmod
# @INTERNAL
# @DESCRIPTION:
# Updates the modules.dep file for the current kernel.
update_depmod() {
	debug-print-function ${FUNCNAME} $*

	# if we haven't determined the version yet, we need too.
	get_version;

	ebegin "Updating module dependencies for ${KV_FULL}"
	if [ -r "${KV_OUT_DIR}"/System.map ]
	then
		depmod -ae -F "${KV_OUT_DIR}"/System.map -b "${ROOT:-/}" ${KV_FULL}
		eend $?
	else
		ewarn
		ewarn "${KV_OUT_DIR}/System.map not found."
		ewarn "You must manually update the kernel module dependencies using depmod."
		eend 1
		ewarn
	fi
}

# @FUNCTION: move_old_moduledb
# @INTERNAL
# @DESCRIPTION:
# Updates the location of the database used by the module-rebuild utility.
move_old_moduledb() {
	debug-print-function ${FUNCNAME} $*

	local OLDDIR="${ROOT%/}"/usr/share/module-rebuild
	local NEWDIR="${ROOT%/}"/var/lib/module-rebuild

	if [[ -f "${OLDDIR}"/moduledb ]]; then
		[[ ! -d "${NEWDIR}" ]] && mkdir -p "${NEWDIR}"
		[[ ! -f "${NEWDIR}"/moduledb ]] && \
			mv "${OLDDIR}"/moduledb "${NEWDIR}"/moduledb
		rm -f "${OLDDIR}"/*
		rmdir "${OLDDIR}"
	fi
}

# @FUNCTION: update_moduledb
# @DESCRIPTION:
# Adds the package to the /var/lib/module-rebuild/moduledb database used by the module-rebuild utility.
update_moduledb() {
	debug-print-function ${FUNCNAME} $*

	local MODULEDB_DIR="${ROOT%/}"/var/lib/module-rebuild
	move_old_moduledb

	if [[ ! -f "${MODULEDB_DIR}"/moduledb ]]; then
		[[ ! -d "${MODULEDB_DIR}" ]] && mkdir -p "${MODULEDB_DIR}"
		touch "${MODULEDB_DIR}"/moduledb
	fi

	if ! grep -qs ${CATEGORY}/${PN}-${PVR} "${MODULEDB_DIR}"/moduledb ; then
		einfo "Adding module to moduledb."
		echo "a:1:${CATEGORY}/${PN}-${PVR}" >> "${MODULEDB_DIR}"/moduledb
	fi
}

# @FUNCTION: remove_moduledb
# @DESCRIPTION:
# Removes the package from the /var/lib/module-rebuild/moduledb database used by
remove_moduledb() {
	debug-print-function ${FUNCNAME} $*

	local MODULEDB_DIR="${ROOT%/}"/var/lib/module-rebuild
	move_old_moduledb

	if grep -qs ${CATEGORY}/${PN}-${PVR} "${MODULEDB_DIR}"/moduledb ; then
		einfo "Removing ${CATEGORY}/${PN}-${PVR} from moduledb."
		sed -i -e "/.*${CATEGORY}\/${PN}-${PVR}.*/d" "${MODULEDB_DIR}"/moduledb
	fi
}

# @FUNCTION: set_kvobj
# @DESCRIPTION:
# It sets the KV_OBJ variable.
set_kvobj() {
	debug-print-function ${FUNCNAME} $*

	if kernel_is ge 2 6
	then
		KV_OBJ="ko"
	else
		KV_OBJ="o"
	fi
	# Do we really need to know this?
	# Lets silence it.
	# einfo "Using KV_OBJ=${KV_OBJ}"
}

# @FUNCTION: get-KERNEL_CC
# @RETURN: Name of the C compiler.
# @DESCRIPTION:
# Return name of the C compiler while honoring variables defined in ebuilds.
get-KERNEL_CC() {
	debug-print-function ${FUNCNAME} $*

	if [[ -n ${KERNEL_CC} ]] ; then
		echo "${KERNEL_CC}"
		return
	fi

	local kernel_cc
	if [ -n "${KERNEL_ABI}" ]; then
		# In future, an arch might want to define CC_$ABI
		#kernel_cc="$(get_abi_CC)"
		#[ -z "${kernel_cc}" ] &&
		kernel_cc="$(tc-getCC $(ABI=${KERNEL_ABI} get_abi_CHOST))"
	else
		kernel_cc=$(tc-getCC)
	fi
	echo "${kernel_cc}"
}

# @FUNCTION: generate_modulesd
# @INTERNAL
# @USAGE: /path/to/the/modulename_without_extension
# @RETURN: A file in /etc/modprobe.d
# @DESCRIPTION:
# This function will generate and install the neccessary modprobe.d file from the
# information contained in the modules exported parms.
# (see the variables MODULESD_<modulename>_ENABLED, MODULESD_<modulename>_EXAMPLES,
# MODULESD_<modulename>_ALIASES, MODULESD_<modulename>_ADDITION and MODULESD_<modulename>_DOCS).
#
# At the end the documentation specified with MODULESD_<modulename>_DOCS is installed.
generate_modulesd() {
	debug-print-function ${FUNCNAME} $*
	[ -n "${MODULES_OPTIONAL_USE}" ] && use !${MODULES_OPTIONAL_USE} && return

	local currm_path currm currm_t t myIFS myVAR
	local module_docs module_enabled module_aliases \
			module_additions module_examples module_modinfo module_opts

	for currm_path in ${@}
	do
		currm=${currm_path//*\/}
		currm=$(echo ${currm} | tr '[:lower:]' '[:upper:]')
		currm_t=${currm}
		while [[ -z ${currm_t//*-*} ]]; do
			currm_t=${currm_t/-/_}
		done

		module_docs="$(eval echo \${MODULESD_${currm_t}_DOCS})"
		module_enabled="$(eval echo \${MODULESD_${currm_t}_ENABLED})"
		module_aliases="$(eval echo \${#MODULESD_${currm_t}_ALIASES[*]})"
		module_additions="$(eval echo \${#MODULESD_${currm_t}_ADDITIONS[*]})"
		module_examples="$(eval echo \${#MODULESD_${currm_t}_EXAMPLES[*]})"

		[[ ${module_aliases} -eq 0 ]]	&& unset module_aliases
		[[ ${module_additions} -eq 0 ]]	&& unset module_additions
		[[ ${module_examples} -eq 0 ]]  && unset module_examples

		# If we specify we dont want it, then lets exit, otherwise we assume
		# that if its set, we do want it.
		[[ ${module_enabled} == no ]] && return 0

		# unset any unwanted variables.
		for t in ${!module_*}
		do
			[[ -z ${!t} ]] && unset ${t}
		done

		[[ -z ${!module_*} ]] && return 0

		# OK so now if we have got this far, then we know we want to continue
		# and generate the modprobe.d file.
		module_modinfo="$(modinfo -p ${currm_path}.${KV_OBJ})"
		module_config="${T}/modulesd-${currm}"

		ebegin "Preparing file for modprobe.d"
		#-----------------------------------------------------------------------
		echo "# modprobe.d configuration file for ${currm}" >> "${module_config}"
		#-----------------------------------------------------------------------
		[[ -n ${module_docs} ]] && \
			echo "# For more information please read:" >> "${module_config}"
		for t in ${module_docs}
		do
			echo "#    ${t//*\/}" >> "${module_config}"
		done
		echo >> "${module_config}"

		#-----------------------------------------------------------------------
		if [[ ${module_aliases} -gt 0 ]]
		then
			echo  "# Internal Aliases - Do not edit" >> "${module_config}"
			echo  "# ------------------------------" >> "${module_config}"

			for((t=0; t<${module_aliases}; t++))
			do
				echo "alias $(eval echo \${MODULESD_${currm}_ALIASES[$t]})" \
					>> "${module_config}"
			done
			echo '' >> "${module_config}"
		fi

		#-----------------------------------------------------------------------
		if [[ -n ${module_modinfo} ]]
		then
			echo >> "${module_config}"
			echo  "# Configurable module parameters" >> "${module_config}"
			echo  "# ------------------------------" >> "${module_config}"
			myIFS="${IFS}"
			IFS="$(echo -en "\n\b")"

			for t in ${module_modinfo}
			do
				myVAR="$(echo ${t#*:}  | grep -o "[^ ]*[0-9][ =][^ ]*" | tail -1  | grep -o "[0-9]")"
				if [[ -n ${myVAR} ]]
				then
					module_opts="${module_opts} ${t%%:*}:${myVAR}"
				fi
				echo -e "# ${t%%:*}:\t${t#*:}" >> "${module_config}"
			done
			IFS="${myIFS}"
			echo '' >> "${module_config}"
		fi

		#-----------------------------------------------------------------------
		if [[ $(eval echo \${MODULESD_${currm}_ALIASES[0]}) == guess ]]
		then
			# So lets do some guesswork eh?
			if [[ -n ${module_opts} ]]
			then
				echo "# For Example..." >> "${module_config}"
				echo "# --------------" >> "${module_config}"
				for t in ${module_opts}
				do
					echo "# options ${currm} ${t//:*}=${t//*:}" >> "${module_config}"
				done
				echo '' >> "${module_config}"
			fi
		elif [[ ${module_examples} -gt 0 ]]
		then
			echo "# For Example..." >> "${module_config}"
			echo "# --------------" >> "${module_config}"
			for((t=0; t<${module_examples}; t++))
			do
				echo "options $(eval echo \${MODULESD_${currm}_EXAMPLES[$t]})" \
					>> "${module_config}"
			done
			echo '' >> "${module_config}"
		fi

		#-----------------------------------------------------------------------
		if [[ ${module_additions} -gt 0 ]]
		then
			for((t=0; t<${module_additions}; t++))
			do
				echo "$(eval echo \${MODULESD_${currm}_ADDITIONS[$t]})" \
					>> "${module_config}"
			done
			echo '' >> "${module_config}"
		fi

		#-----------------------------------------------------------------------

		# then we install it
		insinto /etc/modprobe.d
		newins "${module_config}" "${currm_path//*\/}.conf"

		# and install any documentation we might have.
		[[ -n ${module_docs} ]] && dodoc ${module_docs}
	done
	eend 0
	return 0
}

# @FUNCTION: find_module_params
# @USAGE: A string "NAME(LIBDIR:SRCDIR:OBJDIR)"
# @INTERNAL
# @RETURN: The string "modulename:NAME libdir:LIBDIR srcdir:SRCDIR objdir:OBJDIR"
# @DESCRIPTION:
# Analyze the specification NAME(LIBDIR:SRCDIR:OBJDIR) of one module as described in MODULE_NAMES.
find_module_params() {
	debug-print-function ${FUNCNAME} $*

	local matched_offset=0 matched_opts=0 test="${@}" temp_var result
	local i=0 y=0 z=0

	for((i=0; i<=${#test}; i++))
	do
		case ${test:${i}:1} in
			\()		matched_offset[0]=${i};;
			\:)		matched_opts=$((${matched_opts} + 1));
					matched_offset[${matched_opts}]="${i}";;
			\))		matched_opts=$((${matched_opts} + 1));
					matched_offset[${matched_opts}]="${i}";;
		esac
	done

	for((i=0; i<=${matched_opts}; i++))
	do
		# i			= offset were working on
		# y			= last offset
		# z			= current offset - last offset
		# temp_var	= temporary name
		case ${i} in
			0)	tempvar=${test:0:${matched_offset[0]}};;
			*)	y=$((${matched_offset[$((${i} - 1))]} + 1))
				z=$((${matched_offset[${i}]} - ${matched_offset[$((${i} - 1))]}));
				z=$((${z} - 1))
				tempvar=${test:${y}:${z}};;
		esac

		case ${i} in
			0)	result="${result} modulename:${tempvar}";;
			1)	result="${result} libdir:${tempvar}";;
			2)	result="${result} srcdir:${tempvar}";;
			3)	result="${result} objdir:${tempvar}";;
		esac
	done

	echo ${result}
}

# default ebuild functions
# --------------------------------

# @FUNCTION: linux-mod_pkg_setup
# @DESCRIPTION:
# It checks the CONFIG_CHECK options (see linux-info.eclass(5)), verifies that the kernel is
# configured, verifies that the sources are prepared, verifies that the modules support is builtin
# in the kernel and sets the object extension KV_OBJ.
linux-mod_pkg_setup() {
	debug-print-function ${FUNCNAME} $*
	[ -n "${MODULES_OPTIONAL_USE}" ] && use !${MODULES_OPTIONAL_USE} && return

	local is_bin="${MERGE_TYPE}"

	# If we are installing a binpkg, take a different path.
	if [[ ${is_bin} == binary ]]; then
		linux-mod_pkg_setup_binary
		return
	fi

	# External modules use kernel symbols (bug #591832)
	CONFIG_CHECK+=" !TRIM_UNUSED_KSYMS"

	linux-info_pkg_setup;
	require_configured_kernel
	check_kernel_built;
	strip_modulenames;
	[[ -n ${MODULE_NAMES} ]] && check_modules_supported
	set_kvobj;
}

# @FUNCTION: linux-mod_pkg_setup_binary
# @DESCRIPTION:
# Perform all kernel option checks non-fatally, as the .config and
# /proc/config.gz might not be present. Do not do anything that requires kernel
# sources.
linux-mod_pkg_setup_binary() {
	debug-print-function ${FUNCNAME} $*
	local new_CONFIG_CHECK
	# ~ needs always to be quoted, else bash expands it.
	for config in $CONFIG_CHECK ; do
		optional='~'
		[[ ${config:0:1} == "~" ]] && optional=''
		new_CONFIG_CHECK="${new_CONFIG_CHECK} ${optional}${config}"
	done
	CONFIG_CHECK="${new_CONFIG_CHECK}"
	linux-info_pkg_setup;
}

# @FUNCTION: strip_modulenames
# @DESCRIPTION:
# Remove modules from being built automatically using the default src_compile/src_install
strip_modulenames() {
	debug-print-function ${FUNCNAME} $*

	local i
	for i in ${MODULE_IGNORE}; do
		MODULE_NAMES=${MODULE_NAMES//${i}(*}
	done
}

# @FUNCTION: linux-mod_src_compile
# @DESCRIPTION:
# It compiles all the modules specified in MODULE_NAMES. For each module the econf command is
# executed only if ECONF_PARAMS is defined, the name of the target is specified by BUILD_TARGETS
# while the options are in BUILD_PARAMS (all the modules share these variables). The compilation
# happens inside ${srcdir}.
#
# Look at the description of these variables for more details.
linux-mod_src_compile() {
	debug-print-function ${FUNCNAME} $*
	[ -n "${MODULES_OPTIONAL_USE}" ] && use !${MODULES_OPTIONAL_USE} && return

	local modulename libdir srcdir objdir i n myABI="${ABI}"
	set_arch_to_kernel
	ABI="${KERNEL_ABI}"

	[[ -n ${KERNEL_DIR} ]] && addpredict "${KERNEL_DIR}/null.dwo"

	# Set CROSS_COMPILE in the environment.
	# This allows it to be overridden in local Makefiles.
	# https://bugs.gentoo.org/550428
	local -x CROSS_COMPILE=${CROSS_COMPILE-${CHOST}-}

	BUILD_TARGETS=${BUILD_TARGETS:-clean module}
	strip_modulenames;
	cd "${S}"
	touch Module.symvers
	for i in ${MODULE_NAMES}
	do
		unset libdir srcdir objdir
		for n in $(find_module_params ${i})
		do
			eval ${n/:*}=${n/*:/}
		done
		libdir=${libdir:-misc}
		srcdir=${srcdir:-${S}}
		objdir=${objdir:-${srcdir}}

		if [ ! -f "${srcdir}/.built" ];
		then
			cd "${srcdir}"
			ln -s "${S}"/Module.symvers Module.symvers
			einfo "Preparing ${modulename} module"
			if [[ -n ${ECONF_PARAMS} ]]
			then
				eqawarn "This package relies on the deprecated functionality of econf being called in linux-mod_src_compile (ECONF_PARAMS), which will go away in 30 days (20230107) (https://bugs.gentoo.org/340597)"
				econf ${ECONF_PARAMS} || \
				die "Unable to run econf ${ECONF_PARAMS}"
			fi

			# This looks messy, but it is needed to handle multiple variables
			# being passed in the BUILD_* stuff where the variables also have
			# spaces that must be preserved. If don't do this, then the stuff
			# inside the variables gets used as targets for Make, which then
			# fails.
			eval "emake HOSTCC=\"$(tc-getBUILD_CC)\" \
						LDFLAGS=\"$(get_abi_LDFLAGS)\" \
						${BUILD_FIXES} \
						${BUILD_PARAMS} \
						${BUILD_TARGETS} " \
				|| die "Unable to emake HOSTCC="$(tc-getBUILD_CC)" LDFLAGS="$(get_abi_LDFLAGS)" ${BUILD_FIXES} ${BUILD_PARAMS} ${BUILD_TARGETS}"
			cd "${OLDPWD}"
			touch "${srcdir}"/.built
		fi
	done

	set_arch_to_pkgmgr
	ABI="${myABI}"
}

# @FUNCTION: linux-mod_src_install
# @DESCRIPTION:
# It install the modules specified in MODULE_NAMES. The modules should be inside the ${objdir}
# directory and they are installed inside /lib/modules/${KV_FULL}/${libdir}.
#
# The modprobe.d configuration file is automatically generated if the
# MODULESD_<modulename>_* variables are defined. The only way to stop this process is by
# setting MODULESD_<modulename>_ENABLED=no. At the end the documentation specified via
# MODULESD_<modulename>_DOCS is also installed.
#
# Look at the description of these variables for more details.
linux-mod_src_install() {
	debug-print-function ${FUNCNAME} $*
	[ -n "${MODULES_OPTIONAL_USE}" ] && use !${MODULES_OPTIONAL_USE} && return

	local modulename libdir srcdir objdir i n

	[[ -n ${KERNEL_DIR} ]] && addpredict "${KERNEL_DIR}/null.dwo"

	strip_modulenames;
	for i in ${MODULE_NAMES}
	do
		unset libdir srcdir objdir
		for n in $(find_module_params ${i})
		do
			eval ${n/:*}=${n/*:/}
		done
		libdir=${libdir:-misc}
		srcdir=${srcdir:-${S}}
		objdir=${objdir:-${srcdir}}

		einfo "Installing ${modulename} module"
		cd "${objdir}" || die "${objdir} does not exist"
		insinto "${INSTALL_MOD_PATH}"/lib/modules/${KV_FULL}/${libdir}

		# check here for CONFIG_MODULE_COMPRESS_<compression option> (NONE, GZIP, XZ, ZSTD)
		# and similarily compress the module being built if != NONE.

		if linux_chkconfig_present MODULE_COMPRESS_XZ; then
			xz -T$(makeopts_jobs) --memlimit-compress=50% -q ${modulename}.${KV_OBJ} || die "Compressing ${modulename}.${KV_OBJ} with xz failed"
			doins ${modulename}.${KV_OBJ}.xz
		elif linux_chkconfig_present MODULE_COMPRESS_GZIP; then
			if type -P pigz &>/dev/null ; then
				pigz -p$(makeopts_jobs) ${modulename}.${KV_OBJ} || die "Compressing ${modulename}.${KV_OBJ} with pigz failed"
			else
				gzip ${modulename}.${KV_OBJ} || die "Compressing ${modulename}.${KV_OBJ} with gzip failed"
			fi
			doins ${modulename}.${KV_OBJ}.gz
		elif linux_chkconfig_present MODULE_COMPRESS_ZSTD; then
			zstd -T$(makeopts_jobs) ${modulename}.${KV_OBJ} || "Compressing ${modulename}.${KV_OBJ} with zstd failed"
			doins ${modulename}.${KV_OBJ}.zst
		else
			doins ${modulename}.${KV_OBJ}
		fi
		cd "${OLDPWD}" || die "${OLDPWD} does not exist"

		generate_modulesd "${objdir}/${modulename}"
	done
}

# @FUNCTION: linux-mod_pkg_preinst
# @DESCRIPTION:
# It checks what to do after having merged the package.
linux-mod_pkg_preinst() {
	debug-print-function ${FUNCNAME} $*
	[ -n "${MODULES_OPTIONAL_USE}" ] && use !${MODULES_OPTIONAL_USE} && return

	[ -d "${D%/}/lib/modules" ] && UPDATE_DEPMOD=true || UPDATE_DEPMOD=false
	[ -d "${D%/}/lib/modules" ] && UPDATE_MODULEDB=true || UPDATE_MODULEDB=false
}

# @FUNCTION: linux-mod_pkg_postinst
# @DESCRIPTION:
# It executes /sbin/depmod and adds the package to the /var/lib/module-rebuild/moduledb
# database (if ${D}/lib/modules is created)"
linux-mod_pkg_postinst() {
	debug-print-function ${FUNCNAME} $*
	[ -n "${MODULES_OPTIONAL_USE}" ] && use !${MODULES_OPTIONAL_USE} && return

	${UPDATE_DEPMOD} && update_depmod;
	${UPDATE_MODULEDB} && update_moduledb;
}

# @FUNCTION: linux-mod_pkg_postrm
# @DESCRIPTION:
# It removes the package from the /var/lib/module-rebuild/moduledb database but it doens't
# call /sbin/depmod because the modules are still installed.
linux-mod_pkg_postrm() {
	debug-print-function ${FUNCNAME} $*
	[ -n "${MODULES_OPTIONAL_USE}" ] && use !${MODULES_OPTIONAL_USE} && return
	remove_moduledb;
}

fi

EXPORT_FUNCTIONS pkg_setup src_compile src_install \
	pkg_preinst pkg_postinst pkg_postrm