В одной из своих старых публикаций я описал процесс сборки ядра Linux для Raspberry Pi 3. Собранное ядро запускалось в заранее установленном дистрибутиве Raspbian. Сейчас мы попробуем создать свой дистрибутив Linux и запустить его на плате Raspberry Pi 3 вместо установленного там Raspbian Linux.

Первый вопрос, который напрашивается : «а зачем создавать свой дистрибутив Linux?» .
Для платы Raspberry Pi 3 такая необходимость может возникнуть, если необходимо создать специализированное устройство. Например маршрутизатор или сервер домашней автоматизации. В свой новый образ можно включить только необходимое для работы устройства программное обеспечение и больше ничего лишнего.

Основная цель проделываемой нами работы — это научиться создавать свои дистрибутивы Linux с помощью Yocto Project на примере платы Raspberry Pi 3.
Как разработчиков встраиваемых систем нас в первую очередь интересует возможность создания устройств на базе высокопроизводительного CPU для запуска на нем Embedded Linux .
Образ операционной системы Linux для разрабатываемого устройства будет содержать свой уникальный набор программного обеспечения, а также поддержку драйверов периферии для используемой SoC.

Сборка дистрибутива производиться путем кросс-компиляции на более производительной Linux машине.
Для пользователей Windows можно установить Oracle Virtual Box и запустить Linux в виртуальной среде. Установка образа Fedora Linux в Virtual Box описана в моей публикации Эксперименты с WiFi модулями на основе SoC ESP8266.

На моем двухъядерном Intel Celeron G1840 с тактовой частотой 2,8 ГГц образ Fedora Linux в виртуальной машине работал очень медленно, поэтому я установил более легковесный Linux Lite.

При создании виртуального диска необходимо обеспечить для нужд Yocto не менее 50 Гб дискового пространства (при возможности 100 — 200 Гб ).
После установки дистрибутива Linux Lite на жесткий диск открываем окно терминала (Ctrl+Alt+T) и устанавливаем все необходимые дополнительные пакеты :


$ sudo apt-get update
$ sudo apt-get install gawk wget git diffstat unzip texinfo gcc-multilib \
build-essential chrpath socat cpio python python3 python3-pip python3-pexpect \
xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \
xterm vim -y

Дальше нужно создать в своем домашнем каталоге подкаталог yocto (или назовите его как хотите) :


$ mkdir yocto
$ cd yocto

Загружаем с git репозиториев необходимые для сборки компоненты :


$ git clone git://git.yoctoproject.org/poky

Poky – это эталонный дистрибутив Linux, содержащий систему сборки Open Embedded и набор метаданных.

Загружаем Open Embedded :


$ git clone git://git.openembedded.org/meta-openembedded

Скачиваем слой BSP (Board Support Package) для плат серии Raspberry Pi :


$ git clone git://git.yoctoproject.org/meta-raspberrypi

Запускаем скрипт оболочки oe-init-build-env , который подготовит нам каталог по-умолчанию build для сборки образа и создаст конфигурационные файлы:


$ source poky/oe-init-build-env

Если вас не устраивает название каталога build, то его можно задать явно :


$ . poky/oe-init-build-env rpi3-build

Теперь нужно добавить необходимые слои программного обеспечения. Например поддержка плат Raspberry Pi (BSP пакет) находиться в слое meta-raspberrypi. Точно так же поддержка компьютерной сети , графического интерфейса пользователя, поддержка средств мультимедиа находятся в разных слоях. Свои программы для нового образа вам также необходимо создавать в отдельном слое.


$ bitbake-layers add-layer ../meta-raspberrypi
$ bitbake-layers add-layer ../meta-openembedded/meta-oe
$ bitbake-layers add-layer ../meta-openembedded/meta-python
$ bitbake-layers add-layer ../meta-openembedded/meta-perl
$ bitbake-layers add-layer ../meta-openembedded/meta-multimedia
$ bitbake-layers add-layer ../meta-openembedded/meta-networking
$ bitbake-layers add-layer ../meta-openembedded/meta-gnome
$ bitbake-layers add-layer ../meta-openembedded/meta-xfce

Вместо использования команды bitbake-layers add-layer можно дописать задействованные слои в файл conf/bblayers.conf вручную.
После этого нужно добавить название нашей целевой платы в скрипт conf/local.conf :


$ vim conf/local.conf


MACHINE ?= "raspberrypi3-64"

Процесс сборки происходит очень долго, поэтому при наличии многоядерного процессора сборку можно распараллелить добавлением следующих опций в файл conf/local.conf :


BB_NUMBER_THREADS ?= "2"
PARALLEL_MAKE ?= "-j 2"

Для своего двухъядерного процессора я указал количество потоков и заданий для make равными двум.

Чтобы защититься от ошибок при сборке из-за недоступности какого-то репозитория можно добавить в conf/local.conf зеркала :


SSTATE_MIRRORS = "\
file://.* http://sstate.yoctoproject.org/dev/PATH;downloadfilename=PATH \n \
file://.* http://sstate.yoctoproject.org/2.6/PATH;downloadfilename=PATH \n \
file://.* http://sstate.yoctoproject.org/2.7/PATH;downloadfilename=PATH \n \
"

Собрать базовый образ Linux с интерфейсом командной строки можно с помощью команды :


$ bitbake core-image-base

Запустить сборку образа с поддержкой графического интерфейса GNOME можно при помощи следующей команды :


$ bitbake core-image-sato

Минималистичный образ с поддержкой легковесного графического интерфейса XFCE собирают запуском цели :


$ bitbake core-image-minimal-xfce

Я пробовал собирать все три варианта :

Моя конфигурация сборки выглядит следующим образом :

На момент написания статьи самой свежей версией Yocto была Yocto 2.7 “warrior”, которую я и использовал.

Итак, запускаем сборку образа…

После этого у меня вылезла ошибка, в описании которой указывалось отсутствие доступа к сайту https://www.example.com .

Пришлось заменить URL в конфигурационном файле poky/meta/conf/distro/include/default-distrovars.inc :


$ vim ../poky/meta/conf/distro/include/default-distrovars.inc


CONNECTIVITY_CHECK_URIS ?= “https://www.google.com”

Также мне пришлось добавить в конфигурационный файл conf/local.conf лицензию для faad2 :


LICENSE_FLAGS_WHITELIST_append = “ commercial_faad2”

И установить флаг для библиотеки polkit :


DISTRO_FEATURES_append = " polkit"

После выполнения исправлений снова запускаем сборку образа :


$ bitbake core-image-base

Как только образ будет собран его можно записать на карту памяти micro SD:


$ sudo dd if=tmp/deploy/images/raspberrypi3-64/core-image-base-raspberrypi3-64.rpi-sdimg of=/dev/sdX

/dev/sdX — устройство для чтения карты памяти SD . У меня это USB — microSD card reader, его можно определить при помощи команды :


$ lsblk

Если вы будете вносить какие-то изменения после успешной сборки образа, то компиляция займет значительно меньше времени , чем при первоначальной сборке, поскольку будут собираться только измененные элементы.
В случае необходимости собрать абсолютно новый образ можно освободить место на жестком диске, выполнив команду :


$ bitbake -c cleanall core-image-base

Теперь остается установить карту памяти micro SD в вашу Raspberry Pi 3 и подать питание. Может случиться так, что свежесобранный образ Linux не будет загружаться. В таком случае на экране подключенного к Rpi3 монитора мы ничего не увидим и не сможем понять в чем проблема.
Для этого случая можно подсоединить преобразователь USB-UART (3.3V) к порту UART0 (8 и 10 контакты) на 40 — контактном разъеме Raspberry Pi 3.

Кроме того необходимо разрешить вывод информации во время загрузки системы в UART0.
Для этого снова подсоединяем карту micro SD к ПК и редактируем файлы config.txt и cmdline.txt.

В файл config.txt необходимо добавить одну строчку :


enable_uart=1

Файл cmdline.txt в строке настроек должен содержать такие строки :


console=serial0,115200 console=tty1

Теперь подключаем наш USB-UART и запускаем терминальную программу (например putty).
После подачи питания на плату RPi3 в окне терминала можно наблюдать сообщения о ходе загрузки образа Linux. При невозможности дальнейшей загрузки ядро Linux выведет сообщение «Kernel panic» с детализацией причин паники ядра.


[ 2.109923] Kernel panic - not syncing: No working init found. Try passing init= option to kernel. See Linux Documentation/admin-guide/init.rst for guidance.
[ 2.124351] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.14.112 #1
[ 2.130548] Hardware name: Raspberry Pi 3 Model B Rev 1.2 (DT)

Для добавления в сборку нового программного обеспечения (возможно написанного вами ) необходимо написать свой рецепт . Рецепт представляет собой текстовый файл , который указывает системе сборки откуда взять исходники программного пакета (git , svn, https, локальные файлы), каким образом их конфигурировать и собирать, какие зависимости есть у вашего пакета, в какой формат упаковывать собранный пакет и куда его устанавливать.

Синтаксис языка рецептов bitbake представляет собой комбинацию языка командной оболочки Bash и интерпретируемого языка Python .
Описание формата языка рецептов bitbake на английском языке можно почитать по вот этой ссылке BitBake User Manual.

Сейчас мы попробуем создать свой простой рецепт для сборки и добавления в образ примера TCP – клиента и сервера, работающего на RPi3.
Как я уже упоминал выше по тексту нам необходимо создать новый слой для добавления в него новых рецептов сборки.
Создать новый слой очень просто, это можно сделать прямо из каталога build :


$ bitbake-layers create-layer ../meta-example

Новый слой будет называться meta-example , войдите в этот каталог и просмотрите его структуру :


$ cd ../meta-example
$ ls

Просмотрим конфигурационный файл для нового слоя :


$ cat conf/layer.conf

В переменной BBFILES указаны файлы рецептов, которые будут прочитаны при сборке.
В каталоге recipes-example/example содержится пример рецепта example_0.1.bb .
Этот пример ничего полезного не делает, только выводит сообщение во время сборки. Удалите содержимое файла example_0.1.bb и заполните его следующими строками :

В переменной LIC_FILES_CHKSUM находиться путь к файлу лицензии и контрольная сумма MD5. Если не указать файл лицензии или указать неправильную контрольную сумму, то рецепт не соберется.
В переменной SRC_URI я указал путь к своему репозиторию на github. В SRCREV находиться хеш — сумма последнего коммита.
Функции do_compile() и do_install() выполняют компиляцию исходных и установку исполняемых файлов соответственно.
Вот такой простой рецепт без внешних зависимостей, но все-равно он более наглядный , чем вывод текста на экран.

Проверить работоспособность нашего рецепта можно таким образом. Открываем терминал, в котором вводим команды :


$ cd ~/yocto
$ . poky/oe-init-build-env
$ bitbake example

Отсутствие сообщений об ошибках свидетельствует о работоспособности нового рецепта.
Теперь его можно добавить в собираемый образ, для этого необходимо открыть конфигурационный файл conf/local.conf и дописать в него одну строчку :


$ vim conf/local.conf


IMAGE_INSTALL_append = “ example tmux”

Перед названием пакета example обязательно должен стоять пробел. Пакет tmux я добавил в образ ядра для разделения терминального окна на два и более окон, поскольку для проверки нашего примера нужно будет запустить TCP сервер и клиент в двух разных окнах.
После внесения изменений можно запустить сборку образа , после чего снова записать образ на карту памяти micro SD.


$ bitbake core-image-base
$ sudo dd if=tmp/deploy/images/raspberrypi3-64/core-image-base-raspberrypi3-64.rpi-sdimg of=/dev/sdX

Для варианта сборки образа с графической средой XFCE эти же команды выглядят так :


$ bitbake core-image-minimal-xfce
$ sudo dd if=tmp/deploy/images/raspberrypi3-64/core-image-minimal-xfce-raspberrypi3-64.rpi-sdimg of=/dev/sdX

Дальше можно подсоединить монитор и клавиатуру к плате Rpi3 или же получить доступ к консоли через UART0, который мы задействовали для просмотра сообщений во время загрузки ядра. Не забываем добавлять настройки подключения к UART0 в каждом новом образе в файлах cmdline.txt и config.txt, как я указал выше по тексту.

В результате работы нашего рецепта в образ новой системы будут установлены два исполняемых файла tcp_server и tcp_client.
Эти исполняемые файлы должны запускаться из командной строки Linux .

Запускаем putty , устанавливаем название порта ttyUSB0 и скорость 115200.
Если вы не задали логин и пароль в параметрах сборки образа, то логин по-умолчанию будет root, а пароль не нужен.
В окне приглашения Linux вводим команду :


$ tmux

Теперь разделяем наше окно терминала на два окна по вертикали :


$ tmux split-window -v

Переход между окнами осуществляется нажатием комбинации клавиш ctrl + b + ‘стрелка вверх/вниз’.
Вводим в одном из окон команду :


$ tcp_server

Во втором окне запускаем TCP клиент :


$ tcp_client localhost

Как видите наш пакет example с программами TCP сервера и клиента установлен в новом образе и к тому же работает.

Конечно же для разработки программного обеспечения в Yocto Project есть множество инструментальных средств, в том числе плагин для IDE Eclipse CDT.
Обзор инструментальных средств для разработки ПО в Yocto Project можно вынести в отдельную статью.

На этом пока все, удачных экспериментов с Yocto!

Viewed 409052 times by 62910 viewers

Last modified: 23/10/2020

Author

Comments

Здравствуйте!
Подскажите, пожалуйста.
После добавления своего слоя meta-example постоянно получаю ошибку

DNF version: 4.2.2
cachedir: /home/user/yocto/project01/poky/build/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0-r0/rootfs/var/cache/dnf
Added oe-repo repo from /home/user/yocto/project01/poky/build/tmp/work/qemux86_64-poky-linux/core-image-minimal/1.0-r0/oe-rootfs-repo
repo: using cache for: oe-repo
not found other for:
not found modules for:
not found deltainfo for:
not found updateinfo for:
oe-repo: using metadata from Sat 21 Dec 2019 08:15:06 AM UTC.
Last metadata expiration check: 0:00:01 ago on Sat 21 Dec 2019 08:15:06 AM UTC.
No module defaults found
No match for argument: example
Error: Unable to find a match

Отдельно example отлично собирается.
Сборку пробую core-image-minimal.
Причём данная ошибка присутствует независимо от того, добавляю ли я пакеты openembedded или не добавляю.
Может обязательно надо собирать только core-image-sato?

Добрый день!
Дело в том, что я попытался сделать описанные в моей же статье шаги спустя каких-то пол года на Ubuntu 18.04 и получил ошибки еще при попытке добавить новый слой :

NOTE: Starting bitbake server…
ERROR: Unable to start bitbake server (None)
ERROR: Server log for this session (/home/pshevchenko/yocto/build/bitbake-cookerdaemon.log):
— Starting bitbake server pid 13363 at 2019-12-24 15:48:47.325701 —
ERROR: Traceback (most recent call last):
File «/home/pshevchenko/yocto/poky/bitbake/lib/bb/cookerdata.py», line 168, in wrapped
return func(fn, *args)
File «/home/pshevchenko/yocto/poky/bitbake/lib/bb/cookerdata.py», line 193, in parse_config_file
return bb.parse.handle(fn, data, include)
File «/home/pshevchenko/yocto/poky/bitbake/lib/bb/parse/__init__.py», line 107, in handle
return h[‘handle’](fn, data, include)
File «/home/pshevchenko/yocto/poky/bitbake/lib/bb/parse/parse_py/ConfHandler.py», line 121, in handle
abs_fn = resolve_file(fn, data)
File «/home/pshevchenko/yocto/poky/bitbake/lib/bb/parse/__init__.py», line 125, in resolve_file
raise IOError(errno.ENOENT, «file %s not found in %s» % (fn, bbpath))
FileNotFoundError: [Errno 2] file conf/bitbake.conf not found in /home/pshevchenko/yocto/build

Похожая ситуация у меня возникла во время написания данной статьи, я находил на просторах интернета статьи с описанием процесса сборки дистрибутива Linux с помощью Yocto и ниразу не смог его собрать, повторяя описанные в публикациях шаги.
Тогда я предположил, что это связано со стремительным изменением структуры проекта YOCTO.
К сожадению на данный момент я не располагаю достаточным количеством свободного
времени для выяснения причин неработоспособности описанной мною последовательности с новой версией YOCTO.

С добавлением слоя разобрался. Видимо, дело либо в файле лицензии было, либо в том, что собирал minimal, а не base. Теперь отлично добавляется всё.
Есть ещё вопрос, возможно кто знает ответ. Каким образом добавлять на рабочий стол sato или minimal-xfce свои ярлыки на свои приложения? Что-то пока нигде не нашел. Со временем, конечно, разберусь, просто возможно уже есть ответ на данный вопрос.

Write a Reply or Comment