Létající cirkus (21)

28. 1. 2003
Doba čtení: 7 minut

Sdílet

Je tomu již rok, kdy na ROOTu začínal seriál věnovaný Pythonu. Dnešním dílem pojednávajícím o balíčku distutils naše povídání ukončíme. Pojďme se tedy podívat na distribuci našich programových dítek.

DISTUTILS

Kdysi v dobách pythonového pravěku se distribuce hotových programů, modulů a balíčků řešila různě, někdo dodával programy stylem „urob si sám“, kdy šlo vlastně o tarball různých modulů, balíčků a skriptů spolu s instrukcemi, jak a kam ten který soubor umístit. Jak je jistě každému jasno, nešlo o cestu úplně ideální, a proto se našlo několik způsobů, jak z této situace ven. Některé programy se daly cestou používající autoconf, kdy byla lokální instalace systému osahána skriptem configure a pak pomocí svaté trojice nainstalována. Poněvadž se ale jedná o Python, přišel ve verzi 1.6 Guido van Rossum s novým balíčkem nazvaným distutils.

Dnešní díl poněkud „ošidíme“. Jelikož jsme se ve všech minulých dvaceti dílech vůbec nezmínili o psaní modulů v jazyce C, vynecháme i distribuci takovýchto modulů pomocí distutils. Myslím si, že ten, kdo se dostal ke psaní modulů v C, tento seriál již nepotřebuje a ti, kteří o programování rozšiřujících modulů nic neví, by si z dnešního dílu taktéž nic neodnesli.

TVORBA DISTRIBUCE

Nejprve začneme trochou teorie. Každý programátor, který napíše nějaký program či modul, by neměl zapomínat na to, své dílko důstojným způsobem šířit po světě. Každý sebelepší program je k ničemu, pokud ho uživatel nedokáže nainstalovat a spustit! Vaše práce, tedy pokud píšete svoje programy v Pythonu, je poměrně jednoduchá a nedá se měřit s námahou, kterou musíte vyvinout při šíření třeba programu v C++. Stručně řečeno, musíte udělat pouze následující:

  • Napsat instalační skript pojmenovaný podle konvencí setup.py
  • Sestavit konfigurační soubory pro vaši instalaci
  • Vytvořit distribuci zdrojových kódů
  • V případě, že váš program používá rozšiřující moduly napsané v jiném jazyce, vytvořit případné binární distribuce

INSTALAČNÍ SKRIPT

Nejprve samozřejmě musíme mít napsaný program, pro nějž dále vytvoříme instalační skript. V našem případě se omezíme na následující fiktivní software a naším úkolem bude připravit ho k distribuci:

.:
data/ gnomovision/ LICENCE README setup.py

./data:
config.xml images/

./data/images:
icon1.xpm icon2.xpm

./gnomovision:
compile/ gnmv* __init__.py main.py

./gnomovision/compile:
foo.py __init__.py

Jak vidíte, jde o překladač s nakladačem gnomovision, máme ho uložen ve stejnojmenném adresáři. Ten má i dva podadresáře, jednak jde o adresář data, obsahující sdílené soubory, a dále o adresář gnomovision, v němž jsou uloženy zdrojové soubory. Program je rozdělen do hlavního skriptu gnmv, modulu main.py a balíčku compile. V hlavním adresáři programu najdeme ještě soubory LICENCE a README. Podle seznamu výše musíme nejprve napsat konfigurační skript setup.py. Jeho obsah bude jednoduchý, importuje modul distutils a zavolá funkci setup(), které předá potřebné parametry, jež budou specifikovat seznamy souborů a další užitečné věci:

from distutils.core import setup

setup(name = 'gnomovision',
   description = 'Překladač s nakladačem',
      author = 'Jan Svec',
      author_email = 'honza@py.cz',
      url = 'http://www.root.cz',
   version = '0.1',
      packages = ['gnomovision', 'gnomovision.compile'],
      scripts = ['gnomovision/gnmv'],
      data_files = [('/etc', ['data/config.xml']),
            ('share/gnomovision/images', ['data/images/icon1.xpm',
                    'data/images/icon2.xpm'])
                   ]
)

Funkci setup() můžeme předat různé meta-informace o našem balíčku. Jak vidíte z příkladu výše, jedná se o informace typu jméno balíčku, popis, jméno autora, jeho adresa apod. Tyto informace předáváme jako řetězce pomocí pojmenovaných argumentů.

Druhá část argumentů specifikuje balíčky a soubory, z nichž se náš balíček bude skládat. Pomocí pojmenovaného argumentu packages jsme funkci setup() řekli, že do distribuce má zahrnout balíčky ‚gnomovision‘ a ‚gnomovision.com­pile‘. Kromě těchto balíčků má zahrnout ještě skript uložený do souboru ‚gnomovision/gnmv‘. Nakonec zbývají datové soubory. Zde se jedná o seznam dvojic (jmeno_adresáře, [seznam_soubo­rů_které_tam_přij­dou]). Tedy, do adresáře ‚/etc‘ přijde soubor ‚data/config.xml‘ at­d.

ZDROJOVÁ DISTRIBUCE

Jak je na dobrých systémech zvykem, základní tvar, v němž je software šířen, je balíček zdrojových kódů. Knihovna distutils proto má funkce, které umožňují takový balíček vytvořit.

Zdrojový balíček se nevytváří jen ze souboru setup.py, ale i z dalšího souboru pojmenovaného MANIFEST.in, v něm jsou popsána pravidla, kterými se specifikují soubory, jež budou do balíčku zdrojových souborů zahrnuty. V našem případě vypadá takto:

include LICENCE
include README
include setup.py
graft gnomovision
graft data
global-include README

Jak vidíte, jde o obyčejný textový soubor, jenž má na každém řádku jeden příkaz. Pomocí těchto příkazů se specifikují soubory, které budou vloženy do výsledného tarballu. Těchto příkazů je několik:

  • include – tento příkaz zahrne všechny soubory specifikované předlohami za ním uvedenými (např. ‚include .txt‘ apod.)
  • exclude – opak include, soubory, které odpovídají předlohám za ním, nebudou do tarballu zahrnuty (např. ‚exclude ..swp‘)
  • recursive-include, recursive-exclude – za těmito příkazy je uvedeno jméno adresáře a seznam předloh, pak se na celý tento adresář provede příkaz include/exclude (např. ‚recursive-include src *.py‘)
  • global-include, global-exclude – obdoba rekurzivních příkazů, ale neurčuje se jméno adresáře, neboť tyto příkazy pracují na celém adresářovém stromu zdrojových souborů (např. ‚global-exclude *.pyc *.pyo‘)
  • prune – za příkazem následuje jméno adresáře, který má být kompletně vynechán, (např. ‚prune build‘)
  • draft – za příkazem opět následuje jméno adresáře, který má být naopak kompletně vložen (např. ‚prune data‘)

Pokud jsme si již připravili soubor MANIFEST.in, ve kterém jsme popsali celý zdrojový kód našeho balíčku, můžeme se pustit do vytvoření tarballu příkazem shellu:

% python setup.py sdist

Tento příkaz spustí soubor setup.py a vykoná příkaz knihovny distutils pojmenovaný ‚sdist‘. Ten podle souboru MANIFEST.in vytvoří soubor gnomovision-0.1.tar.gz umístěný v adresáři dist. Pokud by si někdo přál jiný souborový formát než .tar.gz, pak ho může zadat pomocí volby –formats (např. ‚python setup.py sdist –formats=bztar,zip‘, seznam všech dostupných formátů viz ‚python setup.py –help-formats‘).

Volbami skriptu setup.py předanými na příkazovém řádku je možné velice důkladně řídit chování tohoto skriptu. Můžeme určit, jak se bude jmenovat vstupní šablona (typicky jde o MANIFEST.in), kam budou umístěny výstupní soubory atd.

BINÁRNÍ DISTRIBUCE

Mnoho uživatelů balíčků davá přednost binární distribuci před distribucí zdrojových souborů. V našem případě je to poměrně jedno, protože doposud jsme vytvářeli moduly, které byli napsány v čistém Pythonu, tj. neobsahovaly žádné části napsané v C/C++.

Pro vytvoření binární distribuce slouží příkaz obdobný výše uvedenému:

% python setup.py bdist

Ten opět vykoná soubor setup.py, ale tentokráte vytvoří binární distribuci pro náš systém. Opět můžeme specifikovat mnoho voleb, mezi nejdůležitější opět patří přepínač –formats určující formát binárního balíčku (v současnosti gztar, bztar, rpm, zip a wininst, bohužel chybí deb!). Pokud jde o tarbally (gztar a bztar), pak jsou v něm uloženy soubory takovým způsobem, aby se ocitly na správných místech, pokud bude tento TAR rozbalen v kořenovém adresáři. Za zmínku také stojí, že samorozbalovací .exe soubor (formát wininst) se vám vytvoří i na Linuxu!

INSTALACE BALÍČKU

Balíček můžeme nainstalovat jiným příkazem knihovny distutils:

% python setup.py install

Jak je tomu zvykem u všech příkazů, i ‚install‘ můžeme konfigurovat pomocí voleb na příkazovém řádku (pro úplnost dodejme, že kompletní seznam všech příkazů získate příkazem ‚python setup.py –help-commands‘). My si zde uvedeme pouze část z nich. První je dvojice voleb –compile a –no-compile, která rozhoduje, zda kompilovat jednotlivé zdrojové .py soubory do .pyc souborů, či ne. Další volba, která souvisí s kompilací do bytecodu, je volba –optimize, která distutils říká, že soubory se mají kompilovat i do optimalizovaného bytecodu (soubory .pyo).

Další důležitá volba je –force nařizující instalačnímu skriptu, aby přepsal všechny existující soubory. Pro správce systémů může být užitečná volba –root určující adresář, který bude považován za kořenový a vzhledem ke kterému se budou všechny soubory instalovat. A ti, kdo nejsou správci systémů, pravděpodobně budou používat volbu –home nařizující instalaci do domovského adresáře uživatele.

Pro tvůrce balíčků ještě jedna důležitá věc, příkazy install a bdist, pokud narazí na skript (viz argument ‚scripts‘ funkce setup()), který začíná magickou sekvencí #!/nějaká/ces­ta/k/Pythonu, automaticky tento řádek upraví na cestu ukazující na interpretr, kterým byl vykonán skript setup.py (a který se tím pádem považuje za funkční :)

bitcoin_skoleni

ZÁVĚR

Dnešní díl o distutils byl vyvrcholením našeho seriálu. Jak možná někdo zkušenější zjistil, tento díl byl opravdu stručný výtah, pokud budete chtít, podívejte se i do dokumentace jazyka Python, kde je těmto modulům věnován daleko větší prostor.

Celý seriál uzavřeme výrokem: „Je jedno, jak daleko jste došli, vždy se můžete vrátit a zkusit to jinudy.“ Toto moudro platí všude a v programování dvojnásob.