makefile
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMakefile Mode
Makefile 模式
Create and manage Makefiles optimized for AI agent interaction and process lifecycle management.
创建并优化Makefile,以适配AI Agent交互和进程生命周期管理。
Core Philosophy
核心理念
"Start clean. Stop clean. Log everything. Know your state."
Principles:
- AI-agent first: Outputs readable programmatically (no interactive prompts)
- Background by default: Services run detached; read logs, don't spawn terminals
- Comprehensive logging: All output to files at - nothing lost
.logs/ - Process hygiene: Clean starts, clean stops, no orphan processes
- Adaptable patterns: Works for any service topology
"启动要干净,停止要彻底,日志全留存,状态需清晰。"
原则:
- 优先适配AI Agent: 输出内容便于程序读取(无交互式提示)
- 默认后台运行: 服务以分离模式运行;通过日志查看状态,不生成终端窗口
- 全面日志记录: 所有输出均写入目录下的文件,无内容丢失
.logs/ - 进程规范: 干净启动、彻底停止,无孤儿进程残留
- 模式可适配: 适用于任意服务拓扑结构
Pre-Implementation Discovery
实现前的调研
Before creating a Makefile, determine:
在创建Makefile前,需明确以下信息:
Service Topology
服务拓扑
- What services exist? (backend, frontend, workers, etc.)
- Do any services depend on others? (start order)
- Are there external dependencies? (databases, emulators, etc.)
- 存在哪些服务?(后端、前端、工作进程等)
- 服务间是否存在依赖关系?(启动顺序要求)
- 是否有外部依赖?(数据库、模拟器等)
Startup Requirements
启动要求
- What commands start each service?
- What environment variables are needed?
- What ports are used? (must be unique per-service)
- Any initialization steps? (migrations, seeds, etc.)
- 每个服务的启动命令是什么?
- 需要哪些环境变量?
- 使用哪些端口?(每个服务必须使用唯一端口)
- 是否有初始化步骤?(数据迁移、种子数据等)
Testing & Quality
测试与质量保障
- What test commands exist? (unit, integration, e2e)
- What prerequisites for tests? (docker, emulators, etc.)
- What linting/formatting tools? (eslint, ruff, mypy, etc.)
- 有哪些测试命令?(单元测试、集成测试、端到端测试)
- 测试有哪些前置条件?(Docker、模拟器等)
- 使用哪些代码检查/格式化工具?(eslint、ruff、mypy等)
Project Context
项目上下文
- Language/framework? (affects conventions)
- Development vs Production behavior?
- Team conventions? (existing practices to preserve)
- 使用的语言/框架?(会影响约定规范)
- 开发环境与生产环境的行为差异?
- 团队已有约定?(需保留现有实践)
Makefile Architecture
Makefile 架构
Standard structure (in order):
makefile
undefined标准结构(按顺序):
makefile
undefined1. Configuration Variables
1. 配置变量
2. Directory Setup
2. 目录初始化
3. Service Lifecycle Targets (run-, stop-)
3. 服务生命周期目标(run-, stop-)
4. Combined Operations (run, stop, restart)
4. 组合操作(run, stop, restart)
5. Testing & Quality (test, lint)
5. 测试与质量保障(test, lint)
6. Utility Targets (logs, status, help)
6. 工具类目标(logs, status, help)
7. .PHONY declarations
7. .PHONY 声明
undefinedundefinedCore Patterns Library
核心模式库
A. Starting a Service (Background with PID Tracking)
A. 启动服务(后台运行+PID跟踪)
makefile
run-backend:
@mkdir -p .pids .logs
@if lsof -ti:$(BACKEND_PORT) > /dev/null 2>&1; then \
echo "❌ Backend already running on port $(BACKEND_PORT)"; \
exit 1; \
fi
@echo "🚀 Starting backend on port $(BACKEND_PORT)..."
@nohup $(BACKEND_CMD) > .logs/backend.log 2>&1 & echo $$! > .pids/backend.pid
@echo "✅ Backend started (PID: $$(cat .pids/backend.pid))"makefile
run-backend:
@mkdir -p .pids .logs
@if lsof -ti:$(BACKEND_PORT) > /dev/null 2>&1; then \
echo "❌ Backend already running on port $(BACKEND_PORT)"; \
exit 1; \
fi
@echo "🚀 Starting backend on port $(BACKEND_PORT)..."
@nohup $(BACKEND_CMD) > .logs/backend.log 2>&1 & echo $$! > .pids/backend.pid
@echo "✅ Backend started (PID: $$(cat .pids/backend.pid))"B. Stopping a Service (Process Group Cleanup)
B. 停止服务(清理进程组)
makefile
stop-backend:
@if [ -f .pids/backend.pid ]; then \
PID=$$(cat .pids/backend.pid); \
if ps -p $$PID > /dev/null 2>&1; then \
echo "🛑 Stopping backend (PID: $$PID)..."; \
kill -TERM -- -$$PID 2>/dev/null || kill $$PID; \
rm .pids/backend.pid; \
echo "✅ Backend stopped"; \
else \
echo "⚠️ Backend process not found, cleaning up PID file"; \
rm .pids/backend.pid; \
fi \
else \
echo "ℹ️ Backend not running"; \
fimakefile
stop-backend:
@if [ -f .pids/backend.pid ]; then \
PID=$$(cat .pids/backend.pid); \
if ps -p $$PID > /dev/null 2>&1; then \
echo "🛑 Stopping backend (PID: $$PID)..."; \
kill -TERM -- -$$PID 2>/dev/null || kill $$PID; \
rm .pids/backend.pid; \
echo "✅ Backend stopped"; \
else \
echo "⚠️ Backend process not found, cleaning up PID file"; \
rm .pids/backend.pid; \
fi \
else \
echo "ℹ️ Backend not running"; \
fiC. Status Checking
C. 状态检查
makefile
status:
@echo "📊 Service Status:"
@echo ""
@for service in backend frontend; do \
if [ -f .pids/$$service.pid ]; then \
PID=$$(cat .pids/$$service.pid); \
if ps -p $$PID > /dev/null 2>&1; then \
echo "✅ $$service: running (PID: $$PID)"; \
else \
echo "❌ $$service: stopped (stale PID file)"; \
fi \
else \
echo "⚪ $$service: not running"; \
fi; \
donemakefile
status:
@echo "📊 Service Status:"
@echo ""
@for service in backend frontend; do \
if [ -f .pids/$$service.pid ]; then \
PID=$$(cat .pids/$$service.pid); \
if ps -p $$PID > /dev/null 2>&1; then \
echo "✅ $$service: running (PID: $$PID)"; \
else \
echo "❌ $$service: stopped (stale PID file)"; \
fi \
else \
echo "⚪ $$service: not running"; \
fi; \
doneD. Log Tailing
D. 查看日志
makefile
logs:
@if [ -f .logs/backend.log ] || [ -f .logs/frontend.log ]; then \
tail -n 50 .logs/*.log 2>/dev/null; \
else \
echo "No logs found"; \
fi
logs-follow:
@tail -f .logs/*.log 2>/dev/nullmakefile
logs:
@if [ -f .logs/backend.log ] || [ -f .logs/frontend.log ]; then \
tail -n 50 .logs/*.log 2>/dev/null; \
else \
echo "No logs found"; \
fi
logs-follow:
@tail -f .logs/*.log 2>/dev/nullE. Combined Operations
E. 组合操作
makefile
run: run-backend run-frontend
stop: stop-frontend stop-backend # Reverse order for clean shutdown
restart: stop runmakefile
run: run-backend run-frontend
stop: stop-frontend stop-backend # 按逆序停止以实现干净关闭
restart: stop runF. Testing with Prerequisites
F. 带前置条件的测试
makefile
test: test-setup
@echo "🧪 Running tests..."
@$(TEST_CMD)
test-setup:
@if [ -n "$(DOCKER_COMPOSE_FILE)" ] && [ -f "$(DOCKER_COMPOSE_FILE)" ]; then \
docker-compose -f $(DOCKER_COMPOSE_FILE) up -d; \
fimakefile
test: test-setup
@echo "🧪 Running tests..."
@$(TEST_CMD)
test-setup:
@if [ -n "$(DOCKER_COMPOSE_FILE)" ] && [ -f "$(DOCKER_COMPOSE_FILE)" ]; then \
docker-compose -f $(DOCKER_COMPOSE_FILE) up -d; \
fiG. Help Target (Self-Documenting)
G. 帮助目标(自文档化)
makefile
.DEFAULT_GOAL := help
help:
@echo "Available targets:"
@echo ""
@echo " make run Start all services"
@echo " make stop Stop all services"
@echo " make restart Restart all services"
@echo " make status Show service status"
@echo " make logs Show recent logs"
@echo " make logs-follow Follow logs in real-time"
@echo " make test Run all tests"
@echo " make lint Run linters and formatters"
@echo ""
@echo "Individual services:"
@echo " make run-backend Start backend only"
@echo " make run-frontend Start frontend only"
@echo " make stop-backend Stop backend only"
@echo " make stop-frontend Stop frontend only"makefile
.DEFAULT_GOAL := help
help:
@echo "Available targets:"
@echo ""
@echo " make run Start all services"
@echo " make stop Stop all services"
@echo " make restart Restart all services"
@echo " make status Show service status"
@echo " make logs Show recent logs"
@echo " make logs-follow Follow logs in real-time"
@echo " make test Run all tests"
@echo " make lint Run linters and formatters"
@echo ""
@echo "Individual services:"
@echo " make run-backend Start backend only"
@echo " make run-frontend Start frontend only"
@echo " make stop-backend Stop backend only"
@echo " make stop-frontend Stop frontend only"Adaptation Patterns
适配模式
| Scenario | Adaptation |
|---|---|
| Multiple backends | Use suffix naming: |
| Database migrations | Add |
| Emulators | Treat like any other service with PID tracking |
| Docker Compose | Wrap docker-compose commands, track container IDs |
| Monorepo | Use subdirectory variables: |
| Multiple test types | Separate targets: |
| Watch modes | Use separate watch targets, don't mix with regular run |
| 场景 | 适配方案 |
|---|---|
| 多后端服务 | 使用后缀命名: |
| 数据库迁移 | 添加 |
| 模拟器 | 视为普通服务,同样进行PID跟踪 |
| Docker Compose | 封装docker-compose命令,跟踪容器ID |
| 单体仓库 | 使用子目录变量: |
| 多类型测试 | 拆分目标: |
| 监听模式 | 使用独立的watch目标,不与常规run目标混合 |
Best Practices Checklist
最佳实践检查清单
Before completing a Makefile, verify:
- All targets are (or appropriately not)
.PHONY - Port numbers are configurable via variables
- Unique ports per service (no conflicts)
- All logs go to directory
.logs/ - All PIDs go to directory
.pids/ - Process group killing (handles child processes)
- Port conflict detection before start
- Human-readable output (colors/emojis)
- target is default (listed first or
help).DEFAULT_GOAL - Variables use (simple expansion)
:= - Error messages are clear and actionable
- Status command shows actual state
- Clean shutdown on stop (SIGTERM first)
- Idempotent operations (safe to run twice)
完成Makefile前,请验证以下内容:
- 所有目标均已声明为(或按需不声明)
.PHONY - 端口号可通过变量配置
- 每个服务使用唯一端口(无冲突)
- 所有日志均写入目录
.logs/ - 所有PID均写入目录
.pids/ - 支持进程组终止(可处理子进程)
- 启动前检测端口冲突
- 输出内容便于人类阅读(含颜色/表情符号)
- 目标为默认目标(置于开头或设置
help).DEFAULT_GOAL - 变量使用(简单展开)
:= - 错误信息清晰且可执行
- 状态命令显示真实状态
- 停止时执行干净关闭(优先使用SIGTERM)
- 操作具有幂等性(重复执行无异常)
Common Issues & Solutions
常见问题与解决方案
| Problem | Solution |
|---|---|
| PID file exists but process dead | Check |
| Child processes survive parent kill | Use |
| Port already in use | Check with |
| Logs interleaved/unreadable | Separate log files per service |
| Service starts but immediately exits | Redirect stderr: |
| Make variables not evaluated | Use |
| Colors don't show in logs | Use |
| Can't stop service (permission) | Run make with same user that started it |
| 问题 | 解决方案 |
|---|---|
| PID文件存在但进程已终止 | 使用PID文件前先执行 |
| 父进程终止后子进程仍存活 | 使用 |
| 端口已被占用 | 启动前执行 |
| 日志交错/难以阅读 | 为每个服务设置独立日志文件 |
| 服务启动后立即退出 | 重定向stderr: |
| Make变量未被正确求值 | 使用 |
| 日志中不显示颜色 | 使用 |
| 无法停止服务(权限问题) | 使用启动服务的同一用户执行make命令 |
Implementation Workflow
实现流程
Creating a New Makefile
创建新Makefile
- Discovery: Ask questions (see Discovery section)
- Configuration: Set up variables (ports, commands, paths)
- Core services: Implement run/stop for each service
- Combined ops: Add run/stop/restart for all services
- Utilities: Add status, logs, help
- Testing: Add test targets with prerequisites
- Quality: Add lint/format targets
- Validation: Test each target, verify idempotency
- Documentation: Ensure help is complete and accurate
- 调研: 询问相关问题(参考调研部分)
- 配置: 设置变量(端口、命令、路径)
- 核心服务: 为每个服务实现run/stop目标
- 组合操作: 添加所有服务的run/stop/restart目标
- 工具类: 添加status、logs、help目标
- 测试: 添加带前置条件的测试目标
- 质量保障: 添加lint/format目标
- 验证: 测试每个目标,验证幂等性
- 文档: 确保help目标内容完整准确
Amending an Existing Makefile
修改现有Makefile
- Read current Makefile: Understand existing structure
- Identify gaps: Compare against best practices checklist
- Plan changes: Determine what to add/modify
- Preserve conventions: Keep existing naming/style
- Incremental changes: Add features one at a time
- Test each change: Verify nothing breaks
- Update help: Reflect new targets
- 阅读现有Makefile: 理解现有结构
- 识别差距: 与最佳实践检查清单对比
- 规划变更: 确定需要添加/修改的内容
- 保留约定: 遵循现有命名/风格
- 增量变更: 逐个添加功能
- 测试变更: 验证无功能损坏
- 更新帮助: 同步新目标到help中
Complete Template
完整模板
A minimal working template for a full-stack app:
makefile
undefined适用于全栈应用的最小可用模板:
makefile
undefined=============================================================================
=============================================================================
Configuration
Configuration
=============================================================================
=============================================================================
BACKEND_PORT := 3001
FRONTEND_PORT := 3000
BACKEND_CMD := npm run dev --prefix backend
FRONTEND_CMD := npm run dev --prefix frontend
TEST_CMD := npm test
BACKEND_PORT := 3001
FRONTEND_PORT := 3000
BACKEND_CMD := npm run dev --prefix backend
FRONTEND_CMD := npm run dev --prefix frontend
TEST_CMD := npm test
=============================================================================
=============================================================================
Directory Setup
Directory Setup
=============================================================================
=============================================================================
$(shell mkdir -p .pids .logs)
$(shell mkdir -p .pids .logs)
=============================================================================
=============================================================================
Service Lifecycle
Service Lifecycle
=============================================================================
=============================================================================
run-backend:
@if lsof -ti:$(BACKEND_PORT) > /dev/null 2>&1; then
echo "❌ Backend already running on port $(BACKEND_PORT)";
exit 1;
fi @echo "🚀 Starting backend on port $(BACKEND_PORT)..." @nohup $(BACKEND_CMD) > .logs/backend.log 2>&1 & echo $$! > .pids/backend.pid @echo "✅ Backend started (PID: $$(cat .pids/backend.pid))"
echo "❌ Backend already running on port $(BACKEND_PORT)";
exit 1;
fi @echo "🚀 Starting backend on port $(BACKEND_PORT)..." @nohup $(BACKEND_CMD) > .logs/backend.log 2>&1 & echo $$! > .pids/backend.pid @echo "✅ Backend started (PID: $$(cat .pids/backend.pid))"
run-frontend:
@if lsof -ti:$(FRONTEND_PORT) > /dev/null 2>&1; then
echo "❌ Frontend already running on port $(FRONTEND_PORT)";
exit 1;
fi @echo "🚀 Starting frontend on port $(FRONTEND_PORT)..." @nohup $(FRONTEND_CMD) > .logs/frontend.log 2>&1 & echo $$! > .pids/frontend.pid @echo "✅ Frontend started (PID: $$(cat .pids/frontend.pid))"
echo "❌ Frontend already running on port $(FRONTEND_PORT)";
exit 1;
fi @echo "🚀 Starting frontend on port $(FRONTEND_PORT)..." @nohup $(FRONTEND_CMD) > .logs/frontend.log 2>&1 & echo $$! > .pids/frontend.pid @echo "✅ Frontend started (PID: $$(cat .pids/frontend.pid))"
stop-backend:
@if [ -f .pids/backend.pid ]; then
PID=$$(cat .pids/backend.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "🛑 Stopping backend (PID: $$PID)...";
kill -TERM -- -$$PID 2>/dev/null || kill $$PID;
rm .pids/backend.pid;
echo "✅ Backend stopped";
else
echo "⚠️ Backend not found, cleaning up PID file";
rm .pids/backend.pid;
fi
else
echo "ℹ️ Backend not running";
fi
PID=$$(cat .pids/backend.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "🛑 Stopping backend (PID: $$PID)...";
kill -TERM -- -$$PID 2>/dev/null || kill $$PID;
rm .pids/backend.pid;
echo "✅ Backend stopped";
else
echo "⚠️ Backend not found, cleaning up PID file";
rm .pids/backend.pid;
fi
else
echo "ℹ️ Backend not running";
fi
stop-frontend:
@if [ -f .pids/frontend.pid ]; then
PID=$$(cat .pids/frontend.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "🛑 Stopping frontend (PID: $$PID)...";
kill -TERM -- -$$PID 2>/dev/null || kill $$PID;
rm .pids/frontend.pid;
echo "✅ Frontend stopped";
else
echo "⚠️ Frontend not found, cleaning up PID file";
rm .pids/frontend.pid;
fi
else
echo "ℹ️ Frontend not running";
fi
PID=$$(cat .pids/frontend.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "🛑 Stopping frontend (PID: $$PID)...";
kill -TERM -- -$$PID 2>/dev/null || kill $$PID;
rm .pids/frontend.pid;
echo "✅ Frontend stopped";
else
echo "⚠️ Frontend not found, cleaning up PID file";
rm .pids/frontend.pid;
fi
else
echo "ℹ️ Frontend not running";
fi
run-backend:
@if lsof -ti:$(BACKEND_PORT) > /dev/null 2>&1; then
echo "❌ Backend already running on port $(BACKEND_PORT)";
exit 1;
fi @echo "🚀 Starting backend on port $(BACKEND_PORT)..." @nohup $(BACKEND_CMD) > .logs/backend.log 2>&1 & echo $$! > .pids/backend.pid @echo "✅ Backend started (PID: $$(cat .pids/backend.pid))"
echo "❌ Backend already running on port $(BACKEND_PORT)";
exit 1;
fi @echo "🚀 Starting backend on port $(BACKEND_PORT)..." @nohup $(BACKEND_CMD) > .logs/backend.log 2>&1 & echo $$! > .pids/backend.pid @echo "✅ Backend started (PID: $$(cat .pids/backend.pid))"
run-frontend:
@if lsof -ti:$(FRONTEND_PORT) > /dev/null 2>&1; then
echo "❌ Frontend already running on port $(FRONTEND_PORT)";
exit 1;
fi @echo "🚀 Starting frontend on port $(FRONTEND_PORT)..." @nohup $(FRONTEND_CMD) > .logs/frontend.log 2>&1 & echo $$! > .pids/frontend.pid @echo "✅ Frontend started (PID: $$(cat .pids/frontend.pid))"
echo "❌ Frontend already running on port $(FRONTEND_PORT)";
exit 1;
fi @echo "🚀 Starting frontend on port $(FRONTEND_PORT)..." @nohup $(FRONTEND_CMD) > .logs/frontend.log 2>&1 & echo $$! > .pids/frontend.pid @echo "✅ Frontend started (PID: $$(cat .pids/frontend.pid))"
stop-backend:
@if [ -f .pids/backend.pid ]; then
PID=$$(cat .pids/backend.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "🛑 Stopping backend (PID: $$PID)...";
kill -TERM -- -$$PID 2>/dev/null || kill $$PID;
rm .pids/backend.pid;
echo "✅ Backend stopped";
else
echo "⚠️ Backend not found, cleaning up PID file";
rm .pids/backend.pid;
fi
else
echo "ℹ️ Backend not running";
fi
PID=$$(cat .pids/backend.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "🛑 Stopping backend (PID: $$PID)...";
kill -TERM -- -$$PID 2>/dev/null || kill $$PID;
rm .pids/backend.pid;
echo "✅ Backend stopped";
else
echo "⚠️ Backend not found, cleaning up PID file";
rm .pids/backend.pid;
fi
else
echo "ℹ️ Backend not running";
fi
stop-frontend:
@if [ -f .pids/frontend.pid ]; then
PID=$$(cat .pids/frontend.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "🛑 Stopping frontend (PID: $$PID)...";
kill -TERM -- -$$PID 2>/dev/null || kill $$PID;
rm .pids/frontend.pid;
echo "✅ Frontend stopped";
else
echo "⚠️ Frontend not found, cleaning up PID file";
rm .pids/frontend.pid;
fi
else
echo "ℹ️ Frontend not running";
fi
PID=$$(cat .pids/frontend.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "🛑 Stopping frontend (PID: $$PID)...";
kill -TERM -- -$$PID 2>/dev/null || kill $$PID;
rm .pids/frontend.pid;
echo "✅ Frontend stopped";
else
echo "⚠️ Frontend not found, cleaning up PID file";
rm .pids/frontend.pid;
fi
else
echo "ℹ️ Frontend not running";
fi
=============================================================================
=============================================================================
Combined Operations
Combined Operations
=============================================================================
=============================================================================
run: run-backend run-frontend
stop: stop-frontend stop-backend
restart: stop run
run: run-backend run-frontend
stop: stop-frontend stop-backend
restart: stop run
=============================================================================
=============================================================================
Testing & Quality
Testing & Quality
=============================================================================
=============================================================================
test:
@echo "🧪 Running tests..."
@$(TEST_CMD)
lint:
@echo "🔍 Running linters..."
@npm run lint 2>&1 || true
test:
@echo "🧪 Running tests..."
@$(TEST_CMD)
lint:
@echo "🔍 Running linters..."
@npm run lint 2>&1 || true
=============================================================================
=============================================================================
Utilities
Utilities
=============================================================================
=============================================================================
status:
@echo "📊 Service Status:"
@echo ""
@for service in backend frontend; do
if [ -f .pids/$$service.pid ]; then
PID=$$(cat .pids/$$service.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "✅ $$service: running (PID: $$PID)";
else
echo "❌ $$service: stopped (stale PID file)";
fi
else
echo "⚪ $$service: not running";
fi;
done
if [ -f .pids/$$service.pid ]; then
PID=$$(cat .pids/$$service.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "✅ $$service: running (PID: $$PID)";
else
echo "❌ $$service: stopped (stale PID file)";
fi
else
echo "⚪ $$service: not running";
fi;
done
logs:
@tail -n 50 .logs/*.log 2>/dev/null || echo "No logs found"
logs-follow:
@tail -f .logs/*.log 2>/dev/null
clean:
@rm -rf .pids .logs
@echo "🧹 Cleaned up PID and log files"
status:
@echo "📊 Service Status:"
@echo ""
@for service in backend frontend; do
if [ -f .pids/$$service.pid ]; then
PID=$$(cat .pids/$$service.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "✅ $$service: running (PID: $$PID)";
else
echo "❌ $$service: stopped (stale PID file)";
fi
else
echo "⚪ $$service: not running";
fi;
done
if [ -f .pids/$$service.pid ]; then
PID=$$(cat .pids/$$service.pid);
if ps -p $$PID > /dev/null 2>&1; then
echo "✅ $$service: running (PID: $$PID)";
else
echo "❌ $$service: stopped (stale PID file)";
fi
else
echo "⚪ $$service: not running";
fi;
done
logs:
@tail -n 50 .logs/*.log 2>/dev/null || echo "No logs found"
logs-follow:
@tail -f .logs/*.log 2>/dev/null
clean:
@rm -rf .pids .logs
@echo "🧹 Cleaned up PID and log files"
=============================================================================
=============================================================================
Help
Help
=============================================================================
=============================================================================
.DEFAULT_GOAL := help
help:
@echo "Available targets:"
@echo ""
@echo " make run Start all services"
@echo " make stop Stop all services"
@echo " make restart Restart all services"
@echo " make status Show service status"
@echo " make logs Show recent logs (last 50 lines)"
@echo " make logs-follow Follow logs in real-time"
@echo " make test Run tests"
@echo " make lint Run linters"
@echo " make clean Remove PID and log files"
@echo ""
@echo "Individual services:"
@echo " make run-backend Start backend only"
@echo " make run-frontend Start frontend only"
@echo " make stop-backend Stop backend only"
@echo " make stop-frontend Stop frontend only"
.DEFAULT_GOAL := help
help:
@echo "Available targets:"
@echo ""
@echo " make run Start all services"
@echo " make stop Stop all services"
@echo " make restart Restart all services"
@echo " make status Show service status"
@echo " make logs Show recent logs (last 50 lines)"
@echo " make logs-follow Follow logs in real-time"
@echo " make test Run tests"
@echo " make lint Run linters"
@echo " make clean Remove PID and log files"
@echo ""
@echo "Individual services:"
@echo " make run-backend Start backend only"
@echo " make run-frontend Start frontend only"
@echo " make stop-backend Stop backend only"
@echo " make stop-frontend Stop frontend only"
=============================================================================
=============================================================================
.PHONY
.PHONY
=============================================================================
=============================================================================
.PHONY: run run-backend run-frontend stop stop-backend stop-frontend
restart status logs logs-follow test lint clean help
restart status logs logs-follow test lint clean help
undefined.PHONY: run run-backend run-frontend stop stop-backend stop-frontend
restart status logs logs-follow test lint clean help
restart status logs logs-follow test lint clean help
undefinedGitignore Additions
Gitignore 补充内容
Remind users to add these to :
.gitignore.pids/
.logs/提醒用户将以下内容添加到:
.gitignore.pids/
.logs/