armbian_build/lib/functions/main/config-prepare.sh
The-going 699816ddf2 config-prepare: Initialize an empty KERNEL_DRIVERS_SKIP array unless it exists
If the array exists in this location, initializing an empty array
will destroy all the data that was stored in it.
Do not initialize an empty KERNEL_DRIVERS_SKIP array if it exists.

This allows us to create an array anywhere in the script,
including the user configuration, in a secure way.
2025-06-08 18:04:25 +02:00

408 lines
18 KiB
Bash

#!/usr/bin/env bash
#
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (c) 2013-2023 Igor Pecovnik, igor@armbian.com
#
# This file is a part of the Armbian Build Framework
# https://github.com/armbian/build/
# Full version, for building a full image (with BOARD); possibly interactive.
function prep_conf_main_build_single() {
LOG_SECTION="config_early_init" do_with_conditional_logging config_early_init
# if interactive, call prepare-host.sh::check_basic_host() early, to avoid disappointments later.
if [[ -t 0 ]]; then
check_basic_host
fi
# those are possibly interactive. interactive (dialog) and logging don't mix, for obvious reasons.
interactive_config_prepare_terminal # init vars used for interactive
config_possibly_interactive_kernel_board
LOG_SECTION="config_source_board_file" do_with_conditional_logging config_source_board_file
config_possibly_interactive_branch_release_desktop_minimal
LOG_SECTION="config_pre_main" do_with_conditional_logging config_pre_main
LOG_SECTION="do_main_configuration" do_with_conditional_logging do_main_configuration # This initializes the extension manager among a lot of other things, and call extension_prepare_config() hook
interactive_desktop_main_configuration
interactive_finish # cleans up vars used for interactive
LOG_SECTION="do_extra_configuration" do_with_conditional_logging do_extra_configuration
LOG_SECTION="config_post_main" do_with_conditional_logging config_post_main
# Now, if NOT interactive, do some basic checks. If interactive, it has been done 20 lines above.
if [[ ! -t 0 ]]; then
LOG_SECTION="ni_check_basic_host" do_with_logging check_basic_host
fi
# can't aggregate here, since it needs a prepared host... mark to do it later.
mark_aggregation_required_in_default_build_start
display_alert "Configuration prepared for BOARD build" "${BOARD}.${BOARD_TYPE}" "info"
}
# Minimal, non-interactive version.
function prep_conf_main_minimal_ni() {
# needed
LOG_SECTION="config_early_init" do_with_conditional_logging config_early_init
# needed for most stuff, but not for configdump
if [[ "${skip_host_config:-"no"}" != "yes" ]]; then
if [[ "${CONFIG_DEFS_ONLY}" != "yes" ]]; then
check_basic_host
fi
fi
# needed for BOARD= builds.
if [[ "${use_board:-"no"}" == "yes" ]]; then
LOG_SECTION="config_source_board_file" do_with_conditional_logging config_source_board_file
allow_no_family="no"
skip_kernel="no" # contentious: we could do u-boot without kernel...
fi
# not needed, doesnt hurt; might be moved to aggregation
LOG_SECTION="config_pre_main" do_with_conditional_logging config_pre_main
# Required, but does stuff it maybe shouldn't
allow_no_family="${allow_no_family:-"yes"}" \
LOG_SECTION="do_main_configuration" do_with_conditional_logging do_main_configuration # This initializes the extension manager among a lot of other things, and call extension_prepare_config() hook
# Required: does a lot of stuff and extension_prepare_config() hook
LOG_SECTION="do_extra_configuration" do_with_conditional_logging do_extra_configuration
# Calculates CHOSEN_xxx's and optional kernel stuff; runs extension_finish_config() hook
skip_kernel="${skip_kernel:-"yes"}" \
LOG_SECTION="config_post_main" do_with_conditional_logging config_post_main
display_alert "Minimal configuration prepared for build" "prep_conf_main_minimal_ni" "info"
}
# Lean version, for building rootfs, that doesn't need BOARD/BOARDFAMILY; never interactive.
function prep_conf_main_only_rootfs_ni() {
prep_conf_main_minimal_ni
# can't aggregate here, since it needs a prepared host... mark to do it later.
mark_aggregation_required_in_default_build_start
display_alert "Configuration prepared for minimal+rootfs" "prep_conf_main_only_rootfs_ni" "info"
}
function config_source_board_file() {
declare -a BOARD_SOURCE_FILES=()
# This has to be syncronized with get_list_of_all_buildable_boards() in interactive.sh!
# I used to re-use that code here, but it's very slow, specially for CONFIG_DEFS_ONLY.
local -a board_types=("conf" "wip" "csc" "eos" "tvb")
local -a board_file_paths=("${SRC}/config/boards" "${USERPATCHES_PATH}/config/boards")
declare board_file_path board_type full_board_file first_board_type_found
for board_file_path in "${board_file_paths[@]}"; do
[[ ! -d "${board_file_path}" ]] && continue
for board_type in "${board_types[@]}"; do
full_board_file="${board_file_path}/${BOARD}.${board_type}"
if [[ -f "${full_board_file}" ]]; then
BOARD_SOURCE_FILES+=("${full_board_file}")
[[ -z "${first_board_type_found}" ]] && first_board_type_found="${board_type}"
break # only one board type considered, if found. @TODO: this might lead to confusion if both exist; detect and abort.
fi
done
done
# BOARD_TYPE is included in /etc/armbian-release and used for stuff board-side; make it global and readonly
declare -g -r BOARD_TYPE="${first_board_type_found}" # so userpatches can't change support status of existing boards
declare -a sourced_board_configs=()
declare BOARD_SOURCE_FILE
for BOARD_SOURCE_FILE in "${BOARD_SOURCE_FILES[@]}"; do # No quotes, so expand the space-delimited list
display_alert "Sourcing board configuration" "${BOARD_SOURCE_FILE}" "info"
# shellcheck source=/dev/null
source "${BOARD_SOURCE_FILE}"
sourced_board_configs+=("${BOARD_SOURCE_FILE}")
declare board_file_sans_src="${BOARD_SOURCE_FILE#${SRC}/}"
track_general_config_variables "after sourcing board file ${board_file_sans_src}"
done
# Sanity check: if no board config was sourced, then the board name is invalid
[[ ${#sourced_board_configs[@]} -eq 0 ]] && exit_with_error "No such BOARD '${BOARD}'; no board config file found."
# Otherwise publish it as readonly global
declare -g -r SOURCED_BOARD_CONFIGS_FILENAME_LIST="${sourced_board_configs[*]}"
track_general_config_variables "after sourcing board"
# this is (100%?) rewritten by family config!
# answer: this defaults LINUXFAMILY to BOARDFAMILY. that... shouldn't happen, extensions might change it too.
# @TODO: better to check for empty after sourcing family config and running extensions, *warning about it*, and only then default to BOARDFAMILY.
# this sourced the board config. do_main_configuration will source the (BOARDFAMILY) family file.
LINUXFAMILY="${BOARDFAMILY}"
track_general_config_variables "after defaulting LINUXFAMILY to BOARDFAMILY"
# Lets make some variables readonly after sourcing the board file.
# We don't want anything changing them, it's exclusively for board config.
# @TODO: ok but then we need some way to add packages simply via command line or config. ADD_PACKAGES_IMAGE="foo,bar"?
declare -g -r PACKAGE_LIST_BOARD="${PACKAGE_LIST_BOARD}"
declare -g -r PACKAGE_LIST_BOARD_REMOVE="${PACKAGE_LIST_BOARD_REMOVE}"
[[ -z $KERNEL_TARGET ]] && exit_with_error "Board ('${BOARD}') configuration does not define valid kernel config"
return 0 # shortcircuit above
}
function config_early_init() {
# default umask for root is 022 so parent directories won't be group writeable without this
# this is used instead of making the chmod in prepare_host() recursive
umask 002
# Warnings mitigation
[[ -z $LANGUAGE ]] && export LANGUAGE="en_US:en" # set to english if not set
[[ -z $CONSOLE_CHAR ]] && export CONSOLE_CHAR="UTF-8" # set console to UTF-8 if not set
declare -g SHOW_WARNING=yes # If you try something that requires EXPERT=yes.
display_alert "Starting single build process" "${BOARD:-"no BOARD set"}" "info"
# Do not initialize an empty array if it exists.
if [ "${KERNEL_DRIVERS_SKIP[*]}" == "" ]; then
# Prepare array to be filled in by board/family/extensions
declare -g -a KERNEL_DRIVERS_SKIP=()
fi
silent="yes" track_general_config_variables "after config_early_init" # don't log anything, just init the change tracking
return 0 # protect against eventual shortcircuit above
}
function config_pre_main() {
#prevent conflicting setup
if [[ $BUILD_DESKTOP == "yes" ]]; then
BUILD_MINIMAL=no
SELECTED_CONFIGURATION="desktop"
elif [[ $BUILD_MINIMAL != "yes" || -z "${BUILD_MINIMAL}" ]]; then
BUILD_MINIMAL=no # Just in case BUILD_MINIMAL is not defined
BUILD_DESKTOP=no
SELECTED_CONFIGURATION="cli_standard"
elif [[ $BUILD_MINIMAL == "yes" ]]; then
BUILD_DESKTOP=no
PLYMOUTH=no
SELECTED_CONFIGURATION="cli_minimal"
fi
return 0 # shortcircuit above
}
function config_post_main() {
if [[ $COMPRESS_OUTPUTIMAGE == "" || $COMPRESS_OUTPUTIMAGE == no ]]; then
COMPRESS_OUTPUTIMAGE="sha,img"
fi
if [[ "$BETA" == "yes" ]]; then
display_alert "BETA" "BETA==yes, nightly image" "debug"
IMAGE_TYPE=nightly
elif [[ "$BETA" == "no" ]]; then
display_alert "BETA" "BETA==no, stable image" "debug"
IMAGE_TYPE=stable
else
display_alert "BETA" "Not yes nor no, user-built" "debug"
IMAGE_TYPE=user-built
fi
track_general_config_variables "at beginning of config_post_main"
# So for kernel full cached rebuilds.
# We wanna be able to rebuild kernels very fast. so it only makes sense to use a dir for each built kernel.
# That is the "default" layout; there will be as many source dirs as there are built kernel debs.
# But, it really makes much more sense if the major.minor (such as 5.10, 5.15, or 4.4) of kernel has its own
# tree. So in the end:
# <arch>-<major.minor>[-<family>]
# So we gotta explictly know the major.minor to be able to do that scheme.
# If we don't know, we could use BRANCH as reference, but that changes over time, and leads to wastage.
if [[ "${skip_kernel:-"no"}" != "yes" ]]; then
# call hooks to do late validation/mutation of sources, branches, patch dirs, etc.
call_extension_method "late_family_config" <<- 'LATE_FAMILY_CONFIG'
*late defaults/overrides, main hook point for KERNELSOURCE/BRANCH and BOOTSOURCE/BRANCH etc*
LATE_FAMILY_CONFIG
track_general_config_variables "after late_family_config hooks"
# We need BOOTDIR and BOOTBRANCH here, bomb if not
[[ -z "${BOOTDIR}" ]] && exit_with_error "BOOTDIR not set after late_family_config"
[[ -z "${BOOTBRANCH}" ]] && exit_with_error "BOOTBRANCH not set after late_family_config"
declare -g BOOTSOURCEDIR
BOOTSOURCEDIR="u-boot-worktree/${BOOTDIR}/$(branch2dir "${BOOTBRANCH}")"
if [[ -n $ATFSOURCE ]]; then
declare -g ATFSOURCEDIR
ATFSOURCEDIR="${ATFDIR}/$(branch2dir "${ATFBRANCH}")"
fi
if [[ -n $CRUSTSOURCE ]]; then
declare -g CRUSTSOURCEDIR
CRUSTSOURCEDIR="${CRUSTDIR}/$(branch2dir "${CRUSTBRANCH}")"
fi
track_general_config_variables "before handling KERNEL_MAJOR_MINOR in config_post_main"
if [[ "${KERNELSOURCE}" != 'none' ]]; then
if [[ "x${KERNEL_MAJOR_MINOR}x" == "xx" ]]; then
display_alert "Problem: after configuration, there's not enough kernel info" "Might happen if you used the wrong BRANCH. Make sure 'BRANCH=${BRANCH}' is valid." "err"
# if we have KERNEL_TARGET set.
if [[ -n "${KERNEL_TARGET}" ]]; then
# Split KERNEL_TARGET by commas, and display each one.
declare -a KERNEL_TARGET_ARRAY=()
IFS=',' read -ra KERNEL_TARGET_ARRAY <<< "${KERNEL_TARGET}"
for i in "${KERNEL_TARGET_ARRAY[@]}"; do
display_alert "Valid branches for current board" "BOARD=${BOARD} BRANCH=${i}" "info"
done
fi
exit_with_error "BAD config, missing" "KERNEL_MAJOR_MINOR; check BOARD and BRANCH combination" "err"
fi
# assume the worst, and all surprises will be happy ones
declare -g KERNEL_HAS_WORKING_HEADERS="no"
# Parse/validate the the major, bail if no match
declare -i KERNEL_MAJOR_MINOR_MAJOR=${KERNEL_MAJOR_MINOR%%.*}
declare -i KERNEL_MAJOR_MINOR_MINOR=${KERNEL_MAJOR_MINOR#*.}
if [[ "${KERNEL_MAJOR_MINOR_MAJOR}" -ge 6 ]] || [[ "${KERNEL_MAJOR_MINOR_MAJOR}" -ge 5 && "${KERNEL_MAJOR_MINOR_MINOR}" -ge 4 ]]; then # We support 6.x, and 5.x from 5.4
declare -g KERNEL_HAS_WORKING_HEADERS="yes"
declare -g KERNEL_MAJOR="${KERNEL_MAJOR_MINOR_MAJOR}"
elif [[ "${KERNEL_MAJOR_MINOR_MAJOR}" -eq 4 && "${KERNEL_MAJOR_MINOR_MINOR}" -ge 19 ]]; then
declare -g KERNEL_MAJOR=4 # We support 4.19+ (less than 5.0) is supported
elif [[ "${KERNEL_MAJOR_MINOR_MAJOR}" -eq 4 && "${KERNEL_MAJOR_MINOR_MINOR}" -ge 4 ]]; then
declare -g KERNEL_MAJOR=4 # We support 4.x from 4.4
else
# If you think you can patch packaging to support this, you're probably right. Is _worth_ it though?
exit_with_error "Kernel series unsupported" "'${KERNEL_MAJOR_MINOR}' is unsupported, or bad config"
fi
# Default LINUXSOURCEDIR:
declare -g LINUXSOURCEDIR="linux-kernel-worktree/${KERNEL_MAJOR_MINOR}__${LINUXFAMILY}__${ARCH}"
# Allow adding to it with KERNEL_EXTRA_DIR
if [[ "${KERNEL_EXTRA_DIR}" != "" ]]; then
declare -g LINUXSOURCEDIR="${LINUXSOURCEDIR}__${KERNEL_EXTRA_DIR}"
display_alert "Using kernel extra dir: '${KERNEL_EXTRA_DIR}'" "LINUXSOURCEDIR: ${LINUXSOURCEDIR}" "debug"
fi
else
declare -g KERNEL_HAS_WORKING_HEADERS="yes" # I assume non-Armbian kernels have working headers, eg: Debian/Ubuntu generic do.
fi
else
display_alert "Skipping kernel config" "skip_kernel=yes" "debug"
fi
if [[ -n "${BOOTCONFIG}" ]] && [[ "${BOOTCONFIG}" != "none" ]]; then
declare -g ARMBIAN_WILL_BUILD_UBOOT=yes
else
declare -g ARMBIAN_WILL_BUILD_UBOOT=no
fi
# Do some sanity checks for userspace stuff, if RELEASE/DESKTOP_ENVIRONMENT is set.
check_config_userspace_release_and_desktop
# late Userspace / package list fixes; RELEASE and DISTRIBUTION must be set.
fix_userspace_packages_release_and_distro
track_general_config_variables "before calling extension_finish_config"
display_alert "Extensions: finish configuration" "extension_finish_config" "debug"
call_extension_method "extension_finish_config" <<- 'EXTENSION_FINISH_CONFIG'
*allow extensions a last chance at configuration just before it is done*
After kernel versions are set, package names determined, etc.
This runs *late*, and is the final step before finishing configuration.
Don't change anything not coming from other variables or meant to be configured by the user.
EXTENSION_FINISH_CONFIG
track_general_config_variables "after calling extension_finish_config"
return 0 # protect against eventual shortcircuit above
}
# cli-bsp also uses this
function set_distribution_status() {
local distro_support_desc_filepath="${SRC}/config/distributions/${RELEASE}/support"
if [[ ! -f "${distro_support_desc_filepath}" ]]; then
exit_with_error "Distribution dir '${distro_support_desc_filepath}' does not exist"
else
DISTRIBUTION_STATUS="$(cat "${distro_support_desc_filepath}")"
fi
[[ "${DISTRIBUTION_STATUS}" != "supported" ]] && [[ "${EXPERT}" != "yes" ]] && exit_with_error "Armbian ${RELEASE} is unsupported and, therefore, only available to experts (EXPERT=yes)"
return 0 # due to last stmt above being a shortcircuit conditional
}
function check_config_userspace_release_and_desktop() {
# Do some sanity checks for userspace stuff.
# If RELEASE is set, it must be a valid release.
# We'll also check that the RELEASE supports the ARCH.
# Then we'll do the same for RELEASE+DESKTOP_ENVIRONMENT and the ARCH.
if [[ "${RELEASE}" != "" ]]; then
declare release_distro_dir="${SRC}/config/distributions/${RELEASE}"
declare release_distro_arches_file="${release_distro_dir}/architectures"
if [[ ! -d "${release_distro_dir}" ]]; then
exit_with_target_not_supported_error "RELEASE '${RELEASE}' is not supported; there is no '${release_distro_dir}' directory."
fi
if [[ ! -f "${release_distro_arches_file}" ]]; then
exit_with_target_not_supported_error "RELEASE '${RELEASE}' does not have file ${release_distro_arches_file}"
fi
if grep -q "${ARCH}" "${release_distro_arches_file}"; then
display_alert "RELEASE '${RELEASE}' supports ARCH '${ARCH}'" "RELEASE=${RELEASE} ARCH=${ARCH}; see ${release_distro_arches_file}" "debug"
else
exit_with_target_not_supported_error "RELEASE '${RELEASE}' does not support ARCH '${ARCH}'; see ${release_distro_arches_file}"
fi
# Desktop sanity checks, in the same vein.
if [[ "${DESKTOP_ENVIRONMENT}" != "" ]]; then
# If DESKTOP_ENVIRONMENT is set, but BUILD_DESKTOP is not, then we have a problem.
if [[ "${BUILD_DESKTOP}" != "yes" ]]; then
exit_with_error "DESKTOP_ENVIRONMENT is set, but BUILD_DESKTOP is not ==yes - please fix your parameters."
fi
declare desktop_release_distro_dir="${SRC}/config/desktop/${RELEASE}/environments/${DESKTOP_ENVIRONMENT}"
declare desktop_release_distro_arches_file="${release_distro_dir}/architectures"
if [[ ! -d "${desktop_release_distro_dir}" ]]; then
exit_with_target_not_supported_error "RELEASE '${RELEASE}' and Desktop Environment '${DESKTOP_ENVIRONMENT}' combination is not supported; there is no '${desktop_release_distro_dir}' directory."
fi
if [[ ! -f "${desktop_release_distro_arches_file}" ]]; then
exit_with_target_not_supported_error "RELEASE '${RELEASE}' and Desktop Environment '${DESKTOP_ENVIRONMENT}' combination is not supported; there is no '${desktop_release_distro_arches_file}' file."
fi
if grep -q "${ARCH}" "${desktop_release_distro_arches_file}"; then
display_alert "RELEASE '${RELEASE}' and Desktop Environment '${DESKTOP_ENVIRONMENT}' combination is supported" "RELEASE=${RELEASE} ARCH=${ARCH}; see ${desktop_release_distro_arches_file}" "debug"
else
exit_with_target_not_supported_error "RELEASE '${RELEASE}' and Desktop Environment '${DESKTOP_ENVIRONMENT}' combination is not supported; see ${desktop_release_distro_arches_file}"
fi
fi
fi
return 0
}
function fix_userspace_packages_release_and_distro() {
display_alert "fix_userspace_packages_release_and_distro" "For distro '${DISTRIBUTION}' release '${RELEASE}'" "debug"
# Some old hack from the past, not sure if it's still needed. Originally from https://github.com/armbian/build/pull/5881
if [[ $RELEASE == trixie || $ARCH == riscv64 ]]; then remove_packages "cpufrequtils"; fi # this will remove from rootfs as well
# Debian: no need for this package in the rootfs, as it provides add-apt-repository which is not used on our Debian builds
if [[ "${DISTRIBUTION}" == "Debian" ]]; then
display_alert "Not-installing software-properties-common" "For distro '${DISTRIBUTION}' release '${RELEASE}'" "warn"
remove_packages "software-properties-common" "software-properties-gtk" "software-properties-common"
fi
}
# Some utility functions
function branch2dir() {
[[ "${1}" == "head" ]] && echo "HEAD" || echo "${1##*:}"
return 0
}