#!/bin/bash # ============================================================================ # Orange Pi 5 Ultra - update.img ????????? # ???orangepi-build??? - ??????????????? # ============================================================================ set -e LEGACY_WORK_DIR="/data/OrangePi CM5" WORK_DIR="/data/OrangePi_CM5" CACHE_ROOT="/data/OrangePi_cache" BUILD_DATE=$(date +%Y%m%d_%H%M%S) LOG_FILE="${WORK_DIR}/build_${BUILD_DATE}.log" MODE="auto" # ?????? RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # ============================================================================ # ????????? # ============================================================================ log() { echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE" } log_error() { echo -e "${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE" } log_warn() { echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE" } # ============================================================================ # ???????????? # ============================================================================ set_kconfig_option() { local cfg_file=$1 local key=$2 local value=$3 if [ ! -f "$cfg_file" ]; then mkdir -p "$(dirname "$cfg_file")" : > "$cfg_file" fi if grep -q "^${key}=" "$cfg_file"; then sed -i "s|^${key}=.*|${key}=${value}|" "$cfg_file" elif grep -q "^# ${key} is not set" "$cfg_file"; then sed -i "s|^# ${key} is not set|${key}=${value}|" "$cfg_file" else echo "${key}=${value}" >> "$cfg_file" fi } # ============================================================================ # ?????? IMX586 ??????????????????????????? # ============================================================================ enforce_imx586_support() { local BUILD_DIR=$1 local kernel_cfg_dir="${BUILD_DIR}/external/config/kernel" local updated=0 log "????????? IMX586 ???..." # ??? Orange Pi 5 Ultra??k3588 legacy??????????? for cfg in "${kernel_cfg_dir}"/linux-rockchip-rk3588-legacy*.config; do [ -f "$cfg" ] || continue set_kconfig_option "$cfg" "CONFIG_VIDEO_IMX586" "y" updated=1 done # userpatches ?????????????????????????????? IMX586?? local userpatch_cfg="${BUILD_DIR}/userpatches/linux-rockchip-rk3588-legacy-opi5max.config" set_kconfig_option "$userpatch_cfg" "CONFIG_VIDEO_IMX586" "y" updated=1 if [ "$updated" -eq 1 ]; then log "???????IMX586 ???" else log_warn "???????????rk3588 legacy ??????????????????????? fi } # ============================================================================ # ????????IMX586 ?????? # ============================================================================ verify_imx586_support() { local BUILD_DIR=$1 local kernel_tree="${BUILD_DIR}/kernel/orange-pi-5.10-rk35xx" local kernel_cfg="${kernel_tree}/.config" local driver_src="${kernel_tree}/drivers/media/i2c/imx586.c" log "??? IMX586 ??????..." if [ ! -f "$driver_src" ]; then log_error "??? IMX586 ??????: $driver_src" return 1 fi if [ ! -f "$kernel_cfg" ]; then log_error "?????????????? $kernel_cfg" return 1 fi if grep -Eq '^CONFIG_VIDEO_IMX586=(y|m)$' "$kernel_cfg"; then log "??IMX586 ???????? $(grep -E '^CONFIG_VIDEO_IMX586=' "$kernel_cfg" | head -1)" return 0 fi log_error "IMX586 ????????? CONFIG_VIDEO_IMX586=y/m?? return 1 } # ============================================================================ # ???????????????????????????????????# ============================================================================ prepare_workspace() { mkdir -p "$WORK_DIR" if [ -d "$LEGACY_WORK_DIR" ]; then log "?????????? $LEGACY_WORK_DIR" # ??????????????????????????????????????? if [ -d "$LEGACY_WORK_DIR/SDKs" ] && [ ! -e "$WORK_DIR/SDKs" ]; then cp -a "$LEGACY_WORK_DIR/SDKs" "$WORK_DIR/" log "???????SDKs ??????" fi if [ -d "$LEGACY_WORK_DIR/sources" ] && [ ! -e "$WORK_DIR/sources" ]; then cp -a "$LEGACY_WORK_DIR/sources" "$WORK_DIR/" log "???????sources ??????" fi if [ -d "$LEGACY_WORK_DIR/orangepi-build" ] && [ ! -e "$WORK_DIR/orangepi-build" ]; then cp -a "$LEGACY_WORK_DIR/orangepi-build" "$WORK_DIR/" log "???????orangepi-build ??????" fi fi } # ============================================================================ # ??????????? # ============================================================================ check_environment() { log "??????????.." # ?????????? local required_tools=("git" "gcc" "make" "device-tree-compiler") for tool in "${required_tools[@]}"; do if ! command -v "$tool" &> /dev/null; then log_warn "$tool ????????????..." apt-get update apt-get install -y "$tool" else log "??$tool ????? fi done # ?????????????? if ! command -v aarch64-linux-gnu-gcc &> /dev/null; then log_warn "aarch64-linux-gnu-gcc ????????????..." apt-get install -y gcc-aarch64-linux-gnu build-essential else log "??aarch64-linux-gnu-gcc ????? fi log "?????????? } # ============================================================================ # ??? git ???????????# ============================================================================ configure_git() { log "??? git ??????..." git config --global http.connectTimeout 120 git config --global http.postBuffer 524288000 git config --global core.compression 0 git config --global url."https://".insteadOf git:// log "??git ??????" } # ============================================================================ # ?????? - ???1: Gitee???????????? # ============================================================================ download_from_gitee() { local repo_name=$1 local repo_url=$2 local branch=$3 local target_dir=$4 log "?????Gitee ??? $repo_name (???: $branch)..." if [ -d "$target_dir" ]; then log "???????????????..." cd "$target_dir" git pull origin "$branch" 2>&1 && return 0 cd - > /dev/null fi if git clone --depth=1 -b "$branch" "$repo_url" "$target_dir" 2>&1; then log "????Gitee ??????" return 0 else log_warn "??Gitee ??????" return 1 fi } # ============================================================================ # ?????? - ???2: GitHub (????? # ============================================================================ download_from_github() { local repo_name=$1 local repo_url=$2 local branch=$3 local target_dir=$4 local retry_count=3 log "?????GitHub ??? $repo_name (???: $branch)..." if [ -d "$target_dir" ]; then log "???????????????..." cd "$target_dir" git pull origin "$branch" 2>&1 && return 0 cd - > /dev/null fi for ((i=1; i<=retry_count; i++)); do log "GitHub ?????? $i/$retry_count..." if git clone --depth=1 -b "$branch" "$repo_url" "$target_dir" 2>&1; then log "????GitHub ??????" return 0 fi sleep 5 done log_warn "GitHub ?????????? return 1 } # ============================================================================ # ??? orangepi-build # ============================================================================ get_orangepi_build() { log "??? orangepi-build ??????..." local BUILD_DIR="${WORK_DIR}/orangepi-build" # ??????? ?????SDKs ?????? if extract_from_sdks "orangepi-build" "$BUILD_DIR"; then ORANGEPI_BUILD_DIR="$BUILD_DIR" return 0 fi # ??????? Gitee ??? if download_from_gitee \ "orangepi-build" \ "https://gitee.com/orangepi-xunlong/orangepi-build.git" \ "next" \ "$BUILD_DIR"; then ORANGEPI_BUILD_DIR="$BUILD_DIR" return 0 fi # ??????? GitHub if download_from_github \ "orangepi-build" \ "https://github.com/orangepi-xunlong/orangepi-build.git" \ "next" \ "$BUILD_DIR"; then ORANGEPI_BUILD_DIR="$BUILD_DIR" return 0 fi log_error "?????? orangepi-build" return 1 } # ============================================================================ # ?????????????????????????????? # ============================================================================ setup_build_cache_links() { local build_dir=$1 local shared_dl="${CACHE_ROOT}/dl" local shared_toolchains="${CACHE_ROOT}/toolchains" local shared_ext_cache="${CACHE_ROOT}/external-cache" mkdir -p "$shared_dl" "$shared_toolchains" "$shared_ext_cache" # ??????????????????????????????????? if [ -d "$build_dir/dl" ] && [ ! -L "$build_dir/dl" ] && [ -z "$(ls -A "$shared_dl" 2>/dev/null)" ]; then cp -a "$build_dir/dl/." "$shared_dl/" 2>/dev/null || true fi if [ -d "$build_dir/toolchains" ] && [ ! -L "$build_dir/toolchains" ] && [ -z "$(ls -A "$shared_toolchains" 2>/dev/null)" ]; then cp -a "$build_dir/toolchains/." "$shared_toolchains/" 2>/dev/null || true fi if [ -d "$build_dir/external/cache" ] && [ ! -L "$build_dir/external/cache" ] && [ -z "$(ls -A "$shared_ext_cache" 2>/dev/null)" ]; then cp -a "$build_dir/external/cache/." "$shared_ext_cache/" 2>/dev/null || true fi mkdir -p "$build_dir/external" rm -rf "$build_dir/dl" "$build_dir/toolchains" "$build_dir/external/cache" ln -s "$shared_dl" "$build_dir/dl" ln -s "$shared_toolchains" "$build_dir/toolchains" ln -s "$shared_ext_cache" "$build_dir/external/cache" log "????????????? log " dl: $shared_dl" log " toolchains: $shared_toolchains" log " external cache: $shared_ext_cache" } # ============================================================================ # ???3: ?????SDKs ???????????# ============================================================================ extract_from_sdks() { local repo_name=$1 local target_dir=$2 log "?????SDKs ?????? $repo_name..." # ????????????????? if [ -d "$target_dir" ]; then log "?????????? $target_dir" return 0 fi # ???1: ??? orangepi-build-next.zip if [ "$repo_name" = "orangepi-build" ]; then local archive="${WORK_DIR}/SDKs/orangepi-build-next.zip" if [ -f "$archive" ]; then log "???????? $archive" log "?????.." mkdir -p "$target_dir" unzip -q "$archive" -d "$target_dir" 2>/dev/null || return 1 # ??????????????? if [ -d "${target_dir}/orangepi-build"* ]; then mv "${target_dir}"/orangepi-build* "${target_dir}_tmp" rm -rf "$target_dir" mv "${target_dir}_tmp" "$target_dir" elif [ -d "${target_dir}/orangepi-build" ]; then local temp_build="${target_dir}/orangepi-build" mv "$temp_build"/* "$target_dir"/ 2>/dev/null || true rm -rf "$temp_build" fi if [ -f "${target_dir}/build.sh" ]; then log "????SDKs ??????" return 0 fi fi # ???2: ??? OrangePi_Build-master.zip archive="${WORK_DIR}/SDKs/OrangePi_Build-master.zip" if [ -f "$archive" ]; then log "???????????: $archive" log "?????.." mkdir -p "$target_dir" unzip -q "$archive" -d "$target_dir" 2>/dev/null || return 1 # ??????????????? if [ -d "${target_dir}/OrangePi_Build-master" ]; then mv "${target_dir}/OrangePi_Build-master"/* "$target_dir"/ 2>/dev/null || true rmdir "${target_dir}/OrangePi_Build-master" 2>/dev/null || true fi if [ -f "${target_dir}/build.sh" ]; then log "????SDKs ??????" return 0 fi fi return 1 fi return 1 } # ============================================================================ # ????????????????? # ============================================================================ check_local_sources() { log "???????????????????????..." local sources_dir="${WORK_DIR}/sources" if [ ! -d "$sources_dir" ]; then return 1 fi # ??????????orangepi-build ??? for archive in "$sources_dir"/{orangepi-build,u-boot,linux,kernel}*.tar* "$sources_dir"/*.zip; do if [ -f "$archive" ]; then log "??????????? $archive" return 0 fi done return 1 } # ============================================================================ # ??? update.img (??? orangepi-build) # ============================================================================ build_update_img() { local BUILD_DIR=$1 log "???????update.img..." cd "$BUILD_DIR" # ???????????? log "????????????:" ls -la | head -20 >> "$LOG_FILE" # ?????????????? chmod +x build.sh # ????????????????????? # ??????: # BOARD=orangepi5ultra - ???????? # BRANCH=legacy - ??? linux5.10 (??? IMX586 ???) # BUILD_OPT=image - ????????? # RELEASE=bullseye - Debian Bullseye ????? # BUILD_DESKTOP=no - ????????? (??????????????yes) if [ "$MODE" = "menu" ]; then log "?????????????????????..." log "?????ncurses ??????????????????" # ncurses ????????????????? tee ?????? sudo ./build.sh local build_rc=$? else log "?????????????????????..." log "??????: BOARD=orangepi5ultra BRANCH=legacy BUILD_OPT=image KERNEL_CONFIGURE=no" sudo ./build.sh \ BOARD=orangepi5ultra \ BRANCH=legacy \ BUILD_OPT=image \ RELEASE=bullseye \ BUILD_DESKTOP=no \ KERNEL_CONFIGURE=no 2>&1 | tee -a "$LOG_FILE" local build_rc=${PIPESTATUS[0]} fi if [ ${build_rc:-1} -eq 0 ]; then log "????????" return 0 else # ??????????????????????????????????????? local produced_img produced_img=$(find "$BUILD_DIR/output/images" -name "*.img" -type f 2>/dev/null | head -1) if [ -n "$produced_img" ]; then log_warn "build.sh ????????????????????: $produced_img" log_warn "????????????????? return 0 fi log_error "??????" return 1 fi } # ============================================================================ # ????????? # ============================================================================ verify_build() { local BUILD_DIR=$1 log "?????????..." local output_dir="${BUILD_DIR}/output/images" if [ ! -d "$output_dir" ]; then log_error "??????????? $output_dir" return 1 fi # ?????? update.img??????????????.img ??????????? local update_img update_img=$(find "$output_dir" -name "*update*.img" -type f 2>/dev/null | head -1) if [ -z "$update_img" ]; then update_img=$(find "$output_dir" -name "*.img" -type f 2>/dev/null | head -1) fi if [ -z "$update_img" ]; then log_error "???????????(*.img)" return 1 fi log "???????????: $update_img" local img_size=$(du -sh "$update_img" | awk '{print $1}') log "??????: $img_size" # ???????? log "??? SHA256 ?????.." sha256sum "$update_img" > "${update_img}.sha256" log "?????????:" cat >> "$LOG_FILE" << EOF === ?????? === ???: $(date) ??????: $update_img ???: $img_size ????? $(cat "${update_img}.sha256") EOF return 0 } # ============================================================================ # ?????# ============================================================================ main() { case "${1:-}" in menu|interactive) MODE="menu" ;; auto|"") MODE="auto" ;; *) echo "???: $0 [auto|menu]" echo " auto: ???????????? ncurses ????? echo " menu: ?????? ncurses ?????????" exit 1 ;; esac log "==========================================" log "Orange Pi 5 Ultra - update.img ???" log "==========================================" log "??????: $WORK_DIR" log "????????): $LEGACY_WORK_DIR" log "??????: $LOG_FILE" log "??????: $MODE" prepare_workspace cd "$WORK_DIR" || { log_error "????????????"; exit 1; } # ???? ??????? check_environment # ???? ???git configure_git # ???? ??? orangepi-build log "" log "========== ???1: ?????? ==========" if ! get_orangepi_build; then log_error "??? orangepi-build ???" log "" log "??????:" log "1. ??????????? \${WORK_DIR}/SDKs/ ???????????" log " - orangepi-build-next.zip" log " - OrangePi_Build-master.zip" log "" log "2. ?????? SDKs ????????????:" log " a) ????${WORK_DIR}/SDKs/ ?????????" log " b) ????????????????? log " c) ?????????????????????????? log "" log "3. ????????????????? ${WORK_DIR}/sources/ ????? log "" log "4. ???????????:" log " - ???????????????" log " - ???????????? git ???: git config --global credential.helper store" exit 1 fi BUILD_DIR="$ORANGEPI_BUILD_DIR" # ??.5?? ????????? setup_build_cache_links "$BUILD_DIR" # ??.6?? ?????? IMX586 ??? enforce_imx586_support "$BUILD_DIR" # ???? ??? update.img log "" log "========== ???2: ?????? ==========" if ! build_update_img "$BUILD_DIR"; then log_error "????????????????? $LOG_FILE" exit 1 fi # ???? ?????? log "" log "========== ???3: ?????? ==========" if ! verify_build "$BUILD_DIR"; then log_error "??????" exit 1 fi if ! verify_imx586_support "$BUILD_DIR"; then log_error "IMX586 ?????????" exit 1 fi log "" log "==========================================" log "?????????? log "==========================================" log "??????:" log "1. ??????: scp root@www.yuquanjun.cn:/data/OrangePi_CM5/orangepi-build/output/images/*/update.img ./" log "2. ??? RKDevTool ??balenaEtcher ??????" log "==========================================" } # ????????main "$@"