Makefile: единый интерфейс для команд проекта
Каждый проект — живой организм. Он растёт, обрастает зависимостями, тестами, скриптами для деплоя. И рано или поздно ты сталкиваешься с одной и той же проблемой: как управлять всей кучей команд?
Можно хранить их в памяти. Но через месяц ты забудешь, что конкретно делает тот самый python scripts/deploy.py --env=prod --with-migrations. Можно сложить в wiki. Но новый разработчик всё равно придёт к тебе в личку с вопросом "а как это запускается?".
Почему Make?
Makefile — это не просто способ записать команды. Это единая точка входа в проект. Заходишь в репозиторий, пишешь make help и видишь всё, что можно сделать.
Что даёт Makefile на практике:
• Единый интерфейс - неважно, на чём написан проект: Python, Node, Go или Rust. Команды всегда одинаковые: make install, make test, make run.
• Документация, которая не врет - в отличие от wiki, эти инструкции выполняются. Если команда сломается, сборка упадёт.
• Композиция команд - можно собирать сложные цепочки. make deploy может включать линтинг, тесты, сборку и выкат на сервер.
• Отслеживание изменений - make умный. Он перезапускает только то, что действительно нужно (об этом в P.S.).
Разбираем на примерах:
Вариант 1: Python-проект
Стандартный набор команд для любого бэкенда на Python:
Важный нюанс: .PHONY говорит make, что это не настоящие файлы, а просто названия команд. Без этой строчки, если у вас вдруг в папке появится файл clean, команда перестанет работать.
Вариант 2: Node.js + Docker
А вот так выглядит Makefile для фронтенда или микросервиса на Node, который живёт в докере:
Обрати внимание на строчку docker-run: docker-build. Это зависимость. Если набрать make docker-run, make сначала выполнит docker-build (пересоберёт образ), и только потом запустит контейнер.
Где Make реально выручает
Я веду несколько pet-проектов и пару коммерческих. Makefile живёт почти в каждом из них. Вот сценарии, где он незаменим:
1. Onboarding - новый человек в команде. Вместо получасового рассказа "сначала поставь зависимости, потом накати миграции, потом запусти тесты" - просто ссылка на Makefile.
2. CI/CD пайплайны - в GitHub Actions или GitLab CI удобно вызывать те же make test, make build. Если команда поменяется, не надо править пайплайн - достаточно обновить Makefile.
3. Локальная разработка - поднял проект через make up, остановил через make down. Рука запоминает быстрее, чем мозг - длинные команды.
4. Очистка проекта - make clean удаляет кэш, временные файлы, виртуальное окружение. Всё, что захламляет папку.
Где я наступал на грабли
Не буду приукрашивать - у Makefile есть свои подводные камни:
• Табуляция против пробелов - классика. В Makefile команды обязательно начинаются с табуляции. Один пробел - и всё падает с загадочной ошибкой. Бесит жутко, но привыкнуть можно.
• Windows - с ним беда. Make рассчитан на Unix-окружение. Под виндой приходится ставить Cygwin, WSL или mingw. Для студенческих проектов сойдёт, для корпоративной среды - лучше поискать альтернативу.
• Сложная логика - если внутри команд начинаются условия, циклы, проверки - Makefile превращается в безобразие. Тогда лучше выносить это в отдельные скрипты и вызывать их из make.
Вместо заключения
Я не призываю тащить Makefile абсолютно во всё. Для простого статического сайта на HTML он не нужен. Для JS-проекта можно обойтись npm-скриптами.
Но если проект живёт дольше месяца (именно столько времени потребуется, чтобы забыть команды на со старта), если над ним работает больше одного человека, если есть сборка, тесты, деплой - Makefile окупается за первую же неделю.
P.S. Забыл сказать про главную фишку. Make умеет отслеживать изменения файлов. Если вы сделаете правило вида %.o: %.c, он будет перекомпилировать только те объектники, у которых изменился исходник. Для больших проектов на C/C++ это экономит часы. Но даже для скриптовых языков иногда пригождается.
Я в Telegram - t.me/helcode
Я в VK - vk.com/helcode
Я на Boosty - boosty.to/helcode