# Copyright 1999-2017 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # @ECLASS: linux-build.eclass # @MAINTAINER: # Bertrand Jacquin # @BLURB: Eclass for building kernel # @DESCRIPTION: # Build kernel properly case "${EAPI:-0}" in 6) ;; *) die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" ;; esac ETYPE="sources" inherit savedconfig kernel-2 detect_version EXPORT_FUNCTIONS pkg_setup src_prepare src_compile src_install pkg_postinst : ${LINUX_BUILD_MOD_SIG_DAYS:=365} : ${LINUX_BUILD_MOD_SIG_KEY_ALG:=rsa} : ${LINUX_BUILD_MOD_SIG_KEY_SIZE:=2048} SLOT="${PV%.*}" DESCRIPTION="Kernel stable sources and build" HOMEPAGE="https://www.kernel.org" SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" SRCDIR="${WORKDIR}/linux-${KV_FULL}" BUILDDIR="${WORKDIR}/build" KV_EXTRA="${EXTRAVERSION}" S="${SRCDIR}" IUSE="build source" REQUIRED_USE="symlink? ( source )" DEPEND="${DEPEND} sys-devel/bc sys-apps/diffutils sys-apps/kmod virtual/libelf" RDEPEND="${RDEPEND}" # @FUNCTION: _linux-build_configval # @INTERNAL # @DESCRIPTION: # Request a CONFIG value from .config file # Return true if set, and define CONFIG_ # Return false if not set _linux-build_configval() { local _v="CONFIG_$1" # Export only the needed config value # when not already define declare -p "${_v}" > /dev/null 2>&1 \ || . <(sed -n "/^${_v}=/ p" "${BUILDDIR}/.config") case "${!_v}" in "") declare "$_v=n" ; export "${_v}" ; return 1 ;; *) export "${_v}" ; return 0 ;; esac } _linux-build_get-portage-versions() { local -a _v local _rv if [[ "${PF}" != "${P}" ]] ; then _v+=( "${PF}" ) fi _v+=( "${P}" ) if [[ -n "${REPLACING_VERSIONS}" ]] ; then for _rv in ${REPLACING_VERSIONS} ; do _v+=( "${PN}-${_rv}" ) done fi _v+=( "${PN}" ) echo "${_v[@]}" } _linux-build_pkg_setup-build-config() { local _v if ! use savedconfig ; then return 0 fi if [[ -e "${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${PF}" ]] ; then einfo "Restoring configuration from ${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${PF}" eend 0 return 0 fi for _v in $(_linux-build_get-portage-versions) ; do einfo "Checking existence of ${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${_v}" if [[ -e "${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${_v}" ]] ; then eend 0 einfo "Restoring configuration from ${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${PF}" cp "${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${_v}" \ "${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${PF}" \ || die "Failed to copy ${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${_v}" eend 0 return 0 fi eend 1 done return 1 } _linux-build_pkg_setup-build-x509() { local _v for _v in $(_linux-build_get-portage-versions) ; do einfo "Checking existence of ${PORTAGE_CONFIGROOT%/}/etc/ssl/private/${_v}.pem" if [[ -e "${PORTAGE_CONFIGROOT%/}/etc/ssl/private/${_v}.pem" ]] ; then eend 0 mkdir "${T}/certs" einfo "Restoring x509 pair from ${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${PF}" cp --preserve=mode,ownership \ "${PORTAGE_CONFIGROOT%/}/etc/ssl/private/${_v}.pem" "${T}/certs/signing_key.pem" \ || die "Failed to copy ${PORTAGE_CONFIGROOT%/}/etc/ssl/private/${_v}.pem" eend 0 return 0 fi eend 1 done return 1 } _linux-build_pkg_setup-build() { _linux-build_pkg_setup-build-config _linux-build_pkg_setup-build-x509 } linux-build_pkg_setup() { kernel-2_pkg_setup use build && _linux-build_pkg_setup-build } _linux-build_src_prepare_build() { local i mkdir "${BUILDDIR}" mkdir "${WORKDIR}/boot" if [[ -e "${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${PF}" ]] ; then cp "${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${PF}" "${BUILDDIR}/.config" \ || die "Failed to copy ${PORTAGE_CONFIGROOT%/}/etc/portage/savedconfig/${CATEGORY}/${PF}" else ewarn "Generate .config using 'defconfig'" emake defconfig "${myopt[@]}" fi if _linux-build_configval CMDLINE_BOOL && _linux-build_configval CMDLINE ; then einfo "Creating kernel.arg" einfo " CONFIG_CMDLINE='${CONFIG_CMDLINE}'" echo "${CONFIG_CMDLINE}" > "${WORKDIR}/boot/kernel.arg" fi local -a BOOTLOADERS=() case "${ARCH}" in amd64|x86) BOOTLOADERS+=( sys-boot/grub:0 /boot/grub/grub.conf sys-boot/grub:2 /boot/grub/grub.cfg sys-boot/syslinux:0 /boot/extlinux/syslinux.cfg sys-boot/syslinux:0 /boot/extlinux/extlinux.conf ) ;; arm|arm64) BOOTLOADERS+=( sys-boot/raspberrypi-firmware /boot/config.txt ) ;; esac KV_INSTALLED="$(best_version ${CATEGORY}/${PN}:${SLOT})" KV_INSTALLED="${KV_INSTALLED/#${CATEGORY}\/${PN}-}${KV_EXTRA}" # Generate bootloader configuration if [[ -n "${KV_INSTALLED}" ]] ; then for (( i = 0 ; i < ${#BOOTLOADERS[@]} ; i += 2 )) ; do if has_version "${BOOTLOADERS[i]}" && [[ -e "${EPREFIX}/${BOOTLOADERS[i+1]}" ]] ; then BOOTLOADER_DIR="${BOOTLOADERS[i+1]%/*}" BOOTLOADER_FILE="${BOOTLOADERS[i+1]##*/}" break fi done if [[ -n "${BOOTLOADER_DIR}" && -n "${BOOTLOADER_FILE}" ]] ; then mkdir -p "${WORKDIR}/bootloader/${BOOTLOADER_DIR}" # Handle collision protect for (( i = 0 ; i < 9999 ; i++ )) ; do printf -v BOOTLOADER_PROTECTED_FILE "._cfg%04d_${BOOTLOADER_FILE}" "${i}" if [[ ! -e "${EPREFIX}/${BOOTLOADER_DIR}/${BOOTLOADER_PROTECTED_FILE}" ]] ; then break fi done einfo "Generating ${BOOTLOADER_DIR}/${BOOTLOADER_FILE}" sed -e "s@${KV_INSTALLED}@${KV_FULL}@g" \ "${EPREFIX}/${BOOTLOADER_DIR}/${BOOTLOADER_FILE}" \ > "${WORKDIR}/bootloader/${BOOTLOADER_DIR}/${BOOTLOADER_PROTECTED_FILE}" if diff -q \ "${EPREFIX}/${BOOTLOADER_DIR}/${BOOTLOADER_FILE}" \ "${WORKDIR}/bootloader/${BOOTLOADER_DIR}/${BOOTLOADER_PROTECTED_FILE}" > /dev/null ; then rm "${WORKDIR}/bootloader/${BOOTLOADER_DIR}/${BOOTLOADER_PROTECTED_FILE}" fi _CONFIG_PROTECT+=( "${BOOTLOADER_DIR}/${BOOTLOADER_FILE}" ) fi echo "CONFIG_PROTECT='${_CONFIG_PROTECT[@]}'" > "${WORKDIR}/env.d_42-${P}" fi _linux-build_configval MODULES || ewarn "CONFIG_MODULES is not set" _linux-build_configval UEVENT_HELPER_PATH \ && ewarn "CONFIG_UEVENT_HELPER_PATH should be empty" _linux-build_configval FHANDLE || ewarn "CONFIG_FHANDLE is needed for >=sys-fs/udev-210" _linux-build_configval NET || ewarn "CONFIG_NET is needed for >=sys-fs/udev-210" if _linux-build_configval KERNEL_GZIP ; then if ! has_version --host-root "app-arch/gzip" ; then die "app-arch/gzip is required for CONFIG_KERNEL_GZIP" fi elif _linux-build_configval KERNEL_BZIP2 ; then if ! has_version --host-root "app-arch/bzip2" ; then die "app-arch/bzip2 is required for CONFIG_KERNEL_BZIP2" fi elif _linux-build_configval KERNEL_LZMA ; then if ! has_version --host-root "app-arch/lzma" ; then die "app-arch/lzma is required for CONFIG_KERNEL_LZMA" fi elif _linux-build_configval KERNEL_XZ; then if ! has_version --host-root "app-arch/xz-utils" ; then die "app-arch/xz-utils is required for CONFIG_KERNEL_XZ" fi elif _linux-build_configval KERNEL_LZO ; then if ! has_version --host-root "app-arch/lzop" ; then die "app-arch/lzop is required for CONFIG_KERNEL_LZO" fi elif _linux-build_configval KERNEL_LZ4 ; then if ! has_version --host-root "app-arch/lz4" ; then die "app-arch/lz4 is required for CONFIG_KERNEL_LZ4" fi fi if _linux-build_configval MODULE_COMPRESS ; then if _linux-build_configval MODULE_COMPRESS_GZIP ; then if ! has_version --host-root "app-arch/gzip" ; then die "app-arch/gzip is required for CONFIG_MODULE_COMPRESS_GZIP" fi elif _linux-build_configval MODULE_COMPRESS_XZ ; then if ! has_version --host-root "app-arch/xz-utils" ; then die "app-arch/xz-utils is required for CONFIG_MODULE_COMPRESS_XZ" fi else die "CONFIG_MODULE_COMPRESS needs one of ( CONFIG_MODULE_COMPRESS_GZIP CONFIG_MODULE_COMPRESS_XZ )" fi fi if _linux-build_configval MODULE_SIG ; then if ! has_version --host-root "dev-libs/openssl" ; then die "dev-libs/openssl is required for CONFIG_MODULE_SIG" fi if ! _linux-build_configval MODULE_SIG_HASH ; then die "CONFIG_MODULE_SIG_HASH must be defined when using CONFIG_MODULE_SIG" fi mkdir "${BUILDDIR}/certs" if [[ -e "${T}/certs/signing_key.pem" ]] ; then touch "${BUILDDIR}/certs/x509.genkey" cp --preserve=mode,ownership \ "${T}/certs/signing_key.pem" "${BUILDDIR}/certs/signing_key.pem" else einfo "Generating x509 config" cat > "${BUILDDIR}/certs/x509.genkey" <<-EOF [ req ] prompt = no distinguished_name = ${PF}_subj x509_extensions = ${PF}_exts [ ${PF}_subj ] O = Pants On OU = ${KBUILD_BUILD_HOST:-${HOSTNAME}} CN = ${CATEGORY}/${PF} emailAddress = ${KBUILD_BUILD_USER:-${PORTAGE_BUILD_USER}}@${KBUILD_BUILD_HOST:-${HOSTNAME}}" [ ${PF}_exts ] basicConstraints=critical,CA:FALSE keyUsage=digitalSignature subjectKeyIdentifier=hash authorityKeyIdentifier=keyid EOF einfo "Generating x509 ${LINUX_BUILD_MOD_SIG_KEY_ALG} ${LINUX_BUILD_MOD_SIG_KEY_SIZE} / ${CONFIG_MODULE_SIG_HASH} pair" openssl req -x509 -nodes -batch \ -days "${LINUX_BUILD_MOD_SIG_DAYS}" \ -newkey "${LINUX_BUILD_MOD_SIG_KEY_ALG}:${LINUX_BUILD_MOD_SIG_KEY_SIZE}" \ "-${CONFIG_MODULE_SIG_HASH}" \ -outform PEM \ -config "${BUILDDIR}/certs/x509.genkey" \ -out "${BUILDDIR}/certs/signing_key.pem" \ -keyout "${BUILDDIR}/certs/signing_key.pem" \ || die "openssl req fail" fi openssl x509 -inform PEM -noout \ -in "${BUILDDIR}/certs/signing_key.pem" \ -subject fi einfo "Checking configuration file" cp -a "${BUILDDIR}/.config" "${BUILDDIR}/.config.old" if kernel_is -le 3 5 ; then emake oldnoconfig "${myopt[@]}" else emake olddefconfig "${myopt[@]}" fi if ! diff -q \ --ignore-matching-lines '^$' \ --ignore-matching-lines '^#' \ --ignore-matching-lines '^CONFIG_GCC_VERSION=' \ --ignore-matching-lines '^CONFIG_CLANG_VERSION=' \ "${BUILDDIR}/.config.old" "${BUILDDIR}/.config" ; then eerror "You configuration is not up to date" diff -Nu "${BUILDDIR}/.config.old" "${BUILDDIR}/.config" die "Bad configuration" fi emake prepare "${myopt[@]}" } linux-build_src_prepare() { kernel-2_src_prepare for _ex in ${EXTRA_KERNEL_PATCHES[@]} ; do if [[ ! -d "${PORTAGE_CONFIGROOT%/}/etc/portage/patches/${CATEGORY}/${PF}/${_ex}" ]] ; then ewarn "Extra kernel patch serie '${_ex}' not present in ${PORTAGE_CONFIGROOT%/}/etc/portage/patches/${CATEGORY}/${PF}/${_ex}, skipping" continue fi eapply "${PORTAGE_CONFIGROOT%/}/etc/portage/patches/${CATEGORY}/${PF}/${_ex}" done bopt=( -C "${SRCDIR}" KBUILD_OUTPUT="${BUILDDIR}" KCONFIG_CONFIG="${BUILDDIR}/.config" KBUILD_BUILD_USER="${KBUILD_BUILD_USER:-${PORTAGE_BUILD_USER}}" KBUILD_BUILD_HOST="${KBUILD_BUILD_HOST:-${HOSTNAME}}" KBUILD_BUILD_TIMESTAMP="$(date --iso-8601=seconds)" KBUILD_BUILD_VERSION="1" ) copt=( CC="$(tc-getCC)" HOSTCC="${CBUILD}-gcc" CROSS_COMPILE="${CHOST}-" ARCH="$(tc-arch-kernel)" SUBARCH="$(tc-arch-kernel)" ) vopt=( EXTRAVERSION="${KV_EXTRA}" LOCALVERSION= CONFIG_LOCALVERSION= V=1 ) myopt=( "${bopt[@]}" "${copt[@]}" "${vopt[@]}" ) use build && _linux-build_src_prepare_build } _linux-build_src_compile_build() { einfo "Building kernel" emake "${myopt[@]}" } linux-build_src_compile() { use build && _linux-build_src_compile_build } _linux-build_src_install_sources() { kernel-2_src_install } _linux-build_src_install_build() { einfo "Installing kernel" emake install "${myopt[@]}" \ INSTALLKERNEL=../bin/true \ INSTALL_PATH="${WORKDIR}/boot" if _linux-build_configval ARM || _linux-build_configval ARM64 || _linux-build_configval MIPS ; then emake dtbs_install "${myopt[@]}" \ INSTALL_DTBS_PATH="${WORKDIR}/dts" fi insinto "/boot/${KV_FULL}" newins "${BUILDDIR}/.config" kernel.cfg newins "${BUILDDIR}/System.map" System.map case "$(tc-arch-kernel)" in x86) newins "${BUILDDIR}/arch/$(tc-arch-kernel)/boot/bzImage" kernel.img ;; arm|arm64) newins "${BUILDDIR}/arch/$(tc-arch-kernel)/boot/Image" kernel.img ;; esac if _linux-build_configval CMDLINE_BOOL && _linux-build_configval CMDLINE ; then insinto "/boot/${KV_FULL}" doins "${WORKDIR}/boot/kernel.arg" fi if _linux-build_configval MODULES ; then einfo "Installing modules" emake modules_install "${myopt[@]}" \ INSTALL_MOD_PATH="${WORKDIR}" \ INSTALL_MOD_STRIP="${PORTAGE_STRIP_FLAGS}" einfo "Generating modules.dep" depmod -ae -F "${BUILDDIR}/System.map" -b "${WORKDIR}" "${KV_FULL}" \ || die "depmod failed" rm "${WORKDIR}/lib/modules/${KV_FULL}/build" rm "${WORKDIR}/lib/modules/${KV_FULL}/source" insinto /lib doins -r "${WORKDIR}/lib/modules" fi if [[ -e "${WORKDIR}/lib/firmware" ]] ; then einfo "Installing firmwares" insinto /lib doins -r "${WORKDIR}/lib/firmware" fi if [[ -d "${WORKDIR}/dts" ]] ; then einfo "Installing device tree" while read ; do case "${REPLY}" in overlays) insinto /boot doins -r "${WORKDIR}/dts/${REPLY}" ;; broadcom) insinto /boot doins -r "${WORKDIR}/dts/${REPLY}/." ;; *) ewarn "device tree ${REPLY} is not known, installing in default location" insinto /boot doins -r "${WORKDIR}/dts/${REPLY}" ;; esac done < <( find "${WORKDIR}/dts" -mindepth 1 -maxdepth 1 -type d -printf '%P\n' ) fi if [[ -d "${WORKDIR}/bootloader/boot" ]] ; then insinto /boot doins -r "${WORKDIR}/bootloader/boot/." insinto /etc/env.d newins "${WORKDIR}/env.d_42-${P}" "42-${P}" fi use savedconfig && save_config "${BUILDDIR}/.config" } linux-build_src_install() { use build && _linux-build_src_install_build use source && _linux-build_src_install_sources } linux-build_pkg_postinst() { kernel-2_pkg_postinst # FIXME https://github.com/gentoo/gentoo/pull/13031 if ! use symlink && [[ -e "${EROOT}usr/src/linux" ]] ; then rm -rf "${EROOT}usr/src/linux" fi einfo "You may need to:" einfo " make menuconfig ${copt[@]}" }