1 added
1 removed
Original
2026-01-01
Modified
2026-02-26
1
<h2>Введение</h2>
1
<h2>Введение</h2>
2
<p>В жизни многих разработчиков найдётся история про первый рабочий день с новым проектом. После клонирования основного репозитория проекта наступает этап, когда приходится вводить множество команд с определёнными флагами и в заданной последовательности. Без описания команд, в большинстве случаев, невозможно понять что происходит, например:</p>
2
<p>В жизни многих разработчиков найдётся история про первый рабочий день с новым проектом. После клонирования основного репозитория проекта наступает этап, когда приходится вводить множество команд с определёнными флагами и в заданной последовательности. Без описания команд, в большинстве случаев, невозможно понять что происходит, например:</p>
3
<p>Эти команды являются лишь частью того, что необходимо выполнить при разворачивании проекта. В приведённом примере видно, что команды сами по себе длинные, содержат много флагов, а значит, их трудно не только запомнить, но и вводить вручную. Постоянно вести документацию становится сложнее с ростом проекта, она неизбежно устаревает, а порог входа для новичков становится выше, ведь уже никто не в состоянии вспомнить всех деталей проекта. Некоторые такие команды необходимо использовать каждый день, и даже не один раз в день.</p>
3
<p>Эти команды являются лишь частью того, что необходимо выполнить при разворачивании проекта. В приведённом примере видно, что команды сами по себе длинные, содержат много флагов, а значит, их трудно не только запомнить, но и вводить вручную. Постоянно вести документацию становится сложнее с ростом проекта, она неизбежно устаревает, а порог входа для новичков становится выше, ведь уже никто не в состоянии вспомнить всех деталей проекта. Некоторые такие команды необходимо использовать каждый день, и даже не один раз в день.</p>
4
<p>Со временем становится понятно, что нужен инструмент, способный объединить в себе подобные команды, предоставить к ним удобные шорткаты (<em>более короткие и простые команды</em>) и обеспечить самодокументацию проекта. Именно таким инструментом стал<em>Makefile</em>и утилита make. Этот гайд расскажет, как использование этих инструментов позволит свести процесс разворачивания проекта к нескольким коротким и понятным командам:</p>
4
<p>Со временем становится понятно, что нужен инструмент, способный объединить в себе подобные команды, предоставить к ним удобные шорткаты (<em>более короткие и простые команды</em>) и обеспечить самодокументацию проекта. Именно таким инструментом стал<em>Makefile</em>и утилита make. Этот гайд расскажет, как использование этих инструментов позволит свести процесс разворачивания проекта к нескольким коротким и понятным командам:</p>
5
-
<h2>Что такое make и<em>Makefile</em></h2>
5
+
<h2>Что такое<em>make</em>и<em>Makefile</em></h2>
6
<p><em>Makefile</em>- это файл, который хранится вместе с кодом в репозитории. Его обычно помещают в корень проекта. Он выступает и как документация, и как исполняемый код. Мейкфайл скрывает за собой детали реализации и раскладывает "по полочкам" команды, а утилита make запускает их из того мейкфайла, который находится в текущей директории.</p>
6
<p><em>Makefile</em>- это файл, который хранится вместе с кодом в репозитории. Его обычно помещают в корень проекта. Он выступает и как документация, и как исполняемый код. Мейкфайл скрывает за собой детали реализации и раскладывает "по полочкам" команды, а утилита make запускает их из того мейкфайла, который находится в текущей директории.</p>
7
<p>Изначально make предназначалась для автоматизации сборки исполняемых программ и библиотек из исходного кода. Она поставлялась по умолчанию в большинство *nix дистрибутивов, что и привело к её широкому распространению и повсеместному использованию. Позже оказалось что данный инструмент удобно использовать и при разработке любых других проектов, потому что процесс в большинстве своём сводится к тем же задачам - автоматизация и сборка приложений.</p>
7
<p>Изначально make предназначалась для автоматизации сборки исполняемых программ и библиотек из исходного кода. Она поставлялась по умолчанию в большинство *nix дистрибутивов, что и привело к её широкому распространению и повсеместному использованию. Позже оказалось что данный инструмент удобно использовать и при разработке любых других проектов, потому что процесс в большинстве своём сводится к тем же задачам - автоматизация и сборка приложений.</p>
8
<p>Применение мейка в проектах стало стандартом для многих разработчиков, включая крупные проекты. Примеры мейкфайла можно найти у таких проектов, как<a>Kubernetes</a>,<a>Babel</a>,<a>Ansible</a>и, конечно же, повсеместно на<a>Хекслете</a>.</p>
8
<p>Применение мейка в проектах стало стандартом для многих разработчиков, включая крупные проекты. Примеры мейкфайла можно найти у таких проектов, как<a>Kubernetes</a>,<a>Babel</a>,<a>Ansible</a>и, конечно же, повсеместно на<a>Хекслете</a>.</p>
9
<h3>Синтаксис<em>Makefile</em></h3>
9
<h3>Синтаксис<em>Makefile</em></h3>
10
<p>make запускает цели из<em>Makefile</em>, которые состоят из команд:</p>
10
<p>make запускает цели из<em>Makefile</em>, которые состоят из команд:</p>
11
<p>Но недостаточно просто начать использовать мейкфайл в проекте. Чтобы получить эффект от его внедрения, понадобится поработать над разделением команд на цели, а целям дать семантически подходящие имена. Поначалу, перенос команд в Makefile может привести к свалке всех команд в одну цель с "размытым" названием:</p>
11
<p>Но недостаточно просто начать использовать мейкфайл в проекте. Чтобы получить эффект от его внедрения, понадобится поработать над разделением команд на цели, а целям дать семантически подходящие имена. Поначалу, перенос команд в Makefile может привести к свалке всех команд в одну цель с "размытым" названием:</p>
12
<p>Здесь происходит сразу несколько действий: создание файла с переменными окружения, подготовка базы данных, генерация ключей, установка зависимостей и запуск проекта. Это невозможно понять из комментариев и названия цели, поэтому будет правильно разделить эти независимые команды на разные цели:</p>
12
<p>Здесь происходит сразу несколько действий: создание файла с переменными окружения, подготовка базы данных, генерация ключей, установка зависимостей и запуск проекта. Это невозможно понять из комментариев и названия цели, поэтому будет правильно разделить эти независимые команды на разные цели:</p>
13
<p>Теперь, когда команды разбиты на цели, можно отдельно установить зависимости командой make install или запустить приложение через make start. Но остальные цели нужны только при первом разворачивании проекта и выполнять их нужно в определённой последовательности. Говоря языком мейкфайла, цель имеет пререквизиты:</p>
13
<p>Теперь, когда команды разбиты на цели, можно отдельно установить зависимости командой make install или запустить приложение через make start. Но остальные цели нужны только при первом разворачивании проекта и выполнять их нужно в определённой последовательности. Говоря языком мейкфайла, цель имеет пререквизиты:</p>
14
<p>Задачи будут выполняться только в указанной последовательности и только в случае успеха предыдущей задачи. Значит, можно добавить цель setup, чтобы объединить в себе все необходимые действия:</p>
14
<p>Задачи будут выполняться только в указанной последовательности и только в случае успеха предыдущей задачи. Значит, можно добавить цель setup, чтобы объединить в себе все необходимые действия:</p>
15
<p>Теперь развернуть и запустить проект достаточно двумя командами:</p>
15
<p>Теперь развернуть и запустить проект достаточно двумя командами:</p>
16
<p>Благодаря проделанной работе<em>Makefile</em>, команды проекта вместе с флагами сведены в<em>Makefile</em>. Он обеспечивает правильный порядок выполнения и не важно, какие при этом задействованы языки и технологии.</p>
16
<p>Благодаря проделанной работе<em>Makefile</em>, команды проекта вместе с флагами сведены в<em>Makefile</em>. Он обеспечивает правильный порядок выполнения и не важно, какие при этом задействованы языки и технологии.</p>
17
<h2>Продвинутое использование</h2>
17
<h2>Продвинутое использование</h2>
18
<h3>Фальшивая цель</h3>
18
<h3>Фальшивая цель</h3>
19
<p>Использование make в проекте однажды может привести к появлению ошибки make: <имя-цели> is up to date., хотя всё написано правильно. Зачастую, её появление связано с наличием каталога или файла, совпадающего с именем цели. Например:</p>
19
<p>Использование make в проекте однажды может привести к появлению ошибки make: <имя-цели> is up to date., хотя всё написано правильно. Зачастую, её появление связано с наличием каталога или файла, совпадающего с именем цели. Например:</p>
20
<p>Как уже говорилось ранее, изначально make предназначалась для сборок из исходного кода. Поэтому она ищет каталог или файл с указанным именем, и пытается собрать из него проект. Чтобы изменить это поведение, необходимо в конце мейкфайла добавить .PHONY указатель на цель:</p>
20
<p>Как уже говорилось ранее, изначально make предназначалась для сборок из исходного кода. Поэтому она ищет каталог или файл с указанным именем, и пытается собрать из него проект. Чтобы изменить это поведение, необходимо в конце мейкфайла добавить .PHONY указатель на цель:</p>
21
<h3>Последовательный запуск команд и игнорирование ошибок</h3>
21
<h3>Последовательный запуск команд и игнорирование ошибок</h3>
22
<p>Запуск команд можно производить по одной: make setup, make start, make test или указывать цепочкой через пробел: make setup start test. Последний способ работает как зависимость между задачами, но без описания её в мейкфайле. Сложности могут возникнуть, если одна из команд возвращает ошибку, которую нужно игнорировать. В примерах ранее такой командой было создание .env-файла при разворачивании проекта:</p>
22
<p>Запуск команд можно производить по одной: make setup, make start, make test или указывать цепочкой через пробел: make setup start test. Последний способ работает как зависимость между задачами, но без описания её в мейкфайле. Сложности могут возникнуть, если одна из команд возвращает ошибку, которую нужно игнорировать. В примерах ранее такой командой было создание .env-файла при разворачивании проекта:</p>
23
<p>Самый простой (<em>но не единственный</em>) способ "заглушить" ошибку - это сделать логическое ИЛИ прямо в мейкфайле:</p>
23
<p>Самый простой (<em>но не единственный</em>) способ "заглушить" ошибку - это сделать логическое ИЛИ прямо в мейкфайле:</p>
24
<p>Добавлять такие хаки стоит с осторожностью, чтобы не "выстрелить себе в ногу" в более сложных случаях.</p>
24
<p>Добавлять такие хаки стоит с осторожностью, чтобы не "выстрелить себе в ногу" в более сложных случаях.</p>
25
<h3>Переменные</h3>
25
<h3>Переменные</h3>
26
<p>Зачастую в команды подставляют параметры для конфигурации, указания путей, переменные окружения и make тоже позволяет этим управлять. Переменные можно прописать прямо в команде внутри мейкфайла и передавать их при вызове:</p>
26
<p>Зачастую в команды подставляют параметры для конфигурации, указания путей, переменные окружения и make тоже позволяет этим управлять. Переменные можно прописать прямо в команде внутри мейкфайла и передавать их при вызове:</p>
27
<p>Переменные могут быть необязательными и содержать значение по умолчанию. Обычно их объявляют в начале мейкфайла.</p>
27
<p>Переменные могут быть необязательными и содержать значение по умолчанию. Обычно их объявляют в начале мейкфайла.</p>
28
<p>Некоторые переменные в<em>Makefile</em>имеют названия отличные от системных. Например, $PWD называется $CURDIR в<a>мейкфайле</a>:</p>
28
<p>Некоторые переменные в<em>Makefile</em>имеют названия отличные от системных. Например, $PWD называется $CURDIR в<a>мейкфайле</a>:</p>
29
<h2>Заключение</h2>
29
<h2>Заключение</h2>
30
<p>В рамках данного гайда было рассказано об основных возможностях<em>Makefile</em>и утилиты make. Более плотное знакомство с данным инструментом откроет множество других его полезных возможностей: условия, циклы, подключение файлов. В компаниях, где имеется множество проектов, написанных разными командами в разное время, мейкфайл станет отличным подспорьем в стандартизации типовых команд: setup start test deploy ....</p>
30
<p>В рамках данного гайда было рассказано об основных возможностях<em>Makefile</em>и утилиты make. Более плотное знакомство с данным инструментом откроет множество других его полезных возможностей: условия, циклы, подключение файлов. В компаниях, где имеется множество проектов, написанных разными командами в разное время, мейкфайл станет отличным подспорьем в стандартизации типовых команд: setup start test deploy ....</p>
31
<p>Возможность описывать в мейкфале последовательно многострочные команды позволяет использовать его как "универсальный клей" между менеджерами языков и другими утилитами. Широкая распространённость этого инструмента и общая простота позволяют внедрить его в свой проект достаточно легко, без необходимости доработок. Но мейкфайл может быть по-настоящему большим и сложным, это можно увидеть на примере реальных проектов:</p>
31
<p>Возможность описывать в мейкфале последовательно многострочные команды позволяет использовать его как "универсальный клей" между менеджерами языков и другими утилитами. Широкая распространённость этого инструмента и общая простота позволяют внедрить его в свой проект достаточно легко, без необходимости доработок. Но мейкфайл может быть по-настоящему большим и сложным, это можно увидеть на примере реальных проектов:</p>
32
<ul><li><a>Codebattle</a></li>
32
<ul><li><a>Codebattle</a></li>
33
<li><a>Babel</a></li>
33
<li><a>Babel</a></li>
34
<li><a>Kubernetes</a></li>
34
<li><a>Kubernetes</a></li>
35
</ul><h3>Дополнительные материалы</h3>
35
</ul><h3>Дополнительные материалы</h3>
36
<ul><li><a>Руководство по современному Make</a>- "выжимка" из документации на русском языке;</li>
36
<ul><li><a>Руководство по современному Make</a>- "выжимка" из документации на русском языке;</li>
37
<li><a>Утилита make: полезный универсальный инструмент программиста</a>- видео-версия данного гайда.</li>
37
<li><a>Утилита make: полезный универсальный инструмент программиста</a>- видео-версия данного гайда.</li>
38
</ul><p>Мейкфайлы, использованные при составлении гайда:</p>
38
</ul><p>Мейкфайлы, использованные при составлении гайда:</p>
39
<ul><li><a>Hexlet SICP</a></li>
39
<ul><li><a>Hexlet SICP</a></li>
40
<li><a>Hexlet Basics</a></li>
40
<li><a>Hexlet Basics</a></li>
41
</ul>
41
</ul>