Make-код¶
Make-код (от англ. make — делать, производить; также make-файл, makefile) — это текстовый файл, содержащий инструкции для автоматизации сборки программного обеспечения, используемый утилитой make. Make-код описывает зависимости между исходными файлами и команды для их компиляции, компоновки и других операций, что позволяет при повторной сборке перекомпилировать только изменённые части проекта.
¶История
Утилита make была разработана Стюартом Фельдманом в 1976 году в Bell Labs (подразделение AT&T). Первоначально она предназначалась для автоматизации сборки программ на языке C в операционной системе Unix. Идея заключалась в том, чтобы описать в текстовом файле (Makefile) правила преобразования исходных файлов в объектные и исполняемые, а затем запускать только те команды, которые необходимы из-за изменений в исходниках. Фельдман получил за эту разработку премию ACM Software System Award в 2003 году.
С тех пор make стал стандартным инструментом в Unix-подобных системах (Linux, macOS, BSD) и был портирован на многие другие платформы, включая Microsoft Windows (через Cygwin, MinGW или NMake). Существуют различные реализации make, такие как GNU Make (наиболее распространённая), BSD Make, Microsoft NMake и другие. Несмотря на появление более современных систем сборки (CMake, Meson, Gradle), make-файлы остаются широко используемыми, особенно в проектах на C/C++, а также в инфраструктурных скриптах.
¶Структура make-файла
Make-файл состоит из набора правил (rules), каждое из которых имеет следующий синтаксис:
`` цель: зависимости команды ``
- Цель (target) — обычно имя файла, который нужно создать (например,
program.oилиprogram), или имя псевдоцели (например,clean,all). - Зависимости (prerequisites) — файлы, от которых зависит цель. Если хотя бы одна зависимость новее цели, цель считается устаревшей и пересобирается.
- Команды (recipes) — последовательность команд оболочки (shell), которые выполняются для создания цели. Каждая команда должна начинаться с символа табуляции (не пробелов).
¶Пример простого make-файла
``` CC = gcc CFLAGS = -Wall -O2
program: main.o utils.o $(CC) $(CFLAGS) -o program main.o utils.o
main.o: main.c header.h $(CC) $(CFLAGS) -c main.c
utils.o: utils.c utils.h $(CC) $(CFLAGS) -c utils.c
clean: rm -f *.o program ```
В этом примере:
- Определены переменные
CCиCFLAGS. - Цель
programзависит от объектных файловmain.oиutils.o. - Цели
main.oиutils.oописывают компиляцию каждого исходного файла. - Псевдоцель
cleanудаляет все объектные файлы и исполняемый файл.
¶Переменные и функции
Make-код поддерживает переменные, которые упрощают управление параметрами сборки. Переменные могут быть заданы в файле, переданы в командной строке или унаследованы из окружения. Примеры:
``` CC = gcc CFLAGS = -std=c99 -pedantic LDFLAGS = -lm
SRCDIR = src OBJDIR = obj ```
Также в GNU Make доступны встроенные функции для работы со строками и файлами, например:
$(wildcard pattern)— поиск файлов по шаблону.$(patsubst pattern,replacement,text)— замена суффиксов.$(shell command)— выполнение команды оболочки.
¶Автоматические переменные
Для упрощения правил используются автоматические переменные, которые подставляются в команды:
$@— имя цели.$<— имя первой зависимости.$^— список всех зависимостей.$?— список зависимостей, которые новее цели.
Пример с автоматическими переменными:
`` %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ ``
Это правило говорит: «для любого файла с расширением .o, который зависит от соответствующего .c файла, скомпилировать его».
¶Псевдоцели и специальные цели
Псевдоцели (phony targets) — это цели, которые не соответствуют реальным файлам. Они объявляются с помощью .PHONY, чтобы избежать конфликтов с файлами, имеющими то же имя. Типичные псевдоцели:
all— сборка всего проекта (часто первая цель по умолчанию).clean— удаление временных файлов.install— установка программы в систему.test— запуск тестов.
Специальные цели, такие как .DEFAULT, .SUFFIXES, .PRECIOUS, .INTERMEDIATE, управляют поведением make.
¶Условные конструкции
Make-код поддерживает условные директивы, позволяющие адаптировать сборку под разные платформы или конфигурации:
`` ifeq ($(OS),Windows_NT) RM = del /Q else RM = rm -f endif ``
Доступны директивы ifeq, ifneq, ifdef, ifndef.
¶Включение других файлов
Директива include позволяет подключать другие make-файлы, что полезно для разделения конфигурации:
`` include config.mk include $(wildcard *.d) ``
¶Применение
Make-код применяется в самых разных областях разработки:
- Сборка программ на C/C++ — классическое использование.
- Обработка документации — генерация PDF из LaTeX, HTML из Markdown.
- Автоматизация тестирования — запуск тестовых наборов.
- Развёртывание — копирование файлов, настройка окружения.
- Научные вычисления — воспроизводимость экспериментов (например, сборка данных из сырых файлов).
¶Критика и ограничения
Несмотря на широкое распространение, make-код имеет ряд недостатков:
- Синтаксис — чувствительность к табуляции, неочевидные правила экранирования.
- Сложность отладки — ошибки в make-файлах часто трудно диагностировать.
- Платформенная зависимость — команды оболочки могут различаться на Windows и Unix.
- Отсутствие модульности — для больших проектов make-файлы становятся громоздкими.
- Параллельная сборка — хотя
make -jподдерживает параллелизм, правильно описать зависимости бывает сложно.
Для преодоления этих ограничений были созданы инструменты-генераторы make-файлов, такие как CMake, Autotools (GNU Build System), а также альтернативные системы сборки (Ninja, SCons, Meson).
¶Интересные факты
- GNU Make — самая популярная реализация; её версия 3.81 вышла в 2006 году, но до сих пор используется.
- Make-файлы могут быть рекурсивными — вызывать make для подкаталогов, хотя это считается антипаттерном.
- Существует стандарт POSIX для make, но GNU Make поддерживает множество расширений.
- В некоторых проектах make-файлы используются не только для сборки, но и для управления проектом (например, «make deploy», «make migrate»).
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


