-
Notifications
You must be signed in to change notification settings - Fork 16
/
make.tex
232 lines (183 loc) · 16.1 KB
/
make.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
\documentclass[11pt,a4paper,oneside]{article}
\usepackage[utf8]{inputenc}
\usepackage[english,russian]{babel}
\usepackage{amssymb}
%\usepackage{amsmath}
%\usepackage{mathabx}
\usepackage[left=2cm,right=2cm,top=2cm,bottom=2cm,bindingoffset=0cm]{geometry}
\usepackage{bnf}
\usepackage{url}
\newcommand{\lit}[1]{\mbox{`\texttt{#1}'}}
\newcommand{\ntm}[1]{<\mbox{#1}>}
\begin{document}
\begin{center}
\begin{Large}{\bfseries Краткое введение в \texttt{make}}\end{Large}\\
%\vspace{1mm}
%\begin{small} ИТМО, группы M3234..M3239\end{small}\\
%\small Весна 2018 г.
\end{center}
Для сдачи домашних заданий требуется использовать инструмент \texttt{make},
и в связи с этим у многих появляется два вопроса: (а) как им пользоваться, и
(б) что нам даёт умение им пользоваться? Данный документ призван ответить на
эти вопросы.
\section*{Что это за инструмент}
\texttt{make} --- это один из основных инструментов для сборки проектов в ОС
Unix. Также он часто используется и под другими операционными системами.
Несмотря на многочисленные попытки, пока что полноценной замены ему не предложено.
Помимо огромного количества недостатков, у \texttt{make} есть два очень
важных достоинства:
\begin{enumerate}
\item Он есть везде. Его стандарт установился достаточно давно, поэтому практически
под любую распространённую ОС общего назначения он будет доступен.
В частности, есть полноценные реализации для Windows, Unix и Mac OS.
\item Он крайне гибок и мощен. С его помощью можно собрать более-менее любой проект
на практически любом языке.
\end{enumerate}
Именно поэтому он используется на серверах Яндекс.Контест --- альтернативные
варианты (stack, maven и т.п.) могут быть удобнее для конкретного языка, но они
не универсальны, они требуют специальной настройки, репозиториев, и подходят
для узкого набора языков. Если по какой-то причине владельцы сервера не готовы
часто обновлять софт, то все эти варианты сразу отсекаются. Опыт проверки решений
студентов в ИТМО показывает, что даже при наличии полного доступа к компьютеру
всё равно часто оказывается проще собрать проект <<руками>>, полностью отказавшись
от использованной <<продвинутой>> системы сборки.
Скорее всего, вы не раз ещё встретитесь с этим инструментом в своей программистской
практике, поэтому логично не откладывать знакомство.
\section*{Общая структура}
Инструкция для \texttt{make} хранится в файле \texttt{Makefile}. Файл
можно разделить на две части: сперва идут общие определения различных переменных,
которые могут потребоваться в ходе работы, а потом идут описания \emph{правил} ---
особого рода функций.
Если в строке встретился символ \verb!#!, вся строка от этого места до конца
считается комментарием.
\subsection*{Правила и цели}
\emph{Целью} в языке \texttt{make} называется файл из проекта. Некоторые цели
(исходные файлы) не могут быть построены в процессе сборки, для всех же остальных
целей (скажем, для исполнимых файлов) должны существовать правила.
Именем правила является имя файла. Тело правила --- это последовательность
команд ОС, служащая для его построения. Также у правила есть \emph{зависимости}
(\emph{реквизиты}) --- цели, которые должны быть достигнуты перед вызовом самого
правила.
Имя цели \emph{обязательно} начинается с первой колонки. Можно перечислить несколько
целей через пробел. После списка целей ставится двоеточие.
Зависимости указываются после двоеточия в той же строке, что и имя цели, также разделяются
пробелами. Тело правила указывается в последующих строках, обязательно с отступом в один
символ \emph{табуляции} --- принципиально важно, чтобы это была именно табуляция,
а не несколько пробелов.
Следующий пример кажется самоочевидным:
\begin{verbatim}
hello_world.exe: hello_world.cpp
g++ hello_world.cpp -o hello_world.exe
\end{verbatim}
Цель (файл) \verb!hello_world.exe! зависит от исходного файла \verb!hello_world.cpp!
и не может быть построена при его отсутствии.
Некоторые цели не имеют конкретных соответствующих им файлов. Такие цели называют
\emph{абстрактными} (фиктивными, \emph{phony}). Наиболее часто используются следующие
абстрактные цели:
\begin{itemize}
\item \verb!all! --- цель по умолчанию
\item \verb!clean! --- соответствующее правило должно удалить все файлы, строящиеся компилятором
(то есть всё, кроме исходных кодов)
\item \verb!install! --- проинсталлировать проект
\end{itemize}
Чтобы указать, какие цели являются абстрактными, существует директива \verb!.PHONY!:
\begin{verbatim}
.PHONY: all clean install uninstall
\end{verbatim}
В целом, представление о правилах как о функциях довольно точно отражает их суть.
Зависимости можно трактовать как вложенные вызовы других функций.
Однако привязка целей (имён функций) к файлам вносит некоторые отличия от традиционных
функций. Если некоторый файл уже построен и актуален, повторно
правила для его построения вызываться не будут.
Поясним это подробнее. Файл считается устаревшим, если последнее его изменение имело место
раньше, чем последние изменения какой-либо из его зависимостей.
Перед выполнением какого-либо правила \texttt{make} строит дерево зависимостей и
проверяет его актуальность, поднимаясь от листьев к корню.
Как только он находит устаревший файл, он выполняет соответствующее ему правило и
заменяет файл на актуальный.
Правила для абстрактных целей выполняются всегда, абстрактные цели всегда устаревшие.
В самом деле, ведь файлов, имеющих имя абстрактных целей, в проектах обычно не бывает,
и их надо заново <<строить>>. Однако, если эти цели не указаны в директиве \verb!.PHONY!,
а соответствующие файлы существуют, цели начнут вести себя как обычные (файловые).
\subsection*{Макропеременные и правила работы с ними}
Определения переменных даются в начале файла, перед указанием правил, каждое определение
указывается в отдельной строке и соответствует следующей грамматике:
\begin{bnf}\begin{eqnarray*}
\ntm{идентификатор} \lit{=} \ntm{значение}
\end{eqnarray*}\end{bnf}%
Например, мы могли бы написать что-нибудь такое:
\begin{verbatim}
SOURCES=src/x.ml src/y.ml
\end{verbatim}
Если где-то требуется использовать содержимое переменной, пишут знак доллара и
имя переменной в скобках: \verb!$(SOURCES)!. В данном месте произойдёт макроподстановка,
и результат будет неотличим от прямого указания значения: \verb!src/x.ml src/y.ml!.
Помимо переменных, определённых пользователем в начале файла, в мэйкфайле доступны
все переменные окружения. Например, начиная с Windows NT во всех версиях данной ОС
по умолчанию определена переменная окружения \verb!OS!, имеющая значение
\verb!Windows_NT!. Её можно использовать для написания переносимых мэйкфайлов (пример
см. в \verb!ocaml-solution!).
Также существуют следующие особые автоматически определяемые переменные:
\vspace{2mm}
\begin{tabular}{l|l}
Переменная & Значение\\
\hline
\verb!$<! & Первая зависимость цели\\
\verb!$^! & Все зависимости цели, разделённые пробелами\\
\verb!$*! & Базовое имя цели (без расширения и имени каталога)\\
\verb!$@! & Полное имя цели
\end{tabular}
\vspace{2mm}
Бывает, что одно имя нужно получать из другого путём замены. Для этого есть особый
синтаксис:
\begin{bnf}\begin{eqnarray*}
\lit{\$(} \ntm{переменная} \lit{:} \ntm{исх-префис}\lit{\%}\ntm{исх-суффикс}
\lit{=}\ntm{итог-префис}\lit{\%}\ntm{итог-суффикс}\lit{)}
\end{eqnarray*}\end{bnf}%
Данная команда разбивает содержимое переменной по пробелам, и в каждом полученном слове
заменяет начала и концы слов на указанные строчки. Например,
\verb!$(SOURCES:src/%.ml=%.o)! значение \verb!src/x.ml src/y.ml out/z.c! подставит в текст как
\verb!x.o y.o out/z.c!.
Также удобной возможностью макропроцессора мэйкфайлов являются условные конструкции.
Их можно использовать в любой части файла, они имеют относительно традиционный синтаксис:
\begin{verbatim}
ifeq ($(OS),Windows_NT)
DEL=del /f
else
DEL=rm -f
endif
\end{verbatim}
В этом примере мы определяем команду удаления в зависимости от операционной системы.
При необходимости её вызова нужно будет указать макропеременную \verb!DEL!. Например, так
можно задать абстрактное правило, уничтожающее исполнимый файл и объектные файлы,
построенные при компиляции исходников:
\begin{verbatim}
clean:
$(DEL) main.exe $(SOURCES:src/%.c=out/%.o)
\end{verbatim}
Мэйкфайлы обладают ещё многими возможностями, подробнее они описаны в документации.
\section*{Вызов \texttt{make} и особенности мэйкфайлов для Яндекс.Контест}
Построение проекта осуществляется указанием в командной строке команды \verb!make!.
Первым аргументом может идти цель, при её отсутствии предполагается цель \verb!all!.
Чтобы команда успешно отработала, требуется в текущем каталоге иметь \verb!Makefile!,
из которого и будут браться определения правил.
В условиях сказано, что ваш файл компилируется при помощи \verb!make! и запускается при
помощи \verb!make run!. Это значит, что у вас в корне архива должен находиться
\verb!Makefile!, в котором должно быть определено как минимум две
цели --- \verb!all! и \verb!run!.
Цель \verb!all! должна строить проект, а цель \verb!run! --- запускать его.
Помимо этих целей, в эталонных решениях определена абстрактная цель \verb!pack!,
осуществляющая частичную сборку проекта (построение исходников для генерируемых парсеров),
а также упаковывающая пакет для отправки на сервер надлежащим образом.
Чрезмерная зависимость проекта от конкретной среды, в которой он разрабатывается,
сильно мешает его переносимости, делает его неотчуждаемым. Поэтому
принципиально важно, чтобы компиляция выполнялась бы на сервере, исключение может быть
сделано для инструментов, строящих исходный код (например, для yacc и других генераторов парсеров).
Однако и в этом случае требуется, чтобы \verb!Makefile! позволял осуществить полную
сборку проекта при наличии на компьютере соответствующих инструментов.
\section*{Дальнейшая литература}
Данное введение не пытается заменить собой литературу по утилите \verb!make!, за
дальнейшими подробностями мы рекомендуем обратиться к документации.
\url{http://www.gnu.org/software/make/manual/}
\url{http://www.crossplatform.ru/documentation/gnu-make/gnu-make-ru.php}
\end{document}