# Tetris Game - 统一构建系统 # 支持 Windows 和 macOS 应用打包,统一使用 dist 目录 # 基础配置 BINARY_NAME := tetris APP_NAME := TetrisGame VERSION := 1.0 BUILD_TIME := $(shell date '+%Y-%m-%d %H:%M:%S') GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") # 目录配置 DIST_DIR := dist ASSETS_DIR := assets BUILD_TEMP := .build_temp # Go 构建标志 GO_LDFLAGS := -ldflags "-s -w" GO_LDFLAGS_GUI := -ldflags "-s -w -H windowsgui" # 平台特定配置 WINDOWS_DIR := $(DIST_DIR)/windows MACOS_DIR := $(DIST_DIR)/macos LINUX_DIR := $(DIST_DIR)/linux # 版本文件名 WINDOWS_ZIP := $(APP_NAME)-Windows-v$(VERSION).zip MACOS_DMG := $(APP_NAME)-macOS-v$(VERSION).dmg LINUX_TAR := $(APP_NAME)-Linux-v$(VERSION).tar.gz # 颜色输出 BLUE := \033[34m GREEN := \033[32m YELLOW := \033[33m RED := \033[31m RESET := \033[0m .DEFAULT_GOAL := help # 帮助信息 .PHONY: help help: ## 显示帮助信息 @echo "$(BLUE)🎮 Tetris Game 构建系统$(RESET)" @echo "" @echo "$(GREEN)基础命令:$(RESET)" @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " $(YELLOW)%-20s$(RESET) %s\n", $$1, $$2}' $(MAKEFILE_LIST) @echo "" @echo "$(GREEN)示例:$(RESET)" @echo " make all # 构建所有平台" @echo " make windows # 仅构建 Windows 版本" @echo " make macos # 仅构建 macOS 版本" @echo " make clean # 清理所有构建文件" # 信息显示 .PHONY: info info: ## 显示构建信息 @echo "$(BLUE)📋 构建信息$(RESET)" @echo " 应用名称: $(APP_NAME)" @echo " 版本: v$(VERSION)" @echo " 构建时间: $(BUILD_TIME)" @echo " Git 提交: $(GIT_COMMIT)" @echo " Go 版本: $(shell go version)" @echo " 当前平台: $(shell go env GOOS)/$(shell go env GOARCH)" @echo " 分发目录: $(DIST_DIR)/" # 环境检查 .PHONY: check-env check-env: ## 检查构建环境 @echo "$(BLUE)🔍 环境检查$(RESET)" @go version >/dev/null 2>&1 || (echo "$(RED)❌ Go 未安装$(RESET)" && exit 1) @echo "$(GREEN)✅ Go 环境正常$(RESET)" @[ -d "$(ASSETS_DIR)" ] || (echo "$(RED)❌ assets 目录缺失$(RESET)" && exit 1) @echo "$(GREEN)✅ 资源目录存在$(RESET)" @[ -f "main.go" ] || (echo "$(RED)❌ main.go 文件缺失$(RESET)" && exit 1) @echo "$(GREEN)✅ 源代码文件存在$(RESET)" # 准备目录 .PHONY: prepare prepare: ## 准备构建目录 @echo "$(BLUE)📁 准备构建目录$(RESET)" @mkdir -p $(DIST_DIR) @mkdir -p $(WINDOWS_DIR) @mkdir -p $(MACOS_DIR) @mkdir -p $(LINUX_DIR) @mkdir -p $(BUILD_TEMP) # 清理 .PHONY: clean clean: ## 清理构建文件 @echo "$(BLUE)🧹 清理构建文件$(RESET)" @rm -rf $(DIST_DIR) @rm -rf $(BUILD_TEMP) @rm -f *.zip *.dmg *.tar.gz @rm -f $(BINARY_NAME) $(BINARY_NAME).exe @rm -rf TetrisGame.app @echo "$(GREEN)✅ 清理完成$(RESET)" # Windows 构建 .PHONY: build-windows-binary build-windows-binary: check-env prepare @echo "$(BLUE)🪟 构建 Windows 二进制文件$(RESET)" GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build $(GO_LDFLAGS_GUI) -o $(BUILD_TEMP)/$(APP_NAME).exe . @echo "$(GREEN)✅ Windows 二进制文件构建完成$(RESET)" .PHONY: create-windows-startup-script create-windows-startup-script: @echo "创建 Windows 启动脚本..." @echo '@echo off' > $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'chcp 65001 >nul' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo 🎮 正在启动 Tetris Game...' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo.' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo 🎯 游戏控制:' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo ←→ 左右移动' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo ↑ 旋转方块' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo ↓ 快速下降' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo 空格 瞬间下降' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo L 切换中英文' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo 'echo.' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat @echo '"%~dp0$(APP_NAME).exe"' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/启动游戏.bat .PHONY: create-windows-docs create-windows-docs: @echo "创建 Windows 说明文档..." @echo '🎮 Tetris Game - Windows Version v1.0' > $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt @echo '' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt @echo '📥 Installation: This is a portable version, no installation required.' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt @echo '🚀 How to Start: Double-click TetrisGame.exe or 启动游戏.bat' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt @echo '🎯 Game Controls: ←→ Move, ↑ Rotate, ↓ Soft drop, Space Hard drop, L Language' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt @echo '🔧 System Requirements: Windows 10/11 (64-bit)' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt @echo '' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt @echo '© 2025 Tetris Game. All rights reserved.' >> $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/README.txt .PHONY: package-windows package-windows: build-windows-binary @echo "$(BLUE)📦 打包 Windows 应用$(RESET)" # 创建 Windows 应用目录 @rm -rf $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION) @mkdir -p $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION) # 复制主程序文件 @cp $(BUILD_TEMP)/$(APP_NAME).exe $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/ # 复制资源文件 @cp -r $(ASSETS_DIR) $(WINDOWS_DIR)/$(APP_NAME)-Windows-v$(VERSION)/ # 创建启动脚本和文档 @$(MAKE) create-windows-startup-script @$(MAKE) create-windows-docs # 创建压缩包 @cd $(WINDOWS_DIR) && zip -r ../$(WINDOWS_ZIP) $(APP_NAME)-Windows-v$(VERSION)/ @echo "$(GREEN)✅ Windows 应用打包完成: $(DIST_DIR)/$(WINDOWS_ZIP)$(RESET)" # macOS 构建 .PHONY: build-macos-binary build-macos-binary: check-env prepare @echo "$(BLUE)🍎 构建 macOS 二进制文件$(RESET)" go build $(GO_LDFLAGS) -o $(BUILD_TEMP)/$(BINARY_NAME) . @echo "$(GREEN)✅ macOS 二进制文件构建完成$(RESET)" .PHONY: create-macos-plist create-macos-plist: @echo "创建 macOS Info.plist..." @echo '' > $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' CFBundleDisplayName' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' 俄罗斯方块' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' CFBundleExecutable' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' $(BINARY_NAME)' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' CFBundleIdentifier' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' com.tetrisgame.app' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' CFBundleName' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' $(APP_NAME)' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' CFBundleShortVersionString' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' $(VERSION)' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' CFBundleIconFile' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' app' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' LSApplicationCategoryType' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo ' public.app-category.games' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist @echo '' >> $(MACOS_DIR)/$(APP_NAME).app/Contents/Info.plist .PHONY: create-dmg create-dmg: @echo "创建 DMG 文件..." @DMG_SIZE="50m" && \ TEMP_DMG="$(BUILD_TEMP)/temp_$(MACOS_DMG)" && \ MOUNT_POINT="$(BUILD_TEMP)/dmg_mount" && \ rm -rf $$MOUNT_POINT && \ mkdir -p $$MOUNT_POINT && \ hdiutil create -size $$DMG_SIZE -fs HFS+ -volname "Tetris Game" $$TEMP_DMG && \ hdiutil attach $$TEMP_DMG -mountpoint $$MOUNT_POINT && \ cp -R $(MACOS_DIR)/$(APP_NAME).app $$MOUNT_POINT/ && \ ln -s /Applications $$MOUNT_POINT/Applications && \ hdiutil detach $$MOUNT_POINT && \ hdiutil convert $$TEMP_DMG -format UDZO -o $(DIST_DIR)/$(MACOS_DMG) && \ rm -f $$TEMP_DMG .PHONY: package-macos package-macos: build-macos-binary @echo "$(BLUE)📦 打包 macOS 应用$(RESET)" # 创建 .app 包结构 @rm -rf $(MACOS_DIR)/$(APP_NAME).app @mkdir -p $(MACOS_DIR)/$(APP_NAME).app/Contents/MacOS @mkdir -p $(MACOS_DIR)/$(APP_NAME).app/Contents/Resources # 复制可执行文件 @cp $(BUILD_TEMP)/$(BINARY_NAME) $(MACOS_DIR)/$(APP_NAME).app/Contents/MacOS/ @chmod +x $(MACOS_DIR)/$(APP_NAME).app/Contents/MacOS/$(BINARY_NAME) # 复制资源文件 @cp -r $(ASSETS_DIR) $(MACOS_DIR)/$(APP_NAME).app/Contents/Resources/ # 创建 Info.plist @$(MAKE) create-macos-plist # 复制应用图标 @if [ -f "$(ASSETS_DIR)/icons/app.icns" ]; then \ cp "$(ASSETS_DIR)/icons/app.icns" $(MACOS_DIR)/$(APP_NAME).app/Contents/Resources/; \ echo "$(GREEN)✅ 已复制应用图标 app.icns$(RESET)"; \ else \ echo "$(YELLOW)⚠️ 图标文件 $(ASSETS_DIR)/icons/app.icns 不存在$(RESET)"; \ fi # 创建 DMG @$(MAKE) create-dmg @echo "$(GREEN)✅ macOS 应用打包完成: $(DIST_DIR)/$(MACOS_DMG)$(RESET)" # Linux 构建 .PHONY: build-linux-binary build-linux-binary: check-env prepare @echo "$(BLUE)🐧 构建 Linux 二进制文件$(RESET)" @echo "$(YELLOW)⚠️ 注意: Linux 交叉编译需要 CGO 支持,建议在 Linux 系统上构建$(RESET)" @if [ "$$(go env GOOS)" = "linux" ]; then \ go build $(GO_LDFLAGS) -o $(BUILD_TEMP)/$(BINARY_NAME)_linux .; \ else \ echo "$(YELLOW)⚠️ 当前不在 Linux 系统,跳过 Linux 构建$(RESET)"; \ mkdir -p $(BUILD_TEMP); \ echo "# Linux 构建需要在 Linux 系统上进行" > $(BUILD_TEMP)/$(BINARY_NAME)_linux.txt; \ fi @echo "$(GREEN)✅ Linux 二进制文件构建完成$(RESET)" .PHONY: package-linux package-linux: build-linux-binary @echo "$(BLUE)📦 打包 Linux 应用$(RESET)" @if [ "$$(go env GOOS)" = "linux" ] && [ -f "$(BUILD_TEMP)/$(BINARY_NAME)_linux" ]; then \ echo "正在打包 Linux 应用..."; \ rm -rf $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION); \ mkdir -p $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION); \ cp $(BUILD_TEMP)/$(BINARY_NAME)_linux $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/$(BINARY_NAME); \ chmod +x $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/$(BINARY_NAME); \ cp -r $(ASSETS_DIR) $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/; \ echo '#!/bin/bash' > $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ echo 'echo "🎮 Starting Tetris Game..."' >> $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ echo 'cd "$$(dirname "$$0")"' >> $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ echo './$(BINARY_NAME)' >> $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ chmod +x $(LINUX_DIR)/$(APP_NAME)-Linux-v$(VERSION)/start_game.sh; \ cd $(LINUX_DIR) && tar -czf ../$(LINUX_TAR) $(APP_NAME)-Linux-v$(VERSION)/; \ echo "$(GREEN)✅ Linux 应用打包完成: $(DIST_DIR)/$(LINUX_TAR)$(RESET)"; \ else \ echo "$(YELLOW)⚠️ 跳过 Linux 打包(需要在 Linux 系统上构建)$(RESET)"; \ mkdir -p $(LINUX_DIR); \ echo "# Linux 版本需要在 Linux 系统上构建" > $(LINUX_DIR)/README.txt; \ echo "$(YELLOW)⚠️ Linux 版本跳过$(RESET)"; \ fi # 主要构建目标 .PHONY: windows windows: package-windows ## 构建 Windows 版本 .PHONY: macos macos: package-macos ## 构建 macOS 版本 .PHONY: linux linux: package-linux ## 构建 Linux 版本 .PHONY: all all: clean windows macos ## 构建所有支持的平台版本 @if [ "$$(go env GOOS)" = "linux" ]; then \ $(MAKE) linux; \ else \ echo "$(YELLOW)⚠️ 当前平台不支持 Linux 交叉编译,跳过 Linux 构建$(RESET)"; \ fi @echo "" @echo "$(GREEN)🎉 所有平台构建完成!$(RESET)" @echo "" @echo "$(BLUE)📋 构建结果:$(RESET)" @ls -lh $(DIST_DIR)/*.zip $(DIST_DIR)/*.dmg $(DIST_DIR)/*.tar.gz 2>/dev/null || true # 验证和测试 .PHONY: verify verify: ## 验证构建结果 @echo "$(BLUE)🔍 验证构建结果$(RESET)" @echo "" @echo "$(GREEN)构建文件:$(RESET)" @ls -lh $(DIST_DIR)/ 2>/dev/null || echo "无构建文件" @echo "" @if [ -f "$(DIST_DIR)/$(WINDOWS_ZIP)" ]; then \ echo "$(GREEN)✅ Windows 版本: $(WINDOWS_ZIP)$(RESET)"; \ unzip -l $(DIST_DIR)/$(WINDOWS_ZIP) | head -10; \ fi @if [ -f "$(DIST_DIR)/$(MACOS_DMG)" ]; then \ echo "$(GREEN)✅ macOS 版本: $(MACOS_DMG)$(RESET)"; \ fi @if [ -f "$(DIST_DIR)/$(LINUX_TAR)" ]; then \ echo "$(GREEN)✅ Linux 版本: $(LINUX_TAR)$(RESET)"; \ fi # 开发相关 .PHONY: run run: ## 运行游戏(开发模式) @echo "$(BLUE)🎮 启动游戏$(RESET)" go run . .PHONY: test test: ## 运行测试 @echo "$(BLUE)🧪 运行测试$(RESET)" go test -v ./... .PHONY: deps deps: ## 下载依赖 @echo "$(BLUE)📦 下载依赖$(RESET)" go mod download go mod tidy