В одной из своих старых публикаций я описал процесс сборки ядра 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
Я пробовал собирать все три варианта :
Моя конфигурация сборки выглядит следующим образом :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Build Configuration: BB_VERSION = "1.43.0" BUILD_SYS = "x86_64-linux" NATIVELSBSTRING = "universal" TARGET_SYS = "aarch64-poky-linux" MACHINE = "raspberrypi3-64" DISTRO = "poky" DISTRO_VERSION = "2.7+snapshot-20190514" TUNE_FEATURES = "aarch64 cortexa53 crc" TARGET_FPU = "" meta meta-poky meta-yocto-bsp = "master:ff9d4e893c1991cf672cd2c9bb392bd55f16a22c" meta-raspberrypi = "master:7059c374512f1c1c0df9ecab0703d11438bdf78b" meta-oe meta-python meta-perl meta-networking meta-multimedia meta-gnome meta-xfce = "master:7142f09407b81c2221bbf1c5078641ab4bc63ee9" meta-example = ":" |
На момент написания статьи самой свежей версией 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"
После выполнения исправлений снова запускаем сборку образа :
Как только образ будет собран его можно записать на карту памяти 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
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# We have a conf and classes directory, add to BBPATH BBPATH .= ":${LAYERDIR}" # We have recipes-* directories, add to BBFILES BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ ${LAYERDIR}/recipes-*/*/*.bbappend" BBFILE_COLLECTIONS += "meta-example" BBFILE_PATTERN_meta-example = "^${LAYERDIR}/" BBFILE_PRIORITY_meta-example = "6" LAYERDEPENDS_meta-example = "core" LAYERSERIES_COMPAT_meta-example = "warrior" |
В переменной BBFILES указаны файлы рецептов, которые будут прочитаны при сборке.
В каталоге recipes-example/example содержится пример рецепта example_0.1.bb .
Этот пример ничего полезного не делает, только выводит сообщение во время сборки. Удалите содержимое файла example_0.1.bb и заполните его следующими строками :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
DESCRIPTION = "TCP server and client that can be run on Raspberry Pi 3 board" LICENSE = "MIT" SECTION = "examples" DEPENDS = "" SRCREV = "62f4c533077b58525717a5ece2f2c2448f35f6e3" SRC_URI = "git://github.com/PetroShevchenko/cxemotexnika.git" LIC_FILES_CHKSUM = "file://LICENSE;md5=7bd7e85475482a3b039c7c955438fbe7" FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}-${PV}:" S = "${WORKDIR}/git" do_compile() { ${CC} ${CFLAGS} ${LDFLAGS} ${S}/Examples/RaspberryPi3/tcp_server_and_client/tcp_client.c -o tcp_client ${CC} ${CFLAGS} ${LDFLAGS} ${S}/Examples/RaspberryPi3/tcp_server_and_client/tcp_server.c -o tcp_server } do_install() { install -m 0755 -d ${D}${bindir} install -m 0755 ${S}/tcp_client ${D}${bindir} install -m 0755 ${S}/tcp_server ${D}${bindir} } |
В переменной 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 вводим команду :
Теперь разделяем наше окно терминала на два окна по вертикали :
Переход между окнами осуществляется нажатием комбинации клавиш ctrl + b + ‘стрелка вверх/вниз’.
Вводим в одном из окон команду :
$ tcp_server
Во втором окне запускаем TCP клиент :
Как видите наш пакет example с программами TCP сервера и клиента установлен в новом образе и к тому же работает.
Конечно же для разработки программного обеспечения в Yocto Project есть множество инструментальных средств, в том числе плагин для IDE Eclipse CDT.
Обзор инструментальных средств для разработки ПО в Yocto Project можно вынести в отдельную статью.
На этом пока все, удачных экспериментов с Yocto!
Viewed 409052 times by 62910 viewers
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 и получил ошибки еще при попытке добавить новый слой :
Похожая ситуация у меня возникла во время написания данной статьи, я находил на просторах интернета статьи с описанием процесса сборки дистрибутива Linux с помощью Yocto и ниразу не смог его собрать, повторяя описанные в публикациях шаги.
Тогда я предположил, что это связано со стремительным изменением структуры проекта YOCTO.
К сожадению на данный момент я не располагаю достаточным количеством свободного
времени для выяснения причин неработоспособности описанной мною последовательности с новой версией YOCTO.
С добавлением слоя разобрался. Видимо, дело либо в файле лицензии было, либо в том, что собирал minimal, а не base. Теперь отлично добавляется всё.
Есть ещё вопрос, возможно кто знает ответ. Каким образом добавлять на рабочий стол sato или minimal-xfce свои ярлыки на свои приложения? Что-то пока нигде не нашел. Со временем, конечно, разберусь, просто возможно уже есть ответ на данный вопрос.