#!/bin/bash
set -e
# 断点续传编译脚本
# ============ 环境变量与配置(彻底远离 src 目录) ============
WORK_DIR="/root"
CHROMIUM_DIR="$WORK_DIR/chromium"
SRC_DIR="$CHROMIUM_DIR/src"
DEPOT_TOOLS_DIR="$WORK_DIR/depot_tools"
# 核心安全区:将所有自定义状态和脚本放在 chromium 根目录下,防 gclient sync 抹除
STATE_DIR="$CHROMIUM_DIR/.build_state"
BUILD_SCRIPT="$CHROMIUM_DIR/build_headless.sh"
TAG_VERSION="108.0.5359.125"
# ============ 辅助函数 ============
mkdir -p "$STATE_DIR"
check_step() {
local step_name="$1"
local state_file="$STATE_DIR/$step_name"
if [ -f "$state_file" ]; then
echo "✅ 步骤 [$step_name] 已完成,跳过。"
return 0
else
echo "🔄 开始执行步骤 [$step_name]..."
return 1
fi
}
mark_step_done() {
local step_name="$1"
touch "$STATE_DIR/$step_name"
echo "✅ 步骤 [$step_name] 完成并标记。"
}
retry_command() {
local max_retries=5
local retry_count=0
local wait_time=30
until "$@"; do
retry_count=$((retry_count+1))
if [ $retry_count -ge $max_retries ]; then
echo "❌ 命令执行失败,已重试 $max_retries 次: $1"
return 1
fi
echo "⚠️ 命令失败,${wait_time}秒后进行第 $retry_count 次重试..."
sleep $wait_time
wait_time=$((wait_time * 2))
done
return 0
}
# 验证源码完整性
verify_src_integrity() {
if [ ! -f "$SRC_DIR/build/install-build-deps.sh" ]; then
echo "❌ 源码目录关键文件缺失,需要重新同步"
return 1
fi
if [ ! -d "$SRC_DIR/third_party" ]; then
echo "❌ third_party 目录缺失,需要重新同步"
return 1
fi
return 0
}
# ============ 步骤 1: 克隆 depot_tools ============
cd $WORK_DIR
if ! check_step "clone_depot_tools"; then
if [ -d "$DEPOT_TOOLS_DIR" ]; then
echo "⚠️ depot_tools 目录已存在但不完整,删除重建..."
rm -rf "$DEPOT_TOOLS_DIR"
fi
retry_command git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
if ! grep -q "depot_tools" ~/.bashrc; then
echo "export PATH=\"\$PATH:$DEPOT_TOOLS_DIR\"" >> ~/.bashrc
fi
mark_step_done "clone_depot_tools"
fi
export PATH="$PATH:$DEPOT_TOOLS_DIR"
# ============ 步骤 2: Fetch Chromium 源码 ============
if ! check_step "fetch_chromium"; then
# 容错:清除可能导致 fetch 锁死的全局残留配置
rm -f "$CHROMIUM_DIR/.gclient" "$WORK_DIR/.gclient" "$WORK_DIR/.gclient_entries"
# 如果目录已存在但不完整,删除重建
if [ -d "$CHROMIUM_DIR" ] && ! verify_src_integrity; then
echo "⚠️ Chromium 目录存在但不完整,删除重建..."
rm -rf "$CHROMIUM_DIR"
fi
mkdir -p $CHROMIUM_DIR
cd $CHROMIUM_DIR
retry_command fetch --no-history chromium
# 验证 fetch 是否成功
if ! verify_src_integrity; then
echo "❌ fetch 后源码验证失败,请检查网络连接和磁盘空间"
exit 1
fi
mark_step_done "fetch_chromium"
fi
# ============ 步骤 3: 切换标签并同步 ============
cd $SRC_DIR
if ! check_step "checkout_tag"; then
echo "📌 获取指定版本标签: $TAG_VERSION..."
# 使用标准 refs 路径获取标签(兼容所有 git 版本)
if ! retry_command git fetch origin "refs/tags/${TAG_VERSION}:refs/tags/${TAG_VERSION}" --depth 1 2>/dev/null; then
echo "⚠️ 浅克隆获取标签失败,尝试获取所有 108 标签..."
git fetch --tags origin "refs/tags/108.*:refs/tags/108.*" --depth 1
fi
# 验证标签是否存在
if ! git tag -l | grep -q "$TAG_VERSION"; then
echo "❌ 标签 $TAG_VERSION 获取失败"
echo "尝试最终手段:不带 depth 限制获取..."
git fetch origin "refs/tags/${TAG_VERSION}:refs/tags/${TAG_VERSION}"
fi
echo "🔀 切换到标签: $TAG_VERSION"
git checkout -f "refs/tags/$TAG_VERSION"
echo "🔄 同步依赖到 $TAG_VERSION 版本..."
retry_command gclient sync \
--with_branch_heads \
--with_tags \
--delete_unversioned_trees \
--force \
-f -D
# 验证同步后源码完整性
if ! verify_src_integrity; then
echo "⚠️ 同步后源码不完整,尝试深度同步..."
gclient sync --with_branch_heads --with_tags -f -D --delete_unversioned_trees --force
if ! verify_src_integrity; then
echo "❌ 源码完整性验证失败,请检查磁盘空间和网络"
exit 1
fi
fi
mark_step_done "checkout_tag"
fi
# ============ 步骤 4: 安装依赖 ============
if ! check_step "install_deps"; then
cd $SRC_DIR
echo "📦 安装系统依赖..."
retry_command ./build/install-build-deps.sh --unsupported
echo "🔧 运行 gclient runhooks..."
retry_command gclient runhooks
# 验证工具链是否安装完整
if [ ! -d "$SRC_DIR/third_party/llvm-build" ]; then
echo "⚠️ 工具链缺失,重新运行 hooks..."
gclient runhooks --force
fi
mark_step_done "install_deps"
fi
# ============ 步骤 5: 创建独立的编译脚本 ============
echo "📝 在安全区创建/更新编译脚本..."
cat << 'SCRIPT_EOF' > $BUILD_SCRIPT
#!/bin/bash
set -e
CHROMIUM_DIR="/root/chromium"
SRC_DIR="$CHROMIUM_DIR/src"
OUT_DIR="$SRC_DIR/out/HeadlessUngoogled"
BUILD_TARGET="headless_shell"
STATE_DIR="$CHROMIUM_DIR/.build_state"
cd $SRC_DIR
# ============ 编译前完整性检查 ============
echo "=== 0. 编译环境完整性检查 ==="
# 检查工具链
if [ ! -d "$SRC_DIR/third_party/llvm-build" ]; then
echo "⚠️ 工具链缺失,重新同步依赖..."
cd $SRC_DIR
gclient sync --with_branch_heads --with_tags -f -D --delete_unversioned_trees
gclient runhooks
fi
# 检查 gn 工具是否可用
if ! command -v gn &> /dev/null; then
echo "❌ gn 工具未找到,请检查 depot_tools 路径"
exit 1
fi
# 检查磁盘空间(至少需要 20GB)
AVAILABLE_SPACE=$(df -BG "$SRC_DIR" | tail -1 | awk '{print $4}' | sed 's/G//')
if [ "$AVAILABLE_SPACE" -lt 20 ]; then
echo "⚠️ 可用磁盘空间不足 20GB(当前: ${AVAILABLE_SPACE}GB),编译可能失败"
fi
# ============ 智能检查编译配置 ============
NEED_REGENERATE=false
if [ ! -f "$OUT_DIR/build.ninja" ]; then
echo "📋 build.ninja 不存在,需要生成"
NEED_REGENERATE=true
elif [ "$OUT_DIR/args.gn" -nt "$OUT_DIR/build.ninja" ]; then
echo "📋 args.gn 已更新,需要重新生成"
NEED_REGENERATE=true
elif [ ! -f "$STATE_DIR/gn_generated" ]; then
echo "📋 状态标记缺失,重新生成确保一致性"
NEED_REGENERATE=true
fi
if [ "$NEED_REGENERATE" = true ]; then
echo "=== 1. 生成 108 版本兼容的 args.gn ==="
mkdir -p $OUT_DIR
cat <<GN > $OUT_DIR/args.gn
# ============ 基础编译设置 ============
is_debug = false
is_component_build = false
symbol_level = 0
dcheck_always_on = false
# ============ Headless 模式核心 ============
headless = true
use_ozone = true
ozone_platform_headless = true
# ============ Mojo / Media / MSE(网页抓流必需) ============
use_mojo = true
enable_mse = true
enable_media = true
enable_library_loader = true
enable_media_remoting = false
# ============ 视频解码器(支持 TS/MP4 等) ============
ffmpeg_branding = "Chrome"
proprietary_codecs = true
enable_hevc_demuxing = true
# ============ 去 Google 化服务对接 ============
use_official_google_api_keys = false
google_api_key = "no"
google_default_client_id = "no"
google_default_client_secret = "no"
enable_remoting = false
# ============ 关闭无用服务 ============
enable_nacl = false
enable_mdns = false
enable_service_discovery = false
enable_hangout_services_extension = false
enable_reporting = false
enable_crashpad = false
enable_webrtc = false
# ============ 构建环境优化 ============
use_sysroot = true
target_cpu = "x64"
use_lld = true
use_thin_lto = false
treat_warnings_as_errors = false
GN
echo "=== 2. 运行 gn gen 生成构建文件 ==="
gn gen $OUT_DIR
mkdir -p "$STATE_DIR"
touch "$STATE_DIR/gn_generated"
echo "✅ Ninja 构建文件生成完毕"
else
echo "✅ Ninja 文件无变更,跳过 gn gen"
fi
# ============ 编译主体 ============
echo "=== 3. 使用 autoninja 编译(安全断点续编)==="
echo "💡 如果过程中断,直接重新运行: $0"
echo "📊 当前可用磁盘空间: ${AVAILABLE_SPACE}GB"
# 记录编译开始时间
COMPILE_START=$(date +%s)
if autoninja -C $OUT_DIR $BUILD_TARGET; then
COMPILE_END=$(date +%s)
COMPILE_TIME=$((COMPILE_END - COMPILE_START))
echo "=============================================="
echo " 🎉 编译成功!"
echo " ⏱️ 总耗时: $((COMPILE_TIME / 60)) 分 $((COMPILE_TIME % 60)) 秒"
echo " 📂 产物路径: $OUT_DIR/$BUILD_TARGET"
echo " 📏 产物大小: $(du -h $OUT_DIR/$BUILD_TARGET | cut -f1)"
echo "=============================================="
# 创建成功标记
touch "$STATE_DIR/build_success"
else
COMPILE_END=$(date +%s)
COMPILE_TIME=$((COMPILE_END - COMPILE_START))
echo "=============================================="
echo " ❌ 编译失败"
echo " ⏱️ 已耗时: $((COMPILE_TIME / 60)) 分 $((COMPILE_TIME % 60)) 秒"
echo "=============================================="
echo " 💡 故障排查建议:"
echo " 1. 检查磁盘空间: df -h"
echo " 2. 检查内存使用: free -h"
echo " 3. 重新同步依赖: cd $SRC_DIR && gclient sync -f -D"
echo " 4. 清理后重编: rm -rf $OUT_DIR && $0"
echo " 5. 单线程编译排查: autoninja -C $OUT_DIR $BUILD_TARGET -j 1"
exit 1
fi
SCRIPT_EOF
chmod +x $BUILD_SCRIPT
# ============ 步骤 6: 执行编译 ============
echo ""
echo "=============================================="
echo " 🚀 环境准备就绪,拉起独立编译进程"
echo "=============================================="
echo " 📂 安全区编译脚本: $BUILD_SCRIPT"
echo " 📂 状态标记目录: $STATE_DIR"
echo " 🏷️ 目标版本: Chromium $TAG_VERSION"
echo "=============================================="
echo " 💡 提示:"
echo " - 编译中断后直接运行: $BUILD_SCRIPT"
echo " - 完全重新编译: rm -rf $STATE_DIR && $BUILD_SCRIPT"
echo " - 查看编译进度: tail -f $SRC_DIR/out/HeadlessUngoogled/.ninja_log"
echo "=============================================="
echo ""
$BUILD_SCRIPT
No Comments