Makefile для разработчиков — автоматизируйте задачи без использования «баш-спагети»

Обновлено

Make — это инструмент сборки 1977 года, который оказался отличным инструментом для выполнения задач. Один файл Makefile, make test, всё сделано — нет скриптов bash для поддержки, нет зависимостей для установки.

Makefile для разработчиков — Автоматизация задач без Bash-спагети 1
Реклама · УДАЛИТЬ?

Вы знаете, как это происходит. Проект начинается чистым. Затем кто-то добавляет run.sh. Затем build.sh. Затем добавляется deploy.sh который подключает .env и вызывает первые два в определённом порядке, и вдруг появляются шесть файлов shell, которых никто не хочет трогать, и файл README, в котором написано «см. папку с скриптами».

Вносите исправления. Один Makefile в корне проекта, make test, выполнено.

Это не касается систем сборки на языке C. Make был создан до появления Linux и изначально разрабатывался для компиляции с использованием зависимостей — но его основная механика (именованные цели, выполняющие команды на уровне shell) делает его надёжным инструментом для выполнения задач в любой стеке. Node, Python, Go, Rust, Docker, что угодно, что вы создаёте.

Как работает Make на самом деле

Makefile — это список целей. Каждая цель имеет имя, необязательные зависимости и блок команд на shell:

.PHONY: build test lint clean

build:
	npm run build

test:
	npm test

Две вещи, которые мешают новичкам при первом знакомстве:

  • Отступ должен быть настоящим символом табу, а не пробелами. Каждое редактор, который автоматически конвертирует табу, будет безусловно нарушать ваш Makefile, пока вы не настроите его иначе. Это было верно с 1977 года и Make никогда не простит вас за использование пробелов.
  • По умолчанию, Make считает имена целей — именами файлов. Если в корне проекта есть файл build , make build ничего не делает, потому что Make считает, что цель уже «создана». Решение — .PHONY.

Объявите каждую цель, которая не является реальным именем файла, как .PHONY. На практике, Makefiles, используемые как инструменты выполнения задач, объявляют каждую цель, потому что ни одна из них не создаёт файлы. Ваша .PHONY строка в итоге выглядит как первая строка шаблона ниже.

Переменные и переключатели из командной строки

Make имеет собственную синтаксис переменных — выглядит как в shell, но работает иначе:

DOCKER_IMAGE = myapp
TAG = latest

build:
	docker build -t $(DOCKER_IMAGE):$(TAG) .

Переопределение из командной строки: make build TAG=v1.2.3. Не нужно редактировать файлы для версий сборки или развертываний в зависимости от среды. Доступны автоматически переменные среды shell — $(HOME), $(PATH), то, что находится в вашей среде при запуске make.

Готовый шаблон Makefile

Скопируйте это, удалите то, что не подходит, настройте команды под ваш стек:

.PHONY: install build test lint clean run docker-up docker-down help

# --- Config -------------------------------------------------------------------
DOCKER_COMPOSE = docker compose
APP_NAME = myapp

# --- Default target -----------------------------------------------------------
help:
	@echo "Available targets:"
	@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "  %-15s %s\n", $$1, $$2}'

# --- Dev ----------------------------------------------------------------------
install: ## Install dependencies
	npm ci

run: ## Start the dev server
	npm run dev

build: ## Build for production
	npm run build

# --- Quality ------------------------------------------------------------------
lint: ## Run the linter
	npm run lint

test: ## Run the test suite
	npm test

test-watch: ## Run tests in watch mode
	npm run test:watch

# --- Docker -------------------------------------------------------------------
docker-up: ## Start services via docker compose
	$(DOCKER_COMPOSE) up -d

docker-down: ## Stop and remove containers
	$(DOCKER_COMPOSE) down

docker-logs: ## Tail container logs
	$(DOCKER_COMPOSE) logs -f

# --- Cleanup ------------------------------------------------------------------
clean: ## Remove build artifacts and caches
	rm -rf dist node_modules/.cache .next

The help цель использует паттерн grep + awk для извлечения комментариев из текста и форматирования документации. Запустите ## и вы получите отсортированный список всех целей с их описаниями — без необходимости поддерживать отдельные документы. Это самый часто копируемый фрагмент в истории Makefile, и это объясняется. make help и вы получаете отсортированный список всех целевых элементов с их описаниями — не нужно хранить отдельные документы. Это самый часто копируемый фрагмент в истории Makefile, и это имеет причину.

Цепочка целей для CI

Make обрабатывает зависимости встроенно. Перечислите цели как зависимости, чтобы запускать их в порядке:

ci: lint test build ## Full CI check (lint -> test -> build)

make ci выполняет проверку, затем тестирование, затем сборку. Если какое-либо действие завершается с ненулевым кодом выхода, Make останавливается. Это корректное поведение CI — останавливаться громко, а не тихо скрывать ошибку шага.

Подавление отображения команд и выполнение многострочных команд

По умолчанию, Make выводит каждую команду перед её выполнением. Добавьте префикс @ для подавления:

setup:
	@echo "Setting up project..."
	@cp .env.example .env
	@npm ci
	@echo "Done."

Для команд, которые занимают несколько строк, соедините с помощью && — оно останавливается при ошибке, в отличие от точек, которые продолжают выполнение независимо:

migrate:
	npm run db:migrate && \
	npm run db:seed && \
	echo "Migration complete"

Когда Make — неподходящий инструмент

Make поставляется с macOS (через Xcode Command Line Tools) и на всех дистрибутивах Linux. Нет необходимости в установке, нет конфликтов версий, минимальное сопротивление для большинства команд.

Где он не справляется:

  • Окна — WSL работает хорошо, но на нативной Windows Make не работает без Chocolatey, Scoop или порта GnuWin32. Если ваша команда использует нативную Windows, просто — это близкий аналог, специально разработанный для этого пробела.
  • Сложная логика — Make не является языком программирования. Условные операторы и циклы существуют, но они действительно ужасны. Если ваша логика сборки требует настоящего ветвления, напишите полноценный скрипт.
  • Межплатформенные команды shellrm -rf, cpи другие Unix-инструменты не существуют на нативной Windows. Задача (на базе Go) решает эту проблему за счёт встроенной поддержки межплатформенных команд.

Для большинства команд на сервере и полных стеков на Mac или Linux, Make — это практичный стандарт. Он скучен, но это лучший способ — ничего не нужно устанавливать, ничего не нужно обновлять, ничего не ломается при обновлении зависимостей.

Поддержка чистого Makefile

Когда Makefile растёт в результате участия нескольких разработчиков и слияний, отступы и пробелы начинают отклоняться. Поскольку Make чувствителен к пробелам, одна лишняя пробела вместо таба молча нарушает цель без полезного сообщения об ошибке. IO Tools’ Makefile formatter нормализует отступы и удаляет лишние пробелы без изменения логики — полезно как проверка на чистоту до коммита.

Хотите убрать рекламу? Откажитесь от рекламы сегодня

Установите наши расширения

Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска

в Расширение Chrome в Расширение края в Расширение Firefox в Расширение Opera

Табло результатов прибыло!

Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!

Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?

новости с техническими моментами

Примите участие

Помогите нам продолжать предоставлять ценные бесплатные инструменты

Купи мне кофе
Реклама · УДАЛИТЬ?