#!/usr/bin/env bash set -euo pipefail # 更严格的安全设置 # ============================================================================= # 颜色和样式配置 # ============================================================================= readonly RED_COLOR='\033[1;31m' readonly GREEN_COLOR='\033[1;32m' readonly YELLOW_COLOR='\033[1;33m' readonly BLUE_COLOR='\033[1;34m' readonly MAGENTA_COLOR='\033[1;35m' readonly CYAN_COLOR='\033[1;36m' readonly BOLD='\033[1m' readonly RESET='\033[0m' readonly BLINK='\033[5m' # ============================================================================= # 全局常量定义 # ============================================================================= readonly SCRIPT_NAME="OpenWRT Build System" readonly SCRIPT_VERSION="1.0.0" readonly AUTHOR="OPPEN321" readonly BLOG="www.kejizero.online" readonly SUPPORTED_ARCHITECTURES=("rockchip" "x86_64") readonly REQUIRED_USER="zhao" readonly MIRROR="${mirror:-https://raw.githubusercontent.com/your-repo}" # 设置默认镜像 # ============================================================================= # 全局变量 # ============================================================================= GROUP_FLAG=false START_TIME=$(date +%s) CPU_CORES=$(( $(nproc --all) + 1 )) CURRENT_DATE=$(date +%s) # 构建选项(可以从环境变量覆盖) BUILD_FAST="${BUILD_FAST:-n}" BUILD="${BUILD:-y}" BUILD_TOOLCHAIN="${BUILD_TOOLCHAIN:-n}" GCC_VERSION="${GCC_VERSION:-12.3.0}" # ============================================================================= # 函数定义 # ============================================================================= # 打印带颜色的消息 print_color() { local color=$1 shift echo -e "${color}$*${RESET}" } # 打印错误消息并退出 error_exit() { print_color "$RED_COLOR" "❌ 错误: $1" exit 1 } # 打印警告消息 print_warning() { print_color "$YELLOW_COLOR" "⚠️ 警告: $1" } # 打印成功消息 print_success() { print_color "$GREEN_COLOR" "✅ $1" } # 打印信息消息 print_info() { print_color "$BLUE_COLOR" "ℹ️ 信息: $1" } # 验证必需的环境变量 validate_environment() { if [[ "$(whoami)" != "$REQUIRED_USER" ]] && [[ -z "${git_name:-}" || -z "${git_password:-}" ]]; then error_exit "未授权访问。请设置认证信息后再执行此脚本。" fi } # 显示使用帮助 show_usage() { echo -e "\n${BOLD}使用方法:${RESET}" echo -e " bash $0 " echo -e "\n${BOLD}支持的架构:${RESET}" for arch in "${SUPPORTED_ARCHITECTURES[@]}"; do echo -e " • ${GREEN_COLOR}$arch${RESET}" done echo -e "\n${BOLD}环境变量:${RESET}" echo -e " BUILD_FAST=${BUILD_FAST} - 快速构建模式" echo -e " BUILD_TOOLCHAIN=${BUILD_TOOLCHAIN} - 仅构建工具链" echo -e " MIRROR=${MIRROR} - 镜像地址" echo -e "\n${BOLD}示例:${RESET}" echo -e " BUILD_FAST=y bash $0 v24 x86_64" echo -e " bash $0 v24 rockchip" } # 验证参数 validate_arguments() { local version="$1" local arch="$2" if [[ -z "$version" ]]; then error_exit "未指定版本号" fi if [[ -z "$arch" ]]; then error_exit "未指定目标架构" fi local valid_arch=false for supported_arch in "${SUPPORTED_ARCHITECTURES[@]}"; do if [[ "$arch" == "$supported_arch" ]]; then valid_arch=true break fi done if [[ "$valid_arch" == false ]]; then error_exit "不支持的架构: '$arch'" fi } # 显示横幅 show_banner() { clear echo -e "" echo -e "${BOLD}${BLUE_COLOR}╔══════════════════════════════════════════════════════════════════╗${RESET}" echo -e "${BOLD}${BLUE_COLOR}║${RESET} OPENWRT 自动化构建系统 ${BOLD}${BLUE_COLOR}║${RESET}" echo -e "${BOLD}${BLUE_COLOR}╚══════════════════════════════════════════════════════════════════╝${RESET}" echo -e "${BOLD}${BLUE_COLOR}┌────────────────────────────────────────────────────────────────────┐${RESET}" echo -e "${BOLD}${BLUE_COLOR}│${RESET} 🛠️ ${BOLD}开发者:${RESET} $AUTHOR ${BOLD}${BLUE_COLOR}│${RESET}" echo -e "${BOLD}${BLUE_COLOR}│${RESET} 🌐 ${BOLD}博客:${RESET} $BLOG ${BOLD}${BLUE_COLOR}│${RESET}" echo -e "${BOLD}${BLUE_COLOR}│${RESET} 💡 ${BOLD}理念:${RESET} 开源 · 定制化 · 高性能 ${BOLD}${BLUE_COLOR}│${RESET}" echo -e "${BOLD}${BLUE_COLOR}│${RESET} 📦 ${BOLD}版本:${RESET} $SCRIPT_VERSION ${BOLD}${BLUE_COLOR}│${RESET}" echo -e "${BOLD}${BLUE_COLOR}└────────────────────────────────────────────────────────────────────┘${RESET}" echo -e "${BOLD}${BLUE_COLOR}══════════════════════════════════════════════════════════════════════${RESET}" echo -e "${BOLD}🔧 ${GREEN_COLOR}构建开始时间:${RESET} $(date '+%Y-%m-%d %H:%M:%S')" echo -e "${BOLD}⚡ ${GREEN_COLOR}处理器核心数:${RESET} $CPU_CORES" echo -e "${BOLD}🐧 ${GREEN_COLOR}系统用户:${RESET} $(whoami)" echo -e "${BOLD}🏗️ ${GREEN_COLOR}构建模式:${RESET} $([ "$BUILD_FAST" = "y" ] && echo "快速" || echo "标准")" echo -e "${BOLD}${BLUE_COLOR}══════════════════════════════════════════════════════════════════════${RESET}" echo -e "" } # 初始化构建环境 setup_build_environment() { if [[ "$(id -u)" == "0" ]]; then export FORCE_UNSAFE_CONFIGURE=1 export FORCE=1 print_warning "以 root 权限运行,已启用强制不安全配置" fi } # 设置下载进度条 setup_curl_progress() { if curl --help | grep -q progress-bar; then CURL_BAR="--progress-bar" else CURL_BAR="--silent" fi export CURL_BAR } # 设置平台相关变量 setup_platform() { local architecture="$1" case "$architecture" in rockchip) platform="rockchip" toolchain_arch="aarch64_generic" core="arm64" ;; x86_64) platform="x86_64" toolchain_arch="x86_64" core="amd64" ;; *) error_exit "不支持的架构: $architecture" ;; esac export platform toolchain_arch core print_info "目标平台: $platform, 工具链架构: $toolchain_arch, 核心类型: $core" } # 获取最新 OpenWRT 版本 get_latest_version() { start_group "获取最新 OpenWRT 版本" local latest_version latest_version="$(curl -s https://github.com/openwrt/openwrt/tags | grep -Eo "v[0-9\.]+\-*r*c*[0-9]*.tar.gz" | sed -n '/[2-9][4-9]/p' | sed -n 1p | sed 's/v//g' | sed 's/.tar.gz//g')" if [[ -z "$latest_version" ]]; then error_exit "无法获取最新版本号" fi print_success "检测到最新版本: v$latest_version" echo "$latest_version" end_group } # 克隆源代码 clone_source_code() { start_group "克隆源代码" local version="$1" print_info "正在克隆 OpenWRT 源代码..." if ! git clone -b "v$version" https://github.com/openwrt/openwrt; then error_exit "克隆 OpenWRT 源代码失败" fi print_info "正在克隆 ImmortalWRT 源代码..." git clone -b openwrt-24.10 https://github.com/immortalwrt/immortalwrt || print_warning "克隆 ImmortalWRT 失败,继续构建..." print_info "正在克隆 OpenWRT 快照..." git clone -b openwrt-24.10 https://github.com/openwrt/openwrt openwrt_snap || print_warning "克隆 OpenWRT 快照失败,继续构建..." if [[ ! -d "openwrt" ]]; then error_exit "OpenWRT 源代码目录不存在" fi cd openwrt || error_exit "无法进入 openwrt 目录" # 下载密钥和补丁 print_info "下载构建密钥和补丁..." curl -Os "$MIRROR/openwrt/patch/key.tar.gz" && tar zxf key.tar.gz && rm -f key.tar.gz curl -Os "$MIRROR/info.md" || print_warning "无法下载 info.md" end_group } # 更新 feeds update_feeds() { start_group "更新和安装 Feeds" print_info "更新 feeds..." if ! ./scripts/feeds update -a; then error_exit "Feeds 更新失败" fi print_info "安装 feeds..." if ! ./scripts/feeds install -a; then error_exit "Feeds 安装失败" fi end_group } # 应用补丁脚本 apply_patches() { start_group "应用补丁和配置" local scripts=( 00-prepare_base.sh 01-prepare_package.sh 02-prepare_adguard_core.sh 03-preset_mihimo_core.sh 04-preset_homeproxy.sh 06-fix-source.sh 10-custom.sh 99_clean_build_cache.sh ) # 下载补丁脚本 print_info "下载补丁脚本..." for script in "${scripts[@]}"; do if curl -sO "$MIRROR/openwrt/scripts/$script"; then print_success "下载 $script 成功" else print_warning "下载 $script 失败" fi done # 下载平台特定脚本 if [[ "$platform" = "rockchip" ]]; then curl -sO "$MIRROR/openwrt/scripts/05-rockchip_target_only.sh" elif [[ "$platform" = "x86_64" ]]; then curl -sO "$MIRROR/openwrt/scripts/05-x86_64_target_only.sh" fi # 设置执行权限并运行脚本 chmod 0755 ./*.sh print_info "执行补丁脚本..." local patch_scripts=( "00-prepare_base.sh" "01-prepare_package.sh" "02-prepare_adguard_core.sh" "03-preset_mihimo_core.sh" "04-preset_homeproxy.sh" "06-fix-source.sh" ) for script in "${patch_scripts[@]}"; do if [[ -f "$script" ]]; then print_info "执行 $script..." bash "$script" || print_warning "$script 执行出现警告" fi done # 执行平台特定脚本 if [[ "$platform" = "rockchip" ]] && [[ -f "05-rockchip_target_only.sh" ]]; then bash 05-rockchip_target_only.sh elif [[ "$platform" = "x86_64" ]] && [[ -f "05-x86_64_target_only.sh" ]]; then bash 05-x86_64_target_only.sh fi # 执行自定义脚本 if [[ -f "10-custom.sh" ]]; then print_info "执行自定义脚本..." bash 10-custom.sh fi # 清理临时文件 find feeds -type f -name "*.orig" -exec rm -f {} \; rm -f 0*-*.sh 10-custom.sh end_group } # 下载工具链缓存 download_toolchain_cache() { if [[ "$BUILD_FAST" != "y" ]]; then return 0 fi start_group "下载工具链缓存" print_info "正在下载工具链缓存..." local TOOLCHAIN_URL="https://github.com/NeonPulse-Zero/openwrt_caches/releases/download/openwrt-24.10" local toolchain_file="toolchain_musl_${toolchain_arch}_gcc-${GCC_VERSION}.tar.zst" if curl -L "${TOOLCHAIN_URL}/$toolchain_file" -o toolchain.tar.zst $CURL_BAR; then print_success "工具链下载成功" print_info "解压工具链..." if tar -I "zstd" -xf toolchain.tar.zst; then print_success "工具链解压成功" rm -f toolchain.tar.zst mkdir -p bin # 更新文件时间戳 find ./staging_dir/ -name '*' -exec touch {} \; >/dev/null 2>&1 find ./tmp/ -name '*' -exec touch {} \; >/dev/null 2>&1 else print_warning "工具链解压失败,将继续从源码编译" fi else print_warning "工具链下载失败,将继续从源码编译" fi end_group } # 配置编译选项 configure_build() { start_group "配置编译选项" # 清理临时文件 rm -rf tmp/* if [[ "$BUILD" = "n" ]]; then print_info "构建模式设置为 NO,退出配置" exit 0 fi # 下载平台配置文件 print_info "下载平台配置文件..." if [[ "$platform" = "x86_64" ]]; then curl -s "$MIRROR/openwrt/24-config-musl-x86" > .config elif [[ "$platform" = "rockchip" ]]; then curl -s "$MIRROR/openwrt/24-config-musl-rockchip" > .config fi # 添加通用配置 print_info "添加通用配置..." curl -s "$MIRROR/openwrt/24-config-common" >> .config # 生成默认配置 print_info "生成默认配置..." if ! make defconfig; then error_exit "生成默认配置失败" fi end_group } # 编译工具链 build_toolchain() { if [[ "$BUILD_TOOLCHAIN" != "y" ]]; then return 0 fi start_group "编译工具链" print_info "开始编译工具链..." if make -j$CPU_CORES toolchain/compile; then print_success "工具链编译成功" else print_warning "工具链首次编译失败,尝试详细模式..." if ! make -j$CPU_CORES toolchain/compile V=s; then error_exit "工具链编译失败" fi fi # 打包工具链缓存 print_info "打包工具链缓存..." mkdir -p toolchain-cache local cache_file="toolchain-cache/toolchain_musl_${toolchain_arch}_gcc-${GCC_VERSION}.tar.zst" if tar -I "zstd -19 -T$(nproc --all)" -cf "$cache_file" ./{build_dir,dl,staging_dir,tmp}; then print_success "工具链缓存打包成功: $cache_file" else print_warning "工具链缓存打包失败" fi end_group exit 0 } # 编译 OpenWRT build_openwrt() { start_group "编译 OpenWRT" if [[ "$BUILD_TOOLCHAIN" = "y" ]]; then return 0 fi print_info "开始编译 OpenWRT..." # 更新构建日期 sed -i "/BUILD_DATE/d" package/base-files/files/usr/lib/os-release sed -i "/BUILD_ID/aBUILD_DATE=\"$CURRENT_DATE\"" package/base-files/files/usr/lib/os-release # 开始编译 if ! make -j$CPU_CORES IGNORE_ERRORS="n m"; then error_exit "OpenWRT 编译失败" fi print_success "OpenWRT 编译完成" end_group } # 显示构建统计信息 show_build_stats() { local endtime=$(date +'%Y-%m-%d %H:%M:%S') local start_seconds=$(date --date="$starttime" +%s) local end_seconds=$(date --date="$endtime" +%s) local duration=$((end_seconds - start_seconds)) local minutes=$((duration / 60)) local seconds=$((duration % 60)) echo -e "" echo -e "${BOLD}${GREEN_COLOR}══════════════════════════════════════════════════════════════════════${RESET}" echo -e "${BOLD}🏁 ${GREEN_COLOR}构建完成!${RESET}" echo -e "${BOLD}⏰ ${GREEN_COLOR}开始时间:${RESET} $starttime" echo -e "${BOLD}⏱️ ${GREEN_COLOR}结束时间:${RESET} $endtime" echo -e "${BOLD}📊 ${GREEN_COLOR}总耗时:${RESET} ${minutes}分${seconds}秒" echo -e "${BOLD}📦 ${GREEN_COLOR}输出目录:${RESET} $(pwd)/bin/targets/" echo -e "${BOLD}${GREEN_COLOR}══════════════════════════════════════════════════════════════════════${RESET}" echo -e "" } # ============================================================================= # 主程序逻辑 # ============================================================================= main() { local version="${1:-}" local architecture="${2:-}" # 参数验证 validate_arguments "$version" "$architecture" # 显示横幅 show_banner # 环境验证 validate_environment # 环境设置 setup_build_environment setup_curl_progress setup_platform "$architecture" print_success "初始化完成,开始构建 $architecture 架构的 $version 版本" # 记录开始时间 START_TIME=$(date +%s) local starttime=$(date +'%Y-%m-%d %H:%M:%S') # 获取版本并克隆代码 local latest_version latest_version=$(get_latest_version) clone_source_code "$latest_version" # 更新 feeds update_feeds # 应用补丁 apply_patches # 下载工具链缓存(快速模式) download_toolchain_cache # 配置构建选项 configure_build # 编译工具链(如果需要) build_toolchain # 编译 OpenWRT build_openwrt # 显示统计信息 show_build_stats } # 脚本入口点 if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then # 如果没有提供足够的参数,显示使用帮助 if [[ $# -lt 2 ]]; then show_usage error_exit "参数不足,需要指定版本号和目标架构" fi # 执行主程序 main "$@" fi