* add hook to allow customizing before kernel make env creation * Hook runs in docker_cli_prepare_launch() just before DOCKER_EXTRA_ARGS is processed, allowing extensions to add Docker arguments with a more descriptive hook name than add_host_dependencies. * Extension: ccache-remote Enables ccache with remote Redis storage for sharing compilation cache across build hosts. Features: - Auto-discovery via Avahi/mDNS (ccache.local hostname) - Explicit Redis server configuration via CCACHE_REMOTE_STORAGE - Build statistics display at end of build (hit/miss/error rates) - Support for both Docker and native builds - Hooks for kernel and u-boot compilation environments Documentation includes server setup instructions with security warnings, client mDNS configuration, and cache sharing requirements. * uboot: fix ccache environment and add extension hook U-Boot build uses `env -i` which clears all environment variables. CCACHE_DIR and CCACHE_TEMPDIR were not explicitly passed to make, unlike kernel build (kernel-make.sh). This caused ccache to use default directory instead of configured Armbian one, breaking cache statistics and shared cache functionality. Changes: - Add CCACHE_DIR and CCACHE_TEMPDIR to uboot_make_envs - Add uboot_make_config hook for extensions (similar to kernel_make_config), allowing modification of environment variables before compilation * add long list of allowed ccache-related env vars * set permissions to ccache files RW for everyone if cache not private * ccache: add ccache_post_compilation hook for extensions * ccache-remote: use ccache_post_compilation hook instead of cleanup handler Show remote ccache stats after each compilation (kernel, uboot) via hook, instead of once at the end via cleanup handler. Stats now shown even on build failure. * ccache: show stats with safe arithmetic * ccache/uboot: improve code comments per review feedback - uboot.sh: clarify ARMBIAN=foe workaround for dual-compiler scenario - ccache-remote.sh: document that CCACHE_REDIS_CONNECT_TIMEOUT must be set before extension loads * ccache-remote: mask storage URLs in logs Mask CCACHE_REMOTE_STORAGE when emitting Docker env debug logs. * ccache-remote: extract ccache_inject_envs() helper to deduplicate passthrough loops Extract ccache_inject_envs() helper to deduplicate identical passthrough loops in kernel and uboot make config hooks. ccache-remote: rename functions to follow project naming conventions Rename get_redis_stats and mask_storage_url to ccache_get_redis_stats and ccache_mask_storage_url to follow project naming conventions. ccache-remote: mask credentials in debug log output for passthrough loops Mask CCACHE_REMOTE_STORAGE value through ccache_mask_storage_url() before logging in both Docker env and make env passthrough loops to avoid leaking credentials into build logs. * ccache-remote: add HTTP/WebDAV backend and DNS discovery * ccache-remote: move extension script into directory layout * ccache-remote: add server setup docs and config files * ccache-remote: validate Redis credentials in URLs * ccache-remote: document Redis auth options and safe passwords Add separate insecure config example for trusted networks. Recommend URL-safe hex passwords and update setup docs. * ccache-remote: improve Docker loopback handling and IPv6 host parsing
595 lines
27 KiB
Bash
595 lines
27 KiB
Bash
#!/usr/bin/env bash
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# Copyright (c) 2013-2026 Igor Pecovnik, igor@armbian.com
|
|
#
|
|
# This file is a part of the Armbian Build Framework
|
|
# https://github.com/armbian/build/
|
|
|
|
function maybe_make_clean_uboot() {
|
|
if [[ $CLEAN_LEVEL == *make-uboot* ]]; then
|
|
display_alert "${uboot_prefix}Cleaning u-boot tree - CLEAN_LEVEL contains 'make-uboot'" "${BOOTSOURCEDIR}" "info"
|
|
(
|
|
cd "${SRC}/cache/sources/${BOOTSOURCEDIR}" || exit_with_error "crazy about ${BOOTSOURCEDIR}"
|
|
run_host_command_logged make clean
|
|
)
|
|
else
|
|
display_alert "${uboot_prefix}Not cleaning u-boot tree, use CLEAN_LEVEL=make-uboot if needed" "CLEAN_LEVEL=${CLEAN_LEVEL}" "debug"
|
|
fi
|
|
}
|
|
|
|
function patch_uboot_target() {
|
|
local uboot_work_dir=""
|
|
uboot_work_dir="$(pwd)"
|
|
|
|
# outer scope variable: uboot_git_revision, validate that it is set
|
|
if [[ -z "${uboot_git_revision}" ]]; then
|
|
exit_with_error "uboot_git_revision is not set"
|
|
fi
|
|
|
|
display_alert "${uboot_prefix} Checking out to clean sources SHA1 ${uboot_git_revision}" "{$BOOTSOURCEDIR} for ${target_make}"
|
|
git checkout -f -q "${uboot_git_revision}"
|
|
|
|
# remove all git untracked files; echo their names to screen
|
|
# this throws away the baby with the bathwater; rebuilds will be slow. but the risk of shipping wrong binaries is too high.
|
|
display_alert "${uboot_prefix} Cleaning u-boot tree" "${BOOTSOURCEDIR} for '${target_make}'"
|
|
regular_git clean -xfdq
|
|
|
|
maybe_make_clean_uboot
|
|
|
|
# Python patching for u-boot!
|
|
do_with_hooks uboot_main_patching_python
|
|
|
|
# create patch for manual source changes
|
|
if [[ $CREATE_PATCHES == yes ]]; then
|
|
userpatch_create "u-boot"
|
|
fi
|
|
}
|
|
|
|
# this receives version target uboot_name uboottempdir uboot_target_counter as variables.
|
|
# also receives uboot_prefix, target_make, target_patchdir, target_files as input
|
|
function compile_uboot_target() {
|
|
: "${artifact_version:?artifact_version is not set}"
|
|
: "${UBOOT_COMPILER:?UBOOT_COMPILER is not set}"
|
|
|
|
# prepare a CROSS_COMPILE stanza, quoted, with $CCACHE (if not empty) and $UBOOT_COMPILER
|
|
declare cross_compile="undetermined_cross_compile"
|
|
if [[ -n "${CCACHE}" ]]; then
|
|
cross_compile="CROSS_COMPILE='${CCACHE} ${UBOOT_COMPILER}'"
|
|
else
|
|
cross_compile="CROSS_COMPILE='${UBOOT_COMPILER}'"
|
|
fi
|
|
|
|
if [[ "${SHOW_DEBUG}" == "yes" ]]; then
|
|
display_alert "${uboot_prefix}Listing contents of u-boot directory" "'${version}' '${target_make}' before patching" "debug"
|
|
run_host_command_logged "ls -laht"
|
|
fi
|
|
|
|
patch_uboot_target
|
|
|
|
if [[ "${SHOW_DEBUG}" == "yes" ]]; then
|
|
display_alert "${uboot_prefix}Listing contents of u-boot directory" "'${version}' '${target_make}' after patching" "debug"
|
|
run_host_command_logged "ls -laht"
|
|
fi
|
|
|
|
if [[ $CREATE_PATCHES == yes ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# atftempdir comes from atf.sh's compile_atf()
|
|
if [[ -n $ATFSOURCE && -d "${atftempdir}" ]]; then
|
|
display_alert "Copying over bin/elf/itb's from atftempdir" "${atftempdir}" "debug"
|
|
run_host_command_logged cp -pv "${atftempdir}"/*.bin "${atftempdir}"/*.elf "${atftempdir}"/*.itb ./ # only works due to nullglob
|
|
# atftempdir is under WORKDIR, so no cleanup necessary.
|
|
fi
|
|
|
|
# crusttempdir comes from crust.sh's compile_crust()
|
|
if [[ -n $CRUSTSOURCE && -d "${crusttempdir}" ]]; then
|
|
display_alert "Copying over bin/elf's from crusttempdir" "${crusttempdir}" "debug"
|
|
run_host_command_logged cp -pv "${crusttempdir}"/*.bin "${crusttempdir}"/*.elf ./ # only works due to nullglob
|
|
fi
|
|
|
|
# Hook time, for extra post-processing
|
|
call_extension_method "pre_config_uboot_target" <<- 'PRE_CONFIG_UBOOT_TARGET'
|
|
*allow extensions prepare before configuring and compiling an u-boot target*
|
|
Some u-boot targets require extra configuration or pre-processing before compiling.
|
|
For example, changing Python version can be done by replacing the `${BIN_WORK_DIR}/python` symlink.
|
|
PRE_CONFIG_UBOOT_TARGET
|
|
|
|
display_alert "${uboot_prefix}Preparing u-boot config '${BOOTCONFIG}'" "${version} ${target_make}" "info"
|
|
declare -g if_error_detail_message="${uboot_prefix}Failed to configure u-boot ${version} $BOOTCONFIG ${target_make}"
|
|
run_host_command_logged CCACHE_BASEDIR="$(pwd)" \
|
|
"KCFLAGS=-fdiagnostics-color=always" \
|
|
pipetty make "${CTHREADS}" "${BOOTCONFIG}" "${cross_compile}"
|
|
|
|
# for modern (? 2018-2019?) kernel and non spi targets @TODO: this does not belong here
|
|
if [[ ${BOOTBRANCH} =~ ^tag:v201[8-9](.*) && ${target} != "spi" && -f .config ]]; then
|
|
display_alert "Hacking ENV stuff in u-boot config 2018-2019" "for ${target}" "debug"
|
|
sed -i 's/^.*CONFIG_ENV_IS_IN_FAT.*/# CONFIG_ENV_IS_IN_FAT is not set/g' .config
|
|
sed -i 's/^.*CONFIG_ENV_IS_IN_EXT4.*/CONFIG_ENV_IS_IN_EXT4=y/g' .config
|
|
sed -i 's/^.*CONFIG_ENV_IS_IN_MMC.*/# CONFIG_ENV_IS_IN_MMC is not set/g' .config
|
|
sed -i 's/^.*CONFIG_ENV_IS_NOWHERE.*/# CONFIG_ENV_IS_NOWHERE is not set/g' .config
|
|
echo "# CONFIG_ENV_IS_NOWHERE is not set" >> .config
|
|
echo 'CONFIG_ENV_EXT4_INTERFACE="mmc"' >> .config
|
|
echo 'CONFIG_ENV_EXT4_DEVICE_AND_PART="0:auto"' >> .config
|
|
echo 'CONFIG_ENV_EXT4_FILE="/boot/boot.env"' >> .config
|
|
fi
|
|
|
|
# @TODO: this does not belong here
|
|
[[ -f tools/logos/udoo.bmp ]] && run_host_command_logged cp -pv "${SRC}"/packages/blobs/splash/udoo.bmp tools/logos/udoo.bmp
|
|
|
|
# @TODO: why?
|
|
touch .scmversion
|
|
|
|
declare uboot_loglevel="${UBOOT_LOGLEVEL:-"6"}" # default to info
|
|
|
|
# use `scripts/config` instead of sed if available. Cleaner results.
|
|
if [[ ! -f scripts/config ]]; then
|
|
display_alert "scripts/config not found" "u-boot ${version} $BOOTCONFIG ${target_make}" "debug"
|
|
# Old, pre-2022.10 u-boot; does not have the scripts/config script. Do it the old way.
|
|
# $BOOTDELAY can be set in board family config, ensure autoboot can be stopped even if set to 0
|
|
[[ $BOOTDELAY == 0 ]] && echo -e "CONFIG_ZERO_BOOTDELAY_CHECK=y" >> .config
|
|
[[ -n $BOOTDELAY ]] && sed -i "s/^CONFIG_BOOTDELAY=.*/CONFIG_BOOTDELAY=${BOOTDELAY}/" .config || [[ -f .config ]] && echo "CONFIG_BOOTDELAY=${BOOTDELAY}" >> .config
|
|
# armbian specifics u-boot settings; configure the version so UART boot logs show exactly what's in there
|
|
[[ -f .config ]] && sed -i "s/CONFIG_LOCALVERSION=\"\"/CONFIG_LOCALVERSION=\"_armbian-${artifact_version}\"/g" .config
|
|
[[ -f .config ]] && sed -i 's/CONFIG_LOCALVERSION_AUTO=.*/# CONFIG_LOCALVERSION_AUTO is not set/g' .config
|
|
else
|
|
display_alert "scripts/config found" "u-boot ${version} $BOOTCONFIG ${target_make}" "debug"
|
|
|
|
# $BOOTDELAY can be set in board family config, ensure autoboot can be stopped even if set to 0
|
|
if [[ $BOOTDELAY == 0 ]]; then
|
|
display_alert "Adding CONFIG_ZERO_BOOTDELAY_CHECK=y u-boot config" "BOOTDELAY==0 for ${target}" "info"
|
|
run_host_command_logged scripts/config --enable CONFIG_ZERO_BOOTDELAY_CHECK
|
|
fi
|
|
|
|
# If BOOTDELAY is set, either change a preexisting CONFIG_BOOTDELAY or add it
|
|
if [[ -n $BOOTDELAY ]]; then
|
|
display_alert "Hacking autoboot delay in u-boot config" "BOOTDELAY=${BOOTDELAY} for ${target}" "info"
|
|
run_host_command_logged scripts/config --set-val CONFIG_BOOTDELAY "${BOOTDELAY}"
|
|
fi
|
|
|
|
# Hack, up the log level to 6: "info" (default is 4: "warning")
|
|
display_alert "Hacking log level in u-boot config" "LOGLEVEL=${uboot_loglevel} for ${target}" "info"
|
|
run_host_command_logged scripts/config --enable CONFIG_LOG
|
|
run_host_command_logged scripts/config --set-val CONFIG_LOGLEVEL ${uboot_loglevel}
|
|
run_host_command_logged scripts/config --set-val CONFIG_LOG_MAX_LEVEL ${uboot_loglevel}
|
|
|
|
# Include Armbian version so UART bootlogs are drastically more useful
|
|
run_host_command_logged ./scripts/config --disable "LOCALVERSION_AUTO"
|
|
run_host_command_logged ./scripts/config --set-str "LOCALVERSION" "_armbian-${artifact_version}" # crazy quotes!
|
|
fi
|
|
|
|
if [[ "${UBOOT_DEBUGGING}" == "yes" ]]; then
|
|
display_alert "Enabling u-boot debugging" "UBOOT_DEBUGGING=yes" "debug"
|
|
|
|
# Remove unsets...
|
|
cp .config .config.pre.debug
|
|
cat .config.pre.debug | grep -v -e "CONFIG_LOG is not set" -e "CONFIG_ERRNO_STR" > .config
|
|
rm .config.pre.debug
|
|
|
|
# 0 - emergency ; 1 - alert; 2 - critical; 3 - error; 4 - warning; 5 - note; 6 - info; 7 - debug; 8 - debug content; 9 - debug hardware I/O
|
|
cat <<- EXTRA_UBOOT_DEBUG_CONFIGS >> .config
|
|
CONFIG_LOG=y
|
|
CONFIG_LOG_MAX_LEVEL=${uboot_loglevel}
|
|
CONFIG_LOG_DEFAULT_LEVEL=${uboot_loglevel}
|
|
CONFIG_LOG_CONSOLE=y
|
|
CONFIG_SPL_LOG=y
|
|
CONFIG_SPL_LOG_MAX_LEVEL=${uboot_loglevel}
|
|
CONFIG_SPL_LOG_CONSOLE=y
|
|
CONFIG_TPL_LOG=y
|
|
CONFIG_TPL_LOG_MAX_LEVEL=${uboot_loglevel}
|
|
CONFIG_TPL_LOG_CONSOLE=y
|
|
# CONFIG_ERRNO_STR is not set
|
|
EXTRA_UBOOT_DEBUG_CONFIGS
|
|
|
|
run_host_command_logged CCACHE_BASEDIR="$(pwd)" \
|
|
"KCFLAGS=-fdiagnostics-color=always" \
|
|
pipetty make "olddefconfig" "${cross_compile}"
|
|
|
|
fi
|
|
|
|
# cflags will be passed both as CFLAGS, KCFLAGS, and both as make params and as env variables. (some vendor u-boot's are cuckoo)
|
|
# boards/families/extensions can customize this via the hook below
|
|
local -a uboot_cflags_array=(
|
|
"-fdiagnostics-color=always" # color messages
|
|
"-Wno-error=maybe-uninitialized"
|
|
"-Wno-error=misleading-indentation" # patches have mismatching indentation
|
|
"-Wno-error=attributes" # for very old-uboots
|
|
"-Wno-error=address-of-packed-member" # for very old-uboots
|
|
)
|
|
if linux-version compare "${gcc_version_main}" ge "11.0"; then
|
|
uboot_cflags_array+=(
|
|
"-Wno-error=array-parameter" # very old uboots
|
|
)
|
|
fi
|
|
|
|
# Hook time, for extra post-processing
|
|
call_extension_method "post_config_uboot_target" <<- 'POST_CONFIG_UBOOT_TARGET'
|
|
*allow extensions prepare after configuring but before compiling an u-boot target*
|
|
Some u-boot targets require extra configuration or pre-processing before compiling.
|
|
Last chance to change .config for u-boot before compiling.
|
|
Also the only chance to change the (local) array `uboot_cflags_array`.
|
|
POST_CONFIG_UBOOT_TARGET
|
|
|
|
# make olddefconfig, so changes made in hook above are consolidated
|
|
display_alert "${uboot_prefix}Updating u-boot config with olddefconfig" "${version} ${target_make}" "info"
|
|
run_host_command_logged CCACHE_BASEDIR="$(pwd)" \
|
|
"KCFLAGS=-fdiagnostics-color=always" \
|
|
pipetty make "${CTHREADS}" "olddefconfig" "${cross_compile}"
|
|
|
|
if [[ "${UBOOT_CONFIGURE:-"no"}" == "yes" ]]; then
|
|
display_alert "Saving pre-config u-boot defconfig" "UBOOT_CONFIGURE=yes; experimental" "warn"
|
|
run_host_command_logged make savedefconfig
|
|
run_host_command_logged mv -v defconfig defconfig.pre.menuconfig
|
|
|
|
display_alert "Configuring u-boot" "UBOOT_CONFIGURE=yes; experimental" "warn"
|
|
run_host_command_dialog make menuconfig
|
|
display_alert "Exporting saved config" "UBOOT_CONFIGURE=yes; experimental" "warn"
|
|
run_host_command_logged make savedefconfig
|
|
run_host_command_logged cp -v defconfig "${DEST}/defconfig-uboot-${BOARD}-${BRANCH}"
|
|
|
|
display_alert "Diffing before and after defconfigs" "UBOOT_CONFIGURE=yes; experimental" "warn"
|
|
run_host_command_logged diff -u --color=always "defconfig.pre.menuconfig" "${DEST}/defconfig-uboot-${BOARD}-${BRANCH}" "2>&1" "|| true" # no errors please, all to stdout
|
|
|
|
display_alert "Exported saved config (experimental)" "${DEST}/defconfig-uboot-${BOARD}-${BRANCH}" "warn"
|
|
|
|
return 0 # exit after this
|
|
fi
|
|
|
|
##########################################
|
|
# REAL COMPILATION SECTION STARTING HERE #
|
|
##########################################
|
|
|
|
local uboot_cflags="${uboot_cflags_array[*]}"
|
|
local ts=${SECONDS}
|
|
|
|
# Collect make environment variables, similar to 'kernel-make.sh'
|
|
uboot_make_envs=(
|
|
"PATH='${PATH}'" # preserve PATH as-is
|
|
"CFLAGS='${uboot_cflags}'"
|
|
"KCFLAGS='${uboot_cflags}'"
|
|
"CCACHE_BASEDIR=$(pwd)"
|
|
"PYTHONPATH=\"${PYTHON3_INFO[MODULES_PATH]}:${PYTHONPATH}\"" # Insert the pip modules downloaded by Armbian into PYTHONPATH (needed e.g. for pyelftools)
|
|
)
|
|
|
|
# Pass the ccache directories explicitly, since we'll run under "env -i"
|
|
if [[ -n "${CCACHE_DIR}" ]]; then
|
|
uboot_make_envs+=("CCACHE_DIR=${CCACHE_DIR@Q}")
|
|
fi
|
|
if [[ -n "${CCACHE_TEMPDIR}" ]]; then
|
|
uboot_make_envs+=("CCACHE_TEMPDIR=${CCACHE_TEMPDIR@Q}")
|
|
fi
|
|
|
|
# workaround when two compilers are needed
|
|
cross_compile="CROSS_COMPILE=\"${CCACHE:+$CCACHE }$UBOOT_COMPILER\""
|
|
# When UBOOT_TOOLCHAIN2 is set, the board's uboot_custom_postprocess handles compilers;
|
|
# pass a harmless dummy env var since empty make parameters cause errors
|
|
[[ -n $UBOOT_TOOLCHAIN2 ]] && cross_compile="ARMBIAN=foe"
|
|
|
|
call_extension_method "uboot_make_config" <<- 'UBOOT_MAKE_CONFIG'
|
|
*Hook to customize u-boot make environment*
|
|
Called right before invoking make for u-boot compilation.
|
|
Available array to modify:
|
|
- uboot_make_envs[@]: environment variables passed via "env -i" (e.g., CCACHE_REMOTE_STORAGE)
|
|
UBOOT_MAKE_CONFIG
|
|
|
|
display_alert "${uboot_prefix}Compiling u-boot" "${version} ${target_make} with gcc '${gcc_version_main}'" "info"
|
|
declare -g if_error_detail_message="${uboot_prefix}Failed to build u-boot ${version} ${target_make}"
|
|
do_with_ccache_statistics run_host_command_logged_long_running \
|
|
"env" "-i" "${uboot_make_envs[@]}" \
|
|
pipetty make "$target_make" "$CTHREADS" "${cross_compile}"
|
|
|
|
display_alert "${uboot_prefix}built u-boot target" "${version} in $((SECONDS - ts)) seconds" "info"
|
|
|
|
# Save a defconfig, as that will be included as reference in the .deb package
|
|
# Do not fail here; some very (very!) old u-boots like 2011 do not have 'savedefconfig'
|
|
run_host_command_logged "env" "-i" "${uboot_make_envs[@]}" pipetty make savedefconfig "$CTHREADS" "${cross_compile}" ||
|
|
display_alert "${uboot_prefix}Failed to save defconfig" "${version} ${target_make}" "warn"
|
|
|
|
if [[ $(type -t uboot_custom_postprocess) == function ]]; then
|
|
display_alert "${uboot_prefix}Postprocessing u-boot" "${version} ${target_make}"
|
|
uboot_custom_postprocess
|
|
fi
|
|
|
|
# Hook time, for extra post-processing
|
|
call_extension_method "post_uboot_custom_postprocess" <<- 'POST_UBOOT_CUSTOM_POSTPROCESS'
|
|
*allow extensions to do extra u-boot postprocessing, after uboot_custom_postprocess*
|
|
For hacking at the produced binaries after u-boot is compiled and post-processed.
|
|
POST_UBOOT_CUSTOM_POSTPROCESS
|
|
|
|
declare -a target_dst_files=() # to be filled by deploy_built_uboot_bins_for_one_target_to_packaging_area
|
|
deploy_built_uboot_bins_for_one_target_to_packaging_area # copy according to the target_files
|
|
|
|
# Include metadata about the build, for reference; use the target_counter as part of filename to avoid overwriting
|
|
# .config and defconfig go to ${uboottempdir}/usr/lib/${uboot_name}/u-boot-config-target-${target_counter}
|
|
# ${uboottempdir}/usr/lib/${uboot_name}/u-boot-metadata-target-${uboot_target_counter}.sh has general metadata about the target
|
|
cat <<- UBOOT_TARGET_METADATA_SH > "${uboottempdir}/usr/lib/${uboot_name}/u-boot-metadata-target-${uboot_target_counter}.sh"
|
|
declare -a UBOOT_TARGET_BINS=(${target_dst_files[@]@Q})
|
|
declare UBOOT_TARGET_MAKE=${target_make@Q}
|
|
UBOOT_TARGET_METADATA_SH
|
|
|
|
if [[ -f .config ]]; then # Not all u-boots have .config; some very old did boards.cfg or whatever. Ignore in this case
|
|
run_host_command_logged cp -v .config "${uboottempdir}/usr/lib/${uboot_name}/u-boot-config-target-${uboot_target_counter}"
|
|
cat <<- UBOOT_TARGET_METADATA_SH >> "${uboottempdir}/usr/lib/${uboot_name}/u-boot-metadata-target-${uboot_target_counter}.sh"
|
|
declare UBOOT_TARGET_CONFIG="u-boot-config-target-${uboot_target_counter}"
|
|
UBOOT_TARGET_METADATA_SH
|
|
fi
|
|
|
|
if [[ -f defconfig ]]; then # Not all u-boots are capable of savedefconfig, and thus defconfig will not be available
|
|
run_host_command_logged cp -v defconfig "${uboottempdir}/usr/lib/${uboot_name}/u-boot-defconfig-target-${uboot_target_counter}"
|
|
cat <<- UBOOT_TARGET_METADATA_SH >> "${uboottempdir}/usr/lib/${uboot_name}/u-boot-metadata-target-${uboot_target_counter}.sh"
|
|
declare UBOOT_TARGET_DEFCONFIG="u-boot-defconfig-target-${uboot_target_counter}"
|
|
UBOOT_TARGET_METADATA_SH
|
|
fi
|
|
|
|
if [[ $DEBUG == yes ]]; then
|
|
display_alert "${uboot_prefix}Showing u-boot metadata for target" "${version} ${target_make}" "debug"
|
|
run_tool_batcat --file-name "/usr/lib/${uboot_name}/u-boot-metadata-target-${uboot_target_counter}.sh" "${uboottempdir}/usr/lib/${uboot_name}/u-boot-metadata-target-${uboot_target_counter}.sh"
|
|
fi
|
|
|
|
display_alert "${uboot_prefix}Done with u-boot target" "${version} ${target_make}"
|
|
return 0
|
|
}
|
|
|
|
function loop_over_uboot_targets_and_do() {
|
|
# Try very hard, to fault even, to avoid using subshells while reading a newline-delimited string.
|
|
# Sorry for the juggling with IFS.
|
|
declare _old_ifs="${IFS}" _new_ifs=$'\n'
|
|
IFS="${_new_ifs}" # split on newlines only
|
|
display_alert "Looping over u-boot targets" "'${UBOOT_TARGET_MAP}'" "debug"
|
|
declare -i uboot_target_counter=1
|
|
|
|
# save the current state of nullglob into a variable; don't fail
|
|
declare _old_nullglob
|
|
_old_nullglob="$(shopt -p nullglob || true)"
|
|
display_alert "previous state of nullglob" "'${_old_nullglob}'" "debug"
|
|
|
|
# disable nullglob; dont fail if already disabled
|
|
shopt -u nullglob || true
|
|
|
|
# store new state; don't fail
|
|
declare _new_nullglob
|
|
_new_nullglob="$(shopt -p nullglob || true)"
|
|
display_alert "new state of nullglob" "'${_new_nullglob}'" "debug"
|
|
|
|
for target in ${UBOOT_TARGET_MAP}; do
|
|
display_alert "Building u-boot target" "'${target}'" "debug"
|
|
|
|
# reset nullglob to _old_nullglob
|
|
eval "${_old_nullglob}"
|
|
|
|
IFS="${_old_ifs}" # restore for the body of loop
|
|
declare -g target uboot_name uboottempdir version
|
|
declare -g uboot_prefix="{u-boot:${uboot_target_counter}} "
|
|
declare -g target_make target_patchdir target_files
|
|
target_make=$(cut -d';' -f1 <<< "${target}")
|
|
target_patchdir=$(cut -d';' -f2 <<< "${target}")
|
|
target_files=$(cut -d';' -f3 <<< "${target}")
|
|
# Invoke our parameters directly
|
|
"$@"
|
|
# Increment the counter
|
|
uboot_target_counter=$((uboot_target_counter + 1))
|
|
IFS="${_new_ifs}" # split on newlines only for rest of loop
|
|
done
|
|
|
|
IFS="${_old_ifs}"
|
|
# reset nullglob to _old_nullglob
|
|
eval "${_old_nullglob}"
|
|
|
|
uboot_target_counter=$((uboot_target_counter - 1)) # decrement, as we incremented after the last target
|
|
declare -g -i uboot_target_counter="${uboot_target_counter}" # set global, for metadata ("how many targets?")
|
|
|
|
return 0
|
|
}
|
|
|
|
function deploy_built_uboot_bins_for_one_target_to_packaging_area() {
|
|
display_alert "${uboot_prefix}Preparing u-boot targets packaging" "${version} ${target_make}"
|
|
# copy files to build directory
|
|
declare f
|
|
for f in $target_files; do
|
|
declare f_src f_dst
|
|
f_src=$(cut -d':' -f1 <<< "${f}")
|
|
if [[ $f == *:* ]]; then
|
|
f_dst=$(cut -d':' -f2 <<< "${f}")
|
|
else
|
|
f_dst=$(basename "${f_src}")
|
|
fi
|
|
display_alert "${uboot_prefix}Deploying u-boot binary target" "${version} ${target_make} :: ${f_dst}"
|
|
[[ ! -f $f_src ]] && exit_with_error "U-boot artifact not found" "$(basename "${f_src}")"
|
|
run_host_command_logged cp -v "${f_src}" "${uboottempdir}/usr/lib/${uboot_name}/${f_dst}"
|
|
#display_alert "Done with binary target" "${version} ${target_make} :: ${f_dst}"
|
|
target_dst_files+=("${f_dst}") # for metadata
|
|
done
|
|
return 0
|
|
}
|
|
|
|
function compile_uboot() {
|
|
: "${artifact_version:?artifact_version is not set}"
|
|
|
|
display_alert "Compiling u-boot" "BOOTSOURCE: ${BOOTSOURCE}" "debug"
|
|
if [[ -n $BOOTSOURCE ]] && [[ "${BOOTSOURCE}" != "none" ]]; then
|
|
display_alert "Extensions: fetch custom uboot" "fetch_custom_uboot" "debug"
|
|
call_extension_method "fetch_custom_uboot" <<- 'FETCH_CUSTOM_UBOOT'
|
|
*allow extensions to fetch extra uboot sources*
|
|
For downstream uboot et al.
|
|
This is done after `fetch_from_repo`, but before actually compiling u-boot.
|
|
FETCH_CUSTOM_UBOOT
|
|
fi
|
|
|
|
# not optimal, but extra cleaning before overlayfs_wrapper should keep sources directory clean
|
|
maybe_make_clean_uboot
|
|
|
|
if [[ $USE_OVERLAYFS == yes ]]; then
|
|
local ubootdir
|
|
ubootdir=$(overlayfs_wrapper "wrap" "$SRC/cache/sources/$BOOTSOURCEDIR" "u-boot_${LINUXFAMILY}_${BRANCH}")
|
|
else
|
|
local ubootdir="$SRC/cache/sources/$BOOTSOURCEDIR"
|
|
fi
|
|
cd "${ubootdir}" || exit
|
|
|
|
# read uboot version
|
|
local version hash
|
|
version=$(grab_version "$ubootdir")
|
|
hash=$(git --git-dir="$ubootdir"/.git rev-parse HEAD)
|
|
|
|
display_alert "Compiling u-boot" "$version ${ubootdir}" "info"
|
|
|
|
declare gcc_version_main
|
|
gcc_version_main="$(eval env "${UBOOT_COMPILER}gcc" -dumpfullversion -dumpversion)"
|
|
display_alert "Compiler version" "${UBOOT_COMPILER}gcc '${gcc_version_main}'" "info"
|
|
|
|
local uboot_name="linux-u-boot-${BRANCH}-${BOARD}"
|
|
|
|
# create directory structure for the .deb package
|
|
declare cleanup_id="" uboottempdir=""
|
|
prepare_temp_dir_in_workdir_and_schedule_cleanup "uboot" cleanup_id uboottempdir # namerefs
|
|
|
|
mkdir -p "$uboottempdir/usr/lib/u-boot" "$uboottempdir/usr/lib/$uboot_name" "$uboottempdir/DEBIAN"
|
|
|
|
# Allow extension-based u-boot bulding. We call the hook, and if EXTENSION_BUILT_UBOOT="yes" afterwards, we skip our own compilation.
|
|
# This is to make it easy to build vendor/downstream uboot with their own quirks.
|
|
|
|
display_alert "Extensions: build custom uboot" "build_custom_uboot" "debug"
|
|
call_extension_method "build_custom_uboot" <<- 'BUILD_CUSTOM_UBOOT'
|
|
*allow extensions to build their own uboot*
|
|
For downstream uboot et al.
|
|
Set \`EXTENSION_BUILT_UBOOT=yes\` to then skip the normal compilation.
|
|
BUILD_CUSTOM_UBOOT
|
|
|
|
if [[ "${EXTENSION_BUILT_UBOOT}" != "yes" ]]; then
|
|
loop_over_uboot_targets_and_do compile_uboot_target
|
|
else
|
|
display_alert "Extensions: custom uboot built by extension" "not building regular uboot" "debug"
|
|
fi
|
|
|
|
if [[ "${ARTIFACT_WILL_NOT_BUILD:-"no"}" == "yes" ]]; then
|
|
display_alert "Extensions: artifact will not build" "not building regular uboot" "debug"
|
|
return 0
|
|
fi
|
|
|
|
display_alert "Preparing u-boot general packaging" "${version} ${target_make}"
|
|
|
|
local -a postinst_functions=()
|
|
local destination="${uboottempdir}"
|
|
|
|
call_extension_method "pre_package_uboot_image" <<- 'PRE_PACKAGE_UBOOT_IMAGE'
|
|
*allow making some last minute changes before u-boot is packaged*
|
|
This should be implemented by the config to tweak the uboot package, after the board or family has had the chance to.
|
|
You can write to `$destination` here and it will be packaged.
|
|
You can also append to the `postinst_functions` array, and the _content_ of those functions will be added to the postinst script.
|
|
PRE_PACKAGE_UBOOT_IMAGE
|
|
|
|
# Let's binwalk each file in the resulting package for analysis purposes
|
|
display_alert "Analyzing u-boot binaries with binwalk" "${uboot_name}" "info"
|
|
declare binfile base_binfile
|
|
find "${uboottempdir}" -type f | grep -v -e "u-boot-defconfig-target-" -e "u-boot-config-target-" -e "u-boot-metadata-target" | sort | while read -r binfile; do
|
|
base_binfile="$(basename "${binfile}")"
|
|
display_alert "Analyzing u-boot binary with binwalk" "'${base_binfile}' built on ${HOSTRELEASE}" "info"
|
|
run_host_command_logged file --brief "${binfile}" "||" true ";" binwalk --run-as=root "${binfile}" "||" true # do not fail, ever
|
|
|
|
if [[ "${UBOOT_BINS_TO_OUTPUT}" == "yes" ]]; then
|
|
display_alert "Copying u-boot binary to output for later binwalk inspection" "'${base_binfile}' built on ${HOSTRELEASE}" "warn"
|
|
declare target="${SRC}/output/uboot-bin-${uboot_name}-${base_binfile}-host-${HOSTRELEASE}.bin"
|
|
run_host_command_logged cp -v "${binfile}" "${target}"
|
|
fi
|
|
done
|
|
|
|
artifact_package_hook_helper_board_side_functions "postinst" uboot_postinst_base "${postinst_functions[@]}"
|
|
unset uboot_postinst_base postinst_functions destination
|
|
|
|
# declare -f on non-defined function does not do anything (but exits with errors, so ignore them with "|| true")
|
|
cat <<- EOF > "${uboottempdir}/usr/lib/u-boot/platform_install.sh"
|
|
# Armbian u-boot install script for linux-u-boot-${BOARD}-${BRANCH} ${artifact_version}
|
|
# This file provides functions for deploying u-boot to a block device.
|
|
DIR=/usr/lib/$uboot_name
|
|
$(declare -f write_uboot_platform || true)
|
|
$(declare -f write_uboot_platform_mtd || true)
|
|
$(declare -f setup_write_uboot_platform || true)
|
|
EOF
|
|
|
|
if [[ "${SHOW_DEBUG}" == "yes" ]]; then
|
|
display_alert "Showing contents of" "usr/lib/u-boot/platform_install.sh" "info"
|
|
run_tool_batcat --file-name "usr/lib/u-boot/platform_install.sh" "${uboottempdir}/usr/lib/u-boot/platform_install.sh"
|
|
fi
|
|
|
|
# Write general metadata. This is intended to be used board-side, and allows some better gui and reuse.
|
|
# Ensure that all variables used here are hashed in the artifact-uboot.sh during version calculation.
|
|
cat <<- UBOOT_GENERAL_METADATA_SH > "${uboottempdir}/usr/lib/${uboot_name}/u-boot-metadata.sh"
|
|
declare -i UBOOT_NUM_TARGETS=${uboot_target_counter}
|
|
declare UBOOT_BIN_DIR="/usr/lib/${uboot_name}"
|
|
declare UBOOT_VERSION="${version}"
|
|
declare UBOOT_ARTIFACT_VERSION="${artifact_version}"
|
|
declare UBOOT_GIT_REVISION="${hash}"
|
|
declare UBOOT_GIT_SOURCE="${BOOTSOURCE}"
|
|
declare UBOOT_GIT_BRANCH="${BOOTBRANCH}"
|
|
declare UBOOT_GIT_PATCHDIR="${BOOTPATCHDIR}"
|
|
declare UBOOT_PARTITION_TYPE="${IMAGE_PARTITION_TABLE}"
|
|
declare UBOOT_KERNEL_DTB="${BOOT_FDT_FILE}"
|
|
declare UBOOT_KERNEL_SERIALCON="${SERIALCON}"
|
|
declare UBOOT_EXTLINUX_PREFER="${SRC_EXTLINUX:-"no"}"
|
|
declare UBOOT_EXTLINUX_CMDLINE="${SRC_CMDLINE}"
|
|
UBOOT_GENERAL_METADATA_SH
|
|
|
|
if [[ $DEBUG == yes ]]; then
|
|
display_alert "${uboot_prefix}Showing u-boot metadata for target" "${version} ${target_make}" "debug"
|
|
run_tool_batcat --file-name "/usr/lib/${uboot_name}/u-boot-metadata.sh" "${uboottempdir}/usr/lib/${uboot_name}/u-boot-metadata.sh"
|
|
fi
|
|
|
|
display_alert "Running shellcheck" "usr/lib/u-boot/platform_install.sh" "info"
|
|
shellcheck_debian_control_scripts "${uboottempdir}/usr/lib/u-boot/platform_install.sh"
|
|
|
|
display_alert "Das U-Boot .deb package version" "${artifact_version}" "info"
|
|
|
|
# set up control file
|
|
cat <<- EOF > "$uboottempdir/DEBIAN/control"
|
|
Package: linux-u-boot-${BOARD}-${BRANCH}
|
|
Version: ${artifact_version}
|
|
Architecture: $ARCH
|
|
Maintainer: $MAINTAINER <$MAINTAINERMAIL>
|
|
Section: kernel
|
|
Priority: optional
|
|
Provides: armbian-u-boot
|
|
Replaces: armbian-u-boot
|
|
Conflicts: armbian-u-boot, u-boot-sunxi
|
|
Description: Das U-Boot for ${BOARD}
|
|
${artifact_version_reason:-"${version}"}
|
|
EOF
|
|
|
|
# copy license files, config, etc.
|
|
[[ -f .config && -n $BOOTCONFIG ]] && run_host_command_logged cp .config "$uboottempdir/usr/lib/u-boot/${BOOTCONFIG}" # legacy and @TODO should be removed as it has only the last target; we now have per-target configs and defconfigs
|
|
[[ -f COPYING ]] && run_host_command_logged cp COPYING "$uboottempdir/usr/lib/u-boot/LICENSE"
|
|
[[ -f Licenses/README ]] && run_host_command_logged cp Licenses/README "$uboottempdir/usr/lib/u-boot/LICENSE"
|
|
[[ -n $atftempdir && -f $atftempdir/license.md ]] && run_host_command_logged cp "${atftempdir}/license.md" "$uboottempdir/usr/lib/u-boot/LICENSE.atf"
|
|
|
|
display_alert "Building u-boot deb" "(version: ${artifact_version})"
|
|
dpkg_deb_build "${uboottempdir}" "uboot"
|
|
|
|
[[ -n $atftempdir ]] && rm -rf "${atftempdir:?}" # @TODO: intricate cleanup; u-boot's pkg uses ATF's tempdir...
|
|
|
|
done_with_temp_dir "${cleanup_id}" # changes cwd to "${SRC}" and fires the cleanup function early
|
|
|
|
display_alert "Built u-boot deb OK" "linux-u-boot-${BOARD}-${BRANCH} ${artifact_version}" "info"
|
|
return 0 # success
|
|
}
|
|
|
|
function uboot_postinst_base() {
|
|
# Source the armbian-release information file
|
|
# shellcheck source=/dev/null
|
|
[ -f /etc/armbian-release ] && . /etc/armbian-release
|
|
# shellcheck source=/dev/null
|
|
source /usr/lib/u-boot/platform_install.sh
|
|
|
|
if [ "${FORCE_UBOOT_UPDATE:-no}" == "yes" ]; then
|
|
#recognize_root
|
|
root_uuid=$(sed -e 's/^.*root=//' -e 's/ .*$//' < /proc/cmdline)
|
|
root_partition=$(blkid | tr -d '":' | grep "${root_uuid}" | awk '{print $1}')
|
|
root_partition_name=$(echo $root_partition | sed 's/\/dev\///g')
|
|
root_partition_device_name=$(lsblk -ndo pkname $root_partition)
|
|
root_partition_device=/dev/$root_partition_device_name
|
|
|
|
write_uboot_platform "$DIR" "${root_partition_device}"
|
|
sync
|
|
fi
|
|
}
|