-
Notifications
You must be signed in to change notification settings - Fork 1
/
readme_rus.txt
290 lines (222 loc) · 19.9 KB
/
readme_rus.txt
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
Принципы построения данной нерекурсивной системы сборки.
1) Декларативность.
Порядок сборки целей определяется только их зависимостями, нельзя полагаться на порядок включения целевых Makefile'ов (в отличие от рекурсивных систем сборки).
Однако, если нужно задать порядок выполнения Makefile'ов как в рекурсивной системе сборки, зависимость между Makefile'ами нужно указывать явно - через переменную MDEPS. Этот же подход используется, например, при построении исполняемого файла - необходимые библиотеки указываются как зависимости от целевого исполняемого файла.
Система сборки работает в 2 этапа:
- сначала определяются все правила для выполнения всех целей,
- затем эти правила выполняются параллельно с учётом зависимостей между целями.
Для удобства, обычно, структура вложенности Makefile'ов соответствует вложенности директорий проекта - при выполнении сборки в какой-либо директории проекта зачитываются все Makefile'ы из этой директории и её под-директорий.
2) Использование target-specific переменных (переменных, связанных с целью).
Так как этапы построения правил сборки целей и выполнения этих правил разделены, то нельзя использовать переменные этапа построения правил в самих правилах сборки.
Например, при построении правила сборки библиотеки в переменной LIB задаётся имя собираемой библиотеки.
После того, как это правило построено, может быть задано построение правила сборки другой библиотеки, с другим значением переменной LIB.
Если использовать переменную LIB при выполнении правила сборки первой библиотеки - LIB уже содержит имя второй библиотеки.
Чтобы запомнить имя библиотеки для его использования при выполнении правила сборки, необходимо связать переменную LIB с собираемой библиотекой - задать target-specific переменную.
Значение этой переменной будет связано с целью правила сборки - для разных целей будут разные значения target-specific переменной.
Это позволяет использовать один и тот же шаблон правил для построения правил сборки разных библиокек.
3) Отсутствие правил сборки целей по-образцу (pattern rules).
Вместо этого используются шаблоны построения явных правил сборки.
Во-первых, это проще в отладке - всегда можно определённо сказать, какое правило сборки применяются для данной цели,
во-вторых, достаточно использования target-specific переменных, нет необходимости в pattern-specific переменных,
в-третьих, использование pattern-specific переменных может снижать производительность интерпретации Makefile'ов (http://electric-cloud.com/blog/2009/04/makefile-performance-pattern-specific-variables/)
-----------------------------------------------------------------
Описание файлов.
1) defs.mk - файл общих определений, доступных в любом целевом Makefile, включает в себя следующие файлы:
a) top.mk - проверка корректности значений переменных TOP (корневая директория проекта) и XTOP (корневая директория создаваемых в процессе сбоки файлов)
b) functions.mk - вспомогательные функции и определения
c) $(TOP)/make/project.mk - файл дополнительных определений проекта
(включается, если есть - настройки проекта также можно задать через переменные окружения)
d) $(MTOP)/$(OS)/tools.mk - утилиты сборочной платформы OS (содание директорий, копирования файлов и т.д.), MTOP - путь к директории clean-build
2) c.mk - общие шаблоны для сборки целей на языках C или C++, включает в себя следующие файлы:
a) defs.mk - описан выше
b) include $(MTOP)/$(OS)/c.mk - утилиты и дополнительные шаблоны для сборки целей на языках C или C++ (компиляторы) для платформы OS
3) java.mk - общие шаблоны для сборки целей на языках JAVA и SCALA, включает в себя следующие файлы:
a) defs.mk - описан выше
b) include $(MTOP)/$(OS)/java.mk - утилиты и дополнительные шаблоны для сборки целей на языке JAVA для платформы OS
4) all.mk - определяет цель сборки по умолчанию (all) и цель очистки результатов сборки (clean)
5) parallel.mk - выполняет "параллельно" список целевых Makefile'ов, служит для обработки списка целевых Makefile'ов
Для целевой платформы WINDOWS существует ещё 3 дополнительных файла:
6) $(MTOP)/WINXX/auto_c.mk - автонастройка системы сборки под WINDOWS
7) $(MTOP)/WINXX/cres.mk - шаблон для создания ресурсного файла с описанием версии продукта,
подключаемого в каждый исполняемый модуль или динамическую библиотеку.
8) $(MTOP)/WINXX/wix.mk - шаблоны для сборки инсталлятора WiX (Windows Installer XML)
Замечание: файлы defs.mk, c.mk, java.mk, parallel.mk и WINXX/wix.mk разделены на 2 части - для исключения повторного разбора уже разобранных определений. Например, defs.mk будет долго обрабатываться системой сборки (из-за включения _defs.mk) только при его первом включении в целевой Makefile, при последующих включениях defs.mk в другие целевые Makefile'ы, _defs.mk включаться и обрабатываться уже не будет.
Вспомогательные файлы:
make.bat и make.sh - автоматическое определение значения переменной TOP (корня проекта) - через поиск файла .top в родительских директориях текущей директории.
Определять TOP автоматически бывает удобно в случае наличия нескольких директорий с разными версиями проекта.
Если TOP выставляется вручную, то перейдя в директорию с другой версией проекта можно забыть изменить значение TOP и, соответственно, выполнить сборку проекта не из текущей директории.
-----------------------------------------------------------------
Типовые примеры построения правил сборки.
1) Сборка статической библиотеки.
################################
include $(MTOP)/c.mk
LIB := my_lib
SRC := my_source1.c my_source2.c
INCLUDE := my_include1 my_include2
$(DEFINE_TARGETS)
################################
включение $(MTOP)/c.mk добавляет определение шаблонов сборки целей на языках C, C++
LIB - задаёт имя собираемой библиотеки
SRC - список файлов исходных текстов библиотеки
INCLUDE - список дополнительных директорий для поиска #include-файлов
$(DEFINE_TARGETS) - стандартный макрос применения шаблонов правил для сборки указанной цели (в данном случае - библиотеки)
Помимо обязательных переменных LIB, SRC и необязательной INCLUDE, можно также задать:
- DEFINES - список #define-определений.
По-умолчанию, этот список содержит:
PREDEFINES - список глобальных #define-определений из файла проекта $(TOP)/make/project.mk,
OS_PREDEFINES - список глобальных #define-определений целевой операционной системы (например _WIN32_WINNT=0x0501) - из $(MTOP)/$(OS)/c.mk.
Обычно в целевом Makefile список DEFINES дополняется (через DEFINES += my_defs), но можно и исключить глобальные определения из этого списка (через DEFINES := my_defs)
- CMNINCLUDE - глобальный список путей поиска #include-файлов проекта.
По-умолчанию, этот список равен DEFINCLUDE - списку путей из файла настроек проекта $(TOP)/make/project.mk.
Чтобы исключить глобальные пути поиска #include-файлов проекта в целевом Makefile нужно очистить CMNINCLUDE присвоив этой переменной пустое значение (CMNINCLUDE:=)
- INCLUDE - список путей поиска #include-файлов.
Присвоение значения этой переменной в целевом Makefile дополняет пути поиска, по-умолчанию INCLUDE имеет пустое значение.
Пути поиска из INCLUDE имеют приоритет над глобальными путями поиска в CMNINCLUDE, эффективный путь для поиска #include-файлов будет состоять из:
$(INCLUDE) $(CMNINCLUDE) $(SYSINCLUDE)
Обычно в целевом Makefile пути поиска #include-файлов только дополняются, причём добавленные локальные пути поиска должны иметь приоритет над глобальными путями поиска.
Если по-умолчанию переменной INCLUDE присвоить значение глобальных путей поиска, то в Makefile пришлось бы писать
INCLUDE := my_include $(INCLUDE)
что не удобно.
Поэтому глобальные пути поиска #include-файлов вынесены в отдельную переменную - CMNINCLUDE.
- SYSINCLUDE - список путей поиска системных #include-файлов (напр. /usr/include).
Обычно этот список для целевого Makefile формируется через подключение внешних подсистем - через переменную USE.
- SYSLIBPATH - список путей поиска системных библиотек.
Обычно этот список для целевого Makefile формируется через подключение внешних подсистем - через переменную USE.
- SYSLIBS - системные библиотеки, подключаемые к целевой DLL или EXE.
Обычно этот список для целевого Makefile формируется через подключение внешних подсистем - через переменную USE.
- USE - подключение подсистем.
В USE указываются имена подсистем, подключаемых для сборки целевого файла - файлы из $(PROJECT_USE_DIR) (по-умолчанию $(TOP)/make/$(OS)/use).
- DLLS, LIBS, KLIBS - соответственно имена динамических и статических библиотек, необходимых для сборки целевой DLL, EXE или DRV.
По-умолчанию эти списки пусты, UNIX-систем важен порядок перечисления библиотек.
- CFLAGS, CXXFLAGS, ASMFLAGS, LDFLAGS - соответственно дополнительные флаги С, С++-компиляторов, ассемблера и линкера.
По-умолчанию эти списки пусты.
Флаги и опции, используемые при вызове компиляторов целевой платформы, нужно смотреть в соответствующем целевой платформе $(MTOP)/$(OS)/c.mk.
- PCH - имя предкомпилированного заголовочного файла.
Этот файл подключается первым при компиляции файлов исходных текстов, перечисленных в переменной WITH_PCH.
- WITH_PCH - список файлов исходных текстов, компилируемых с предкомпилённым заголовочным файлом.
Если под целевой платформой не поддерживается использование предкомпилённых заголовочных файлов, то файлы из списка WITH_PCH компилируются обычным образом - также, как и файлы из списка SRC.
- RPATH - runtime path - пути для поиска динамических библиотек при запуске установленного приложения.
Переменная RPATH используется только для UNIX-систем, по уолчанию равна $(INST_RPATH).
- MAP - version script - файл с описанием видимости символов (глобальные/локальные) динамической библиотеки.
Используется только для UNIX-систем, для GNU LD.
- DEF - module definition file - файл с описанием экспортируемых символов динамической библиотеки.
Используется только для WINDOWS.
- RES - список ресурсных файлов, подключаемых в целевую DLL или EXE.
Эта переменная используется только для целевой платформы WINDOWS.
2) Создание утилиты.
################################
TOOL_MODE := 1
include $(MTOP)/c.mk
EXE := my_tool
SRC := my_tool_source.c
$(DEFINE_TARGETS)
################################
Здесь присваивается непустое значение переменной TOOL_MODE (которое будет очищено в $(DEFINE_TARGETS)).
Тем самым, следующее включение $(MTOP)/c.mk переопределит пути системы сборки для создаваемых файлов на пути для утилит сборки.
А при создании утилит сборки будет использован компилятор $(TCC) - для исходных текстов на языке C, или $(TCXX) - для исходных текстов на языке C++.
Компилятор утилит $(TCC), используемый в режиме TOOL_MODE может отличаться от компилятора языка C обычного режима $(СС). В этом случае будет выполнена кросс-компиляция - когда собираемые в обычном режиме исполняемые файлы могут не работать на сборочной платформе, в отличие от собираемых в режиме TOOL_MODE утилит сборки.
3) Генерация файлов.
################################
include $(MTOP)/defs.mk
MY_GENERATED := $(GEN_DIR)/my_dir/my_file.txt
$(call ADD_GENERATED,$(MY_GENERATED))
$(MY_GENERATED): MY_OPTIONS := my_options
$(MY_GENERATED): $(call GET_TOOL,my_tool) $(VPREFIX)my_source
$(call ospath,$<) $(MY_OPTIONS) -o $(call ospath,$(word 2,$^))
$(DEFINE_TARGETS)
################################
включение $(MTOP)/defs.mk добавляет определение стандартных функций и определений, таких как:
GEN_DIR - путь к директории для сгенерённых файлов (который берёт начало от $(XTOP));
ADD_GENERATED - функция для добавления сгенерённых файлов к сборке - директория $(GET_DIR)/my_dir будет создана автоматически, при выполнении make clean сгенерённые файлы будут удалены;
VPREFIX - относительный путь от текущей директории до директории, в которой находится целевой Makefile. Таким образом, путь к my_source может быть указан относительно целевого Makefile;
GET_TOOL - функция получения полного пути к утилите, ранее добавленной в сборку;
ospath - функция преобразования путей с обратными слешами в пути, специфичные для сборочной платформы (c:/a/b -> c:\a\v\b);
Также в данном Makefile используются:
MY_GENERATED - произвольно выбранное имя переменной, не обязательно уникальное - система сборки поддерживает режим проверки переопределения зарезервированных имён;
$< - автоматическая переменная - имя первой зависимости цели, в данном случае это $(call GET_TOOL,my_tool);
$^ - автоматическая переменная - список всех зависимостей цели в порядке их перечисления;
$(word 2,$^) - имя второй зависимости цели, в данном случае это $(VPREFIX)my_source (замечание: VPREFIX не была объявлена как target-specific переменная, поэтому нельзя использовать выражение $(VPREFIX)my_source в теле правила - VPREFIX может быть изменена после описания правила построения цели но до выполнения этого правила);
MY_OPTIONS - объявление target-specific переменной - последующие переопределения переменной my_options никак не скажутся на значение этой переменной в правиле генерации $(MY_GENERATED);
$(DEFINE_TARGETS) - стандартный макрос применения шаблонов правил для сборки указанной цели (в данном случае - )
4) Генерация нескольких файлов в одном правиле.
################################
include $(MTOP)/defs.mk
MY_GENERATED := $(addprefix $(GEN_DIR)/my_dir/,my_file1.txt my_file2.txt)
$(call MULTI_TARGET,$(MY_GENERATED),$(call GET_TOOL,my_tool) $(VPREFIX)my_source,$$(call \
ospath,$$<) $(MY_OPTIONS) -o $(VPREFIX)my_source)
$(DEFINE_TARGETS)
################################
Функция MULTI_TARGET, определённая в $(MTOP)/defs.mk, принимает 3 аргумента:
- список сгенерённых файлов,
- список зависимостей сгенерённых файлов,
- правило генерации файлов.
Так как правило генерации файлов будет раскрыто дважды - первый раз во время вызова MULTI_TARGET, второй - во время выполнения правила, то вызов $(ospath) и переменной $< экранирован двойным $$.
Также, нет необходимости объявлять target-specific переменные - значения MY_OPTIONS и VPREFIX будут раскрыты в момент вызова MULTI_TARGET.
5) Выполняем группу Makefile'ов.
################################
MDEPS := my_gen.mk
TO_MAKE := tool1.mk lib1/my_lib.mk my_exe
include $(MTOP)/parallel.mk
################################
Цели, указанные в Makefile'ах tool1.mk, lib1/my_lib.mk и my_exe/Makefile будут выполнены параллельно с учетом зависимостей между целями.
Присвоенное начение MDEPS указывает на то, что при сборке этого Makefile'а параллельно с my_gen.mk, цели из my_gen.mk должны быть выполнены до выполнения любых целей в tool1.mk, lib1/my_lib.mk и my_exe/Makefile (также и в этих Makefile'ах могут быть указаны зависимости от других Makefile'ов - через переменную MDEPS).
Если данный Makefile выполняется индивидуально, значение MDEPS игнорируется.
6) Собираем что-то уникальное, например выполняем тесты.
################################
include $(MTOP)/defs.mk
MDEPS := build_tests.mk
TESTS := rb_test c_base64_test memstack_test
$(call ADD_GENERATED,$(addprefix $(GEN_DIR)/tests/,$(addsuffix .tsmt,$(TESTS))))
define TEST_RULE
$(newline)
$(GEN_DIR)/tests/$t.tsmt: $(BIN_DIR)/$t$(EXE_SUFFIX)
$$(call SUP,TEST,$$<)$$< > $(GEN_DIR)/tests/$t.out
$(if $(VERBOSE),,@)$$(call TOUCH,$$@)
endef
$(eval $(foreach t,$(TESTS),$(TEST_RULE)))
$(DEFINE_TARGETS)
################################
Здесь определяется шаблон TEST_RULE - для построения правил выполнения тестов, подключённых к системе сборки вызовом ADD_GENERATED.
-----------------------------------------------------------------
Более подробно шаблоны построения правил документированы в соответствующих подключаемых файлах - $(MTOP)/defs.mk, $(MTOP)/c.mk и т.д.
Описание некоторых переменных и функций системы сборки.
$(NO_DEPS) - выставляется в непустое значение для отключения авто-генерации зависимостей объектных файлов от заголовочных файлов, подключённых компилируемыми файлами на языке С или С++
переменные - значения символов:
$(empty) - пустое значение
$(space) - пробел,
$(tab) - табуляция,
$(comma) - запятая,
$(newline) - перевод строки,
$(comment) - символ комментария.
функции:
unspaces - замена всех пробелов в аргументе на ?,
ifaddq - обрамление аргумента двойными кавычками, если аргумент содержит пробелы,
qpath - добавление префикса и, если необходимо, то обрамление аргумента двойными кавычками с заменой ? на пробелы в аргументе (эта функция, например, используется для формирования списка путей поиска #include файлов языков C/C++ в системых директориях с пробелами при сборке с использованием MS Visual Studio),
tolower/toupper - функции преобразования аргумента в нижний/верхний регистр,
padto - вычисление длины строки из пробелов для выравнивания текста (используется в кратком выводе вызываемых утилит - если make вызван без V=1),
xargs - вызов произвольной функции-обработчика списка, имеющей ограничение на количество элементов в списке (используестся для xcmd),
xcmd - вызов утилиты, принимающей на вход ограниченное число агрументов (используется при ограничениях на максимальную длину коммандной строки, например в Windows XP максимальная длина коммандной строки - 8191 символов),
normp - нормализация пути - удаление избыточных относительных смен директорий в пути (напр. a/b/../c -> a/c),
relpath - вычисление относительного пути от одной директории к другой (напр. $(call relpath,/aa/bb/cc,/aa/dd/qq) -> ../../dd/qq),
join_with - соединение данным символом всех элементов списка в один элемент.
некоторые обязательные переменные:
$(TARGET) - цель сборки проекта (PROJECTD для DEBUG-сборки, PROJECT для RELEASE-сборки и т.д.),
$(DEBUG) - значение переменной не пустое в случае отладочной сборки проекта (значение $(TARGET) оканчивается на D),
$(SUPPORTED_OSES) - список операционных систем, для которых может быть выполнена сборка конкретного проекта,
$(SUPPORTED_CPUS) - список архитектур процессора, для которых может быть выполнена сборка конкретного проекта,
$(SUPPORTED_TARGETS) - список типов сборок, для которых может быть выполнена сборка конкретного проекта,
$(OS) - целевая операционная система, под которой будет работать собранный проект и на которой осуществляется сборка проекта,
$(CPU) - целевая архитектура процессора. Значение этой переменной используется только если не определено значение
$(UCPU) - целевая архитектура процессора для исполнения в пространстве пользователя,
$(KCPU) - целевая архитектура процессора для исполнения в пространстве ядра операционной системы,
$(TCPU) - архитектура процессора, на котором осуществляется сборка проекта;
$(VERBOSE) - значение 1 - включает детальный вывод вызываемых команд сборки целей (VERBOSE выставляется в 1 при запуске make с параметром V=1), значение 0 - отключает детальный вывод вызываемых команд (вместо полной команды выводится мненоника, например CXX file.c),
$(INFOMF) - внутренняя переменная, выставляется в непустое значение при запуске make с параметром M=1 - для показа имени Makefile'а, в котором было определено правило для выполнения конкретной цели (для отладки сборки во второй фазе - выполнения правил сборки),
$(MDEBUG) - внутренняя переменная, выставляется в непустое значение при запуске make с параметром D=1 - для показа целей, правила выполнения которых определяет данный Makefile (для отладки сборки в первой фазе - построения правил сборки),
$(MCHECK) - внутренняя переменная, выставляется в непустое значение при запуске make с параметром C=1 - для проверки корректности Makefile'а до выполнения сборки;
функции:
$(SUP) - показывает либо детальный вывод вызываемой команды, либо мнемонику команды - в зависимости от значения $(VERBOSE);
$(ospath) - преобразует аргумент(ы) - пути к файлам и директориям - из UNIX-представления в представление операционной системы $(OS) (напрмер для Windows c:/opt/file -> c:\opt\file),
$(isrelpath) - возвращает не пустое значение если аргумент - относительный путь к файлу.
ЗАМЕЧАНИЕ: в системе сборки предполагается, что пути к целевым файлам и файлам-зависимостям не содержат пробелов.
Обработка путей с пробелами затруднительна, т.к. пробел интерпретируется как разделитель елементов списка (перед обработкой путей с пробелами можно заменить пробел на какой-нибудь символ, например ?, а после обработки - заменить ? обратно на пробел).