news 2026/6/10 20:49:39

Makefile入门实战让构建自动化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Makefile入门实战让构建自动化

很多人觉得Makefile是C/C++的东西,跟自己没关系。

其实Makefile就是一个任务自动化工具,什么项目都能用。我现在Python、Go、前端项目都会写个Makefile,把常用命令封装起来。

这篇讲讲Makefile的基本写法,看完就能上手。

为什么用Makefile

项目里常用的命令:

# 启动开发环境docker-composeup -dexport$(cat.env|xargs)python manage.py runserver# 跑测试pytest tests/ -v# 构建镜像dockerbuild -t myapp:v1.2.3.dockerpush myapp:v1.2.3# 部署sshserver"cd /app && git pull && systemctl restart myapp"

每次都敲一遍很烦,而且新人来了不知道怎么跑。

写个Makefile:

.PHONY: dev test build deploy dev: docker-compose up -d python manage.py runserver test: pytest tests/ -v build: docker build -t myapp:$(VERSION) . deploy: ssh server "cd /app && git pull && systemctl restart myapp"

然后:

makedev# 启动开发环境maketest# 跑测试makebuildVERSION=v1.2.3# 构建镜像makedeploy# 部署

新人来了,先make help或者看Makefile就知道怎么跑项目。

基本语法

最简单的形式

目标: 依赖 命令

注意:命令前面必须是Tab,不是空格,这是很多人踩的坑。

hello: echo "Hello, World!"
makehello# echo "Hello, World!"# Hello, World!

依赖

build: clean test echo "开始构建" clean: rm -rf dist/ test: pytest

执行make build时,会先执行clean和test。

变量

# 定义变量 APP_NAME = myapp VERSION = 1.0.0 # 使用变量 build: docker build -t $(APP_NAME):$(VERSION) .

命令行传入变量:

makebuildVERSION=2.0.0

环境变量

# 从环境变量获取,有默认值 DB_HOST ?= localhost DB_PORT ?= 3306 run: DB_HOST=$(DB_HOST) DB_PORT=$(DB_PORT) python app.py
makerun# 使用默认值DB_HOST=prod.dbmakerun# 使用环境变量makerunDB_HOST=prod.db# 命令行传入

伪目标

如果目录里有个文件叫test,执行make test会说"已是最新"。

用.PHONY声明伪目标:

.PHONY: test clean build test: pytest

所有不生成文件的目标都应该声明为.PHONY。

静默执行

默认make会打印执行的命令,加@可以隐藏:

hello: @echo "Hello"

或者全局静默:

make-s hello

多行命令

默认每行命令在单独的shell里执行,上一行的变量下一行拿不到:

# 这样不行 test: cd /tmp pwd # 还是在原来的目录 # 这样可以 test: cd /tmp && pwd # 或者用反斜杠 test: cd /tmp && \ pwd && \ ls

错误处理

默认命令失败就停止。加-可以忽略错误:

clean: -rm -rf dist/ # 即使失败也继续

或者用 || true:

clean: rm -rf dist/ || true

实用模式

帮助信息

.PHONY: help help: @echo "可用命令:" @echo " make dev - 启动开发环境" @echo " make test - 运行测试" @echo " make build - 构建镜像" @echo " make deploy - 部署到服务器" # 把help放第一个,make不带参数就显示帮助 .DEFAULT_GOAL := help

更高级的写法,自动从注释生成:

.PHONY: help help: ## 显示帮助信息 @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' dev: ## 启动开发环境 docker-compose up -d test: ## 运行测试 pytest build: ## 构建镜像 docker build -t myapp .
makehelp# dev 启动开发环境# test 运行测试# build 构建镜像

include其他文件

# 引入其他Makefile include config.mk # 如果文件不存在不报错 -include local.mk

条件判断

ifeq ($(ENV), prod) DB_HOST = prod.db.com else DB_HOST = localhost endif run: @echo "连接 $(DB_HOST)"

获取Git信息

GIT_COMMIT := $(shell git rev-parse --short HEAD) GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) BUILD_TIME := $(shell date +%Y%m%d-%H%M%S) build: docker build \ --build-arg GIT_COMMIT=$(GIT_COMMIT) \ --build-arg BUILD_TIME=$(BUILD_TIME) \ -t myapp:$(GIT_COMMIT) .

检查命令是否存在

check-docker: @which docker > /dev/null || (echo "请先安装docker" && exit 1) build: check-docker docker build -t myapp .

实际项目示例

Go项目

.PHONY: build test run clean help APP_NAME := myapp VERSION := $(shell git describe --tags --always --dirty) BUILD_TIME := $(shell date -u +%Y-%m-%dT%H:%M:%SZ) LDFLAGS := -X main.Version=$(VERSION) -X main.BuildTime=$(BUILD_TIME) help: ## 帮助 @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' build: ## 构建 go build -ldflags "$(LDFLAGS)" -o bin/$(APP_NAME) . test: ## 测试 go test -v ./... run: build ## 运行 ./bin/$(APP_NAME) clean: ## 清理 rm -rf bin/ lint: ## 代码检查 golangci-lint run docker: ## 构建Docker镜像 docker build -t $(APP_NAME):$(VERSION) . .DEFAULT_GOAL := help

Python项目

.PHONY: install dev test lint format clean help PYTHON := python3 VENV := .venv PIP := $(VENV)/bin/pip PYTEST := $(VENV)/bin/pytest help: @echo "make install - 安装依赖" @echo "make dev - 启动开发服务" @echo "make test - 运行测试" @echo "make lint - 代码检查" @echo "make format - 格式化代码" $(VENV): $(PYTHON) -m venv $(VENV) install: $(VENV) $(PIP) install -r requirements.txt dev: install $(VENV)/bin/python manage.py runserver test: install $(PYTEST) tests/ -v lint: $(VENV)/bin/flake8 src/ $(VENV)/bin/mypy src/ format: $(VENV)/bin/black src/ tests/ $(VENV)/bin/isort src/ tests/ clean: rm -rf $(VENV) __pycache__ .pytest_cache .mypy_cache find . -type d -name "__pycache__" -exec rm -rf {} +

前端项目

.PHONY: install dev build test lint deploy help NODE_ENV ?= development help: @echo "make install - 安装依赖" @echo "make dev - 启动开发服务" @echo "make build - 构建生产版本" @echo "make deploy - 部署" install: npm ci dev: npm run dev build: NODE_ENV=production npm run build test: npm test lint: npm run lint deploy: build rsync -avz --delete dist/ server:/var/www/app/

Docker项目

.PHONY: up down logs ps build push clean help COMPOSE := docker-compose IMAGE := myapp REGISTRY := registry.example.com VERSION := $(shell git describe --tags --always) help: @echo "make up - 启动所有服务" @echo "make down - 停止所有服务" @echo "make logs - 查看日志" @echo "make build - 构建镜像" @echo "make push - 推送镜像" up: $(COMPOSE) up -d down: $(COMPOSE) down logs: $(COMPOSE) logs -f ps: $(COMPOSE) ps build: docker build -t $(REGISTRY)/$(IMAGE):$(VERSION) . docker tag $(REGISTRY)/$(IMAGE):$(VERSION) $(REGISTRY)/$(IMAGE):latest push: build docker push $(REGISTRY)/$(IMAGE):$(VERSION) docker push $(REGISTRY)/$(IMAGE):latest clean: $(COMPOSE) down -v --rmi local docker system prune -f

常见问题

Tab vs 空格

命令前必须是Tab,不是空格。如果你的编辑器把Tab转成空格了,会报错:

Makefile:2: *** missing separator. Stop.

VSCode可以在状态栏点击"空格:4"切换成Tab。

变量展开

# 立即展开 A := $(shell date) # 延迟展开 B = $(shell date)

:= 定义时就计算,= 使用时才计算。

Windows兼容

Windows上没有make命令,可以:

  • 用WSL
  • 安装MinGW的make
  • 用nmake(语法略有不同)

或者干脆用跨平台的工具如just、task。


Makefile不复杂,核心就是:

  • 目标、依赖、命令
  • 变量
  • .PHONY

写好一个Makefile,整个团队都能统一操作方式,还能当文档用。

值得花半小时学一下。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 9:04:36

轻松搞定CUDA安装问题:PyTorch-CUDA-v2.7镜像实测推荐

轻松搞定CUDA安装问题:PyTorch-CUDA-v2.7镜像实测推荐 在深度学习项目开发中,你是否经历过这样的场景?明明代码写得没问题,模型结构也正确,可一运行就报错: CUDA error: no kernel image is available for …

作者头像 李华
网站建设 2026/6/10 9:11:16

AI开发者必备:PyTorch-CUDA-v2.7镜像提升训练效率实战分享

AI开发者必备:PyTorch-CUDA-v2.7镜像提升训练效率实战分享 在深度学习项目开发中,你是否经历过这样的场景:刚写完一个新模型结构,满心期待地运行脚本,结果却卡在了 torch.cuda.is_available() 返回 False?或…

作者头像 李华
网站建设 2026/6/10 9:12:29

电商API接口实录对接:1688混批价格函数处理

在电商开发这行摸爬滚打快十年,对接过不少平台的 API,但若说最让人头疼的,1688 商品详情 API 绝对能排进前三。从批发场景特有的数据结构,到接口权限的严格管控,每一步都藏着 “惊喜”。今天就把这些年踩过的坑、攒下的…

作者头像 李华
网站建设 2026/6/10 9:14:51

深度解析TSMessages性能监控:10个提升通知渲染效率的终极技巧

TSMessages作为iOS平台备受推崇的消息通知库,其渲染性能直接关系到应用的用户体验。在复杂应用场景中,通知的频繁展示往往成为性能瓶颈的关键因素。本文将为您揭示TSMessages性能监控的核心奥秘,帮助您构建高效稳定的通知系统。 【免费下载链…

作者头像 李华
网站建设 2026/6/10 9:07:44

设计系统革命:Penpot如何重塑数字产品创作流程

设计系统革命:Penpot如何重塑数字产品创作流程 【免费下载链接】penpot Penpot - The Open-Source design & prototyping platform 项目地址: https://gitcode.com/GitHub_Trending/pe/penpot 在当今数字化浪潮中,设计系统已成为企业级产品开…

作者头像 李华
网站建设 2026/6/10 9:06:10

Legendary终极指南:开源Epic游戏启动器完整使用教程

Legendary终极指南:开源Epic游戏启动器完整使用教程 【免费下载链接】legendary Legendary - A free and open-source replacement for the Epic Games Launcher 项目地址: https://gitcode.com/gh_mirrors/le/legendary Legendary是一款功能强大的开源命令行…

作者头像 李华