Дата и время публикации:
Задача и пути решения
1. Задача
1.1 Структура интегрируемого пакета
Состоит в том, чтобы некоторый проект, состоящий из одного приложения и статической библиотеки, собирать из исходных кодов в Yocto-poky вместо предварительный сборки и закладки отдельных приложений, что должно несомненно облегчить переход под ту или иную аппаратную платформу или архитектуру процессора.
Конечно, было простым решением показать на широко используемом примере типа "Hello world", но автор этой статьи избрал более интересный пример – интеграцию исходного кода статической библиотеки libmy.a для "подхвата" её в будущем во время сборки пользовательского приложения myapp.
Таким образом, будет реализована некоторая схема зависимостей встраиваемого программного обеспечения, показанная на рисунке 1.1
Рисунок 1.1
Как показано на рисунке 1.1 в директорию содержащую Yocto Project включается поддиректория BBPATH/layers, которая содержит в свою очередь подчиненные ей директории, содержащие уровни с рецептами, согласно которых будет создан результирующий пакет с исполняемым бинарным кодом, а затем установлен в ходе финальной сборки образа rootfs, в последствии заливаемого в перезаписываемую память "железки".
В данном случае, интегрируемый в Yocto-poky слой будет layer-myapps, который будет содержать пару рецептов:
- статической библиотеки libmy.a;
- "подхвата" её приложение myapp.a во время своей сборки.
В дампе 1.2 показано директорий директорий в Yocto-poky слой будет layer-myapps .
дамп 1.2
... BBPATH/layers BBPATH/layers/layer-myapps BBPATH/layers/layer-myapps/conf BBPATH/layers/layer-myapps/myreciepts BBPATH/layers/layer-myapps/myreciepts BBPATH/layers/layer-myapps/myreciepts/myapp.bb BBPATH/layers/layer-myapps/myreciepts/myapp/ BBPATH/layers/layer-myapps/myreciepts/myapp/myapp-1.1.tar.gz BBPATH/layers/layer-myapps/myreciepts/libmy.bb BBPATH/layers/layer-myapps/myreciepts/libmy/ BBPATH/layers/layer-myapps/myreciepts/libmy/libmy-1.2.tar.gz ...
1.2 Статической библиотеки libmy.a
Содержит некоторый исходные код, который компилируется и включается в состав архива libm.a в формате перемещаемого объектного файла, который принято называть статической библиотекой.
В листинге 1.3 приведен пример инициализации некоторого устройства src/libmy.с, который использует активно ввод-вывод с отображением в память (англ.memory-mapped I/O, MMIO) .
Листинг 1.3
/* file libmy.c */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #include <limits.h> … #include <libmy/libmy.h> . . . /* Получение имени файла с абсолютным путем по идентификатору устройства */ const char* iface_devname_make(int devid) { char *devnamep = malloca (PATH_MAX+1); if ( devnamep ) { . . . return devnamep; } return "NONAMDEV"; } . . . static int iface_hardware_init ( iface_t *ifacep ) { hwdevp = iface_hwdev_get (ifacep->hwdev_config,); if( hwdevp && ifacep->iface_devname) { /* Открытие устройства */ if( (hwp->hw_fd=open ( ifacep->iface_devname, ... )) == -1) { return IFACE_FAILURE; } /* Получение конфигурации платы */ hwp->hw_config = mmap( hwp->hw_addr, hwp->hw_size, PROT_READ | PROT_WRITE,MAP_SHARED,hwp->hw_fd,hwp->hw_offset); if ( hwp->hw_config ) { /* непосредственное выполнение некоторых операций с устройством в целях настройки и инициализации */ return IFACE_DONE } return IFACE_FAILURE; } . . . int iface_init ( iface_t *ifacep, const char *name, ifacehandler_t iface_funcp) { static int devid = 0; /* идентификатор инициализируемого устройства */ if( ifacep ) { if ( ifacep->is_init == UNITIALIZED ) { /* соберем имя некоторого устройства, использующего ввод-вывод с отображением в память */ ifacep->iface_devname = iface_devname_make(devid); /* инициализация аппаратных средств */ if ( iface_hardware_init(ifacep) == IFACE_DONE ) { ifacep->iface_devid = ++devid; ifacep->iface_ name = name; ifacep->iface_run = iface_funcp; ifacep->is_init = ITIALIZED; return IFACE_DONE } } return IFACE_FAILURE; } . . .
В листинге 1.4 – заголовочный файл ${top_srcdir}/include/libmy/libmy.h.
Листинг 1.4
/* file libmy/libmy.h */ #ifndef __MYLIB_H #define __MYLIB_H 1 . . . #define UNITIALIZED 1000 #define ITIALIZED 1001 . . . #define IFACE_DONE 2201 #define IFACE_FAILURE 5505 . . . typedef int (ifacehandler_t *) (void) . . . typedef struct { unsigned int iface_devid; /* идентификатор устройства */ const char* iface_ name; /* имя устройства */ ifacehandler_t iface_run; /* функция обрботки */ int is_init; /* признак инициализации */ }iface_t; . . . extern const char* iface_devname_make(int devid) extern int iface_init ( iface_t *ifacep, const char *name, ifacehandler_t iface_funcp) . . . . . . #endif /* __MYLIB_H*/
Итак, имеем некоторую библиотеку, которая встраивается в локальную копию проекта Yocto-poke, сформированную на основе выбранных ранее слоев с метаданными, которые содержат источники получения свободно-распространяемых, открытых исходных текстов программ (англ. Open Sources), сделанных в них локальных настроек conf/layer.conf, правила сборки и установки в файлах рецептов с расширением *.bb .
Cамо дерево проекта libmy.a, предназначенное для автоматической сборки пакета с использованием Autoconf и Automake, показано фрагментарно в листинге 1.5
Листинг 1.5
... include/ include/libmy/libmy.h ... src/Makefile.am src/libmy.с ... CHANGELOG ... configure configure.ac ... LICENSE Makefile.am ...
Дерево показанное в листинге 1.5, будет собраться c использованием пакета autotool , утилиты которой последовательно используют такие приложения, как autoconf и automake и т.п. При этом по необходимости будут автоматически использоваться вспомогательные программы и различные скрипты настройки сборкой пакета и его размещения в корневой файловой системы (англ.rootfs) .
2. Пути решения
В слое meta-mylayer создадим директорию libmy и файл libmy.bb, как показано в дапме 2.1
Дамп 2.1
user@home:~//Builds/meta-mylayer/$ mkdir libmy && touch libmy.bb
Затем, откроем в любом удобном редакторе, например набирающий среди разработчиков популярность VIM(1) и сделаем следующие записи, как показано в листинге 2.2
листинге 2.2
DESCRIPTION = " My own static library to use internal targets" SECTION = " libs" PACKAGES = " libmy libmy-dev libmy-staticdev" DEPENDS = " glib-2.0" . . . # Разрешить создавать пакеты без содержимого ALLOW_EMPTY_${PN} = "1" #ALLOW_EMPTY_${PN}-dev = "1" #ALLOW_EMPTY_${PN}-staticdev = "1" # В виду пропуска сборки пакета для /debug/ INSANE_SKIP_${PN} = "installed-vs-shipped" inherit autotools gettext PV = "1.2" S = "${WORKDIR}/${PN}-${PV}" SRC_URI = "\ file://${PN}-${PV}.tar.gz;md5=c353e5dca7a2564cb8fbe0f9e8555f1f \ \ " # Подчинененная директория ${B}/include/libmy , где лежат заголовочные файлы libmy_subdir = "/libmy" # Поддиректория ${B}/include/ libmy_build_includedir = "${B}/include${libmy_subdir}" libmy_source_includedir = "${S}/include${libmy_subdir}" do_install() { . . . install -d ${D}${libdir}/ install -m 0644 ${B}/staticdevs/libmy.a ${D}${libdir}/ install -d ${D}${includedir}${libmy_subdir} install -m 0644 -D ${libmy_source_includedir}/*.h ${D}${includedir}${libmy_subdir} } FILES_${PN}-dev = "${includedir}${libmy_subdir}/*.h" FILES_${PN}-staticdev = "${libdir}/*.a"
Как показано в листинге 2.2, на выходе будем иметь пакеты libmy и libmy-dev и libmy-staticdev, которые указаны в переменой PACKAGE, а в DEPENDS – зависимости, например пакет бибиотеки glib-2.0, как это дедается в нащем примере. При этом собираемый пакет libmy будет фиктивным, что мы и указываем в ALLOW_EMPTY_${PN}, а ввиду пропуска сборки пакета с исходным кодом в директории */debug/* , используемой целях отладки программы, в переменной INSANE_SKIP_${PN} указываем "installed-vs-shipped".
Все собираемые на прикладном уровне пользовательские приложения и библиотеки примитивов абстрактной функциональности, которые используют autoconf и automake, требуют указывать наследование пакета Autotools с использования inherit, заставляющий BitBake обращаться к файлу autotools.bbclass, которой, в свою очередь, использует определеные в нем все определения на всех этапах сборки пакета программного обеспечения на основе Autotool.
Согласно представленной ранее иерархии в дампе 1.2, в переменной SRC_URI указан локальный источник в директории BBPATH/layers/layer-myapps/myreciepts/libmy/, в которой находится libmy-1.2.tar.gz . При этом имя файла записывается в принятой нотации в Autotools, которая состоит из имени пакета ${PN} и её версии ${PV} .
На финальном этапе сборки, перед упоковкой, пакета производится размещение, то бишь установка, заоголовочных файлов и файла статической библиотеки в директории ${D}${includedir}${libmy_subdir} и ${D}${includedir}${libmy_subdir} соответственно. При этом, в ${libmy_subdir} указано имя подчиненной директории mylib , которое используется в нотации подключения заголовочного файла подобно той <libmy/libmy.h>, что использовали в листинге 1.1
\(\infty\)
3. Библиография
3.1 Yocto Project Development Manual. Best practices autobuilders
3.2 Yocto Poky Refrence Manual
3.3 OEManual. Syntax of recipes
3.4 Yocto Bitbake Recipe How To Override do_install() and do_install_append()