name: Build Custom WRT on: workflow_dispatch: inputs: project: description: "选择 WRT 项目" required: true default: "immortalwrt" type: choice options: - openwrt - immortalwrt - x-wrt - lienol - lede version_type: description: "版本类型" required: true default: "stable" type: choice options: - "snapshot" - "stable" branch: description: "snapshot-branch" required: false default: "master" type: string tag: description: "stable-tag" required: false default: "v24.10.2" type: string config_path: description: "config 路径" required: true default: "config/myconfig" type: string threads: description: "编译线程数(留空或填写 0 则自动使用 nproc)" required: false default: "0" type: string jobs: build: runs-on: ubuntu-latest steps: - name: Checkout current repository uses: actions/checkout@v4 - name: Determine Git ref id: refinfo run: | if [ "${{ inputs.version_type }}" = "snapshot" ]; then echo "ref=${{ inputs.branch }}" >> $GITHUB_OUTPUT else echo "ref=${{ inputs.tag }}" >> $GITHUB_OUTPUT fi - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential clang flex bison g++ gawk gettext git \ libncurses-dev libssl-dev python3 python3-dev python3-setuptools \ rsync unzip zlib1g-dev file wget curl \ gzip tar zip xz-utils bzip2 zstd \ make cmake autoconf automake libtool patch diffutils \ findutils grep sed help2man texinfo \ libelf-dev libfuse-dev liblzma-dev libxml2-dev libyaml-dev \ uuid-dev device-tree-compiler antlr3 gperf \ time bc jq xxd swig upx-ucl ccache ecj fastjar imagemagick \ llvm linux-tools-common libbpf-dev linux-tools-$(uname -r) - name: Determine Git URL id: projectinfo run: | case "${{ inputs.project }}" in immortalwrt) echo "url=https://github.com/immortalwrt/immortalwrt.git" >> $GITHUB_OUTPUT ;; x-wrt) echo "url=https://github.com/x-wrt/x-wrt.git" >> $GITHUB_OUTPUT ;; openwrt) echo "url=https://git.openwrt.org/openwrt/openwrt.git" >> $GITHUB_OUTPUT ;; lienol) echo "url=https://github.com/Lienol/openwrt.git" >> $GITHUB_OUTPUT ;; lede) echo "url=https://github.com/coolsnowwolf/lede.git" >> $GITHUB_OUTPUT ;; *) echo "❌ 未知项目: ${{ inputs.project }}" >&2 exit 1 ;; esac - name: Clone repository run: | echo "📥 克隆 ${{ inputs.project }} 仓库" git clone "${{ steps.projectinfo.outputs.url }}" wrt cd wrt echo "🔖 切换到版本:${{ steps.refinfo.outputs.ref }}" git checkout "${{ steps.refinfo.outputs.ref }}" - name: Copy diy.sh run: | echo "📂 复制 diy.sh 到 wrt 目录" cp diy.sh wrt/diy.sh - name: Run diy.sh working-directory: wrt run: | echo "🔧 执行 diy.sh" chmod +x diy.sh ./diy.sh - name: Update and install feeds working-directory: wrt run: | echo "📦 更新 feeds" ./scripts/feeds update -a echo "📦 安装 feeds" ./scripts/feeds install -a - name: Setup configuration run: | echo "📋 复制配置:${{ inputs.config_path }} → wrt/.config" if [ ! -f "${{ inputs.config_path }}" ]; then echo "❌ 找不到配置文件:${{ inputs.config_path }}" exit 1 fi cp "${{ inputs.config_path }}" wrt/.config # 校验 .config 是否与原始配置完全相同 if cmp -s "${{ inputs.config_path }}" wrt/.config; then echo "✅ .config 与 ${{ inputs.config_path }} 完全一致" else echo "❌ .config 与 ${{ inputs.config_path }} 不一致,输出差异:" diff -u "${{ inputs.config_path }}" wrt/.config || true exit 1 fi cd wrt echo "🔄 运行 make oldconfig" make oldconfig - name: Download source packages working-directory: wrt run: | echo "⬇️ 下载所有源码包" if [ "${{ inputs.threads }}" = "0" ] || [ -z "${{ inputs.threads }}" ]; then JOBS=$(nproc) else JOBS=${{ inputs.threads }} fi set -o pipefail if ! make download -j${JOBS}; then echo "⚠️ 多线程下载失败,尝试单线程下载..." make download -j1 fi - name: Build Firmware working-directory: wrt run: | if [ "${{ inputs.threads }}" = "0" ] || [ -z "${{ inputs.threads }}" ]; then JOBS=$(nproc) else JOBS=${{ inputs.threads }} fi echo "🚀 全量编译(并行 ${JOBS})开始" START=$(date "+%Y-%m-%d %H:%M:%S") echo "⏱️ 编译开始:${START}" set -o pipefail # 第一次尝试多线程编译,并保存日志 if ! (time make world -j${JOBS} 2>&1 | tee world_debug.log); then echo "⚠️ 多线程编译失败,尝试使用单线程并输出详细信息..." # 单线程模式输出详细信息,并追加到同一日志 time make world -j1 V=s 2>&1 | tee -a world_debug.log echo "❌ 单线程编译后依然失败,以下是匹配关键字的错误行:" grep -E -i "(error:|failed|fatal|cannot install package)" -n world_debug.log || true exit 1 fi END=$(date "+%Y-%m-%d %H:%M:%S") echo "✅ 编译成功" echo "⏱️ 编译结束:${END}" - name: list all target files run: | echo ">>> 打印 wrt/bin/targets 下所有文件:" if [ -d wrt/bin/targets ]; then find wrt/bin/targets -type f | sed 's/^/ - /' else echo "❗ wrt/bin/targets 目录不存在" fi - name: Upload firmware artifacts uses: actions/upload-artifact@v4 with: name: ${{ inputs.project }}-output path: | wrt/bin/targets/**/*.img wrt/bin/targets/**/*.bin wrt/bin/targets/**/*.tar.gz wrt/bin/targets/**/*.zip if-no-files-found: warning - name: Upload build log uses: actions/upload-artifact@v4 with: name: ${{ inputs.project }}-build-log path: wrt/world_debug.log