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