Egyedi Linux disztribúció készítése Yocto-val

Többször felmerült már, hogy tudnék egy meglévő disztribúciót úgy testre szabdni, hogy az én céljaimnak megfeleljen, pl kicsi hadware-en szeretném futtatni, csak az legyen a disztribúcióban amire nekem is szükségem van, legyen egy grafikus felület, de nem fontos olyan sokrétű desktop felület, mint pl egy gnome vagy kde. A Yocto-val kezdtem el ismerkedni, és hátha ez a projekt (a Yocto) mást is érdekel, az első lépések tapasztalatait szeretném megosztani egy mini blogbejegyzésben.

Mivel még most ismerkedek a projekttel, ezért ha valamit nem jól írtam, akkor kérem, hogy aki jól ért hozzá, az javítson, vagy egészítsen ki.

A Yocto egy eszköz arra, hogy saját egyedi Linux disztribúciót buildeljünk (könnyen reprodukálható módon), csak azokat a lehetőségeket beletéve a disztribúcióba, amikre szükség van. Nagy közössége van, a kis felhasználóktól a nagy cégekig, azt célozták meg, hogy embedded Linuxt buildeljenek függetlenül a hardware-től. Tehát egy-egy board gyártója a Yoctohoz biztosít különböző csomagokat (layereket), amiknek segítségével az általa gyártott hardware-re lehet így embedded linux disztribúciót buildelni (legyen az Intel, STM, Texas Instruments, vagy akár Raspberry PI stb...) A projekt kb 15 évre tekint vissza, kiforrta magát, stabil, megbízható eszközkészletté vált.

A Yocto segítségével a linuxunkat layerekből modulárisan építjük fel. A layerek receptekből állnak, amik az egyes build folyamatokat írják le.
A layerekre példa:

  • Poky: Ez a Yocto Projekt referencia disztribúciója, egy alapvető linuxot tartalmaz, az alapvető konfig fájlokkal. Ez a működő rendszer alapja.
  • BSP layerek: azaz Board support package-ek, ez az adott hardware támogatásához szükséges layert tartalmazza, beleértve a bootloadert, kernelt, drivereket. Ilyen pl a meta-raspberrypi, meta-npx, meta-intel, meta-xilinx, stb...
  • Openembedded layerek: A meta-openembedded a közösség által létrehozott layerekkel, recepteket tartalmazza. pl meta-networking, meta-python, meta-multimedia, stb... vagy a meta-oe ami általános recepteket tartalmaz, mint pl rendszer utility-k, alacsonyabb szintű komponensek, stb...

Az openembedded ha jól értettem egy ökoszisztéma, egy build framework. A Yocto is ennek megfelelően működik, az openembedded által leírt eszközöket integrálja, és szabványosítja. A buildelést a bitbake tool segítségével végzi.

A Yocto projekttel való ismerkedést érdemes a következő oldalon kezdeni: https://docs.yoctoproject.org/brief-yoctoprojectqs/index.html (Ez a quick start oldal)

Én Fedora 41-en buildeltem (még hivatalosan nincs benne a támogatott OS-ek között, de minden tökéletesen működött, mert a Fedora 40 úgy tudom, hogy benne van). De lehet használni Ubuntut, vagy egy sor másik linux disztribúciót.

Egy LTS Poky release-t választottam ki a következő oldalról: https://wiki.yoctoproject.org/wiki/Releases A Scarthgap verziót választottam.

Egy üres GIT repository-t készítettem, amihez hozzáadtam a következő submodule-okat (layereket):

git submodule add -b scarthgap https://git.yoctoproject.org/poky poky
git submodule add -b scarthgap https://git.yoctoproject.org/meta-raspberrypi meta-raspberrypi
git submodule add -b scarthgap https://github.com/openembedded/meta-openembedded meta-openembedded

A .gitmodules fájlom így néz ki: ($PROJECT_DIR/.gitmodules)

[submodule "poky"]
	path = poky
	url = https://git.yoctoproject.org/poky
	branch = scarthgap
[submodule "meta-raspberrypi"]
	path = meta-raspberrypi
	url = https://git.yoctoproject.org/meta-raspberrypi
	branch = scarthgap
[submodule "meta-openembedded"]
	path = meta-openembedded
	url = https://github.com/openembedded/meta-openembedded
	branch = scarthgap

Ezt adtam hozzá a .gitignore-hoz: ($PROJECT_DIR/.gitignore)

downloads
sstate-cache
build-rpi4/*
!build-rpi4/conf

A build környezetet inicializálni így lehet:

source poky/oe-init-build-env build-rpi4

A buildelés innentől kezdve a build-rpi4 könyvtárban történik, és azon belül a conf könyvtárban vannak az alapbeállítások, pl hogy milyen rétegeket használunk (bblayers.conf), és azokat hogyan paraméterezzük (local.conf).

Ez a bblayers.conf fájlom: ($PROJECT_DIR/build-rpi4/conf/bblayers.conf)

# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
# changes incompatibly
POKY_BBLAYERS_CONF_VERSION = "2"

BBPATH = "${TOPDIR}"
BBFILES ?= ""

BBLAYERS ?= " \
  ${TOPDIR}/../poky/meta \
  ${TOPDIR}/../poky/meta-poky \
  ${TOPDIR}/../poky/meta-yocto-bsp \
  ${TOPDIR}/../meta-raspberrypi \
  ${TOPDIR}/../meta-openembedded/meta-oe \
  ${TOPDIR}/../meta-openembedded/meta-python \
  ${TOPDIR}/../meta-openembedded/meta-multimedia \
  ${TOPDIR}/../meta-openembedded/meta-networking \
  ${TOPDIR}/../meta-custom-conf \
  "

A meta-custom-conf rétegről később írok.

A local.conf fájlom végére a következőt fűztem: ($PROJECT_DIR/build-rpi4/conf/local.conf)

# Custom Raspberry Pi config

MACHINE = "raspberrypi4-64"

GPU_MEM = "256"
ENABLE_UART = "1"
ENABLE_I2C = "1"
ENABLE_SPI = "1"
BOOT_DELAY = "0"
RPI_USE_U_BOOT = "1"
DISPMANX_OFFLINE = "1"
KERNEL_CMDLINE = "dwc_otg.lpm_enable=0 console=tty1 console=serial0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait net.ifnames=0"

RPI_EXTRA_CONFIG = "\n\
dtparam=audio=on\n\
hdmi_drive=2\n\
hdmi_force_hotplug=1\n\
dtoverlay=gpio-fan,gpiopin=18,temp=65000\n\
"

RPI_KERNEL_DEVICETREE_OVERLAYS:append = " overlays/gpio-fan.dtbo"

INIT_MANAGER = "systemd"
DISTRO_FEATURES:append = " systemd pam"

EXTRA_IMAGE_FEATURES:append = " ssh-server-dropbear package-management"
PACKAGE_CLASSES = "package_deb package_rpm package_ipk"

IMAGE_INSTALL:append = " hungarian-locale tzdata alsa-utils"
IMAGE_INSTALL:append = " gzip bzip2 xz tar zip unzip coreutils findutils diffutils file vim iputils procps util-linux curl opkg"

DEFAULT_TIMEZONE = "Europe/Budapest"

LICENSE_FLAGS_ACCEPTED = "synaptics-killswitch"

A legtöbb beállítás magáért beszél, de a MACHINE változóban adtam meg a hardware környezetet, utána több raspberry PI-vel kapcsolatos beállítás van. A RPI_KERNEL_DEVICETREE_OVERLAYS egy érdekes volt, mert a meta-raspberrypi layerben benne van gpu-fan.dtbo fájl (device tree blob overlay), de alap esetben nem másolta oda a yocto, ez a fájl ahhoz kell, hogy a CPU hűtést vezérelni tudjuk, és a config.txt-ben vannak a beállításai. A kernelnek van szüksége a dtbo fájlokra, az egyes hardware konfigurációkat írják le, dtbo nélkül a kernel nem tudná, hogy kommunikáljon az eszközzel.

Az INIT_MANAGER-t átállítottam systemd-re. sysvinit volt az alapértelmezett beállítás.
Az EXTRA_IMAGE_FEATURES-ben az SSH szervert adtam hozzá, és a package management-et.

Az egyes receptek tartalmaznak licensz hivatkozásokat (a licensz tartalmából számolt hash code-okkal), és ha jól értettem a LICENSE_FLAGS_ACCEPTED-del egyes esetekben ezt el kell fogadni.

A bblayers.conf fájlomhoz hozzáadtam egy egyedi receptet, ez a meta-custom-conf, és az IMAGE_INSTALL részbe beleírtam egy csomagot, amit ez a recept tartalmaz: " hungarian-locale" a meta-custom-conf layerből.

Ezt a saját layert következő paranccsal lehet létrehozni például:

bitbake-layers create-layer meta-custom-conf

vagy kézzel.

A könyvtár szerkezet a következő: ($PROJECT_DIR/meta-custom-conf)

./conf
./conf/layer.conf
./README
./COPYING.MIT
./recipes-core
./recipes-core/hungarian-locale
./recipes-core/hungarian-locale/files
./recipes-core/hungarian-locale/files/locale.conf
./recipes-core/hungarian-locale/files/vconsole.conf
./recipes-core/hungarian-locale/files/locale.sh
./recipes-core/hungarian-locale/hungarian-locale.bb

A létrehozott layer.conf-ot nem bántottam, a layerre vonatkozó beállítások vannak benne, pl melyik verzióval kompatibilis (itt most a scarthgap), név, prioritás, és hol keresse a yocto (vagy a bitbake) a layerhez tartozó recepteket. ($PROJECT_DIR/meta-custom-conf/conf/layer.conf)

# 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-custom-conf"
BBFILE_PATTERN_meta-custom-conf = "^${LAYERDIR}/"
BBFILE_PRIORITY_meta-custom-conf = "6"

LAYERDEPENDS_meta-custom-conf = "core"
LAYERSERIES_COMPAT_meta-custom-conf = "scarthgap"

A hungarian-locale receptet a recipes-core könyvtárba tettem, tehát it vagyunk: meta-custom-conf/recipes-core/hungarian-locale: ($PROJECT_DIR/meta_custom-conf/recipes-core/hungarian-locale/hungarian-locale.bb)

SUMMARY = "Hungarian locale configuration"
DESCRIPTION = "Hungarian language support package including: \
    UTF-8 character encoding, \
    Hungarian keyboard layout (hu), \
    Console font configuration (Lat2-Therminus16), \
    Locale settings (hu_HU.UTF-8), \
    and all required language and font packages"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"

inherit allarch systemd

# Locale generation settings
ENABLE_BINARY_LOCALE_GENERATION = "1"
GLIBC_GENERATE_LOCALES = "hu_HU.UTF-8 en_US.UTF-8"
IMAGE_LINGUAS ?= "hu-hu en-us"

SRC_URI = " \
    file://locale.conf \
    file://vconsole.conf \
    file://locale.sh \
"

do_install() {
    install -d ${D}${sysconfdir}
    install -d ${D}${sysconfdir}/profile.d
    install -m 0644 ${WORKDIR}/locale.conf ${D}${sysconfdir}/
    install -m 0644 ${WORKDIR}/vconsole.conf ${D}${sysconfdir}/
    install -m 0644 ${WORKDIR}/locale.sh ${D}${sysconfdir}/profile.d/
}

FILES:${PN} = " \
    ${sysconfdir}/locale.conf \
    ${sysconfdir}/vconsole.conf \
    ${sysconfdir}/profile.d/locale.sh \
"

RDEPENDS:${PN} += " \
    glibc-utils \
    localedef \
    glibc-binary-localedata-hu-hu \
    glibc-binary-localedata-en-us \
    glibc-gconv-utf-16 \
    glibc-gconv-utf-32 \
    glibc-gconv-ibm850 \
    glibc-charmap-utf-8 \
    glibc-localedata-i18n \
    glibc-localedata-hu-hu \
    glibc-localedata-en-us \
    console-tools \
    kbd \
    kbd-keymaps \
    kbd-consolefonts \
    ttf-dejavu-sans \
    ttf-dejavu-sans-mono \
    ttf-dejavu-sans-condensed \
    ttf-dejavu-serif \
    ttf-dejavu-serif-condensed \
    ttf-dejavu-common \
"

Az inherit systemd itt lehet, hogy nem is kell, csak bent maradt egy régi próbálkozás, az allarch azt jelenti, hogy olyan recept, ami architektúra független, és az ezzel kapcsolatos beállításokat örököljük itt.

Az SRC_URI-ban mondjuk meg, hogy honnan szedheti a program a recepthez szükséges egyéb fájlokat (használhatunk akár https://, vagy git:// stb.. sémát is). Az egyes lépéseket a do_compile, do_install, do_deploy, stb... részek írják le, és a FILES:${PN} részben vannak a keletkezett fájlok. Érdekesség, úgy tapasztaltam, ha olyan receptet írok, amiben nem keletkezik semmi, csak pl függőséget, vagy egyéb beállítást próbálok hozzáadni, akkor a fordítás hibára fog futni.
Az RDEPENDS-ben vannak a recept függőségei. Itt a ttf-dejavu-* felesleges is szerintem.

(Egy megjegyzés: bbappend kiterjesztésű fájlokkal más layerekből más receptek fájljait egészíthetjük ki a saját receptünkben)

A konfigurációhoz szükséges fájlokat a files könyvtárba tettem: ($PROJECT_DIR/meta-custom-conf/recipes-core/hungarian-locale/files/locale.conf)

LANG="hu_HU.UTF-8"
LC_ALL="hu_HU.UTF-8"

($PROJECT_DIR/meta-custom-conf/recipes-core/hungarian-locale/files/locale.sh)

#!/bin/sh
export LANG="hu_HU.UTF-8"
export LC_ALL="hu_HU.UTF-8"

($PROJECT_DIR/meta-custom-conf/recipes-core/hungarian-locale/files/vconsole.conf)

KEYMAP=hu
XKBLAYOUT=hu
XKBMODEL=pc105
XKBOPTIONS=terminate:ctrl_alt_bksp
FONT=Lat2-Terminus16

 

A recept segítségével a Linux disztribuciónkban az UTF-8 kódolás lesz beállítva, hu_HU.UTF-8 locale-lal, magyar billentyűzet kiosztással, és fonttal, és a konzolban ez jól fog működni.

A fordítás a projekt kiinduló könyvtárában a

bitbake core-image-weston 

paranccsal történik. Ez lefordítja a linux disztribúciót, és beleteszi a weston grafikus környezetet is.

Az első buildelés nekem egy 11. generációs i5-ös gépen több mind egy óra volt. A további buildelések már gyorsak (pár másodperc), csak a módosítások buildelődnek újra.

A westonról: https://wayland.pages.freedesktop.org/weston/
A weston a referencia implementációja a wayland kompozitornak, kicsi, egyszerű, stabil, jól használható embedded rendszerekben, pl.: autók, egyszerű felületek, stb...

Fájl kiírása SD kártyára:

bmaptool copy --bmap build-rpi4/tmp/deploy/images/raspberrypi4-64/core-image-weston-raspberrypi4-64.rootfs.wic.bmap build-rpi4/tmp/deploy/images/raspberrypi4-64/core-image-weston-raspberrypi4-64.rootfs.wic.bz2 /dev/sda

A bmaptool optimalizálva írja ki az image-et, gyorsabban mint a dd, mert az üres részeket átugorja.

 

Egy raspberry pi 4b (4Gb-on) nekem kb 3-5 másodperc alatt bootol be a lefordított linux.

Hálózat: ahogy a systemd-t engedélyeztem, nem nagyon kellett vele foglalkozni, mert automatikusan kért IP címet DHCP-n. Úgy látom, hogy a wifi is benne van.

Remélem, hogy valakinek hasznos lesz a leírás, a cél annyi volt, hátha más is kedvet kap a Yocto-val való kisérletezéshez. Az egyes konfig fájlok lehetőségeit, a szintaxisokat, a könyvtárstruktúrákat érdemes a yocto doksijában elolvasni, ahol minden teljes körűen le van írva. (itt ez nyilván nem volt cél)

Hozzászólások

Szerkesztve: 2025. 02. 02., v – 20:26

Köszi a doksit, nekem hasznos lesz! :)

Szerkesztve: 2025. 02. 02., v – 23:04

+1 subscribe.

És köszönet :) Xilinx/Zynq/ARM rendszereken meg saját RISC-V hardveren is kipróbálom!

Mi a benefit, érezhetően gyorsabb a rendszer?

Nehéz összehasonlítani, mert a Weston-t használom, ami egy kicsi program a Gnome-hoz, vagy akár az XFCE-hez képest is.

Gyors a rendszer, egy Raspberry PI 4B 4Gb-os lapkán sem rossz.

Na most gyorsan el lehet oda jutni, ha valaki ezt elkezdi megnézni, hogy akkor van ennek csak értelme, ha valaki:

  • Ismerkedni akar ezzel
  • Valami embedded dolgot csinál, kis/egyedi hardware-en kell futnia.

Egyébként nagyon nagy szívás, hogy fordítgatni kell, layereket vadászni, tehát nehezebb vele elindulni. Meg 1000 best practice lehet, amit meg kell ismerni. Egy-egy apró beállítással több órát küzdöttem (mert többféle módon meg lehet csinálni), és kiderült, hogy ki van vezetve egy opcióba, pl csak a local.conf-ba kell egy sor. :)

Másik példa:

Oké, hogy van egy alap rendszerem, de hogy teszek rá fel bármit is? Hiába van apt-om, rpm-em, vagy pkg-m, nem tudok rá felerőltetni pl egy böngészőt csak úgy, pl a C library verziója is eltérhet, meg kismillió függőség lehet, ami kell. Ilyenkor újabb csomagok/rétegek, stb... ez egy elég bonyolult dolog.

Én a fentit úgy oldottam meg, hogy kitaláltam, hogy flatpak-ozok. Ekkor derült ki, hogy ezt nem is én találtam ki, mert eleve embedded rendszerekben használják ezeket a sandbox-os csomagokat. A flatpak-hoz most úgy látom (de nem biztos, hogy jól látom), hogy ahhoz három éve nem commitoltak, és a yocto oldal is figyelmeztet, hogy ez valószínűleg egy régebbi, elhagyott layer.

Majd megtaláltam a SNAP-et (az Ubuntus-t). Az Canonical SNAP layere pöccre fordul, és működik, a yocto disztribúciómba betettem a meta-snapd réteget (plusz a beállítások), és snap install -lal fel tudtam tenni pl a Brave böngészőt.

Közben a SNAP-pel a szívás:

  • Ugye itt sandbox-ban (readonly squashfs-sel+konténerben) futnak a programok. Interfészekkel csatlakozik egy-egy alkalmazás a host géphez, hogy pl legyen hang, elérje az USB drive-ot, stb... Telepítéskor ezeket a snap megkeresi, és összekapcsolja a környezettel.
  • Egyrésztől ez tök jó, mert kb úgy futhat egy alkalmazás, ahogy Android alatt is, nem látják egymást, biztonságos, immutable csomagok, atomi update, stb... Nincs az a probléma, ami embedded linux alatt lehet, hogy Te fordítottad, és minden-minden függőség hiányzik.
  • De fel kellett tennem a pulse-audio-t a Yocto-ba, mert a SNAP, és a Brave ahhoz akart kapcsolódni, egyébként nem volt hang. Az ALSA-val simán nem működött, ami alapból a Yocto-ban volt (mindenféle plusz beállítás nélkül)

Tehát ott tartok, hogy van egy Yocto rendszerem, de benne van minden, ami ellen ágálni szoktak itt az emberek, meg bloat-osnak mondják, meg hogy a Canonical elrabolta a linuxot, és eltéríti, stb...: systemd, pulseaudio, canonical snap. Közben az a zavarba ejtő dolog, hogy ezt embedded linux területen nyomatja pl a Canonical (is), és szerintem ezt sokan félreértik, mert én úgy látom, hogy itt még van is értelme.

 

Gondolatok még a snapről: Ezt zseniálisan csinálta a Canonical, egy pillanat alatt rávilágított azzal, hogy a SNAP yocto réteget megcsinálták, hogy lehet hogy nekem az Ubuntu Core kellene, nem a Yocto, ami szintén embedded/IOT-s fejlesztésekhez van.

Én meg most kicsit zavarban vagyok, hogy nem is tudtam, hogy a systemd, pulseaudio, snap, és társainak pont hogy IOT/embedded developmentnél is van értelme, és erre is használják.

Tehát nekem a fő cél ezzel főleg a hobbizás és a tanulás, egy kicsit a területemtől eltérő ismeretek szerzése volt. Érdekes ebbe így belecsöppenni. Én nem annyira gyakorlati hasznot keresek vele, de el tudom képzelni, hogy csináljak pl most akár egy TV-BOX-ot (ami nem android, de fut rajta a YT, Moonlight (game streaming), Plex (szintén böngészővel), stb... Azt is el tudom képzelni, hogy home automatizációban felhasználjam. De közben én teljesen más területen vagyok (más jellegű fejlesztés), ennek a hobbin kívül nekem más előnye nincs.

Most kb van egy 20 pontból álló listám, amit ki kellene próbálni még a Yocto-val, és meg kellene nézni ezt az Ubuntu Core-t.

 

Gyakorlati tapasztalatok egyébként az RPI4-gyel: úgy hogy leszedtem a felbontást 4k-ról (TV-n néztem) 1920x1080@60hz-re a youtube videók (a nagyok is) teljesen jól mennek 720p60hz-val, amit a youtube választott ki, mint optimális felbontást ebben a környezetben (RPI4B 4Gb).

A YT videó nézés közben kereken 1Gb memória van használatban (mindenestől), ami azért elég jó.

A snappel, pulse-audióval, stb.. ki tudom egészíteni majd a leírást, ha esetleg valakit érdekel.