Makefile生成器 makefile-generator

这是一个全面的工具包,用于生成遵循当前标准和约定的最佳实践Makefiles,适用于C/C++、Python、Go、Java和通用项目。关键词包括:Makefile生成、构建自动化、CI/CD集成、GNU编码标准。

DevOps 0 次安装 0 次浏览 更新于 3/4/2026

Makefile生成器

概览

使用当前标准和约定生成适用于C/C++、Python、Go、Java和通用项目的制作就绪Makefiles。当创建新的Makefiles、为项目(C/C++、Python、Go、Java)设置构建系统、实施构建自动化和CI/CD集成时,使用此技能。

何时使用

  • 从头开始创建新的Makefiles
  • 为项目设置构建系统(C/C++、Python、Go、Java)
  • 实施构建自动化和CI/CD集成
  • 将手动构建过程转换为Makefiles
  • 用户要求“创建”、“生成”或“编写”Makefile

不要用于: 验证现有的Makefiles(使用devops-skills:makefile-validator)、调试(使用make -d)或运行构建。

生成工作流程

第1阶段:收集需求

收集以下类别的信息。如果信息缺失或不明确,使用AskUserQuestion:

类别 需要的信息
项目 语言(C/C++/Python/Go/Java)、结构(单目录/多目录)
构建 源文件、输出工件、依赖项、构建顺序
安装 PREFIX位置、目录(bin/lib/share)、要安装的文件
目标 all、install、clean、test、dist、help(需要哪些?)
配置 编译器、标志、pkg-config依赖项、交叉编译

何时使用AskUserQuestion(必须询问):

条件 示例问题
未指定语言 “这个项目是什么编程语言?(C/C++/Go/Python/Java)”
项目结构不清楚 “这是一个单目录还是多目录项目?”
请求Docker但未知注册表 “应该使用哪个容器注册表?(docker.io/ghcr.io/custom)”
可能存在多个二进制文件 “这个构建是单个二进制文件还是多个可执行文件?”
需要安装目标但路径不清楚 “二进制文件应该安装在哪里?(默认:/usr/local/bin)”
提到交叉编译 “目标平台/架构是什么?”

何时跳过AskUserQuestion(使用默认值):

  • 用户明确提供所有所需信息
  • 标准项目类型,具有明显的默认值(例如,“带Docker的Go项目”→使用标准Go+Docker模式)
  • 用户说“使用默认值”或“标准设置”

默认假设(如果没有询问):

  • 单目录项目结构
  • PREFIX=/usr/local
  • 标准目标:all、build、test、clean、install、help
  • 无交叉编译

第2阶段:文档查找

当必需(必须执行查找):

  • 用户请求与不熟悉的工具、框架或构建系统集成
  • 未涵盖在第3阶段示例中的复杂构建模式(例如,Bazel、Meson、自定义工具链)
  • Docker/容器集成(Dockerfile构建、多阶段、注册表推送)
  • CI/CD平台特定集成(GitHub Actions、GitLab CI、Jenkins)
  • 针对不寻常目标或嵌入式系统的交叉编译
  • 包管理器集成(Conan、vcpkg、Homebrew公式)
  • 多二进制或多库项目
  • 通过ldflags或构建时变量嵌入版本

当可选(可以跳过外部查找):

  • 标准语言模式已涵盖在第3阶段(C/C++、Go、Python、Java)
  • 简单的单二进制项目,没有外部依赖项
  • 用户提供完整的需求,没有歧义
  • 内部文档已经全面覆盖所需的模式

查找流程(按顺序进行):

  1. 始终先咨询内部文档/使用Read工具(主要真相来源):

    需求 阅读此文档
    Docker/容器目标 docs/patterns-guide.md(模式8:Docker集成)
    多二进制项目 docs/patterns-guide.md(模式7:多二进制项目)
    带版本嵌入的Go项目 docs/patterns-guide.md(模式5:Go项目)
    并行构建、缓存、ccache docs/optimization-guide.md
    凭据、机密、API密钥 docs/security-guide.md
    复杂依赖项、模式规则 docs/patterns-guide.md
    仅序贯先行条件 docs/optimization-guide.mddocs/targets-guide.md
    变量、赋值运算符 docs/variables-guide.md

    关键: 生成期间必须明确使用Read工具查阅相关文档,即使您之前已经了解。不要依赖于早期对话的上下文。这确保模式始终是最新的,并正确应用。

    所需工作流程示例(Docker + Go带版本嵌入):

    # 第1步:使用Read工具获取Go模式
    Read: docs/patterns-guide.md(找到模式5:Go项目)
    
    # 第2步:使用Read工具获取Docker模式
    Read: docs/patterns-guide.md(找到模式8:Docker集成)
    
    # 第3步:使用Read工具进行安全考虑
    Read: docs/security-guide.md(docker-push的凭据处理)
    
    # 第4步:生成Makefile结合模式
    # 第5步:在Makefile头部记录查阅的文档
    

    重要: 内部文档包含经过审查的生产就绪模式。在外部查找之前始终阅读相关文档。

  2. 尝试context7用于外部工具文档(当内部文档不涵盖特定工具时):

    # 仅在内部文档未涵盖的工具/框架NOT covered in internal docs
    mcp__context7__resolve-library-id: "<tool-name>"
    mcp__context7__get-library-docs: topic="<integration-topic>"
    
    # 示例主题:
    # - 对于Docker:topic="dockerfile最佳实践"
    # - 对于Go:topic="go build ldflags"
    # - 对于特定工具:topic="<tool> makefile集成"
    

    注意: Context7可能没有GNU Make特定文档。如果内部文档提供足够的模式,则跳过。

  3. 退回到WebSearch(仅当内部文档或context7中未找到模式时):

    "<specific-feature>" makefile最佳实践2025
    示例:"docker makefile最佳实践2025"
    示例:"go ldflags版本makefile 2025"
    

    触发WebSearch时: 内部文档不涵盖特定集成AND context7返回无相关结果。

注意: 在生成的Makefile头部记录您查阅的内部文档(添加注释)。

第3阶段:生成Makefile

头部(选择一种风格)

传统(POSIX兼容):

.DELETE_ON_ERROR:
.SUFFIXES:

现代(GNU Make 4.0+,推荐):

SHELL := bash
.ONESHELL:
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
.SUFFIXES:
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules

标准变量

# 用户可覆盖(使用?=)
CC ?= gcc
CFLAGS ?= -Wall -Wextra -O2
PREFIX ?= /usr/local
DESTDIR ?=

# GNU安装目录
BINDIR ?= $(PREFIX)/bin
LIBDIR ?= $(PREFIX)/lib
INCLUDEDIR ?= $(PREFIX)/include

# 项目特定(使用:=)
PROJECT := myproject
VERSION := 1.0.0
SRCDIR := src
BUILDDIR := build
SOURCES := $(wildcard $(SRCDIR)/*.c)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(BUILDDIR)/%.o)

语言特定构建规则

C/C++:

$(TARGET): $(OBJECTS)
	$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@

$(BUILDDIR)/%.o: $(SRCDIR)/%.c
	@mkdir -p $(@D)
	$(CC) $(CPPFLAGS) $(CFLAGS) -MMD -MP -c $< -o $@

-include $(OBJECTS:.o=.d)

Go:

$(TARGET): $(shell find . -name '*.go') go.mod
	go build -o $@ ./cmd/$(PROJECT)

Python:

.PHONY: build
build:
	python -m build

.PHONY: develop
develop:
	pip install -e .[dev]

Java:

$(BUILDDIR)/%.class: $(SRCDIR)/%.java
	@mkdir -p $(@D)
	javac -d $(BUILDDIR) -sourcepath $(SRCDIR) $<

标准目标

.PHONY: all clean install uninstall test help

## 构建所有目标
all: $(TARGET)

## 安装到PREFIX
install: all
	install -d $(DESTDIR)$(BINDIR)
	install -m 755 $(TARGET) $(DESTDIR)$(BINDIR)/

## 移除构建文件
clean:
	$(RM) -r $(BUILDDIR) $(TARGET)

## 运行测试
test:
	# 添加测试命令

## 显示帮助
help:
	@echo "$(PROJECT) v$(VERSION)"
	@echo "目标:all, install, clean, test, help"
	@echo "覆盖:make CC=clang PREFIX=/opt"

第4阶段:验证和格式化

关键:始终使用devops-skills:makefile-validator技能进行验证。

1. 按照上述阶段生成Makefile
2. 调用devops-skills:makefile-validator技能
3. 修复任何识别出的错误(必须有0个错误)
4. 应用格式化修复(见下面的"格式化步骤")
5. 修复警告(如果可行,应该修复;如果跳过,解释原因)
6. 为大型/生产项目解决信息项
7. 重新验证直到检查通过
8. 输出结构化验证报告(必需 - 见下面的格式)

格式化步骤(必需)

当mbake报告格式化问题时,您必须要么:

  1. 自动应用格式化(对于小问题首选):

    mbake format <Makefile>
    
  2. 解释为什么不应用(如果格式化会破坏功能):

    格式化不应用,因为:
    - [具体原因,例如,"heredoc语法会被破坏"]
    - 推荐手动审查:[具体行]
    

格式化决策指南:

mbake报告 行动
“会重新格式化”,没有具体问题 使用mbake format自动应用
具体的空格/缩进问题 使用mbake format自动应用
复杂的heredocs或多行字符串中的问题 跳过格式化,输出中解释
# bake-format off部分中的问题 跳过(故意禁用)

验证通过标准:

级别 要求 行动
错误(0个必需) 语法错误、缺少制表符、无效目标 必须在完成前修复
警告(如果可行则修复) 格式化问题、缺少优化 应该修复;如果跳过,解释原因
信息(生产中解决) 增强建议、风格偏好 应该为生产Makefiles解决

已知mbake误报(可以安全忽略):

mbake验证器可能会报告针对有效的GNU Make特殊目标的警告。这些是误报,可以忽略:

mbake警告 实际状态 解释
“未知特殊目标’.DELETE_ON_ERROR’” ✅有效 删除失败构建工件的关键GNU Make目标
“未知特殊目标’.SUFFIXES’” ✅有效 设置/禁用后缀规则的标准GNU Make目标
“未知特殊目标’.ONESHELL’” ✅有效 GNU Make 3.82+单壳执行食谱功能
“未知特殊目标’.POSIX’” ✅有效 POSIX合规性声明

验证报告输出(必需)

验证完成后,您必须以以下格式输出结构化报告。这不是可选的。

所需报告格式:

## 验证报告

**结果:** [通过/带警告通过/未通过]
**错误:** [计数]
**警告:** [计数]
**信息:** [计数]

### 错误修复
- [列出每个错误及其修复方式,如果0个错误则为"无"]

### 警告解决
- [列出已修复的每个警告]

### 跳过的警告(及原因)
- [列出未修复的每个警告并解释原因]
- 示例:"mbake报告'.DELETE_ON_ERROR'未知 - 这是一个有效且关键的GNU Make
  特殊目标(误报)"

### 应用的格式化
- [是/否] - [如果没有应用格式化,解释为什么跳过]

### 解决的信息项
- [列出为生产Makefiles解决的信息项]
- [或"N/A - 简单项目"如果不适用]

### 剩余问题(如果有)
- [列出需要用户注意的任何问题]
- [或"无 - Makefile已准备就绪"]

完整报告示例:

## 验证报告

**结果:** 带警告通过
**错误:** 0
**警告:** 2
**信息:** 1

### 错误修复
- 无

### 警告解决
- 已修复:添加了安装目标的错误处理(|| exit 1)

### 跳过的警告(及原因)
- mbake报告".DELETE_ON_ERROR"未知 - 这是一个有效且关键的GNU Make
  特殊目标,确保失败的构建不会留下损坏的文件。
  参见:https://www.gnu.org/software/make/manual/html_node/Special-Targets.html

### 应用的格式化
- 是 - 应用`mbake format`修复了空格问题

### 解决的信息项
- 为Docker目标添加了.NOTPARALLEL(并行安全性)
- 为docker-push目标添加了错误处理

### 剩余问题
- 无 - Makefile已准备就绪

常见信息项:

信息项 何时修复 如何修复
“没有序贯先行条件的mkdir” 大型项目(>10个目标) 使用target: prereqs | $(BUILDDIR)模式
“配方命令缺少错误处理” 临界操作(安装、部署) 在.SHELLFLAGS中添加set -e或使用&&链接
“考虑使用ccache” 编译时间长 添加CC := ccache $(CC)模式
“检测到并行敏感命令” Docker/npm/pip目标 为受影响目标添加.NOTPARALLEL:或适当的依赖项

生产质量要求(Docker/部署目标必须解决):

当生成包含Docker或部署目标的Makefiles时,您必须应用这些生产模式:

  1. docker-push的错误处理:

    ## 将Docker映像推送到注册表(带错误处理)
    docker-push: docker-build
    	@echo "推送$(IMAGE)..."
    	docker push $(IMAGE) || { echo "推送$(IMAGE)失败"; exit 1; }
    	docker push $(IMAGE_LATEST) || { echo "推送$(IMAGE_LATEST)失败"; exit 1; }
    
  2. Docker目标的并行安全性:

    # 防止Docker目标并行执行(竞态条件)
    .NOTPARALLEL: docker-build docker-push docker-run
    

    或使用适当的依赖项进行序列化:

    docker-push: docker-build  # 确保构建完成后再推送
    docker-run: docker-build   # 确保构建完成后再运行
    
  3. 安装目标的错误处理:

    install: $(TARGET)
    	install -d $(DESTDIR)$(PREFIX)/bin || exit 1
    	install -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/bin/ || exit 1
    

注意: 当验证显示有关错误处理或并行安全性的信息项时,您必须为任何包含Docker、部署或安装目标的Makefile解决它们。在您的响应中解释应用了哪些模式。

验证清单:

  • [ ] 语法正确(make -n通过)
  • [ ] 所有非文件目标都有.PHONY
  • [ ] 制表符缩进(不是空格)
  • [ ] 没有硬编码的凭据
  • [ ] 用户可覆盖变量使用?=
  • [ ] 存在.DELETE_ON_ERROR
  • [ ] 包括MAKEFLAGS优化(现代头部)
  • [ ] 构建目录的序贯先行条件(大型项目)
  • [ ] 临界配方中的错误处理(安装、部署、docker-push)

最佳实践

变量

  • 用户可覆盖(CC、CFLAGS、PREFIX)使用?=
  • 项目特定(SOURCES、OBJECTS)使用:=
  • 使用pkg-config:CFLAGS += $(shell pkg-config --cflags lib)

目标

  • 始终声明非文件目标的.PHONY
  • 默认目标应为all
  • 使用.DELETE_ON_ERROR以确保安全
  • 使用##注释为帮助目标添加文档

目录创建

创建构建目录的两种方法:

简单(内联mkdir):

$(BUILDDIR)/%.o: $(SRCDIR)/%.c
	@mkdir -p $(@D)
	$(CC) $(CFLAGS) -c $< -o $@

优化(序贯先行条件): 防止目录时间戳变化时不必要的重建。

$(BUILDDIR):
	@mkdir -p $@

$(BUILDDIR)/%.o: $(SRCDIR)/%.c | $(BUILDDIR)
	$(CC) $(CFLAGS) -c $< -o $@

对于具有许多目标的大型项目,请使用序贯先行条件(|)。

配方

  • 使用制表符,永远不要使用空格
  • 在shell中引用变量:$(RM) "$(TARGET)"
  • 对于安静的命令使用@前缀
  • 首先使用make -n测试

辅助脚本(可选)

这些脚本是快速模板生成的可选便捷工具

何时使用脚本与手动生成

场景 建议
简单、标准项目(单二进制文件,无特殊功能) ✅ 使用generate_makefile_template.sh以提高速度
复杂项目(Docker、多二进制文件、自定义模式) ❌ 使用手动生成以获得完全控制
向现有Makefile添加目标 ✅ 使用add_standard_targets.sh
用户有特定的格式化/风格要求 ❌ 使用手动生成
快速原型/概念验证 ✅ 使用脚本,稍后自定义
生产就绪Makefile ⚠️ 从脚本开始,然后手动自定义

generate_makefile_template.sh

为特定项目类型生成完整的Makefile模板。

bash scripts/generate_makefile_template.sh [TYPE] [NAME]

类型:c, c-lib, cpp, go, python, java, generic

示例:

bash scripts/generate_makefile_template.sh go myservice
# 创建具有Go模式、版本嵌入、标准目标的Makefile

add_standard_targets.sh

向现有Makefile添加缺失的标准GNU目标。

bash scripts/add_standard_targets.sh [MAKEFILE] [TARGETS...]

目标:all, install, uninstall, clean, distclean, test, check, help

示例:

bash scripts/add_standard_targets.sh Makefile install uninstall help
# 如果它们不存在,则添加安装、卸载、帮助目标

注意: 按照第3阶段模式手动生成的结果等同于脚本,但允许更多自定义。

文档

docs/中的详细指南:

资源