Makefile
parent
143c27233c
commit
d188a7d953
1 changed files with 191 additions and 0 deletions
191
Makefile.md
Normal file
191
Makefile.md
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
# 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
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
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)
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
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` — Запуск программы (опционально).
|
||||||
|
|
||||||
|
Далее цели для объектных файлов:
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
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. **Переменные**:
|
||||||
|
- Вы можете определить переменные, например:
|
||||||
|
```makefile
|
||||||
|
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`, чтобы удалить результаты сборки:
|
||||||
|
```makefile
|
||||||
|
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
|
||||||
|
|
||||||
|
- **Отступы**: в строках команд (после цели и двоеточия) должен стоять **таб** (символ табуляции), а не пробелы.
|
||||||
|
- **Разделяйте** логические секции пустыми строками и комментариями.
|
||||||
|
- **Используйте переменные** для повторяющихся частей (имена компилятора, ключей, библиотек), чтобы правки были в одном месте.
|
||||||
|
|
||||||
|
**Пример** (аккуратного оформления):
|
||||||
|
|
||||||
|
```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 по-прежнему широко используется.
|
Loading…
Add table
Add a link
Reference in a new issue