gitgoodordietrying

Makefile & Build

开发编程v1.0.0
作者:gitgoodordietrying更新于 2026-05-11makefile-build@clawhub_gitgoodordietrying/makefile-build
代码生成脚本工具#Docker

据 AlphaMoat 统计,截至 2026-09,Makefile & Build 累计下载 2,676 次、获 3 个星标,在全部 5,078 个 AI 技能中排名第 3,966 位,在「开发编程」分类(577 个)中排名第 498 位。

累计安装
122
累计下载
2,676
星标
3
全站排名
#3,966
全站前 79% · 「开发编程」前 87%
平台累计安装累计下载星标评论
ClawHub ↗812,6453-
SkillHub ↗1222,6763—

各平台的计数口径不同,统计时间不一致。

这个技能是做什么的

内容涵盖目标、依赖、变量、模式规则、伪目标及 Go、Python、Node.js、Docker 的示例,并包含清理、部署和推送目标。复制或生成的目标可能删除文件、安装依赖、发布镜像或部署代码;执行前应逐项审查,并固定依赖版本。

资料发布于 2026-10-29

可以用来做什么

  • 为项目整理 build、test、lint 等任务
  • 比较 Make、Just 与 Task 的项目任务管理方式
  • 审查 clean、deploy 或 push 目标的副作用

什么时候用

  • 需要建立或改进项目级构建自动化,并能先审查可执行目标及其副作用时

示例提示词

以下是根据技能文档生成的示例,不代表实际运行结果。

为项目设计 build 与 test 目标,只输出 Makefile 草案,不运行命令。
审查一个 clean 目标可能影响的路径及执行前需要确认的事项。

月度数据趋势

累计下载2,676
1,5292,1452,7612026-03 · 累计下载 1,6142026-05 · 累计下载 2,0272026-06 · 累计下载 2,1662026-07 · 累计下载 2,3992026-08 · 累计下载 2,5262026-09 · 累计下载 2,67626-0326-09
星标3
2342026-03 · 星标 32026-05 · 星标 32026-06 · 星标 32026-07 · 星标 32026-08 · 星标 32026-09 · 星标 326-0326-09

2026-09 起统计方法调整:同名技能按作者分别统计,并覆盖全部技能。图中虚线为调整前的月份,与之后的数据不直接比较,也不计算跨越调整的增长。

月份累计下载环比星标
2026-092,676—3
2026-082,526+5.3%3
2026-072,399+10.8%3
2026-062,166+6.9%3
2026-052,027—3
2026-031,614—3

SKILL.md 原文

以下是作者发布的原始文件,按纯文本显示,本站未做修改或审核;其中的链接不可点击,命令请核实后再运行。抓取于 2026-10-23。

12 KB · ClawHub v1.0.0
---
name: makefile-build
description: Write Makefiles for any project type. Use when setting up build automation, defining multi-target builds, managing dependencies between tasks, creating project task runners, or using Make for non-C projects (Go, Python, Docker, Node.js). Also covers Just and Task as modern alternatives.
metadata: {"clawdbot":{"emoji":"🔨","requires":{"anyBins":["make","just","task"]},"os":["linux","darwin","win32"]}}
---

# Makefile & Build

Write Makefiles for project automation across any language. Covers targets, dependencies, variables, pattern rules, phony targets, and using Make for Go, Python, Docker, and Node.js projects. Includes Just and Task as modern alternatives.
展开全部(共 513 行)
## When to Use

- Automating build, test, lint, deploy commands
- Defining dependencies between tasks (build before test)
- Creating a project-level task runner (consistent across team)
- Replacing long CLI commands with short memorable targets
- Managing multi-step build processes
- Any project that needs a `make build && make test && make deploy` workflow

## Makefile Basics

### Structure

```makefile
# target: prerequisites
#     recipe (MUST be indented with TAB, not spaces)

build: src/main.go
	go build -o bin/app src/main.go

test: build
	go test ./...

clean:
	rm -rf bin/

# First target is the default (runs with bare `make`)
```

### Variables

```makefile
# Simple assignment
CC = gcc
CFLAGS = -Wall -O2

# Deferred assignment (expanded when used)
FILES = $(wildcard src/*.go)

# Immediate assignment (expanded when defined)
VERSION := $(shell git describe --tags --always)

# Conditional assignment (only if not already set)
PORT ?= 8080

# Use variables
build:
	$(CC) $(CFLAGS) -o app main.c
	@echo "Version: $(VERSION)"
```

### Automatic variables

```makefile
# $@ = target name
# $< = first prerequisite
# $^ = all prerequisites
# $* = stem (pattern match)
# $(@D) = directory of target
# $(@F) = filename of target

bin/app: src/main.go src/util.go
	go build -o $@ $^
# $@ = bin/app
# $^ = src/main.go src/util.go
# $< = src/main.go

# Pattern rule
%.o: %.c
	$(CC) -c -o $@ $<
# For foo.o: $@ = foo.o, $< = foo.c, $* = foo
```

### Phony targets (not files)

```makefile
# Without .PHONY, if a file named "clean" exists, `make clean` does nothing
.PHONY: build test clean lint fmt help

build:
	go build -o bin/app ./cmd/app

test:
	go test ./...

clean:
	rm -rf bin/ dist/

# List all targets
help:
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2}'
```

### Self-documenting Makefile

```makefile
.DEFAULT_GOAL := help

build: ## Build the application
	go build -o bin/app ./cmd/app

test: ## Run all tests
	go test -v ./...

lint: ## Run linters
	golangci-lint run

clean: ## Remove build artifacts
	rm -rf bin/ dist/

help: ## Show this help
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \
		awk 'BEGIN {FS = ":.*?## "}; {printf "  \033[36m%-15s\033[0m %s\n", $$1, $$2}'
```

## Language-Specific Makefiles

### Go

```makefile
BINARY_NAME := myapp
VERSION := $(shell git describe --tags --always --dirty)
LDFLAGS := -ldflags "-X main.version=$(VERSION)"
GOFILES := $(shell find . -name '*.go' -not -path './vendor/*')

.PHONY: all build test lint clean run

all: lint test build

build: ## Build binary
	CGO_ENABLED=0 go build $(LDFLAGS) -o bin/$(BINARY_NAME) ./cmd/$(BINARY_NAME)

test: ## Run tests
	go test -race -coverprofile=coverage.out ./...

test-coverage: test ## Show coverage report
	go tool cover -html=coverage.out

lint: ## Run linters
	golangci-lint run ./...

fmt: ## Format code
	gofmt -w $(GOFILES)

run: build ## Build and run
	./bin/$(BINARY_NAME)

clean: ## Clean build artifacts
	rm -rf bin/ coverage.out

# Cross-compilation
build-linux: ## Build for Linux
	GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o bin/$(BINARY_NAME)-linux-amd64 ./cmd/$(BINARY_NAME)

build-all: ## Build for all platforms
	GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o bin/$(BINARY_NAME)-linux-amd64 ./cmd/$(BINARY_NAME)
	GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o bin/$(BINARY_NAME)-darwin-arm64 ./cmd/$(BINARY_NAME)
	GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o bin/$(BINARY_NAME)-windows-amd64.exe ./cmd/$(BINARY_NAME)
```

### Python

```makefile
PYTHON := python3
VENV := .venv
BIN := $(VENV)/bin

.PHONY: all install test lint fmt clean run

all: install lint test

$(VENV)/bin/activate:
	$(PYTHON) -m venv $(VENV)
	$(BIN)/pip install --upgrade pip

install: $(VENV)/bin/activate ## Install dependencies
	$(BIN)/pip install -r requirements.txt
	$(BIN)/pip install -r requirements-dev.txt

test: ## Run tests
	$(BIN)/pytest -v --cov=src --cov-report=term-missing

lint: ## Run linters
	$(BIN)/ruff check src/ tests/
	$(BIN)/mypy src/

fmt: ## Format code
	$(BIN)/ruff format src/ tests/

run: ## Run application
	$(BIN)/python -m src.main

clean: ## Remove venv and caches
	rm -rf $(VENV) __pycache__ .pytest_cache .mypy_cache .ruff_cache
	find . -type d -name '__pycache__' -exec rm -rf {} + 2>/dev/null || true
```

### Node.js / TypeScript

```makefile
.PHONY: all install build test lint clean dev

all: install lint test build

node_modules: package.json
	npm install
	@touch node_modules

install: node_modules ## Install dependencies

build: node_modules ## Build TypeScript
	npx tsc

test: node_modules ## Run tests
	npx vitest run

test-watch: node_modules ## Run tests in watch mode
	npx vitest

lint: node_modules ## Lint code
	npx eslint src/ --ext .ts,.tsx
	npx tsc --noEmit

fmt: node_modules ## Format code
	npx prettier --write 'src/**/*.{ts,tsx}'

dev: node_modules ## Run in development mode
	npx tsx watch src/index.ts

clean: ## Clean build artifacts
	rm -rf dist/ node_modules/.cache
```

### Docker

```makefile
IMAGE_NAME := myapp
VERSION := $(shell git describe --tags --always)
REGISTRY := ghcr.io/myorg

.PHONY: build push run stop clean

build: ## Build Docker image
	docker build -t $(IMAGE_NAME):$(VERSION) -t $(IMAGE_NAME):latest .

push: build ## Push to registry
	docker tag $(IMAGE_NAME):$(VERSION) $(REGISTRY)/$(IMAGE_NAME):$(VERSION)
	docker tag $(IMAGE_NAME):latest $(REGISTRY)/$(IMAGE_NAME):latest
	docker push $(REGISTRY)/$(IMAGE_NAME):$(VERSION)
	docker push $(REGISTRY)/$(IMAGE_NAME):latest

run: ## Run container
	docker run --rm -p 8080:8080 --name $(IMAGE_NAME) $(IMAGE_NAME):latest

stop: ## Stop container
	docker stop $(IMAGE_NAME) 2>/dev/null || true

clean: ## Remove images
	docker rmi $(IMAGE_NAME):$(VERSION) $(IMAGE_NAME):latest 2>/dev/null || true

compose-up: ## Start with docker compose
	docker compose up -d --build

compose-down: ## Stop compose
	docker compose down

compose-logs: ## Follow compose logs
	docker compose logs -f
```

## Advanced Patterns

### Conditional logic

```makefile
# OS detection
UNAME := $(shell uname -s)
ifeq ($(UNAME),Darwin)
    SED := sed -i ''
else
    SED := sed -i
endif

# Environment-based config
ENV ?= development
ifeq ($(ENV),production)
    CFLAGS += -O2
    LDFLAGS += -s -w
else
    CFLAGS += -g -O0
endif

# Check if command exists
HAS_DOCKER := $(shell command -v docker 2>/dev/null)
docker-build:
ifndef HAS_DOCKER
	$(error "docker is not installed")
endif
	docker build -t myapp .
```

### Multi-directory builds

```makefile
SERVICES := api worker scheduler

.PHONY: build-all test-all $(SERVICES)

build-all: $(SERVICES)

$(SERVICES):
	$(MAKE) -C services/$@ build

test-all:
	@for svc in $(SERVICES); do \
		echo "Testing $$svc..."; \
		$(MAKE) -C services/$$svc test || exit 1; \
	done
```

### Include other Makefiles

```makefile
# Split large Makefile into modules
include mk/docker.mk
include mk/test.mk
include mk/deploy.mk

# Optional include (no error if missing)
-include .env.mk
```

### Silent execution and output control

```makefile
# @ suppresses command echo
install:
	@echo "Installing dependencies..."
	@npm install

# .SILENT for entire targets
.SILENT: help clean

# Make less verbose globally
MAKEFLAGS += --no-print-directory
```

## Just (Modern Alternative)

### Justfile syntax

```just
# justfile — simpler than Make, no TAB requirement

# Set shell
set shell := ["bash", "-euo", "pipefail", "-c"]

# Variables
version := `git describe --tags --always`
default_port := "8080"

# Default recipe (first one)
default: lint test build

# Recipes
build: ## Build the application
    go build -ldflags "-X main.version={{version}}" -o bin/app ./cmd/app

test: ## Run tests
    go test -race ./...

lint: ## Run linters
    golangci-lint run

run port=default_port: build ## Run with optional port
    ./bin/app --port {{port}}

clean: ## Clean artifacts
    rm -rf bin/ dist/

# Recipes with dependencies
deploy: build test
    ./scripts/deploy.sh

# OS-specific
[linux]
install-deps:
    sudo apt install -y build-essential

[macos]
install-deps:
    brew install go golangci-lint

# List recipes
help:
    @just --list
```

```bash
# Install: https://github.com/casey/just
# Run:
just          # Default recipe
just build    # Specific recipe
just run 9090 # With argument
just --list   # List all recipes
```

## Task (Go Task Runner)

### Taskfile.yml

```yaml
# Taskfile.yml
version: '3'

vars:
  VERSION:
    sh: git describe --tags --always
  BINARY: myapp

tasks:
  default:
    deps: [lint, test, build]

  build:
    desc: Build the application
    cmds:
      - go build -ldflags "-X main.version={{.VERSION}}" -o bin/{{.BINARY}} ./cmd/{{.BINARY}}
    sources:
      - ./**/*.go
    generates:
      - bin/{{.BINARY}}

  test:
    desc: Run tests
    cmds:
      - go test -race ./...

  lint:
    desc: Run linters
    cmds:
      - golangci-lint run

  run:
    desc: Build and run
    deps: [build]
    cmds:
      - ./bin/{{.BINARY}} {{.CLI_ARGS}}

  clean:
    desc: Clean artifacts
    cmds:
      - rm -rf bin/ dist/

  docker:build:
    desc: Build Docker image
    cmds:
      - docker build -t {{.BINARY}}:{{.VERSION}} .

  # Task with preconditions
  deploy:
    desc: Deploy to production
    preconditions:
      - sh: test -f bin/{{.BINARY}}
        msg: "Build first: task build"
      - sh: git diff --quiet
        msg: "Uncommitted changes detected"
    cmds:
      - ./scripts/deploy.sh
```

```bash
# Install: https://taskfile.dev/installation/
# Run:
task          # Default task
task build    # Specific task
task --list   # List all tasks
```

## Make vs Just vs Task

| Feature | Make | Just | Task |
|---|---|---|---|
| Config format | Makefile (TAB-sensitive) | justfile | Taskfile.yml |
| Dependencies | File-based + phony | Recipe-based | Task-based |
| File change detection | Built-in | No | sources/generates |
| Variables | Yes (complex) | Yes (simple) | Yes (YAML) |
| Cross-platform | Needs make installed | Single binary | Single binary |
| Learning curve | High | Low | Low |
| Best for | C/C++ builds, complex deps | Task runner replacement | YAML-native projects |

## Tips

- The number one Makefile bug: using spaces instead of tabs for indentation. Make requires literal TAB characters in recipes.
- `.PHONY` every target that isn't a real file. Without it, `make clean` won't run if a file named `clean` exists.
- Use `@` prefix to suppress command echo for cleaner output: `@echo "Building..."` prints only "Building...", not the echo command itself.
- The self-documenting `help` target (with `## comments`) is worth adding to every Makefile. `make help` becomes the project's command reference.
- Make is overkill for simple task running. If you just want named commands, Just or Task are simpler and don't have the TAB footgun.
- Use `?=` for variables users might want to override: `PORT ?= 8080` lets `PORT=9090 make run` work.
- For polyglot projects (Go + Python + Docker), a Makefile at the root that delegates to language-specific tools is a clean pattern.
- Make's file-based dependency tracking is genuinely powerful for build systems. If your project compiles files, Make's `target: prerequisites` model avoids unnecessary rebuilds.

「开发编程」分类下的热门技能

gitgoodordietrying 的其他技能

数据月份:2026-09 · 下载/星标/安装数聚合自公开技能注册库(ClawHub、SkillHub),按月更新。口径说明见数据方法。