Következő Előző Tartalomjegyzék Kilépés

1. Áttekintés

1.1. Debian kontra Dpkg

Mindenekelőtt egy esetlegesen felmerülő tévhitet szeretnénk eloszlatni. Az UHU nem Debian alapú disztribúció. Az UHU dpkg alapú disztribúció. Csomagkezelőként a dpkg-t választottuk, de ez nem jelenti azt, hogy bármely más téren a Debiant kívánjuk követni.

Az elkészült bináris csomagok formátuma terén megfigyelhető egy-két apró eltérés a Debian csomagokhoz képest. Általában igyekeztünk minden információt beletenni a csomagba, amely a Debian csomagokban is benne van (például md5sums fájl), méghozzá azonos szintaxissal és azonos szemantikával. A rendszert ugyanakkor néhány saját fájllal (például stat, uhuinfo) is kiegészítettük.

A csomagok elkészítési mechanizmusa vajmi kevés hasonlóságot mutat a Debian rendszerével. Például nincsen "rules" fájlunk, és a "control" fájlt is csak mellesleg generáljuk a csomagkészítés során, mert erre mindenképpen szüksége van a dpkg-nak. A debhelper helyett is saját szkripteket használunk.

1.2. Célok, avagy mi nem tetszik a Debian csomagkészítési rendszerében

Fordításhoz szükséges csomagok

Nem állítom biztosan, de valahogy úgy tűnik, hogy egy Debian csomag készítése során a Build-depends opcióval megadhatunk csomagokat, melyekre szükség van, de szó sincs arról, hogy egyéb csomagok esetleg telepítve vannak-e.

Számtalan program van (gondoljunk csak például az MPlayer-re), amely csomó mindenki mással összelinkeli magát. Képtelenség kézzel pontosan feltérképezni mindazon csomagok halmazát, amelyeket az MPlayer használ, ha fordításkor megtalál. Ha akár egyet is kifelejtünk, akkor egyszer azzal együtt, másszor pedig anélkül fordítjuk a progit. Ez a következetlen viselkedés sokkal rosszabb, mintha következetesen az adott támogatás nélkül fordul le a progi.

A fordítást semmiképpen sem végezhetjük az igazi, futó rendszer alatt, hiszen azt valaki használja, külön fordítási célt szolgáló hardver parkot pedig nem engedhetünk meg magunknak (meg hülyeség is volna). Mitöbb, minden programot egy adott UHU disztribhez akarunk fordítani. Az is lehet, hogy máshoz, mint ami a gépen telepítve van.

Éppen ezért a fordításokat mind-mind egy chroot rendszeren belül végezzük. A chroot rendszerben csak a fordításhoz szükségesként felsorolt csomagok (plusz függőségeik) lesznek telepítve, semmi több.

Kötelező adatok

Nagyon szép, hogy a dpkg képes olyan csomagot előállítani, amelyben a fájlrendszer egy általunk megadott részét csomagolja be, de ily módon akár hamis md5sums vagy Installed-Size értékeket tartalmazó csomagokat is lehet készíteni. Sőt, nem is biztos, hogy ezek az adatok szerepelnek egyáltalán. Hiányzik a dpkg-ból az a réteg, amely a teljes mértékben kötelező mezőket helyesen kitöltve csomagolja be a fájlrendszer adott pontját.

Rules

A rules fájllal több problémánk is van.

A Makefile szintaxist jelen feladatra teljesen fölöslegesnek és indokolatlanul bonyolultnak tartjuk, és ebben csak egy apró mozzanat, hogy cifrább shell kódot (pl. while-ciklus) kényelmetlen leírni benne.

Rossz gondolatnak tartjuk, hogy minden egyes csomagnak saját magának kell meghívnia a mindenféle dh_ szkriptet. Ez nehezen karbantartható, és sok hibalehetőséget rejt (ki veszi észre, ha az egyik csomagban véletlenül kimarad egy fázis, vagy két fázis rossz sorrendben követi egymást?). A dh_ szkripteknek, avagy azok megfelelőinek meghívása a fordító rendszer feladata kell hogy legyen. Ily módon garantálható, hogy minden standard lépés meg legyen hívva minden csomagra. A teljesen kötelezőek ily módon nem hagyhatók ki. Ha egy standard lépést (például dependencia-keresést vagy FHS-nek megfelelés ellenőrzését) ki akarja hagyni egy csomag, akkor a kihagyás tényét (és sosem a végrehajtás tényét) kell speciálisan közölnie egy konfig fájlban.

Control

A control fájllal kapcsolatban sem szimpatizáltunk azzal az ötlettel, hogy minden adatot egy fájlban tárolunk. Ami külön adat, az legyen mind-mind egy külön apró fájl. Így sokkal egyszerűbb például a release értéket növelni egy újrafordításkor.

Ellenőrzés

A dpkg semmilyen információt nem tárol az általa telepített fájlok inode-információiról (tulaj, jogok stb.), így lehetetlenség egy telepítés ép vagy sérült módját ellenőrizni. Ezen egy "stat" nevű fájl bevezetésével segítünk. Ez a fájl a csomagokhoz tartozó fájlokról tárolja el a legfontosabb meta-adatokat (tulaj, csoport, mód, fájltípus, utolsó módosítás, közönséges fájl esetén méret, device esetén major-minor, szimlink esetén hova mutat).

Könyvtárak

A dpkg csomagkezelő semmilyen támogatást nem nyújt arra, hogy könyvtárak tulajdonosát vagy jogosultságát beállítsuk. Az elsőnek telepített csomag, amely véletlenül létrehozza a könyvtárat, olyan tulajjal és joggal hozza létre, ahogyan az ő tar fájljában az szerepelt, és ez ezután mindvégig úgy marad. Ez nekünk nem tetszik.

A dpkg azt sem tartja számon, hogy egy könyvtár tulajdonképpen melyik csomaghoz is tartozik. Ezen is segítünk.

A fent bevezetett "stat" fájlban megemlítjük azokat a könyvtárakat, amelyek igazából a csomaghoz tartoznak. Például az ispell csomag esetén a /, a /usr és a /usr/lib nem, de a /usr/lib/ispell már a csomag része. Ezt természetesen a csomagkészítő feladata korrektül meghatározni. A csomagnak ily módon részét képező könyvtárak megjelennek a "stat" fájlban, és postinstall fázisban a tulaj, csoport és jog mezőket beállítjuk rájuk.

Postinst és társai

Általános gyakorlat a különféle disztribeknél, hogy a csomagkészítési mechanizmus mindenféle kódot fűz hozzá a postinstall szkripthez. Ennek is több hátrányát látjuk. Az egyik, hogy ez esetben a postinst szkript kötelezően egy előre rögzített nyelven (bash) kell hogy íródjon, érdekes lenne ugyanis mondjuk egy perl szkript végére sh kódot rakni. A másik, ami igen undorító, hogy nehéz karbantartani. Véleményünk szerint a csomagnak legfeljebb azt kell tudnia, hogy _mit_ kell vele megtenni, de azt semmiképp nem, hogy _hogyan_. A _hogyan_ az egy másik, uhu-pkg nevű csomag feladata. Például egy csomag azt tudhatja magáról, hogy létre akar hozni egy felhasználót, vagy telepíteni akar egy info fájlt, de az ne legyen beledrótozva, hogy ezt hogyan kell megtenni.

Preinst szkriptet nem használunk, mint ahogyan a Pre-Depends mezőt sem. Postinst-ből megy minden, amit telepítés után kell megtenni. Prerm-ből mennek az élvezérelt jellegű dolgok (például user eltávolítása vagy info fájl kiszedése), ahol a kiszedés tényét kell egy programnak megmondanunk. Postrm-ből mennek a szintvezérelt dolgok (például ldconfig), ahol a jelenlegi fájlrendszer állapot alapján kell valamit újra elölről elkészíteni.

Pocsék tervezés

A Debian csomagkészítő rendszere úgy van megtervezve és kivitelezve, hogy annak szinte semelyik komponensét nem lehet egyedül használni. Hiányzik a réteges felépítés. Hiányzik az, hogy az egyes komponensek ne csak a többivel tudjanak együttműködni, hanem önmagukban is valami értelmes dolgot csináljanak. Hiányzik az, hogy az építőkövek ne adott speciális problémára (egymáshoz való illesztésre) legyenek tervezve, hanem általános feladatoknak képesek legyenek megfelelni. A Debian csomagkészítő rendszeréből lehetetlenség egy-egy komponenst önmagában használni, mivel mindegyikbe az elejétől a végéig bele van drótozva, hogy ő pontosan milyen környezetben, milyen egyéb szkriptek közepette működik. Ezért gyakorlatilag semmit nem használunk belőle, a "dpkg-deb --build" lépést leszámítva. Tehát a debhelper (dh_*) szkripteket sem.

1.3. Terminológia

Build, Compile, Pack

A legtöbb csomagkezelő rendszer nem túl szerencsés módon build-nek hívja a csomagkészítés teljes egészét, valamint build-nek hívja ennek azt a lépését is, amikor a tényleges fordítás (általában ugye ./configure; make) zajlik. A Debian szerencsére a fájlok tényleges becsomagolására (dpkg-deb --build) sem talált ki jobb szót a build-nél. Mi a csomagkészítés folyamatának teljes egészére használjuk a build kifejezést, a lefordítás lépést compile-nak, az elkészült fájlrendszerből .uhu fájl készítése lépést pack-nek hívjuk. Ezen terminológia szerint a build folyamat nagyjából az alábbi részekből tevődik össze: mindenféle előkészület, kicsomagolás, compile, install, csinosítgatás, pack, majd esetleg az elkészült csomag másolása vagy takarítás magunk után.

Version, Release

A Version és Release szavakat az RPM terminológiája szerint használjuk. Version alatt mindig a fő, hivatalos verziószámot értjük, ez a Debian szerinti verzió mező első fele (a kötőjel előtti rész). Release-nek hívjuk azt, hogy hányadszor fordítunk csomagot az adott verzióból, ez a Debian szerinti verzió mező második fele (a kötőjel utáni rész), amit ők gyakran Debian-Revision néven emlegetnek.

Summary, Description

Ismét az RPM terminológiát követve Summary-nek hívjuk az egysoros leírást (a Debian definíciója szerinti Description első sorát), és Description-nek hívjuk a hosszú leírást (a Debian értelmezése szerinti Description második és azt követő sorait).

Sourcename

Sourcename-nek hívjuk a forrás csomag nevét. Ez általában megegyezik az egyik alcsomag nevével, de nem mindig. Például az uhubuild forrás csomagból sok uhubuild-valami bináris csomag készül, de nem készül uhubuild nevű bináris csomag.

1.4. Felépítés

Az uhu csomagkészítési mechanizmusát igyekeztünk réteg szerkezetűre tervezni, ezeket a rétegeket a belsőktől a külsők felé fogjuk ismertetni. Minden ilyen réteg olyan szkripteket tartalmaz, amelyek önmagukban megállják a helyüket és valami értelmes dolgot csinálnak, és mit sem tudnak a köréjük épülő egyéb rétegekről. Természetesen a külső rétegbe tartozó szkriptek használják a beljebb lévő rétegek szkriptjeit, ezáltal kiegészítik, továbbfejlesztik azokat.

A rendszer tervezésekor törekedtünk arra, hogy bármiféle komoly infrastruktúra felépítése vagy egyéb energiabefektetés nélkül, tehát minimális munkával bárki bármikor újrafordíthasson egy UHU csomagot tökéletesen ugyanolyan környezetben, mint ahogyan ezt mi tesszük.

Először foglaljuk össze a rétegeket, majd ezután ismertetjük azokat részletesen.

uhubuild-pack

Nagyjából a "dpkg --build" lépés, tehát a fájlrendszer adott könyvtára alatt lévő fájlok .deb csomaggá összerámolása. Egy-két plusz lépéssel van kiegészítve, amelyeket a build rendszer egészétől teljesen függetlenül minden UHU csomagra végre kell hajtani, mint például az md5 összegek vagy a telepített méret kiszámítása.

uhubuild-build

Az uhubuild-build szkript (az uhubuild-here csomag része) egy csomag forrását fordítja le, elkészítve ebből az egy vagy több bináris csomagot. A szkriptnek a lefordítandó forráskódot és a hozzá tartozó adminisztratív információkat egy nemsoká ismertetendő könyvtárszerkezetben kell megadni, ahol általában a különböző típusú információkat külön fájlok tartalmazzák. Például külön-külön fájlban kell tárolni a csomag verzióját, release értékét, a maintainer nevét, minden egyes készülő bináris csomagra annak rövid és hosszú leírását, a dependenciákat stb.

Lehetőség van snapshot megadására is. A csomagkészítés során két alkalommal, a compile és az install fázis után készülhet snapshot, ahonnan később folytatni lehet a csomagkészítést.

Az uhubuild-szkript a fájlrendszer szerkezet alapján a futó rendszerben lefordítja a csomagot, és megadott helyre lerakja az elkészült *.uhu fájlokat.

A szkript teljes egészében úgy van tervezve, hogy sima felhasználóként tudjon futni. A telepítési fázisra a pretendroot nevű függvénytárat használja, amely segítségével lehetőségünk van virtuálisan root (vagy bármilyen) tulajdonúnak látszó fájl létrehozásához (tehát nagyon hasonlít a Debian fakeroot csomagjához). Mindemellett a forrás könyvtárstruktúrát nem piszkálja, azt csak olvashatónak tételezi fel.

Mivel a forrás fa különféle helyekről származhat (verziókezelőből, vfat fájlrendszerről), az itt lévő fájlok jogainak semmiféle jelentéssel nem szabad bírniuk. Amennyiben a fájlok mindenki által olvashatóak, és semmi több, a csomagkészítésnek helyesen kell végigmennie.

A szkript nem törődik azzal, hogy root-ként fut-e, de illik nem root-ként indítani. Nem törődik azzal, hogy az igazi rendszerben, vagy chroot alatt fut-e. Nem törődik azzal sem, hogy a fordítás sikerességéhez szükséges csomagok telepítve vannak-e.

uhubuild-chrootbuild

Ez a szkript (uhubuild-under-chroot csomag része) szintén a megadott csomagot fordítja le, viszont egy általa felépített chroot rendszerben. A szkriptet root-ként kell indítani. Az előzőhöz hasonlóan nem feltételez írási jogot a fordítandó cuccok könyvtárára.

A chroot rendszer felépítéséhez természetesen szükség van arra, hogy az UHU csomagok *.uhu fájlként (tehát nem telepített formában) valahol elérhetők legyenek.

A chroot-on belüli fordítás egyik óriási előnye, hogy nem feltétlenül kell az élesen futó disztrib verziójához passzolni. Például egy élesen futó UHU Linux 1.2 alatt simán lehet UHU Linux 1.0-hoz passzoló csomagot fordítani.

A szkript először felépít egy chroot környezetet, amelyben a csomag fordításához szükséges csomagok lesznek telepítve, beleértve a függősek miatt szükségessé váló csomagokat is, de semmi több. Amennyiben egy használható chroot környezet már létezik a fájlrendszer megadott pontján, az esetben azt pofozza ki az új igényeknek megfelelően, tehát nem nulláról kezdi azt felépíteni.

A chroot környezetnek mindenképpen része lesz az uhubuild-here csomag, amely létrehoz ott egy uhubuild nevű felhasználót és annak /var/uhubuild home könyvtárát.

Következő lépésben szkriptünk csatolja a /proc és /dev fájlrendszereket a chroot rendszer alá, valamint egy "mount --bind" hívással a ccache könyvtárat, a fordítandó forrás könyvtárát és a snapshot fájlt (ha van) is elérhetővé teszi.

Ezt követően végrehajt egy chroot hívást, a chroot rendszeren belül uhubuild felhasználóvá vált, és meghívja az uhubuild-build szkriptet (gy.k. a belső réteget), amely itt elvégzi majd a fordítást.

Végezetül leválasztja a csatolt fájlrendszereket, és kimásolja az elkészült eredményt.

uhubuild-ennek-még-nem-tudjuk-mi-a-neve

Míg az előző két réteg teljes mértékben offline fordításról szólt (az összes adatnak elérhetőnek kellett lennie a fájlrendszerben), addig ez a réteg szól az adatok megfelelő helyről leszippantásáról.

A csomag adminisztrációs adatainak egy részét közvetlenül fájlként szedi ki az SVN-ből, más részét SVN-metaadatból vagy egyéb trükkös helyről nyeri.

A forráskódokat pedig letölti a netről, ha szükséges.

Ha megvan ezekkel, akkor hívja az uhubuild-chrootbuild szkriptet.


Következő Előző Tartalomjegyzék Kilépés