#!/bin/bash set -e # 安装 Image Builder 构建所需依赖 install_dependencies() { apt install -y build-essential libncurses-dev zlib1g-dev gawk git \ gettext libssl-dev xsltproc rsync wget unzip python3 qemu-utils mkisofs zstd } # 下载并解压 x86-64 的 Image Builder # 参数 1: ImmortalWrt 版本号,例如 25.12.0 # 输出: 解压的后 Image Builder 目录绝对路径 download_imagebuilder() { local version="$1" local file="immortalwrt-imagebuilder-$version-x86-64.Linux-x86_64.tar.zst" local url="https://downloads.immortalwrt.org/releases/$version/targets/x86/64/$file" local folder="immortalwrt-imagebuilder-$version-x86-64.Linux-x86_64" local marker="$folder/.ready" if [ -f "$marker" ]; then echo "$(pwd)/$folder" return 0 fi # 如果目录存在但不完整,清理 if [ -d "$folder" ] && [ ! -f "$marker" ]; then echo "[WARN] found incomplete folder, cleaning..." >&2 rm -rf "$folder" fi # 下载(强制覆盖) wget -O "$file" "$url" >&2 # 解压 tar -I zstd -xvf "$file" >&2 touch "$marker" echo "$(pwd)/$folder" } build(){ # ──────────────────────────────────────────── # 设备 Profile # 运行 `make info` 查看所有可用 profile # ──────────────────────────────────────────── PROFILE="generic" # x86_64 通用 profile,可改为 x86_64 等 # ──────────────────────────────────────────── # 自定义文件目录(映射到固件根文件系统) # ──────────────────────────────────────────── FILES_DIR="files" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" BUILDER_DIR="${1}" # ──────────────────────────────────────────── # 固件输出目录 # ──────────────────────────────────────────── OUTPUT_DIR="$BUILDER_DIR/output" PROJECT_OUTPUT_DIR="$SCRIPT_DIR/output" # ──────────────────────────────────────────── # 固件文件名附加标识(可留空) # ──────────────────────────────────────────── EXTRA_IMAGE_NAME="" # ============================================================= # 插件包列表 # - 前面加 - 表示从固件中移除该包,例如 -dnsmasq # - 每行一个,方便增删注释 # ============================================================= PKG_LIST=( -dropbear openssh-server openssh-sftp-server vim-full nano-plus bash shadow-chsh luci-i18n-vlmcsd-zh-cn luci-i18n-argon-config-zh-cn luci-i18n-package-manager-zh-cn luci-i18n-firewall-zh-cn luci-i18n-arpbind-zh-cn luci-i18n-ttyd-zh-cn # 现代终端工具 ripgrep diffutils less eza fish # 分区扩容 luci-i18n-diskman-zh-cn cfdisk resize2fs e2fsprogs losetup # 代理插件 luci-i18n-daed-zh-cn luci-i18n-homeproxy-zh-cn sing-box ) # 动态拼接成字符串 PACKAGES=$(printf "%s " "${PKG_LIST[@]}") # 颜色输出 GREEN="\033[0;32m" YELLOW="\033[1;33m" RED="\033[0;31m" NC="\033[0m" echo -e "${GREEN}========================================${NC}" echo -e "${GREEN} OpenWrt Image Builder 开始构建${NC}" echo -e "${GREEN}========================================${NC}" echo -e " Profile : ${YELLOW}${PROFILE}${NC}" echo -e " Files 目录 : ${YELLOW}${FILES_DIR}${NC}" echo -e " 输出目录 : ${YELLOW}${OUTPUT_DIR}${NC}" echo -e " 项目输出目录: ${YELLOW}${PROJECT_OUTPUT_DIR}${NC}" echo -e " 镜像标识 : ${YELLOW}${EXTRA_IMAGE_NAME}${NC}" echo "" # 切换到 Image Builder 目录 cd "$BUILDER_DIR" # 复制 files 目录下的自定义文件到 Image Builder 的 files 目录 cp ${SCRIPT_DIR}/files/* $BUILDER_DIR/files/ -rf # 修改.config文件, 不构建以下格式固件 sed -i \ -e 's/^CONFIG_ISO_IMAGES=y/# CONFIG_ISO_IMAGES is not set/' \ -e 's/^CONFIG_QCOW2_IMAGES=y/# CONFIG_QCOW2_IMAGES is not set/' \ -e 's/^CONFIG_VDI_IMAGES=y/# CONFIG_VDI_IMAGES is not set/' \ -e 's/^CONFIG_VMDK_IMAGES=y/# CONFIG_VMDK_IMAGES is not set/' \ -e 's/^CONFIG_VHDX_IMAGES=y/# CONFIG_VHDX_IMAGES is not set/' \ .config # 检查是否在 imagebuilder 目录下 if [ ! -f "Makefile" ]; then echo -e "${RED}[错误] 未找到 Makefile,请在 imagebuilder 根目录下运行本脚本!${NC}" exit 1 fi # 创建 files 目录(如果不存在) if [ ! -d "$FILES_DIR" ]; then echo -e "${YELLOW}[提示] files/ 目录不存在,已自动创建${NC}" mkdir -p "$FILES_DIR" fi mkdir -p "$OUTPUT_DIR" # 执行构建 make image \ PROFILE="$PROFILE" \ PACKAGES="$PACKAGES" \ FILES="$FILES_DIR" \ BIN_DIR="$OUTPUT_DIR" \ EXTRA_IMAGE_NAME="$EXTRA_IMAGE_NAME" # 构建结果判断 if [ $? -eq 0 ]; then if [ "$OUTPUT_DIR" != "$PROJECT_OUTPUT_DIR" ]; then if [ ! -d "$OUTPUT_DIR" ]; then echo -e "${RED} 未找到构建输出目录: ${OUTPUT_DIR}${NC}" exit 1 fi if [ -e "$PROJECT_OUTPUT_DIR" ]; then BACKUP_OUTPUT_DIR="${PROJECT_OUTPUT_DIR}.bak.$(date +%Y%m%d%H%M%S)" if ! mv "$PROJECT_OUTPUT_DIR" "$BACKUP_OUTPUT_DIR"; then echo -e "${RED} 备份已有输出目录失败: ${PROJECT_OUTPUT_DIR}${NC}" exit 1 fi echo -e "${YELLOW} 已有输出目录,已备份到: ${BACKUP_OUTPUT_DIR}${NC}" fi if ! mv "$OUTPUT_DIR" "$PROJECT_OUTPUT_DIR"; then echo -e "${RED} 移动构建输出目录失败: ${OUTPUT_DIR} -> ${PROJECT_OUTPUT_DIR}${NC}" exit 1 fi fi echo "" echo -e "${GREEN}========================================${NC}" echo -e "${GREEN} 构建成功!${NC}" echo -e "${GREEN} 固件路径: ${PROJECT_OUTPUT_DIR}${NC}" echo -e "${GREEN}========================================${NC}" else echo "" echo -e "${RED}========================================${NC}" echo -e "${RED} 构建失败,请检查上方错误日志${NC}" echo -e "${RED}========================================${NC}" exit 1 fi } # 项目根目录,用来保证从任意位置执行 main.sh 都能找到其他脚本 project_dir="$(cd "$(dirname "$0")" && pwd)" cd "$project_dir" # 要构建的 ImmortalWrt 版本, 可以在 https://github.com/immortalwrt/immortalwrt 查询版本号 version="25.12.0" # 安装依赖 install_dependencies # 下载并解压 Image Builder,返回解压后的目录路径 builder_dir="$(download_imagebuilder "$version")" # 构建固件 build $builder_dir