#!/bin/bash # 跨平台编译脚本 # 支持编译多个操作系统和架构的版本 set -e # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 项目信息 PROJECT_NAME="agent" BUILD_DIR="bin" MAIN_PACKAGE="./cmd/agent" # 版本配置文件路径 VERSION_FILE="version.json" # 从版本配置文件读取版本信息 read_version_config() { local version_file="${VERSION_FILE}" if [ ! -f "$version_file" ]; then return 1 fi # 检查是否有 jq 命令 if command -v jq &> /dev/null; then local version=$(jq -r '.version' "$version_file" 2>/dev/null) if [ -n "$version" ] && [ "$version" != "null" ]; then echo "$version" return 0 fi else # 如果没有 jq,使用 grep 和 sed 解析 JSON local version=$(grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' "$version_file" 2>/dev/null | sed 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') if [ -n "$version" ]; then echo "$version" return 0 fi fi return 1 } # 初始化版本号(从配置文件读取,如果失败则使用时间戳) VERSION_CONFIG=$(read_version_config) if [ $? -eq 0 ] && [ -n "$VERSION_CONFIG" ]; then VERSION="${VERSION:-$VERSION_CONFIG}" else VERSION="${VERSION:-$(date +%Y%m%d-%H%M%S)}" fi # 支持的平台列表 # 格式: OS/ARCH PLATFORMS=( "linux/amd64" "linux/arm64" "darwin/amd64" "darwin/arm64" "windows/amd64" "windows/arm64" ) # 显示使用说明 usage() { echo -e "${BLUE}使用方法:${NC}" echo " $0 [选项]" echo "" echo -e "${BLUE}选项:${NC}" echo " -h, --help 显示帮助信息" echo " -p, --platform PLATFORM 只编译指定平台 (例如: linux/amd64)" echo " -l, --list 列出所有支持的平台" echo " -c, --clean 编译前清理输出目录" echo " -j, --jobs N 并行编译数量 (默认: 4)" echo " -v, --version VERSION 设置版本号 (默认: 从 version.json 读取)" echo " -s, --simple-only 只生成不带版本号的文件(默认生成两个)" echo "" echo -e "${BLUE}示例:${NC}" echo " $0 # 编译所有平台" echo " $0 -p linux/amd64 # 只编译 Linux AMD64" echo " $0 -j 2 # 使用2个并行任务" echo " $0 -c # 清理后编译" } # 列出所有平台 list_platforms() { echo -e "${BLUE}支持的平台:${NC}" for platform in "${PLATFORMS[@]}"; do echo " - $platform" done } # 清理输出目录 clean_build() { if [ -d "$BUILD_DIR" ]; then echo -e "${YELLOW}清理输出目录...${NC}" rm -rf "$BUILD_DIR" fi mkdir -p "$BUILD_DIR" } # 编译单个平台 build_platform() { local os_arch=$1 local simple_only=$2 # 是否只生成不带版本号的文件 local os=$(echo $os_arch | cut -d'/' -f1) local arch=$(echo $os_arch | cut -d'/' -f2) local output_path if [ "$simple_only" = "true" ]; then # 只生成不带版本号的文件 output_path="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}" if [ "$os" = "windows" ]; then output_path="${output_path}.exe" fi else # 生成带版本号的文件 output_path="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}-${VERSION}" if [ "$os" = "windows" ]; then output_path="${output_path}.exe" fi fi echo -e "${BLUE}[编译]${NC} ${os}/${arch} -> ${output_path}" if GOOS=$os GOARCH=$arch go build -ldflags "-s -w -X main.version=${VERSION}" \ -o "$output_path" "$MAIN_PACKAGE" 2>&1; then echo -e "${GREEN}[成功]${NC} ${os}/${arch}" # 如果不是只生成简单版本,则创建不带版本号的副本(方便使用) if [ "$simple_only" != "true" ]; then local simple_name="${BUILD_DIR}/${PROJECT_NAME}-${os}-${arch}" if [ "$os" = "windows" ]; then simple_name="${simple_name}.exe" fi cp "$output_path" "$simple_name" 2>/dev/null || true fi return 0 else echo -e "${RED}[失败]${NC} ${os}/${arch}" return 1 fi } # 主函数 main() { local selected_platforms=() local clean=false local jobs=4 local list_only=false local simple_only=false # 解析参数 while [[ $# -gt 0 ]]; do case $1 in -h|--help) usage exit 0 ;; -p|--platform) selected_platforms+=("$2") shift 2 ;; -l|--list) list_only=true shift ;; -c|--clean) clean=true shift ;; -j|--jobs) jobs="$2" shift 2 ;; -v|--version) VERSION="$2" shift 2 ;; -s|--simple-only) simple_only=true shift ;; *) echo -e "${RED}未知参数: $1${NC}" usage exit 1 ;; esac done # 如果只是列出平台,则退出 if [ "$list_only" = true ]; then list_platforms exit 0 fi # 确定要编译的平台 if [ ${#selected_platforms[@]} -eq 0 ]; then selected_platforms=("${PLATFORMS[@]}") else # 验证平台是否支持 for platform in "${selected_platforms[@]}"; do local found=false for p in "${PLATFORMS[@]}"; do if [ "$p" = "$platform" ]; then found=true break fi done if [ "$found" = false ]; then echo -e "${RED}错误: 不支持的平台 '$platform'${NC}" echo "" list_platforms exit 1 fi done fi # 清理(如果需要) if [ "$clean" = true ]; then clean_build else mkdir -p "$BUILD_DIR" fi echo -e "${GREEN}========================================${NC}" echo -e "${GREEN}开始跨平台编译${NC}" echo -e "${GREEN}========================================${NC}" echo -e "项目名称: ${BLUE}${PROJECT_NAME}${NC}" echo -e "版本号: ${BLUE}${VERSION}${NC}" echo -e "输出目录: ${BLUE}${BUILD_DIR}${NC}" echo -e "并行任务数: ${BLUE}${jobs}${NC}" echo -e "平台数量: ${BLUE}${#selected_platforms[@]}${NC}" echo "" # 导出函数和变量供后台任务使用 export -f build_platform export PROJECT_NAME BUILD_DIR VERSION MAIN_PACKAGE RED GREEN YELLOW BLUE NC # 使用后台任务进行并行编译 local success_count=0 local fail_count=0 local temp_file=$(mktemp) # 导出变量供后台任务使用 export simple_only # 启动编译任务 for platform in "${selected_platforms[@]}"; do ( if build_platform "$platform" "$simple_only"; then echo "SUCCESS $platform" >> "$temp_file" else echo "FAIL $platform" >> "$temp_file" fi ) & # 控制并行数量 while [ $(jobs -r | wc -l | tr -d ' ') -ge "$jobs" ]; do sleep 0.1 done done # 等待所有后台任务完成 wait # 统计结果 if [ -f "$temp_file" ]; then while IFS= read -r line; do if [[ $line == SUCCESS* ]]; then ((success_count++)) elif [[ $line == FAIL* ]]; then ((fail_count++)) fi done < "$temp_file" rm -f "$temp_file" fi echo "" echo -e "${GREEN}========================================${NC}" echo -e "${GREEN}编译完成${NC}" echo -e "${GREEN}========================================${NC}" echo -e "成功: ${GREEN}${success_count}${NC}" echo -e "失败: ${RED}${fail_count}${NC}" echo "" if [ $fail_count -eq 0 ]; then echo -e "${GREEN}所有平台编译成功!${NC}" echo "" echo -e "${BLUE}编译输出文件:${NC}" ls -lh "$BUILD_DIR" | grep "$PROJECT_NAME" | awk '{print " " $9 " (" $5 ")"}' else echo -e "${RED}部分平台编译失败,请检查错误信息${NC}" exit 1 fi } # 运行主函数 main "$@"