Описание состава и механизмов использования набора рекурсивных Makefile'ов.
Компоненты сборочной системы находятся в каталоге ${KPDA_HOST}/mk
.
Утилита GNU make из состава Комплекта разработчика поддерживает автоматическое добавление каталогов, содержащих компоненты рекурсивной сборочной системы, в список поиска (cм. описание утилиты make), поэтому использование переменной MAKEFLAGS становится необязательным. При этом графическая среда разработки QNX Momentics IDE в любом случае автоматически добавляет опцию -I$QNX_TARGET/usr/include к переменной MAKEFLAGS в процессе сборки проектов. Соответственно, фактически используемая рекурсивная сборочная подсистема определяется тем, какая операционная система (и, соответственно, набор компонентов) выбраны в меню "Window -> Preferences -> QNX -> SDK" . |
Корневым файлом сборочной системы является файл qconfig.mk
, его подключение осуществляется из файлов Makefile
с помощью директивы include
. Пример:
$ cat common.mkifndef QCONFIGQCONFIG=qconfig.mkendifinclude $(QCONFIG)INSTALLDIR=usr/bininclude $(MKFILES_ROOT)/qtargets.mk
В данном примере местоположение файла qconfig.mk
может быть переопределено с помощью переменной QCONFIG
. Явное переопределение используется редко, и в подавляющем большинстве случаев в результате подключается файл, доступный по умолчанию (т.е. ${KPDA_HOST}/mk/qconfig.mk
).
Переменная MKFILES_ROOT в примере выше становится доступна после подключения файла qconfig.mk , который является главным (корневым) подключаемым файлом сборочной системы. |
В данном разделе перечислены некоторые переменные сборочной подсистемы ЗОСРВ "Нейтрино":
родительском
(на уровень выше) каталоге которых присутствует файл Makefile, содержащий запись "LIST=LIB". Переменная USE_LIST
поддерживает возможность задания множественных значений как через пробел, так и через запятую: Переменная USE_LIST не предназначена для использования на уровнях OS , CPU и VARIANT , т.е. её использование допустимо только на вышестоящих уровнях рекурсивного дерева каталогов проектов (например, для сборки какого-либо подмножества проектов). |
-j
(распараллеливание всего сборочного дерева, начиная с корня; см. раздел "Общие замечания и рекомендации"). Переключение в legacy-режим выполняется путём установки любого значения, отличного от yes (напр. make RECURSE_FAST=no install). Значение по умолчанию: yes MV_HOST
объявлена в файле qconfig.mk
и содержит имя команды, предназначенной для перемещения файлов. Переменная добавлена в качестве расширения к набору переменных CP_HOST
, LN_HOST
, RM_HOST
и т.д. FINDUP_HOST
объявлена в файле qconf-linux64.mk
и содержит имя служебной утилиты findup-unix
, предназначенной для поиска указанного каталога вверх по дереву каталогов относительно текущего уровня. Пример: qmacros.mk
): LDVFLAG_gcov = -fprofile-arcsCCVFLAG_gcov = -O0 -Wc,-fprofile-arcs -Wc,-ftest-coverageEXTRA_CLEAN_gcov = *.gcno
Т.е. в результате по команде make clean помимо стандартных объектных файлов (*.o) будут также удалены файлы *.gcno, создаваемые компилятором при в режиме покрытия кода (GNU gcov).
С помощью рекурсивной сброчной подсистемы ЗОСРВ "Нейтрино" можно выполнять сборку проектов, построенных на базе некоторых популярных в настоящее время систем: GNU Autotools (autoconf/automake), CMake, Meson, qmake (Qt). Подход к построению проектов примерно одинаков и состоит из нескольких шагов:
Добавление иерархии сборочных каталогов можно выполнить как вручную, так и с помощью утилиты addvariant (далее приведены примеры её использования в зависимости от типа проекта). Настройка проекта выполняется с помощью редактированя файла common.mk
, который обычно создаётся в корневом каталоге проекта. Перечень поддерживаемых файлом common.mk конструкций (переменных, функций) зависит от используемой системы и будет рассмотрен далее.
Задание значений переменных осуществляется согласно правилам GNU make. Общие рекомендации:
+=
. Пример: LIBS+=socket
"="
или ":="
. Пример: USETARGET=$(DESTDIR)/usr/bin/xzdec
Операторы присвоения "=" и ":=" в GNU make имеют ряд принципиальных отличий, о которых важно помнить при работе с рекурсивной сборочной подсистемой. Подробнее: GNU make: Flavors |
Переопределение функций осуществляется с помощью директивы define
. Пример (переопределение функции POST_INSTALL):
define POST_INSTALL$(shell echo "VAR1=Value" > $(DESTDIR)/usr/bin/app.cfg)endef
autotools.mk
. Данный модуль поддерживает сборку как проектов, исходный код которых заранее подготовлен с помощью инструментов Autotools (т.е. содержит готовый скрипт configure
), так и проектов, требующих предварительной подготовки (например, с помощью утилиты autoreconf
или встроенного скрипта autogen.sh
). Предыдущая версия средств поддержки сборочной системы GNU Autotools аналогична реализованной в QNX SDP и состоит из двух компонентов: подключаемого модуля qmake-cfg.mk и исполняемого файла build-cfg . С точки зрения сборочной системы ЗОСРВ "Нейтрино" модуль qmake-cfg.mk является устаревшим и не рекомендуется к использованию в новых проектах. |
Пример файла common.mk
для проекта на базе сборочной системы Autotools:
ifndef QCONFIGQCONFIG=qconfig.mkendifinclude $(QCONFIG)#CONFIGUREFLAGS += <configure_option>#LIBS += mylib#USEFILE=%1>%C --help#USETARGET=$(DESTDIR)/usr/bin/$(NAME)#PINFOTARGET=$(DESTDIR)/usr/lib/lib1.so#PINFOTARGET+=$(DESTDIR)/usr/lib/lib2.soinclude $(MKFILES_ROOT)/autotools.mkinclude $(MKFILES_ROOT)/qtargets.mk
Конфигурационные переменные модуля autotools.mk
autoreconf
, если в проекте отсутствуют (или не предусмотрены) скрипты bootstrap
, autogen.sh
и buildconf.sh
. $
(PROJECT_ROOT)/bootstrap
или $
(PROJECT_ROOT)/autogen.sh
, если они имеются. Пример: # Не использовать проект po4a (PO for anything) при первичной (bootstrap) конфигурации проектаBOOTSTRAPOPTS=--no-po4a
confiugure
, выполняющему настройку проекта перед сборкой. Список параметров, поддерживаемых скриптом configure , в общем случае индивидуален для каждого проекта и может быть уточнён с комощью команды ./configure --help |
CONFIGUREFLAGS += -CCONFIGUREFLAGS += -prefix=/usrCONFIGUREFLAGS += --with-threads --with-history --without-pythonCONFIGUREFLAGS += --without-lzmaCONFIGUREFLAGS += --without-zlib
.tarball-version
(см. описание цели update-gnu-version
).
Функции модуля autotools.mk
TARGET_CONFIGURE
содержит вызовы функци PRE_CONFIGURE
и POST_CONFIGURE
, которые также могут быть определены в common.mk
. Модуль также позволяет использовать переменные и функции, описанные в разделе Общие переменные и функции.
Цели (targets) модуля autotools.mk
.tarball-version
. Файл .tarball-version
нужен для корректной сборки проектов, которые получают информацию о своей версии из git-репозитория с помощью утилиты gnulib/build-aux/git-version-gen
. При обновлении таких проектов необходимо с помощью данной цели обновлять файл .tarball-version
. В т.н. "релизных" (Release) версиях проектов, использующих gnulib , git-version-gen не применяется, и файл .tarball-version создавать или обновлять не требуется. |
cmake.mk
. Предыдущая реализация, состоящая из модуля cmake-cfg.mk и исполнямого файла build-cmake , в настоящий момент считается устаревшей и не рекомендуется к использованию в новых проектах. |
Пример файла common.mk
для проекта на базе сборочной системы CMake:
ifndef QCONFIGQCONFIG=qconfig.mkendifinclude $(QCONFIG)#CMAKEFLAGS += -DCMAKE_OPTION=value#LIBS += mylib#USEFILE=%1>%C --help#USETARGET=$(DESTDIR)/usr/bin/$(NAME)#PINFOTARGET=$(DESTDIR)/usr/lib/lib1.so#PINFOTARGET+=$(DESTDIR)/usr/lib/lib2.soinclude $(MKFILES_ROOT)/cmake.mkinclude $(MKFILES_ROOT)/qtargets.mk
Конфигурационные переменные модуля cmake.mk
Функции модуля cmake.mk
Модуль также позволяет использовать переменные и функции, описанные в разделе Общие переменные и функции.
Поддержка сборочной системы Meson обеспечивается модулем meson.mk
.
Пример файла common.mk
для проекта на базе сборочной системы Meson:
ifndef QCONFIGQCONFIG=qconfig.mkendifinclude $(QCONFIG)#MESONFLAGS += -Doption=value#LIBS += mylib#USEFILE=%1>%C --help#USETARGET=$(DESTDIR)/usr/bin/$(NAME)#PINFOTARGET=$(DESTDIR)/usr/lib/lib1.so#PINFOTARGET+=$(DESTDIR)/usr/lib/lib2.soinclude $(MKFILES_ROOT)/meson.mkinclude $(MKFILES_ROOT)/qtargets.mk
Конфигурационные переменные модуля meson.mk
Модуль также позволяет использовать переменные и функции, описанные в разделе Общие переменные и функции.
Поддержка сборочной системы Qt обеспечивается модулем qmake.mk
.
Пример файла common.mk
для проекта на базе сборочной системы qmake:
ifndef QCONFIGQCONFIG=qconfig.mkendifinclude $(QCONFIG)# Использовать qmake5-*#QMAKEVERSION = 5#QMAKEFLAGS += <QMAKE OPTION># default use qmake .pro file $(PROJECT_ROOT)/$(NAME).proQMAKEPROFILE = $(PROJECT_ROOT)/$(NAME).pro#USEFILE=%1>%C --help#USETARGET=$(DESTDIR)/usr/bin/$(NAME)#PINFOTARGET=$(DESTDIR)/usr/lib/lib1.so#PINFOTARGET+=$(DESTDIR)/usr/lib/lib2.soinclude $(MKFILES_ROOT)/qmake.mkinclude $(MKFILES_ROOT)/qtargets.mk
Конфигурационные переменные модуля qmake.mk
5
. Значение по умолчанию: отсутствует (пустое значение соответствует Qt версии 4
) qmake
. ".pro"
). По умолчанию используется файл <имя_проекта> .pro ( <имя_проекта> определяется через служебную переменную "$(NAME)" рекурсивной сборочной подсистемы). |
Модуль также позволяет использовать переменные и функции, описанные в разделе Общие переменные и функции.
В данном разделе перечислены переменные и функции, которые могут быть использованы в файлах common.mk
, использующих все вышеперечисленные модули поддержки сборочных систем.
Универсальные переменные файла common.mk
Данные переменные поддерживаются всеми модулями поддержки внешних сборочных систем (если в примечании не указано иное).
# Линкеру будут переданы дополнительные аргументы -lsocket -lmLIBS += socket m
# Подробный диагностический вывод процесса линковкиLDFLAGS += -Wl,--verbose
# Для проектов, собираемых с отладочной информацией (вариант g), будет подключена дополнительная библиотекаLDVFLAG_g += -lmydebug
# Компилятору будет передан дополнительный аргумент -std=c++11CCFLAGS += -Wc,-std=c++11
# Для проектов, собираемых с отладочной информацией (вариант g), будет использован дополнительный макросCCVFLAG_g += -DMY_DEBUG
-i
. Содержимое PINFO-сообщения определяется содержимым макроопределения PINFO. Пример:
|
define PINFOPINFO DESCRIPTION=library for XML processingendefPINFOTARGET=$(DESTDIR)/usr/lib/libxml2.so.11
Содержимое сообщения должно быть задано в файле, на который ссылается стандартная переменная $USEFILE |
USETARGET =$(DESTDIR)/usr/bin/lzmadecUSETARGET+=$(DESTDIR)/usr/bin/lzmainfoUSETARGET+=$(DESTDIR)/usr/bin/xzUSETARGET+=$(DESTDIR)/usr/bin/xzdec
Универсальные функции
TARGET_MAKE
содержит вызовы функций PRE_INSTALL
, PRE_MAKE
, ADD_USAGE_TARGET
, POST_INSTALL
и POST_MAKE
, которые также могут быть переопределены в файле common.mk
.
Подключаемые модули позволяют динамически расширять функциональность сборочной системы. Реализованы в виде отдельных файлов, имеющих расширение ".mk"
и подключаемых с помощью директивы include
из родительских файлов. В настоящий момент модули поддерживаются следующими файлами:
qtargets.mk
(подкаталог qtargets) qconfig.mk
(подкаталог qconf)
Все модули, перечисленные в данном разделе, автоматически подключаются из родительских файлов и, соответствено, не требуют повторного подключения из common.mk |
Подключаемые модули разделены по подсистемам и находятся в соответствующих подкаталогах $KPDA_HOST/mk/inc
.
Данные модули предназначены для расширения списка поддерживаемых целей (target'ов) команды make, что позволяет автоматизировать выполнение наиболее часто решаемых задач.
Модуль cppcheck.mk
реализует поддержку статического анализа исходного кода проекта на языках C и C++ с помощью статического анализатора cppcheck, входящего в состав инструментальных средств Комплекта разработчика для ЗОСРВ "Нейтрино".
В настоящее время модуль cppcheck.mk поддерживает только статический анализ следующих типов проектов:
Статический анализ проектов, построенных на базе внешних сборочных систем (таких, как |
Цели (targets) модуля cppcheck.mk
Управляющие переменные модуля cppcheck.mk
project-cppcheck.cfg
): CPPCHECK_EXTRA_LIBRARIES:=$(PROJECT_ROOT)/project-cppcheck.cfg
Дополнительная информация о создании пользовательских конфигурационных файлов и библиотек собрана в статье Использование статического анализатора cppcheck |
/tmp
(используются платформо-специфичные имена):
Назначение: выполнение отложенного POST_INSTALL
путём запуска скрипта do-pinstall.sh
(расположен в корневом каталоге сборочной системы, является её частью и в общем случае не требует модификации). Данный механизм позволяет выполнить действия, описанные в функциях POST_INSTALL различных проектов, после выполнения всех остальных действий (т.е., например, после выполнения команды make install). Основное назначение механизма отложенного POST_INSTALL - уменьшение вероятности возникновения т.н. "гонок" (race conditions) при одновременной сборке и инсталляции проекта для нескольких целевых архитектур.
Цели (targets) модуля postinstall.mk
POST_INSTALL
. Для выполнения данной команды должна быть предварительно установлена или явно задана переменная DELAYED_POST_INSTALL_DIR. Пример: $ make DELAYED_POST_INSTALL_DIR=/tmp pinstall |
Управляющие переменные модуля postinstall.mk
$ export DELAYED_POST_INSTALL_DIR=/tmp$ make install$ make pinstall
Пример задания функции POST_INSTALL с поддержкой режима отложенного выполнения в файле common.mk:
define POST_INSTALL# 1. Выполнение действий с файлами в целевом каталоге$(call MAKE_DELAYED_POST_INSTALL,$(RM_HOST) $(DESTDIR)/unneeded/files)# 2. skip: блокирование действий для файлов (актуально для автоматического перемещения заголовочных и shared-файлов из CPU-специфичных каталогов)$(call MAKE_DELAYED_POST_INSTALL,$(DESTDIR)/usr/include/<cpu_header>,skip)# 3. prune: удаление пустых каталогов (по умолчанию: только $(DESTDIR)"/usr/share и $(DESTDIR)/usr/include).# Каталоги могут стать пустыми, например, после выполнения других действий из POST_INSTALL.$(call MAKE_DELAYED_POST_INSTALL,$(DESTDIR)/<empty dir1> $(DESTDIR)/<empty dir1>,prune)endef
|
Данные модули предназначены для расширения и переопределения штатных механизмов сборочной системы.
Данный модуль предназначен для автоматического добавления объектов Build Targets в проекты BSP, импортированные в среду QNX Momentics IDE (т.к. загрузка и сохранение Build Targets не поддерживаются штатными средствами IDE, в т.ч. операциями Import/Export).
Порядок использования:
Сообщение
в окне |
Также можно добавлять Build Targets с помощью команды make и управляющих переменных. Пример:
$ make BUILD_TARGET=custom BUILD_ARGS=-Cimages
В результате выполнения данной команды в проект будет добавлен Build target с именем custom, соответствующей команде make -Cimages custom.
$ make COMPILER_DRIVER=qcc install # для большинства архитектур аналогично make install (см. файл qconfig.mk) $ make COMPILER_DRIVER=kcc COMPILER_TYPE=gcc # использовать конфигурацию gcc для драйвера kcc $ make COMPILER_DRIVER= install # выполнить сборку проекта без использования драйвера (т.е. непосредственно используя gcc)
В настоящее время механизм выбора драйвера компиляции и типа компилятора в значительной степени утратил свою актуальность по причине наличия единственного возможного драйвера ( kcc/ qcc), а также по причине перехода на использование компилятора gcc в качестве основного.
Для сборки проектов под архитектуру e2kle (платформа "Эльбрус") в настоящее время в рекурсивной сборочной системе используются промежуточные врапперы ntoe2k-* , предоставляющие интерфейс к оригинальному компилятору lcc . Соответственно, вариант COMPILER_TYPE=lcc в качестве самостоятельного значения не используется. |
qcc
, компилятор: gcc
): make install gcc
): make COMPILER_DRIVER= install Значение по умолчанию для переменной COMPILER_DRIVER
вычисляется в файле qconfig.mk
. Оно зависит от текущих значений переменных OS
и CPU
, описывающих целевую систему, а также от значения COMPILER_TYPE
.
Значение по умолчанию для переменной COMPILER_TYPE
может быть задано следующими способами:
COMPILER
, заданной в файле Makefile
соответствующей сборочной ветки или в файле common.mk
. Пример: COMPILER:=iccinclude ../../../common.mk
nto/x86/o.icc
будет по умолчанию предпринята попытка использовать компилятор icc; список валидных значений компиляторов перечислен в переменной compilers
файла qmacros.mk
) DEFCOMPILER_TYPE
(обычно в файле "os_<имя_ос>.mk"
для соответствующей целевой ОС) или DEFCOMPILER_TYPE_$
(CPU)
. Данные переменные являются системными, их переопределение в общем случае не рекомендуется. |
$ addvariant -i OS nto x86 o $ addvariant o.gcov $ make VARIANTLIST=gcov
В результате будет собрано приложение, способное в процессе работы генерировать данные в формате GNU Code Coverage (gcov), которые далее могуть быть пронанализированы, например, средствами QNX Momentics IDE (подробнее: Using Code Coverage).
При сборке проекта в варианте gcov к имени результирующих исполняемых файлов и библиотек будет добавлен суффикс -gcov (т.е., например, для проекта test в каталоге nto/x86/o.gcov* будет создан исполняемый файл test-gcov ) |
Параллельная (многопоточная) сборка позволяет сократит время построения проекта путём одновременной обработки нескольких translation units на разных ядрах центрального процессора. Рекурсивная сборочная подсистема ЗОСРВ "Нейтрино" поддерживает два режима параллельной сборки:
Принудительной переключение сборочной системы в режим совместимости (legacy) следует выполнять только в экспериментальных целях (например, при при некорректном завершении процесса сборки проектов, изначально разработанных в среде QNX SDP, а также в процессе миграции с ОСРВ QNX Neutrino 6.x на ЗОСРВ "Нейтрино"); в любом случае, рекомендуем в подобных ситуациях обращаться в службу Технической поддержки. |
Рекомендации:
-j
(напр. make -j16 install). Переменную JLEVEL
имеет смысл использовать только в legacy-режиме (напр. make RECURSE_FAST=no JLEVEL=16 install). Одновременное использование опции -j
и переменной JLEVEL
не рекомендуется. Makefile
. Пример:
$ # Каталог proj1 содержит два подкаталога: набор библиотек (подкаталог lib) и набор утилит (utils), для сборки которых этот набор библиотек необходим $ ls proj1 lib utils Makefile $ $ cat proj1/Makefile #EARLY_DIRS=lib utils: lib include recurse.mk
В данном примере указана явная зависимость подкаталога utils
от lib
(запись utils: lib), и при параллельной сборке сборочная подсистема в первую очередь выполнит операции внутри lib
, а затем перейдёт в utils
.
В рекурсивной сборочной системе QNX SDP для решения задачи указания зависимостей использовались переменные EARLY_DIRS и LATE_DIRS (см. закомментированную строку EARLY_DIRS=lib). Эти переменные содержат списки компонентов, которые необходимо собирать в первую (EARLY_DIRS) или в последнюю (LATE_DIRS) очередь. При этом компоненты внутри этих списков собирались в том порядке, в котором они были перечислены (т.е. слева-направо, один за другим). При использовании сборочной системы ЗОСРВ "Нейтрино" в нативном режиме параллельной сборки порядок сборки компонентов внутри списков EARLY_DIRS и LATE_DIRS не определён (является произвольным и определяется утилитой GNU make). Поэтому при использовании списков EARLY_DIRS/LATE_DIRS дополнительно необходимо явно указать зависимости между перечисленными в них компонентами (в первую очередь это следует учитывать при переносе проектов из QNX SDP), или же отказаться от использования данных списков в пользу явного задания зависимостей между основными и EARLY-/LATE-компонентами (см. запись utils: lib в данном примере).
|
Данный механизм используется для переопределения значения управляющих переменных для индивидуального проекта или группы проектов.
В начало override-файлов рекомендуется добавлять конструкции вида
для контроля использования и порядка подключения (т.к. в случае наличия нескольких override-файлов в проекте они могут взаимно переопределять значения переменных с одинаковыми именами). |
Makefile.dnm
рекомендуется добавлять в него краткое описание причины, по которой отключен данный компонент или ветка сборочного дерева. Поскольку сборочная подсистема проверяет только наличие файла Makefile.dnm
, его содержимое может быть произвольным (в т.ч. на русском языке в любой кодировке).LIST
(напр. LIST=tag
) чувствительно к регистру (при выборочной сборке с помощью конструкций вида make tagLIST=... или make EXCLUDE_tagLIST=...). То есть записи LIST=tag
и LIST=TAG
соответствуют двум разным подмножествам. При задании тэгов рекомендуется придерживаться заглавного регистра (по аналогии с имеющимися списками: LIST=CPU , LIST=OS , LIST=UTILS и т.д.). |
Пошаговое создание рекурсивного проекта "Hello World!"
$ mkdir HelloWorldProj $ cd HelloWorldProj $ cat > HelloWorld.c <<EOF #include <stdio.h> int main(void) { printf("Hello, World!\n"); return 0; }EOF $ echo -e "This is Hello World Application" > HelloWorldProj.use $ mkdir -p nto/x86/o $ echo -e "LIST=OS\ninclude recurse.mk" > Makefile $ echo -e "LIST=CPU\ninclude recurse.mk" > nto/Makefile $ echo -e "LIST=VARIANT\ninclude recurse.mk" > nto/x86/Makefile $ echo -e "include ../../../common.mk" > nto/x86/o/Makefile $ cat > common.mk <<EOF include qconfig.mk include $(MKFILES_ROOT)/qtargets.mk EOF $ ls nto/x86/o Makefile $ make ... $ ls -l nto/x86/o HelloWorld.o HelloWorldProj Makefile
${KPDA_HOST}/mk/REVISION.complete
.
Предыдущий раздел: Сборочное окружение