мета-данные страницы
  •  

Это старая версия документа!


Нужно для: cmake (https://www.opennet.ru/docs/RUS/gnumake/)

_ NTB: Сборка = компиляция + линковка. Если запустить `make` то программа попытается найти файл с именем по умолчание `Makefile` в текущем каталоге и выполнить инструкции из него. Если в текущем каталоге есть несколько мейкфайлов, то можно указать на нужный вот таким образом: `make -f MyMakefile` Работу `make` можно представить себе так: ``` {Из чего делаем? (реквизиты)} —> [Как делаем? (команды)] —> {Что делаем? (цели)} ``` ## Общая структура MakeFile состоит из набора правил, которые в свою очередь описываются: 1) целями (то, что данное правило делает); 2) реквизитами (то, что необходимо для выполнения правила и получения целей); 3) командами (выполняющими данные преобразования). В общем виде синтаксис makefile можно представить так: ``` # Индентация осуществляется исключительно при помощи символов табуляции, # каждой команде должен предшествовать отступ <цели>: <реквизиты> <команда #1> … <команда #n> ``` _ ## Инкрементная компиляция Если файлов в проекте много, при каждой сборке весь проект компилируется полностью, а это долго. Решение - разделить компиляцию на два этапа: трансляция и линковка.

Теперь, когда внесены изменения в один из исходников, достаточно произвести его трансляцию, а затем произвести линковку всех объектных файлов. Такой подход называется инкрементной компиляцией. Для ее поддержки make сопоставляет время изменения целей и их реквизитов (используя данные файловой системы), благодаря чему самостоятельно решает какие правила следует выполнить, а какие можно просто проигнорировать:

```makefile main.o: main.c

gcc -c -o main.o main.c

hello.o: hello.c

gcc -c -o hello.o hello.c

hello: main.o hello.o

gcc -o hello main.o hello.o

``` При первом запуске `make` попытается сразу получить цель `hello`, но для неё нужны `main.o` и `hello.o`, а их нет, так что `make` ищет правила для них и выполняет. Как только все реквизиты будут получены, make вернется к выполнению отложенной цели. (Отсюда следует, что make выполняет правила рекурсивно.)

_ ## Фиктивные цели «фиктивные» (phony) цели позволяют осуществлять с помощью `make` не только сборку программы. Вот краткий список стандартных целей: - `all` — является стандартной целью по умолчанию. При вызове `make` ее можно явно не указывать. - `clean` — очистить каталог от всех файлов полученных в результате компиляции. - `install` — произвести инсталляцию - `uninstall` — и деинсталляцию соответственно. Для того чтобы make не искал файлы с такими именами, их следует определить в Makefile, при помощи директивы .PHONY ```makefile .PHONY: all clean install uninstall all: hello # сборка clean: # очистка от файлов, созданых во время сборки rm -rf hello *.o main.o: main.c gcc -c -o main.o main.c hello.o: hello.c gcc -c -o hello.o hello.c hello: main.o hello.o gcc -o hello main.o hello.o install: # инсталяция install ./hello /usr/local/bin uninstall: # деинсталяция rm -rf /usr/local/bin/hello ``` ВАЖНО: `clean` необходим, что бы принудительно пересобрать проект с нуля, так как если реквизит `hello` уже существует, `make` его переделывать не будет. Однако, в данном случаи достаточно руками удалить `hello` и запустить сборку, что бы не пересобрать все объектники. _ ## Использование переменных и комментариев Переменные - удобный способ учесть возможность того, что проект будут собирать другим компилятором или с другими опциями. ```makefile CC=g++ # Это комментарий, который говорит, что переменная CC указывает компилятор, используемый для сборки CFLAGS=-c -Wall # Это еще один комментарий. Он поясняет, что в переменной CFLAGS лежат флаги, которые передаются компилятору

hello: main.o

$(CC) main.o -o prog

main.o: main.cpp

$(CC) $(CFLAGS) main.cpp

``` По умолчанию make станет выполнять самое первое правило, если цель выполнения не была явно указана при вызове: ```shell $ make <цель> ``` ## Автоматические переменные - `$@` Имя цели обрабатываемого правила - `$<` Имя первой зависимости обрабатываемого правила - `$^` Список всех зависимостей обрабатываемого правила

подробнее [тут](https://rus-linux.net/nlib.php?name=/MyLDP/algol/gnu_make/gnu_make_3-79_russian_manual.html#SEC101) _ ## Примеры (разработка) #### Демонстрация удобства использования MakeFile Пример компиляции руками: ```shell # main.cpp - главный файл # functions.h - прототипы всех ф-ий # factorial.cpp - инклудит functions.h и определяет реализацию тамошних ф-ий # hello.cpp - g++ main.cpp hello.cpp factorial.cpp -o prog ``` Долго каждый раз писать. Да и при разрастании проекта можно запутаться. Автоматизируем. Для нашего примера мейкфайл будет выглядеть так: ```makefile all: g++ main.cpp hello.cpp factorial.cpp -o hello ``` Использовать несколько целей в одном мейкфайле полезно для больших проектов. Это связано с тем, что при изменении одного файла не понадобится пересобирать весь проект, а можно будет обойтись пересборкой только измененной части. Пример: ```makefile all: hello hello: main.o factorial.o hello.o g++ main.o factorial.o hello.o -o hello main.o: main.cpp g++ -c main.cppfactorial.o: factorial.cpp g++ -c factorial.cpp hello.o: hello.cpp g++ -c hello.cpp clean: rm -rf *.o hello ``` Теперь у цели `all` есть только зависимость, но нет команды. В этом случае make при вызове последовательно выполнит все указанные в файле зависимости этой цели. Еще добавилась новая цель `clean`. Она традиционно используется для быстрой очистки всех результатов сборки проекта. Очистка запускается так: `make -f Makefile-2 clean` #### Универсальный MakeFile ```makefile CC=g++ CFLAGS=-c -Wall LDFLAGS= SOURCES=main.cpp hello.cpp factorial.cpp OBJECTS=$(SOURCES:.cpp=.o) EXECUTABLE=prog all: $(SOURCES) $(EXECUTABLE) $(EXECUTABLE): $(OBJECTS) $(CC) $(LDFLAGS) $(OBJECTS) -o $@ .cpp.o: $(CC) $(CFLAGS) $< -o $@ ``` _

## Примеры (использование)

установка при помощи исходников (любые, программы и библиотеки). Допустим, наш целевой пакет называется «hello». 1) Получаем код: можно клонировать репозиторий: ```shell git clone hello cd hello ``` ИЛИ используем тарболл: ```shell tar -xf hello-1.0.tar.xz ```

2) Сборка: если хотим использовать голый make: ```shell make PREFIX=/префикс-который-вы-хотите ``` если используем autotools: ```shell ./configure –prefix=/префикс-который-вы-хотите make ``` если используем cmake: ```shell cmake -DCMAKE_INSTALL_PREFIX=/префикс-который-вы-хотите . make ``` Откуда точка в конце? Дело в том, что cmake'у нужно передавать путь к сорцам. А поскольку у нас не out of tree build, мы собираем здесь же. Сорцы находятся там же, где находимся мы. Поэтому точка, т. е. текущий каталог.

3) Установка: Используя make: ```shell make PREFIX=/префикс-который-вы-хотите install ``` Используя autotools или cmake: ```shell make install ```

Cборка всегда осуществляется с обычными правами, а вот установка осуществляется с теми правами, которые нужны, чтобы записать в prefix.