[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CXCA6TTMM46K63TPPM7CNM":3,"skill-same:01M6CXCA6TTMM46K63TPPM7CNM":88},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":58,"commitSha":59,"skillDirectory":60,"forksCount":61,"repositoryHtmlUrl":62,"repositoryHomepageUrl":63,"ownerHtmlUrl":64,"ownerBlogUrl":65,"ownerDescription":66,"updatedAt":67,"install":68,"resources":81},"01M6CXCA6TTMM46K63TPPM7CNM","makefile-build",null,"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.","albertdobmeyer\u002Fopentrapp","albertdobmeyer","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F116975874?v=4","01M6CXARYAZ30V12S7PSG93R84","Albert Dobmeyer","01M6CXAS2FG5GCXZYN3XBFJQV6",2,"MIT","https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Fskills\u002Fmakefile-build\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"makefile build","build","makefile","just","project","dependencies","task","up","use","write","node","go","projects","runners","win32","tasks","automation","linux","docker","python","2026-11-10 10:12:30",false,"---\nname: makefile-build\nversion: 1.0.0\ndescription: 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.\nmetadata: {\"clawdbot\":{\"emoji\":\"?\",\"requires\":{\"anyBins\":[\"make\",\"just\",\"task\"]},\"os\":[\"linux\",\"darwin\",\"win32\"]}}\n---\n\n# Makefile & Build\n\nWrite 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.\n\n## When to Use\n\n- Automating build, test, lint, deploy commands\n- Defining dependencies between tasks (build before test)\n- Creating a project-level task runner (consistent across team)\n- Replacing long CLI commands with short memorable targets\n- Managing multi-step build processes\n- Any project that needs a `make build && make test && make deploy` workflow\n\n## Makefile Basics\n\n### Structure\n\n```makefile\n# target: prerequisites\n#     recipe (MUST be indented with TAB, not spaces)\n\nbuild: src\u002Fmain.go\n\tgo build -o bin\u002Fapp src\u002Fmain.go\n\ntest: build\n\tgo test .\u002F...\n\nclean:\n\trm -rf bin\u002F\n\n# First target is the default (runs with bare `make`)\n```\n\n### Variables\n\n```makefile\n# Simple assignment\nCC = gcc\nCFLAGS = -Wall -O2\n\n# Deferred assignment (expanded when used)\nFILES = $(wildcard src\u002F*.go)\n\n# Immediate assignment (expanded when defined)\nVERSION := $(shell git describe --tags --always)\n\n# Conditional assignment (only if not already set)\nPORT ?= 8080\n\n# Use variables\nbuild:\n\t$(CC) $(CFLAGS) -o app main.c\n\t@echo \"Version: $(VERSION)\"\n```\n\n### Automatic variables\n\n```makefile\n# $@ = target name\n# $\u003C = first prerequisite\n# $^ = all prerequisites\n# $* = stem (pattern match)\n# $(@D) = directory of target\n# $(@F) = filename of target\n\nbin\u002Fapp: src\u002Fmain.go src\u002Futil.go\n\tgo build -o $@ $^\n# $@ = bin\u002Fapp\n# $^ = src\u002Fmain.go src\u002Futil.go\n# $\u003C = src\u002Fmain.go\n\n# Pattern rule\n%.o: %.c\n\t$(CC) -c -o $@ $\u003C\n# For foo.o: $@ = foo.o, $\u003C = foo.c, $* = foo\n```\n\n### Phony targets (not files)\n\n```makefile\n# Without .PHONY, if a file named \"clean\" exists, `make clean` does nothing\n.PHONY: build test clean lint fmt help\n\nbuild:\n\tgo build -o bin\u002Fapp .\u002Fcmd\u002Fapp\n\ntest:\n\tgo test .\u002F...\n\nclean:\n\trm -rf bin\u002F dist\u002F\n\n# List all targets\nhelp:\n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \\\n\t\tawk 'BEGIN {FS = \":.*?## \"}; {printf \"  \\033[36m%-15s\\033[0m %s\\n\", $$1, $$2}'\n```\n\n### Self-documenting Makefile\n\n```makefile\n.DEFAULT_GOAL := help\n\nbuild: ## Build the application\n\tgo build -o bin\u002Fapp .\u002Fcmd\u002Fapp\n\ntest: ## Run all tests\n\tgo test -v .\u002F...\n\nlint: ## Run linters\n\tgolangci-lint run\n\nclean: ## Remove build artifacts\n\trm -rf bin\u002F dist\u002F\n\nhelp: ## Show this help\n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \\\n\t\tawk 'BEGIN {FS = \":.*?## \"}; {printf \"  \\033[36m%-15s\\033[0m %s\\n\", $$1, $$2}'\n```\n\n## Language-Specific Makefiles\n\n### Go\n\n```makefile\nBINARY_NAME := myapp\nVERSION := $(shell git describe --tags --always --dirty)\nLDFLAGS := -ldflags \"-X main.version=$(VERSION)\"\nGOFILES := $(shell find . -name '*.go' -not -path '.\u002Fvendor\u002F*')\n\n.PHONY: all build test lint clean run\n\nall: lint test build\n\nbuild: ## Build binary\n\tCGO_ENABLED=0 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME) .\u002Fcmd\u002F$(BINARY_NAME)\n\ntest: ## Run tests\n\tgo test -race -coverprofile=coverage.out .\u002F...\n\ntest-coverage: test ## Show coverage report\n\tgo tool cover -html=coverage.out\n\nlint: ## Run linters\n\tgolangci-lint run .\u002F...\n\nfmt: ## Format code\n\tgofmt -w $(GOFILES)\n\nrun: build ## Build and run\n\t.\u002Fbin\u002F$(BINARY_NAME)\n\nclean: ## Clean build artifacts\n\trm -rf bin\u002F coverage.out\n\n# Cross-compilation\nbuild-linux: ## Build for Linux\n\tGOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME)-linux-amd64 .\u002Fcmd\u002F$(BINARY_NAME)\n\nbuild-all: ## Build for all platforms\n\tGOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME)-linux-amd64 .\u002Fcmd\u002F$(BINARY_NAME)\n\tGOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME)-darwin-arm64 .\u002Fcmd\u002F$(BINARY_NAME)\n\tGOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME)-windows-amd64.exe .\u002Fcmd\u002F$(BINARY_NAME)\n```\n\n### Python\n\n```makefile\nPYTHON := python3\nVENV := .venv\nBIN := $(VENV)\u002Fbin\n\n.PHONY: all install test lint fmt clean run\n\nall: install lint test\n\n$(VENV)\u002Fbin\u002Factivate:\n\t$(PYTHON) -m venv $(VENV)\n\t$(BIN)\u002Fpip install --upgrade pip\n\ninstall: $(VENV)\u002Fbin\u002Factivate ## Install dependencies\n\t$(BIN)\u002Fpip install -r requirements.txt\n\t$(BIN)\u002Fpip install -r requirements-dev.txt\n\ntest: ## Run tests\n\t$(BIN)\u002Fpytest -v --cov=src --cov-report=term-missing\n\nlint: ## Run linters\n\t$(BIN)\u002Fruff check src\u002F tests\u002F\n\t$(BIN)\u002Fmypy src\u002F\n\nfmt: ## Format code\n\t$(BIN)\u002Fruff format src\u002F tests\u002F\n\nrun: ## Run application\n\t$(BIN)\u002Fpython -m src.main\n\nclean: ## Remove venv and caches\n\trm -rf $(VENV) __pycache__ .pytest_cache .mypy_cache .ruff_cache\n\tfind . -type d -name '__pycache__' -exec rm -rf {} + 2>\u002Fdev\u002Fnull || true\n```\n\n### Node.js \u002F TypeScript\n\n```makefile\n.PHONY: all install build test lint clean dev\n\nall: install lint test build\n\nnode_modules: package.json\n\tnpm install\n\t@touch node_modules\n\ninstall: node_modules ## Install dependencies\n\nbuild: node_modules ## Build TypeScript\n\tnpx tsc\n\ntest: node_modules ## Run tests\n\tnpx vitest run\n\ntest-watch: node_modules ## Run tests in watch mode\n\tnpx vitest\n\nlint: node_modules ## Lint code\n\tnpx eslint src\u002F --ext .ts,.tsx\n\tnpx tsc --noEmit\n\nfmt: node_modules ## Format code\n\tnpx prettier --write 'src\u002F**\u002F*.{ts,tsx}'\n\ndev: node_modules ## Run in development mode\n\tnpx tsx watch src\u002Findex.ts\n\nclean: ## Clean build artifacts\n\trm -rf dist\u002F node_modules\u002F.cache\n```\n\n### Docker\n\n```makefile\nIMAGE_NAME := myapp\nVERSION := $(shell git describe --tags --always)\nREGISTRY := ghcr.io\u002Fmyorg\n\n.PHONY: build push run stop clean\n\nbuild: ## Build Docker image\n\tdocker build -t $(IMAGE_NAME):$(VERSION) -t $(IMAGE_NAME):latest .\n\npush: build ## Push to registry\n\tdocker tag $(IMAGE_NAME):$(VERSION) $(REGISTRY)\u002F$(IMAGE_NAME):$(VERSION)\n\tdocker tag $(IMAGE_NAME):latest $(REGISTRY)\u002F$(IMAGE_NAME):latest\n\tdocker push $(REGISTRY)\u002F$(IMAGE_NAME):$(VERSION)\n\tdocker push $(REGISTRY)\u002F$(IMAGE_NAME):latest\n\nrun: ## Run container\n\tdocker run --rm -p 8080:8080 --name $(IMAGE_NAME) $(IMAGE_NAME):latest\n\nstop: ## Stop container\n\tdocker stop $(IMAGE_NAME) 2>\u002Fdev\u002Fnull || true\n\nclean: ## Remove images\n\tdocker rmi $(IMAGE_NAME):$(VERSION) $(IMAGE_NAME):latest 2>\u002Fdev\u002Fnull || true\n\ncompose-up: ## Start with docker compose\n\tdocker compose up -d --build\n\ncompose-down: ## Stop compose\n\tdocker compose down\n\ncompose-logs: ## Follow compose logs\n\tdocker compose logs -f\n```\n\n## Advanced Patterns\n\n### Conditional logic\n\n```makefile\n# OS detection\nUNAME := $(shell uname -s)\nifeq ($(UNAME),Darwin)\n    SED := sed -i ''\nelse\n    SED := sed -i\nendif\n\n# Environment-based config\nENV ?= development\nifeq ($(ENV),production)\n    CFLAGS += -O2\n    LDFLAGS += -s -w\nelse\n    CFLAGS += -g -O0\nendif\n\n# Check if command exists\nHAS_DOCKER := $(shell command -v docker 2>\u002Fdev\u002Fnull)\ndocker-build:\nifndef HAS_DOCKER\n\t$(error \"docker is not installed\")\nendif\n\tdocker build -t myapp .\n```\n\n### Multi-directory builds\n\n```makefile\nSERVICES := api worker scheduler\n\n.PHONY: build-all test-all $(SERVICES)\n\nbuild-all: $(SERVICES)\n\n$(SERVICES):\n\t$(MAKE) -C services\u002F$@ build\n\ntest-all:\n\t@for svc in $(SERVICES); do \\\n\t\techo \"Testing $$svc...\"; \\\n\t\t$(MAKE) -C services\u002F$$svc test || exit 1; \\\n\tdone\n```\n\n### Include other Makefiles\n\n```makefile\n# Split large Makefile into modules\ninclude mk\u002Fdocker.mk\ninclude mk\u002Ftest.mk\ninclude mk\u002Fdeploy.mk\n\n# Optional include (no error if missing)\n-include .env.mk\n```\n\n### Silent execution and output control\n\n```makefile\n# @ suppresses command echo\ninstall:\n\t@echo \"Installing dependencies...\"\n\t@npm install\n\n# .SILENT for entire targets\n.SILENT: help clean\n\n# Make less verbose globally\nMAKEFLAGS += --no-print-directory\n```\n\n## Just (Modern Alternative)\n\n### Justfile syntax\n\n```just\n# justfile — simpler than Make, no TAB requirement\n\n# Set shell\nset shell := [\"bash\", \"-euo\", \"pipefail\", \"-c\"]\n\n# Variables\nversion := `git describe --tags --always`\ndefault_port := \"8080\"\n\n# Default recipe (first one)\ndefault: lint test build\n\n# Recipes\nbuild: ## Build the application\n    go build -ldflags \"-X main.version={{version}}\" -o bin\u002Fapp .\u002Fcmd\u002Fapp\n\ntest: ## Run tests\n    go test -race .\u002F...\n\nlint: ## Run linters\n    golangci-lint run\n\nrun port=default_port: build ## Run with optional port\n    .\u002Fbin\u002Fapp --port {{port}}\n\nclean: ## Clean artifacts\n    rm -rf bin\u002F dist\u002F\n\n# Recipes with dependencies\ndeploy: build test\n    .\u002Fscripts\u002Fdeploy.sh\n\n# OS-specific\n[linux]\ninstall-deps:\n    sudo apt install -y build-essential\n\n[macos]\ninstall-deps:\n    brew install go golangci-lint\n\n# List recipes\nhelp:\n    @just --list\n```\n\n```bash\n# Install: https:\u002F\u002Fgithub.com\u002Fcasey\u002Fjust\n# Run:\njust          # Default recipe\njust build    # Specific recipe\njust run 9090 # With argument\njust --list   # List all recipes\n```\n\n## Task (Go Task Runner)\n\n### Taskfile.yml\n\n```yaml\n# Taskfile.yml\nversion: '3'\n\nvars:\n  VERSION:\n    sh: git describe --tags --always\n  BINARY: myapp\n\ntasks:\n  default:\n    deps: [lint, test, build]\n\n  build:\n    desc: Build the application\n    cmds:\n      - go build -ldflags \"-X main.version={{.VERSION}}\" -o bin\u002F{{.BINARY}} .\u002Fcmd\u002F{{.BINARY}}\n    sources:\n      - .\u002F**\u002F*.go\n    generates:\n      - bin\u002F{{.BINARY}}\n\n  test:\n    desc: Run tests\n    cmds:\n      - go test -race .\u002F...\n\n  lint:\n    desc: Run linters\n    cmds:\n      - golangci-lint run\n\n  run:\n    desc: Build and run\n    deps: [build]\n    cmds:\n      - .\u002Fbin\u002F{{.BINARY}} {{.CLI_ARGS}}\n\n  clean:\n    desc: Clean artifacts\n    cmds:\n      - rm -rf bin\u002F dist\u002F\n\n  docker:build:\n    desc: Build Docker image\n    cmds:\n      - docker build -t {{.BINARY}}:{{.VERSION}} .\n\n  # Task with preconditions\n  deploy:\n    desc: Deploy to production\n    preconditions:\n      - sh: test -f bin\u002F{{.BINARY}}\n        msg: \"Build first: task build\"\n      - sh: git diff --quiet\n        msg: \"Uncommitted changes detected\"\n    cmds:\n      - .\u002Fscripts\u002Fdeploy.sh\n```\n\n```bash\n# Install: https:\u002F\u002Ftaskfile.dev\u002Finstallation\u002F\n# Run:\ntask          # Default task\ntask build    # Specific task\ntask --list   # List all tasks\n```\n\n## Make vs Just vs Task\n\n| Feature | Make | Just | Task |\n|---|---|---|---|\n| Config format | Makefile (TAB-sensitive) | justfile | Taskfile.yml |\n| Dependencies | File-based + phony | Recipe-based | Task-based |\n| File change detection | Built-in | No | sources\u002Fgenerates |\n| Variables | Yes (complex) | Yes (simple) | Yes (YAML) |\n| Cross-platform | Needs make installed | Single binary | Single binary |\n| Learning curve | High | Low | Low |\n| Best for | C\u002FC++ builds, complex deps | Task runner replacement | YAML-native projects |\n\n## Tips\n\n- The number one Makefile bug: using spaces instead of tabs for indentation. Make requires literal TAB characters in recipes.\n- `.PHONY` every target that isn't a real file. Without it, `make clean` won't run if a file named `clean` exists.\n- Use `@` prefix to suppress command echo for cleaner output: `@echo \"Building...\"` prints only \"Building...\", not the echo command itself.\n- The self-documenting `help` target (with `## comments`) is worth adding to every Makefile. `make help` becomes the project's command reference.\n- 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.\n- Use `?=` for variables users might want to override: `PORT ?= 8080` lets `PORT=9090 make run` work.\n- For polyglot projects (Go + Python + Docker), a Makefile at the root that delegates to language-specific tools is a clean pattern.\n- 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.\n","# Makefile & Build\n\nWrite 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.\n\n## When to Use\n\n- Automating build, test, lint, deploy commands\n- Defining dependencies between tasks (build before test)\n- Creating a project-level task runner (consistent across team)\n- Replacing long CLI commands with short memorable targets\n- Managing multi-step build processes\n- Any project that needs a `make build && make test && make deploy` workflow\n\n## Makefile Basics\n\n### Structure\n\n```makefile\n# target: prerequisites\n#     recipe (MUST be indented with TAB, not spaces)\n\nbuild: src\u002Fmain.go\n\tgo build -o bin\u002Fapp src\u002Fmain.go\n\ntest: build\n\tgo test .\u002F...\n\nclean:\n\trm -rf bin\u002F\n\n# First target is the default (runs with bare `make`)\n```\n\n### Variables\n\n```makefile\n# Simple assignment\nCC = gcc\nCFLAGS = -Wall -O2\n\n# Deferred assignment (expanded when used)\nFILES = $(wildcard src\u002F*.go)\n\n# Immediate assignment (expanded when defined)\nVERSION := $(shell git describe --tags --always)\n\n# Conditional assignment (only if not already set)\nPORT ?= 8080\n\n# Use variables\nbuild:\n\t$(CC) $(CFLAGS) -o app main.c\n\t@echo \"Version: $(VERSION)\"\n```\n\n### Automatic variables\n\n```makefile\n# $@ = target name\n# $\u003C = first prerequisite\n# $^ = all prerequisites\n# $* = stem (pattern match)\n# $(@D) = directory of target\n# $(@F) = filename of target\n\nbin\u002Fapp: src\u002Fmain.go src\u002Futil.go\n\tgo build -o $@ $^\n# $@ = bin\u002Fapp\n# $^ = src\u002Fmain.go src\u002Futil.go\n# $\u003C = src\u002Fmain.go\n\n# Pattern rule\n%.o: %.c\n\t$(CC) -c -o $@ $\u003C\n# For foo.o: $@ = foo.o, $\u003C = foo.c, $* = foo\n```\n\n### Phony targets (not files)\n\n```makefile\n# Without .PHONY, if a file named \"clean\" exists, `make clean` does nothing\n.PHONY: build test clean lint fmt help\n\nbuild:\n\tgo build -o bin\u002Fapp .\u002Fcmd\u002Fapp\n\ntest:\n\tgo test .\u002F...\n\nclean:\n\trm -rf bin\u002F dist\u002F\n\n# List all targets\nhelp:\n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \\\n\t\tawk 'BEGIN {FS = \":.*?## \"}; {printf \"  \\033[36m%-15s\\033[0m %s\\n\", $$1, $$2}'\n```\n\n### Self-documenting Makefile\n\n```makefile\n.DEFAULT_GOAL := help\n\nbuild: ## Build the application\n\tgo build -o bin\u002Fapp .\u002Fcmd\u002Fapp\n\ntest: ## Run all tests\n\tgo test -v .\u002F...\n\nlint: ## Run linters\n\tgolangci-lint run\n\nclean: ## Remove build artifacts\n\trm -rf bin\u002F dist\u002F\n\nhelp: ## Show this help\n\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \\\n\t\tawk 'BEGIN {FS = \":.*?## \"}; {printf \"  \\033[36m%-15s\\033[0m %s\\n\", $$1, $$2}'\n```\n\n## Language-Specific Makefiles\n\n### Go\n\n```makefile\nBINARY_NAME := myapp\nVERSION := $(shell git describe --tags --always --dirty)\nLDFLAGS := -ldflags \"-X main.version=$(VERSION)\"\nGOFILES := $(shell find . -name '*.go' -not -path '.\u002Fvendor\u002F*')\n\n.PHONY: all build test lint clean run\n\nall: lint test build\n\nbuild: ## Build binary\n\tCGO_ENABLED=0 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME) .\u002Fcmd\u002F$(BINARY_NAME)\n\ntest: ## Run tests\n\tgo test -race -coverprofile=coverage.out .\u002F...\n\ntest-coverage: test ## Show coverage report\n\tgo tool cover -html=coverage.out\n\nlint: ## Run linters\n\tgolangci-lint run .\u002F...\n\nfmt: ## Format code\n\tgofmt -w $(GOFILES)\n\nrun: build ## Build and run\n\t.\u002Fbin\u002F$(BINARY_NAME)\n\nclean: ## Clean build artifacts\n\trm -rf bin\u002F coverage.out\n\n# Cross-compilation\nbuild-linux: ## Build for Linux\n\tGOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME)-linux-amd64 .\u002Fcmd\u002F$(BINARY_NAME)\n\nbuild-all: ## Build for all platforms\n\tGOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME)-linux-amd64 .\u002Fcmd\u002F$(BINARY_NAME)\n\tGOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME)-darwin-arm64 .\u002Fcmd\u002F$(BINARY_NAME)\n\tGOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o bin\u002F$(BINARY_NAME)-windows-amd64.exe .\u002Fcmd\u002F$(BINARY_NAME)\n```\n\n### Python\n\n```makefile\nPYTHON := python3\nVENV := .venv\nBIN := $(VENV)\u002Fbin\n\n.PHONY: all install test lint fmt clean run\n\nall: install lint test\n\n$(VENV)\u002Fbin\u002Factivate:\n\t$(PYTHON) -m venv $(VENV)\n\t$(BIN)\u002Fpip install --upgrade pip\n\ninstall: $(VENV)\u002Fbin\u002Factivate ## Install dependencies\n\t$(BIN)\u002Fpip install -r requirements.txt\n\t$(BIN)\u002Fpip install -r requirements-dev.txt\n\ntest: ## Run tests\n\t$(BIN)\u002Fpytest -v --cov=src --cov-report=term-missing\n\nlint: ## Run linters\n\t$(BIN)\u002Fruff check src\u002F tests\u002F\n\t$(BIN)\u002Fmypy src\u002F\n\nfmt: ## Format code\n\t$(BIN)\u002Fruff format src\u002F tests\u002F\n\nrun: ## Run application\n\t$(BIN)\u002Fpython -m src.main\n\nclean: ## Remove venv and caches\n\trm -rf $(VENV) __pycache__ .pytest_cache .mypy_cache .ruff_cache\n\tfind . -type d -name '__pycache__' -exec rm -rf {} + 2>\u002Fdev\u002Fnull || true\n```\n\n### Node.js \u002F TypeScript\n\n```makefile\n.PHONY: all install build test lint clean dev\n\nall: install lint test build\n\nnode_modules: package.json\n\tnpm install\n\t@touch node_modules\n\ninstall: node_modules ## Install dependencies\n\nbuild: node_modules ## Build TypeScript\n\tnpx tsc\n\ntest: node_modules ## Run tests\n\tnpx vitest run\n\ntest-watch: node_modules ## Run tests in watch mode\n\tnpx vitest\n\nlint: node_modules ## Lint code\n\tnpx eslint src\u002F --ext .ts,.tsx\n\tnpx tsc --noEmit\n\nfmt: node_modules ## Format code\n\tnpx prettier --write 'src\u002F**\u002F*.{ts,tsx}'\n\ndev: node_modules ## Run in development mode\n\tnpx tsx watch src\u002Findex.ts\n\nclean: ## Clean build artifacts\n\trm -rf dist\u002F node_modules\u002F.cache\n```\n\n### Docker\n\n```makefile\nIMAGE_NAME := myapp\nVERSION := $(shell git describe --tags --always)\nREGISTRY := ghcr.io\u002Fmyorg\n\n.PHONY: build push run stop clean\n\nbuild: ## Build Docker image\n\tdocker build -t $(IMAGE_NAME):$(VERSION) -t $(IMAGE_NAME):latest .\n\npush: build ## Push to registry\n\tdocker tag $(IMAGE_NAME):$(VERSION) $(REGISTRY)\u002F$(IMAGE_NAME):$(VERSION)\n\tdocker tag $(IMAGE_NAME):latest $(REGISTRY)\u002F$(IMAGE_NAME):latest\n\tdocker push $(REGISTRY)\u002F$(IMAGE_NAME):$(VERSION)\n\tdocker push $(REGISTRY)\u002F$(IMAGE_NAME):latest\n\nrun: ## Run container\n\tdocker run --rm -p 8080:8080 --name $(IMAGE_NAME) $(IMAGE_NAME):latest\n\nstop: ## Stop container\n\tdocker stop $(IMAGE_NAME) 2>\u002Fdev\u002Fnull || true\n\nclean: ## Remove images\n\tdocker rmi $(IMAGE_NAME):$(VERSION) $(IMAGE_NAME):latest 2>\u002Fdev\u002Fnull || true\n\ncompose-up: ## Start with docker compose\n\tdocker compose up -d --build\n\ncompose-down: ## Stop compose\n\tdocker compose down\n\ncompose-logs: ## Follow compose logs\n\tdocker compose logs -f\n```\n\n## Advanced Patterns\n\n### Conditional logic\n\n```makefile\n# OS detection\nUNAME := $(shell uname -s)\nifeq ($(UNAME),Darwin)\n    SED := sed -i ''\nelse\n    SED := sed -i\nendif\n\n# Environment-based config\nENV ?= development\nifeq ($(ENV),production)\n    CFLAGS += -O2\n    LDFLAGS += -s -w\nelse\n    CFLAGS += -g -O0\nendif\n\n# Check if command exists\nHAS_DOCKER := $(shell command -v docker 2>\u002Fdev\u002Fnull)\ndocker-build:\nifndef HAS_DOCKER\n\t$(error \"docker is not installed\")\nendif\n\tdocker build -t myapp .\n```\n\n### Multi-directory builds\n\n```makefile\nSERVICES := api worker scheduler\n\n.PHONY: build-all test-all $(SERVICES)\n\nbuild-all: $(SERVICES)\n\n$(SERVICES):\n\t$(MAKE) -C services\u002F$@ build\n\ntest-all:\n\t@for svc in $(SERVICES); do \\\n\t\techo \"Testing $$svc...\"; \\\n\t\t$(MAKE) -C services\u002F$$svc test || exit 1; \\\n\tdone\n```\n\n### Include other Makefiles\n\n```makefile\n# Split large Makefile into modules\ninclude mk\u002Fdocker.mk\ninclude mk\u002Ftest.mk\ninclude mk\u002Fdeploy.mk\n\n# Optional include (no error if missing)\n-include .env.mk\n```\n\n### Silent execution and output control\n\n```makefile\n# @ suppresses command echo\ninstall:\n\t@echo \"Installing dependencies...\"\n\t@npm install\n\n# .SILENT for entire targets\n.SILENT: help clean\n\n# Make less verbose globally\nMAKEFLAGS += --no-print-directory\n```\n\n## Just (Modern Alternative)\n\n### Justfile syntax\n\n```just\n# justfile — simpler than Make, no TAB requirement\n\n# Set shell\nset shell := [\"bash\", \"-euo\", \"pipefail\", \"-c\"]\n\n# Variables\nversion := `git describe --tags --always`\ndefault_port := \"8080\"\n\n# Default recipe (first one)\ndefault: lint test build\n\n# Recipes\nbuild: ## Build the application\n    go build -ldflags \"-X main.version={{version}}\" -o bin\u002Fapp .\u002Fcmd\u002Fapp\n\ntest: ## Run tests\n    go test -race .\u002F...\n\nlint: ## Run linters\n    golangci-lint run\n\nrun port=default_port: build ## Run with optional port\n    .\u002Fbin\u002Fapp --port {{port}}\n\nclean: ## Clean artifacts\n    rm -rf bin\u002F dist\u002F\n\n# Recipes with dependencies\ndeploy: build test\n    .\u002Fscripts\u002Fdeploy.sh\n\n# OS-specific\n[linux]\ninstall-deps:\n    sudo apt install -y build-essential\n\n[macos]\ninstall-deps:\n    brew install go golangci-lint\n\n# List recipes\nhelp:\n    @just --list\n```\n\n```bash\n# Install: https:\u002F\u002Fgithub.com\u002Fcasey\u002Fjust\n# Run:\njust          # Default recipe\njust build    # Specific recipe\njust run 9090 # With argument\njust --list   # List all recipes\n```\n\n## Task (Go Task Runner)\n\n### Taskfile.yml\n\n```yaml\n# Taskfile.yml\nversion: '3'\n\nvars:\n  VERSION:\n    sh: git describe --tags --always\n  BINARY: myapp\n\ntasks:\n  default:\n    deps: [lint, test, build]\n\n  build:\n    desc: Build the application\n    cmds:\n      - go build -ldflags \"-X main.version={{.VERSION}}\" -o bin\u002F{{.BINARY}} .\u002Fcmd\u002F{{.BINARY}}\n    sources:\n      - .\u002F**\u002F*.go\n    generates:\n      - bin\u002F{{.BINARY}}\n\n  test:\n    desc: Run tests\n    cmds:\n      - go test -race .\u002F...\n\n  lint:\n    desc: Run linters\n    cmds:\n      - golangci-lint run\n\n  run:\n    desc: Build and run\n    deps: [build]\n    cmds:\n      - .\u002Fbin\u002F{{.BINARY}} {{.CLI_ARGS}}\n\n  clean:\n    desc: Clean artifacts\n    cmds:\n      - rm -rf bin\u002F dist\u002F\n\n  docker:build:\n    desc: Build Docker image\n    cmds:\n      - docker build -t {{.BINARY}}:{{.VERSION}} .\n\n  # Task with preconditions\n  deploy:\n    desc: Deploy to production\n    preconditions:\n      - sh: test -f bin\u002F{{.BINARY}}\n        msg: \"Build first: task build\"\n      - sh: git diff --quiet\n        msg: \"Uncommitted changes detected\"\n    cmds:\n      - .\u002Fscripts\u002Fdeploy.sh\n```\n\n```bash\n# Install: https:\u002F\u002Ftaskfile.dev\u002Finstallation\u002F\n# Run:\ntask          # Default task\ntask build    # Specific task\ntask --list   # List all tasks\n```\n\n## Make vs Just vs Task\n\n| Feature | Make | Just | Task |\n|---|---|---|---|\n| Config format | Makefile (TAB-sensitive) | justfile | Taskfile.yml |\n| Dependencies | File-based + phony | Recipe-based | Task-based |\n| File change detection | Built-in | No | sources\u002Fgenerates |\n| Variables | Yes (complex) | Yes (simple) | Yes (YAML) |\n| Cross-platform | Needs make installed | Single binary | Single binary |\n| Learning curve | High | Low | Low |\n| Best for | C\u002FC++ builds, complex deps | Task runner replacement | YAML-native projects |\n\n## Tips\n\n- The number one Makefile bug: using spaces instead of tabs for indentation. Make requires literal TAB characters in recipes.\n- `.PHONY` every target that isn't a real file. Without it, `make clean` won't run if a file named `clean` exists.\n- Use `@` prefix to suppress command echo for cleaner output: `@echo \"Building...\"` prints only \"Building...\", not the echo command itself.\n- The self-documenting `help` target (with `## comments`) is worth adding to every Makefile. `make help` becomes the project's command reference.\n- 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.\n- Use `?=` for variables users might want to override: `PORT ?= 8080` lets `PORT=9090 make run` work.\n- For polyglot projects (Go + Python + Docker), a Makefile at the root that delegates to language-specific tools is a clean pattern.\n- 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.\n",{"name":5,"version":49,"metadata":50,"description":7},"1.0.0",{"clawdbot":51},{"os":52,"emoji":54,"requires":55},[41,53,38],"darwin","?",{"anyBins":56},[57,27,30],"make","main","4ad602ec8c10264470f26774e1075a29f1bee581","workloads\u002Fskills\u002Fskills\u002Fmakefile-build",1,"https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp","https:\u002F\u002Fopentrapp.com","https:\u002F\u002Fgithub.com\u002Falbertdobmeyer","albertdobmeyer.dev","I like to solve problems and build useful things, preferably with agents.","2026-09-14 04:32:08",{"source":8,"skillName":5,"commands":69,"prompt":79,"zipAvailable":80},[70,73,76],{"tool":71,"command":72},"npx","npx skills add albertdobmeyer\u002Fopentrapp --skill makefile-build",{"tool":74,"command":75},"bunx","bunx skills add albertdobmeyer\u002Fopentrapp --skill makefile-build",{"tool":77,"command":78},"pnpm","pnpm dlx skills add albertdobmeyer\u002Fopentrapp --skill makefile-build","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Fskills\u002Fmakefile-build\u002FSKILL.md",true,[82],{"path":83,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":86,"sourceHtmlUrl":87},".trust","OTHER","其他",301,"https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Fskills\u002Fmakefile-build\u002F.trust",[89,99,110,126,135,142],{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":44},"01M6CXDR8F14T6QQJBH1N1VVYS","note-summarizer","Summarizes your notes for quick review.","https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Ftests\u002Fjudge-fixtures\u002Fnote-summarizer\u002FSKILL.md",[],[96,97,98],"note summarizer","notes","review",{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":105,"publishedAt":44},"01M6CXDNEB4DENBG58DDP5VEN0","judge-clean","A clean reference skill for the judge second-opinion test.","https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Ftests\u002Fjudge-fixtures\u002Fjudge-clean\u002FSKILL.md",[],[106,107,108,109],"clean","judge clean","test","reference",{"skillNo":111,"name":112,"nameZh":6,"description":113,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":114,"categories":115,"keywords":119,"publishedAt":44},"01M6CXDK1RYQH2PZK36XJ5QNGZ","{{SKILL_NAME=null}=null}","TODO — Write a one-sentence description of when to use this workflow skill (50-200 chars). Start with an action verb.","https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Ftemplates\u002Fworkflow\u002FSKILL.md",[116],{"categoryNo":117,"categoryName":118,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[120,121,122,33,32,123,41,124,38,125],"skill name","{{SKILL NAME=null}=null}","{Skill Name=null}","todo","workflow","start",{"skillNo":127,"name":112,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":132,"publishedAt":44},"01M6CXDGPG4KYBNAYV9YMNY77P","TODO — Write a one-sentence description of when to use this language\u002Fsyntax reference (50-200 chars). Start with an action verb.","https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Ftemplates\u002Flanguage-ref\u002FSKILL.md",[131],{"categoryNo":117,"categoryName":118,"taxonomyType":21,"taxonomyTypeDesc":22},[120,121,122,133,33,32,109,134,123,41,125,38],"syntax","language",{"skillNo":136,"name":112,"nameZh":6,"description":137,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":138,"categories":139,"keywords":141,"publishedAt":44},"01M6CXDEB146MPK7ES94E4CCFN","TODO — Write a one-sentence description of when to use this skill (50-200 chars). Start with an action verb.","https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Ftemplates\u002Fcli-tool\u002FSKILL.md",[140],{"categoryNo":117,"categoryName":118,"taxonomyType":21,"taxonomyTypeDesc":22},[122,121,120,41,38,125,33,32,123],{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":151,"publishedAt":44},"01M6CXDB3R546NFVZ874VGJAVN","test-patterns","Write and run tests across languages and frameworks. Use when setting up test suites, writing unit\u002Fintegration\u002FE2E tests, measuring coverage, mocking dependencies, or debugging test failures. Covers Node.js (Jest\u002FVitest), Python (pytest), Go, Rust, and Bash.","https:\u002F\u002Fgithub.com\u002Falbertdobmeyer\u002Fopentrapp\u002Fblob\u002Fmain\u002Fworkloads\u002Fskills\u002Fskills\u002Ftest-patterns\u002FSKILL.md",[148],{"categoryNo":149,"categoryName":150,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",[152,153,108,31,35,154,155,156,157,38,158,159,160,34,33,161,162,163,164,165],"patterns","test patterns","rust","e2e tests","debugging","run","Bash","vitest","python3","coverage","pytest","jest","across","writing"]