1 Makefile
Sergey edited this page 2024-12-22 21:00:09 +03:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Makefile: Зачем Он Нужен и Как Им Пользоваться

Makefile — это специальный файл (по умолчанию названный Makefile или makefile), который содержит инструкции по сборке (компиляции и линковке) вашего проекта на C (или другом языке). Команда make читает этот файл и выполняет нужные команды, упрощая вам жизнь: вместо того чтобы вручную прописывать все вызовы компилятора, вы пишете правила (targets), и make всё делает за вас.

Ниже приводятся основные моменты и возможности Makefile, а также пример с пояснениями.


Основные Преимущества Makefile

  1. Автоматизация сборки: не нужно вручную запускать компилятор для каждого .c файла.
  2. Умная перестройка: make отслеживает зависимости. Если вы меняете один исходник, перекомпилируется только он (а не весь проект).
  3. Меньше ошибок: все команды собраны в одном месте, не требуется постоянно повторять одни и те же флаги при компиляции.
  4. Читаемость: хорошо оформленный Makefile облегчает понимание процесса сборки для всего проекта.

Как Создать Makefile

  1. В любом текстовом редакторе создайте файл с именем Makefile (или makefile).

  2. Внутри пропишите правила (targets). Каждое правило имеет вид:

    цель: зависимости
    	[команды]
    
    • цель (target) — обычно имя файла, который вы хотите получить, или псевдоним (например, all, clean).
    • зависимости (dependencies) — файлы или цели, от которых зависит эта цель.
    • команды (commands) — строки, которые выполняются, если необходимо обновить цель.
  3. Запустите make (при необходимости с указанием цели, например: make all).


Пример Makefile с Пояснениями

Рассмотрим часть реального Makefile (сократив его для наглядности). Пусть у нас есть файлы main.c, SCP.c, hope.c, tools.c, которые должны собраться в один исполняемый файл a.exe.

Переменная CFLAGS

CFLAGS = -mfpmath=sse \
         -fstack-protector-all \
         -W \
         -Wall \
         -Wextra \
         -Wunused \
         -Wcast-align \
         -Werror \
         -pedantic \
         -pedantic-errors \
         -Wfloat-equal \
         -Wpointer-arith \
         -Wformat-security \
         -Wmissing-format-attribute \
         -Wformat=1 \
         -Wwrite-strings \
         -Wcast-align \
         -Wno-long-long \
         -std=gnu99 \
         -Wstrict-prototypes \
         -Wmissing-prototypes \
         -Wmissing-declarations \
         -Wold-style-definition \
         -Wdeclaration-after-statement \
         -Wbad-function-cast \
         -Wnested-externs \
         -O3 \
         -D_DEBUG -g \
         -c
  • -mfpmath=sse: Использование SSE-инструкций для операций с плавающей точкой (оптимизация).
  • -fstack-protector-all: Включает защиту стека (Stack Smashing Protector) для всех функций, чтобы предотвратить переполнение буфера.
  • -W, -Wall, -Wextra: Включают различные предупреждения компилятора (базовые, расширенные и т.д.).
  • -Wunused, -Wcast-align, -pedantic, ...: Все эти флаги усиливают проверки, делая код более безопасным и соответствующим стандартам. Например, -Wfloat-equal предупреждает о сравнении float/double на равенство (что обычно опасно из-за погрешностей).
  • -Werror: Преобразует все предупреждения (warning) в ошибки (error). Если компилятор что-то заподозрил, сборка останавливается.
  • -std=gnu99: Задаёт стандарт языка — GNU C99.
  • -O3: Оптимизация на максимальном уровне.
  • -D_DEBUG -g: Добавляет отладочную информацию. -D_DEBUG определяет макрос _DEBUG, а -g включает отладочные символы.
  • -c: Флаг, указывающий «только компилировать, но не линковать». В результате получаются .o файлы.

Такие флаги иногда применяются в университетах для строгой проверки кода (например, «эмуляция компилятора института»).

Правила (Targets)

all: main.o SCP.o hope.o tools.o
	gcc main.o SCP.o hope.o tools.o -lssp && del *.o
	a.exe
  • Цель: all
  • Зависимости: main.o, SCP.o, hope.o, tools.o
  • Команда:
    1. gcc main.o SCP.o hope.o tools.o -lssp && del *.o
      • Компонуем все объектные файлы в один исполняемый.
      • -lssp (под Windows) означает «подключить библиотеку Stack Smashing Protector». На Linux обычно достаточно -fstack-protector-all (без отдельной библиотеки).
      • del *.o (в Windows) удаляет объектные файлы после успешного линкования. На Linux аналог — rm *.o.
    2. a.exe — Запуск программы (опционально).

Далее цели для объектных файлов:

main.o: main.c
	gcc $(CFLAGS) main.c

SCP.o: SCP.c
	gcc $(CFLAGS) SCP.c

hope.o: hope.c
	gcc $(CFLAGS) hope.c

tools.o: tools.c
	gcc $(CFLAGS) tools.c

Здесь:

  • main.o: main.c говорит: «чтобы получить main.o, нам нужен main.c (и возможно его заголовки). Выполни gcc $(CFLAGS) main.c».
  • Переменная $(CFLAGS) подставляется (рассказано выше).

Когда вы набираете в терминале make, по умолчанию выполняется цель all. Если .o файлы ещё не существуют или их зависимости изменились, make пересоберёт нужные части.


Дополнительные Возможности

  1. Переменные:

    • Вы можете определить переменные, например:
      CC = gcc
      INCLUDES = -I./include -I/usr/local/include
      
      main.o: main.c
      	$(CC) $(CFLAGS) $(INCLUDES) main.c
      
  2. Фоновые сборки: make -j4 — собирать в 4 потока параллельно (на многоядерном процессоре быстрее).

  3. Файл «clean»: часто добавляют цель clean, чтобы удалить результаты сборки:

    clean:
    	rm -f *.o a.exe
    

    (На Windows используйте del вместо rm).

  4. Файл «install»: если проект большой, иногда пишут команды установки в make install.


Почему -lssp Только для Windows?

  • На некоторых системах (особенно Linux) поддержка Stack Smashing Protector (-fstack-protector-all) встроена в стандартные библиотеки, и не нужно отдельно подключать -lssp.
  • В Windows MinGW-окружении (или иных) библиотека ssp может идти отдельно, и нужно явно указать -lssp.

Если при линковке на Linux компилятор ругается, что не знает -lssp, можно убрать этот флаг.


Правильное Оформление Makefile

  • Отступы: в строках команд (после цели и двоеточия) должен стоять таб (символ табуляции), а не пробелы.
  • Разделяйте логические секции пустыми строками и комментариями.
  • Используйте переменные для повторяющихся частей (имена компилятора, ключей, библиотек), чтобы правки были в одном месте.

Пример (аккуратного оформления):

CC = gcc
CFLAGS = -Wall -Werror -O2 -c
TARGET = a.exe

all: main.o utils.o
	$(CC) main.o utils.o -o $(TARGET)

main.o: main.c
	$(CC) $(CFLAGS) main.c

utils.o: utils.c
	$(CC) $(CFLAGS) utils.c

clean:
	rm -f *.o $(TARGET)

Небольшая Историческая Справка

  • Make был создан в 1970-х в Bell Labs (где появились Unix, C и т.д.) для автоматизации сборки проектов.
  • Стандартная утилита make существует практически во всех Unix-подобных системах.
  • С течением лет появились расширения: GNU make (самая популярная реализация), CMake (более сложный и переносимый), Ninja (быстрая сборка), но базовый Makefile по-прежнему широко используется.