Найти тему
Блокнот математика

make — сборка сложных проектов

Когда я освоил make, моя жизнь существенно облегчилась. Я полагал, что люди либо знают make лучше меня, либо не знают и не хотят знать, но ошибался. Участвуя в сложном проекте, я написал makefile для одной из компонент вместо скрипта, который собирал ее, и понял, что многие классные специалисты, компилирующие сложные проекты, make могут не знать — он просто не попался им на пути.

make — это утилита для сборки проектов, хотя ее можно применять для других целей. Суть в целях. Целью может быть файл, а еще может быть абстрактная цель. Цели могут зависеть одна от другой; запрещены только циклические зависимости. Абстрактная цель всегда не выполнена; цель-файл не выполнена, если файл старше чем те, от которых он зависит.

Цели описываются в Makefile (или makefile), утилита make читает его и выполняет невыполненные цели. Выполнение цели — это выполнение некоторых команд, указанных в описании цели.

Это теория. Теперь пример. Допустим, у нас есть файлы книги в ТеХ: book.tex, 1.tex, 2.tex, 3.tex, book.bib. Мы создаем цель book:

book: book.tex 1.tex 2.tex 3.tex book.bib
<Tab> pdflatex book.tex
<Tab> -bibtex8 book.aux
<Tab> pdflatex book.tex
<Tab> pdflatex book.tex

Поясним. book — это цель. После двоеточия — зависимости. Ниже команды, перед ними должен стоять символ табуляции — ну, так повелось. Знак минус перед bibtex8 означает, что ошибочное завершение команды не должно останавливать сборку. Бибтех ругается, если нет, например, года издания или автора — библиография будет неправильная. Но книга-то соберется.

Вместо book.tex в командах можно писать $< — первая зависимость.

UPDATE. Цель может быть файлом, а может быть абстрактной, вроде all, clean или book. Если такого файла нет, цель считается абстрактной. Но если файл такой появится, будут проблемы. Поэтому в большом проекте такие цели лучше отметить как абстрактные с помощью ключа .PHONY:
.PHONY: all clean book

make без аргументов выполняет цель all (и все, от которых она зависит). Можно указать цель явно: make love (только цель love надо определить).

Меня поправили, что make без аргументов выполняет первую цель в файле (хотя можно указать цель по умолчанию). По традиции all и идет первой.

Сказанного уже хватит, чтобы начать пользоваться. Целей может быть много: можно собрать книгу по-быстрому, без библиографии; можно предварительно удалить вспомогательные файлы; можно сделать цель backup и сохранить текст в архив. Можно отдельной целью записать файлы book.aux и book.bbl — тогда бибтех будет срабатывать только тогда, когда менялся bib-файл.

Вот простой makefile для сборки диссертации. Вверху — определяются переменные. Далее — цели. Быстрая сборка, синонимы (кто помнит, как я назвал цель??) И основные команды, которые и делают всю работу.
Вот простой makefile для сборки диссертации. Вверху — определяются переменные. Далее — цели. Быстрая сборка, синонимы (кто помнит, как я назвал цель??) И основные команды, которые и делают всю работу.

Идем дальше. В проекте на Си или Фортране обычно много файлов, и компилировать их все надо редко. Файл компилируется в объектный, и потом им можно пользоваться для сборки проекта. В Фортране это ключ -c. Поэтому очень удобно собирать только измененные файлы, и весь проект. Можно его сразу даже и запустить.

Важно: make не копает глубоко и смотрит только на дату и время изменения файла. Изменился файл — значит, пересоберем его и те, которые от него зависят.

У меня обычно есть цели all (традиционная), go (all + запустить), continue (запустить с контрольной точки).

Можно задать неявное правило, чтобы не описывать однотипные действия для разных файлов:

%.o: %.f90
<Tab> fortran -c -o $@ $^

Здесь описаны сразу все цели-файлы вида *.o, которые зависят от соответствующих фортрановских файлов и обрабатываются однотипной командой. Черную магию с долларами — сейчас объясню!

Ничто не мешает задать цель несколько раз, что удобно для указания зависимостей. В неявном правиле объектник зависит от исходника, и все; а отдельно можно указать зависимости без команд:

earth.o: atmo.o ocean.o sealife.o landlife.o
ocean.o: sealife.o

Теперь первым скомпилируется sealife (и если его не трогать, он больше компилироваться не будет), потом ocean, потом earth (до него, не важно, когда, будут собраны еще два).

Переменные. В файле можно определить переменные: NAME=myprog.x Пробелы считаются. Переменная может быть пустой или содержать некий текст, например:

MODULES=earth.o atmo.o ocean.o sealife.o landlife.o

Доступ к переменной — через доллар:

$(NAME): $(MODULES)
<Tab>fortran -o $(NAME) $(MODULES)

Если переменная не определена в файле, она ищется среди переменных окружения. Если не нашлась, считается пустой. Очень удобно.

Есть много деталей, на которых не останавливаюсь! Например, когда подставлять значения переменных, через которые выражены новые переменные — при определении или при использовании. Это редко нужно.

Есть специальные переменные. Они удобны, но в неявных правилах просто необходимы! В их числе:

$@ — имя цели. Удобно, чтобы компилятор создал именно такой файл.

@^ — список зависимостей. Удобно, чтобы передать их компилятору.

@< — первая зависимость. Удобно, если создается объектник, и прочие зависимости нужны только для отслеживания, пора ли компилировать файл.

Есть еще функции для преобразования текста, например, чтобы отцепить расширение и прицепить другое.

Правильно все выразить через переменные. Компилятор, ключи, пути, имя проекта, детали запуска. Тогда будет что-то вроде:

NAME=xyz_$(CPUS)
$(NAME): $(MODULES)
<Tab>$(FC) $(OPTIONS) -c -o $@ $(IPATH) $(LPATH) $^
all: $(NAME)
go: all
<Tab> $(LAUNCHER) $(CPUS) $(TIME) $(DIR) $(NAME)

В makefile, в принципе, можно занести любые команды! Узнали, создали цель, забыли. Потом make printer и все будет.

Переменные окружения доступны как обычные переменные: $(PATH), например. Это очень важно, когда нужно линковать библиотеки: пути к ним обычно и указаны в переменных окружения.

Комментарии пишите! После решетки # . Ею же можно закомментировать что-то, если надо: OPTIONS=# -check-bounds

Про make есть куча материалов. Главное, знать, что это есть и оно Вам по силам! Удачи, коллеги.

Путеводитель по каналу