\documentclass[12pt,a4paper]{report}
\usepackage[margin=2cm]{geometry}
\usepackage[latin2]{inputenc}
\usepackage{t1enc}
\usepackage[magyar]{babel}
\usepackage[curve,frame]{xy}
\usepackage{latexsym}
\usepackage{moreverb}
\usepackage{multicol}
\usepackage{rotating}
\usepackage{indentfirst}
%\usepackage{pstricks}
\usepackage{multind}
\makeindex{peldak}
\begin{document}
\title{GNU rendszerben fejlesztés}
\author{Dévényi Károly \and Pásztor György}%\thanks{Kösznöm Dévényi Károlynak, hogy a neve alatt futhatott ez a speckoll, valamint Máté András halgatómnak, hogy oly lelkesen elvállalta a \emph{sed}, \emph{awk}ról, \emph{perl}ről és dokumentációkról szóló fejezetek utólagos megírását.}
\date{Utolsó módosítás: \today}
\maketitle
\pagenumbering{roman}
\tableofcontents
\clearpage
\pagenumbering{arabic}
\pagestyle{plain}
\renewcommand{\chaptermark}[1]{}
\chapter{I. félév}
\section{A programozáshoz használt segédeszközök}
\subsection{A programozáshoz használt szövegszerkesztő (VIM) bemutatása, ,,testre-szabása'', stb.}
\subsubsection{Az alap vi bemutatása}
A vi használatában három üzemmód van:
\begin{description}
\item[insert mode]Beszúró üzemmód. Szabadon gépelhetünk szöveget, ez bekerül a dokumentumba
\item[command mode]Különböző parancsokat adhatunk ki (pl. kurzor alatti karakter törlése {\bf x}, sor törlése {\bf dd}, beszúrás {\bf i}, utána-írás/{\sl append} {\bf a}, új-sor kezdés {\bf o})
\item[ed mode]Különböző az ed szövegszerkesztőben megszokott parancsokat adhatunk ki (pl. fájlba írás {\bf :w}, fájl beolvasása {\bf :r{\sl fájlnév}}, helyettesítés {\bf :s})
\end{description}
\begin{figure}[h]
\xy *+\hbox{\sc insert}="i"*\frm{-,},
(45,-10)*+\hbox{\sc command}="c"  *\frm{-,},
(10,-10)*+\hbox{\sl Esc}="a"*\frm{-},
"i";"c" **\crv{"a"} ?>*\dir{>},
(30,0)*+\hbox{{\bf i},{\bf a},{\bf o}}="b"*\frm{-},
"c";"i" **\crv{"b"} ?>*\dir{>},
(15,-40)*+\hbox{\sc ed}="e"*\frm{-,},
(25,-20)*+\hbox{\bf :}="x"*\frm{-},
(45,-30)*+\hbox{{\sl Ent},{\sl Back}}="y"*\frm{-},
"e";"c" **\crv{"y"} ?>*\dir{>},
"c";"e" **\crv{"x"&} ?>*\dir{>}
\endxy
\caption{Váltás a vi módjai közt}
\end{figure}
\subsubsection{A command mód fontosabb parancsai}
\begin{description}
\item[x]Annak a karakternek a kitörlése, amin a kurzor áll
\item[d]Sor, vagy sorok törlése
\item[y]Sor, vagy sorok vágólapra helyezése
\item[p]Vágólap beillesztése a kurzor után
\item[i]Beszúró módba váltás, a kurzor helyére szúr be
\item[a]Beszúró módba váltás, a kurzor utáni helyre kezd beszúrni
\item[o]Beszúró módba váltás, új sort kezd, a kurzor utáni sorban
\item[w]Következő szóra ugrás
\item[c]Szövegrész cseréje
\item[/]Reguláris kifejezés keresése.
\item[?]Reguláris kifejezés keresése a szövegben visszafele haladva.
\item[n]A következő találat megkeresése, az előzőleg már megadott regexp-hez.
\item[h l j k]Balra, Jobbra, Le, Fel mozgás a szövegben. (Általában a kurzorbillentyűk ugyanúgy használhatók)
\item[\~]Megcseréli az aktuális karaktert, ha az kisbetűs volt annak nagybetűs változatára, ill. ha nagybetűs volt, akkor a kisbetűs változatára.
\item[.]Megismétli a legutolsó vi parancsot
\end{description}
Megj.: a p,i,a,o parancsoknak van nagybetűs változata is. A vi ,,gondolkodásmódja'', amikor parancsot adunk ki:\\
{\bf [Multiplikációs szám]}{\sc parancs}{\bf [[Multiplikációs szám] Argumentum ]}\\
Pl. törlés {\sl (d)}, vagy vágólapra másolás {\sl (y)} esetén tudatni kell a vi-jal, hogy ,,mit'' szeretnénk kivágni. Pl. ha szeretnénk a kurzortól kezdődő 14 betűt a vágólapra tenni, akkor a következő billentyűket kell leütnünk: {\bf d14{\sc space}}\\
További példák: \index{peldak}{vi alap példák}\\
\begin{tabular}{ll}
2$\times$5 sor törlése & {\bf 2d5d} \\
5 sor vágólapra tétele & {\bf 5yy} vagy {\bf y5y}\\
14 karakter törlése & {\bf d14\textvisiblespace} vagy {\bf 14d\textvisiblespace} vagy {\bf 14x}\\
5 szó vágólapra tétele & {\bf y5w} vagy {\bf 5yw}\\
2 szó kicserélése a 'broaf' szövegre & {\bf c2wbroaf{\setlength{\fboxsep}{1pt} \fbox{\sc esc}}}
\end{tabular}\\
Megjegyzések:
\begin{itemize}
\item {\setlength{\fboxsep}{1pt} \fbox{\sc esc}}{\sl -re azért van szükség, mert a c parancs is beszúró módba tesz.}
\item A nagybetűs változatok:\\
\begin{tabular}{cll}
 & {\hfill kisbetűs eset \hfill} & {\hfill nagybetűs eset \hfill} \\
i/I & beszúr & sor elejére szúr be \\
o/O & következő sorba kezd új sort & előző sorba kezdi az új sort \\
p/P & utána beilleszt & aktuális pozíciótól kezdve beilleszt \\
a/A & a kurzor után beilleszt & a sor végére illeszt be
\end{tabular}
\end{itemize}
\subsubsection{Az ed mód fontosabb parancsai}
\begin{description}
\item[r]fájl beolvasása. A kurzor utáni sorban kezdve beszúrja a megadott fájl tartalmát.
\item[w]fájl elmentése. Ha fájlnevet is megadunk, akkor a megadott fájlnévbe ment. Ha előtte megadjuk, hogy csak bizonyos sorokra vonatkozzon a parancs, akkor csak azokat a sorokat menti el. Pl. a kurzor sorát, és az utána következő még 4 sort (tehát összesen 5 sort) szeretnénk egy másik fájlba elmenteni, akkor a kiadandó parancs: {\bf :,+4w masikfile.txt}
\item[q]Kilépés. Ha megváltozott a fájl, és nem mentettük azóta, akkor nem lép ki, hanem figyelmeztet.
\item[wq]Elmenti a fájlt, és utána lép ki.
\item[q!]Mindenféleképp kilép.
\item[w!]Ha a fájl írásvédett, akkor is megpróbálja felülírni.
\item[s]csere {\sl (szubsztitúció)}. Reguláris kifejezést adhatunk meg cserére, és a perl-ben megszokott módon lehet kifejezéseket megadni. Részleteket lásd később. Néhány példa:\index{peldak}{vi regexp példák}
\end{description}
\begin{tabular}{ll}
Az aktuális sorban a joe szót cseréljük ki vim-re. & {\bf :s/joe/vim/} \\
Az aktuális sorban az összes joe szót cseréljük ki vim-re. & {\bf :s/joe/vim/g} \\
Az aktuális és köv 2 sorban a sor első joe-ját cseréljük ki vim-re. & {\bf :,+2s/joe/vim/} \\
Az első sortól az utolsó előttiig a sor első joe-ját cseréljük ki vim-re. & {\bf :1,{\textdollar}-1s/joe/vim/}
\end{tabular}
\subsubsection{A VIM-ben megjelent új parancsok}
\begin{description}
\item[V]{\sl Visual Line}: Sorok kijelölésére szolgál, és a megadott parancsot az ily-módon kijelölt sorokra hajtja végre. Pl. Ha nem tudjuk fejből, hogy hány sort szeretnénk a vágólapra tenni, akkor csak kijelöljük őket, és utána y-t ütünk.
\item[$^\wedge$V]{\sl Visual Block}: Hasonló az előzőhöz, de itt nem sorokat, hanem téglalap alakú területeket tudunk a szövegben kijelölni.
\item[<]Kijjebhúzza a kijelölt programblokkot.
\item[>]Beljebhúzza a kijelölt programblokkot.
\end{description}
\subsubsection{A VIM-ben megjelent új ed-szerű parancsok}
\begin{description}
\item[:sp]{\sl Split screen}: Vízszintesen kétfelé osztja a képernyőt, és ha fájlnevet is megadunk, akkor a megadott fájlnevet betölti a képernyő másik felébe.
\item[:vsplit]{\sl Vertical Split screen}: Ugyanaz mint az előző, csak függőlegesen vágja ketté a képernyőt.
\end{description}
A szétosztott képernyők esetén a mozgás a képernyőrészek közt a {\setlength{\fboxsep}{1pt} \fbox{\sc ctrl}}-{\bf w} -vel történik. Figyelem: Ez csak command módban használható!\\
Használata: Ha még egyszer leütjük, akkor ciklikusan a következőre ugrik. Ha megadott irányba akarunk elmozdulni, akkor a már megszokott módon leütjük a {\bf h}, {\bf j}, {\bf k}, {\bf l} billentyűk valamelyikét, vagy a kurzormozgató nyilak valamelyikét. Ha az aktuális képszeletet szeretnénk növelni, akkor a {\bf +}, ill ha csökkenteni szeretnénk akkor a {\bf -} billentyűket kell leütni. Itt is ugyanúgy üthetünk előtte vagy a {\setlength{\fboxsep}{1pt} \fbox{\sc ctrl}}-{\bf w} után számokat, hogy adott számszor hajtsa végre a műveletet (, vagyis ne csak 1 sorral növekedjen/csökkenjen az ablak mérete, hanem pl. 5-el: {\setlength{\fboxsep}{1pt} \fbox{\sc ctrl}}-{\bf w 5+}).
\subsubsection{Makrózás a vim-ben}
A vim a makrókat az angol abc 26 betűjével azonosítja. Ha egy makrót rögzíteni akarunk, akkor üssük le a {\bf q} betűt, majd a makró {\sl nevét}. Az ezután következő vi parancsokat a vim megjegyzi. Ha a makrónkat be akarjuk fejezni, akkor adjuk ki ismét a {\bf q} parancsot. Ha a státuszsor be van kapcsolva, akkor a makró rögzítése közben a státuszsorban a {\sl recording} felirat látható. A makrót tartalmazó vi parancsokat elő akarjuk hívni, akkor a {\bf @} jelet és a makró nevét kell leütni. Ha a makrót egymás után többször akarjuk végrehajtani, akkor a {\bf @} előtt üssük le a számot is, ahányszor végre akarjuk hajtani.
\subsubsection{Néhány hasznos alapbeállítás, .vimrc}
\begin{description}
\item[syntax on] Syntax highlighting bekapcsolása. Automatikusan megpróbálja felismerni a szerkesztett fájl
típusát, és az ehhez tartozó szintaxismodult betölti, és ennek megfelelően ,,színezi a szöveg részeit.
\item[filetype plugin on] Ha felismerte a fájltípust, akkor ennek megfelelően betölt néhány ehhez tartozó alapbeállítást. Pl. C fájlok esetén automatikusan indentel gépelés közben. Gyakorlatban ki kell próbálni, pl. egy {\bf switch} elágazásnál.
\item[set showcmd]A részlegesen begépelt parancsot jelzi a státuszsorban
\item[set showmatch]Ha épp zárójelet lezárunk, akkor egy pillanatra megmutatja a párját
\item[set ignorecase]Keresésnél nem számít a kis és nagybetű különbsége
\item[set incsearch]Inkrementális keresés
\item[set ruler]A státuszsorban, mindig mutatja a kurzor pozícióját, ill. hogy a szövegben hol állunk
\item[set history=50]A vi-ban kiadott parancsok pufferét 50 parancsra visszamenőleg megőrzi
\item[set ts=8 sts=4 sw=2]Indentelésnél 8 space-t cserél ki egy tab-ra {\sl (tab space)}, egy tab leütésre 4 space-t tesz ki {\sl (soft tab space)}, 2 space-el húzza beljebb a szöveget, ahol be kell húzni {\sl (space width)}
\item[set tw=0]Nem töri el a sorokat. Beállítható, hogy hány karakter széles legyen a szöveg {\sl (text width)} szerkesztés közben, és ha szélesebbre nyúlik amit gépeltünk, azt eltöri a megadott szélességnek megfelelően. Pl. ha levelezőből külső editornak használjuk, akkor érdemes egy {\bf :set tw=76} paranccsal kezdeni.
\end{description}
\subsubsection{További vim információk}
A vimről további információkat a \cite{vimtutor} {\bf vimtutor} programból szerezhetünk, valamint a vim-ben van {\sl online} súgó is, ami a {\bf :help} parancsal érhető el. Ha a súgó hivatkozhat más sugó oldalakra is. Ezek {\vrule jelek\vrule} közt vannak. Ha az adott témát akarjuk inkább olvasni, akkor üssük le a {\setlength{\fboxsep}{1pt} \fbox{\sc ctrl}}-{\bf \rbrack} -t. Ha vissza akarunk menni az előző témára, akkor a {\setlength{\fboxsep}{1pt} \fbox{\sc ctrl}}-{\bf t} billentyűkombinációt üssük le. Ha egy adott témát akarunk olvasni, akkor azt elérhetjük közvetlenül a {\bf :help {\sl témanév}} parancsal.
\subsection{A screen bemutatása}
Ide jön a Miham előadásának az anyaga
\subsection{A CVS bemutatása}
\setlength{\columnseprule}{.4pt}
\begin{multicols}{2}
I can't imagine programming without it\dots that would be like parachuting without a parachute!\par
\hfill --Brian Fitzpatrick on CVS
\columnbreak
\par
El sem tudnám képzelni a programozást enélkül\dots Olyan mintha ejtőernyőznék ejtőernyő nélkül!\par
\hfill --Brian Fitzpatrick a CVS-ről
\end{multicols}
\subsubsection{Bevezető}
A cvs arra jó, hogy több ember együtt tudjon dolgozni egy projekten. Ha valaki használt már más hasonló rendszert, akkor ismerős lehet számára a zárol-módosít-elenged filozófia mely szerint, ha vki egy fájlt módosítani akar, akkor előtte zárolja, majd módosítja és a végén a zárolást elengedi. Ez avval jár, hogy miközben zárolva van a fájl, más nem férhet hozzá, stb. Ez a módszer működik ha a fejlesztők személyesen is ismerik egymást, találkoznak személyesen, és minden face-to-face kommunikációt bevetnek stb. Azonban egy projektet általában a világ számos részén levő fejlesztők fejlesztenek. Ezért helyette a CVS-nél a másol-módosít-összefésül modellt használják. Ami az alábbiak szerint működik:
\begin{enumerate}
\item A fejlesztő kér egy működő változatot a CVS-től. Ezt ,,checkout''nak is hívjuk. Képzeljük el úgy mint amikor egy könyvet kiveszünk a könyvtárból.
\item A fejlesztő szabadon szerkeszti a saját működő másolatát. Ugyanebben az időben más fejlesztők dolgoznak a saját működő másolatukkal, lévén ezek mind külön másolatok. Képzeljük úgy el, mintha mindenki kivette volna a könyvtárból ugyanazt a könyvet, és mindenki írogatná bele a saját megjegyzéseit a margóra, vagy akár teljes lapokat újraírna. (Természetesen tekintsünk el attól a ténytől, hogy ez egy könyvtáros szemében könyvrongálás
\begin{sideways}
(-:
\end{sideways}
)
\item A fejlesztő befejezi a változtatásait és beküldi ({\sl commitolja}) egy naplóbejegyzés ({\sl log message}) kíséretében amelyben megmagyarázza a változtatások természetét és céljait. Mintha a könyvtárat tájékoztatnánk a változtatásainkról, és közölnénk, hogy mit és miért változtattunk. Viszont leszúrás helyett a változtatásaink bekerülnének a mesterpéldányba, ahol azok mindörökké meg vannak örökítve.
\item Eközben más fejlesztők megkérdezhetik a CVS-t, hogy lássák, hogy változott-e a mesterpéldány, és ha igen, akkor eszerint frissítse az ő munkapéldányaikat. ({\sl update})
\end{enumerate}
A CVS felfogásában minden a projektben résztvevő fejlesztő egyenlő. Hogy mikor {\sl commit}oljunk és mikor {\sl update}ljünk, az lehet egyéni is, illetve előírhatja a projekt szabályzata. Egy általános stratégia hogy mindig {\sl update}ljünk mielőtt egy nagyobb változtatásba kezdenénk, és akkor {\sl commit}oljunk, amikor a változtatást befejeztük, az használható, és futtatható. Ilymódon a mesterváltozat mindig ,,futtatható'' állapotban marad.\par
Természetesen felmerül a kérdés, hogy mi van, ha {\bf A} és {\bf B} fejlesztők dolgoznak a saját példányaikon, eltérő változtatásokat csinálnak, de a változtatásaik érintenek közös területeket is. Ezt {\sl konfliktusnak} hívják, és a CVS figyelmezteti {\bf B} fejlesztőt, ahogy megpróbálja {\sl commit}olni a változtatásait. Ahelyett, hogy engedné {\bf B}nek hogy folytassa, a CVS bejelenti, hogy konfliktust talált és konfliktusjelzőket (könnyen felismerhető szöveges jelzők) helyez a megfelelő pontokra.\dots Természetesen a konfliktus feloldása a fejlesztőkre vár, a CVS nem tudja kitalálni a helyes megoldást.\par
Tekintsük át részletesen mi történik a mesterpéldánnyal (, vagy ahogy a CVS terminológia hívja {\sl Repository}val). Nézzük az alábbi szituációt:
\begin{enumerate}
\item Két fejlesztő, {\bf A} és {\bf B} {\sl checkout}olják a projekt egy-egy munkaváltozatát ugyanabban az időpontban. A projekt még az elején van, még senki nem komitolt bele így a fájlok még eredeti állapotukban vannak.
\item {\bf A}-ra rájön az alkothatnék, és egy csomót dolgozik a projekten, és utána ezeket {\sl commit}olja.
\item Eközben {\bf B} TV-t néz.
\item {\bf A} továbbra is megihletődött állapotban folytatja a kódolást, és egy újabb adag változást {\sl commit}ol. Így a {\sl Repository} már tartalmazza az eredeti fájlokat, {\bf A} első módosításait, és ezeket a módosításokat is.
\item Eközben {\bf B} armagetronozik.
\item Villámcsapásként az égből {\bf C} is csatlakozik a projekthez, és ő is {\sl checkout}olja a projekt egy munkapéldányát. {\bf C} munkapéldánya már a legutolsó módosítások szerint néz ki.
\item {\bf A}ban még mindig dúl a munkavágy, így egy újabb adag változást {\sl commit}el.
\item Végül {\bf B}nek is megjön az ihlete, és rájön, hogy ideje dolgozni. Nem zavartatja magát avval, hogy {\sl update}lje a munkaváltozatát, egyszerűen csak belepiszkít a fájlokba, esetleg olyanokba is, amiket A is módosított. Ezután {\bf B} {\sl commit}eli a változtatásait.
\end{enumerate}
Ennél az utolsó pontnál több dolog is történhet. Ha {\bf B} semmi olyan fájlon nem változtatott, amin {\bf A} is, akkor a {\sl commit} sikerülni fog. Egyébként a CVS észreveszi, hogy {\bf B} munkaváltozatában némelyik fájlja már idejétmúlt ({\bf outdated}), és hivatkozva a repository utolsó állapotára figyelmezteti {\bf B}-t, hogy {\sl update}lnie kell mielőtt {\sl commit}olna.\par
Amikor {\bf B} {\sl update}l, a CVS beolvasztja ({\sl merge}li) {\bf A} összes változtatását {\bf B} másolataiba. Esetleg ezek közül némelyik ütközhet {\bf B} még nem {\sl commit}olt változtatásával. Ekkor ezeket {\bf B}-nek fel kell oldania, mielőtt commitel.\par
Ha most {\bf C} {\sl update}l, akkor számos új változtatást fog kapni a {\sl repozitórium}ból: {\bf A} harmadik {\sl commit}jának eredményét, és {\bf B} első {\scshape \bfseries sikeres} változtatásainak eredményét.\par
A CVS rendszerint változtatásokat szolgál ki, a megfelelő sorrendben. A fejlesztők munkaváltozatainak elavultságától függő mennyiségben küld változtatni-valókat a szinkronizálásokhoz. Ennélfogva a {\sl repozitóriumnak} tárolnia kell a projekt legeleje óta történt összes változást egyenként. A CVS ezeket növekvő {\sl diff}ekként tárolja. Ennélfogva képes, egy akármilyen régi munkaváltozathoz képes előállítani, hogy mi a különbség a jelenlegihez képest, és hatékonyan naprakésszé tenni a munkaváltozatot. Ez a fejlesztők számára lehetővé teszi azt és, hogy a régebbi munkaváltozatokat is áttekintsék, illetve megtudják a különbséget bármely két változtatás közt. (Ami hasznos lehet például, ha valamikor bekerült a {\sl repozitóriumba} egy hiba, és ki tudják deríteni, hogy az melyik változtatásnál, és mivel kerülhetett be, stb.) \par
\subsubsection{Néhány tesztfeladat:}
\begin{itemize}
\item Elkezdeni egy projektet, és a forrását {\sl import}álni a cvs-be.
\item Minden a projekthez tartozó személy {\sl checkout}oljon egy {\sl munkapéldány}t a {\sl repozitórium}ból.
\item Dolgozzanak a fejlesztők, majd {\sl commit}eljenek, updateljenek.
\item Vegyenek fel a fejlesztők új fájlt a cvs-be, ill. távolítsanak el onnan már nem szükségeset.
\item Nézzék meg két adott verzió közt a különbséget.
\end{itemize}
\par
\vfill
A használt kifejezések:
\begin{description}
\item[Revision]Egy kommitelt változás egy fájl vagy egy rakat fájl történetében. A revízió egy ,,pillanatkép'' egy állandóan változó projektről.
\item[Repository]A mester másolat ahol a CVS a projekt teljes Revíziótörténetet tárolja. Minden projektnek pontosan egy Repozitóriuma van.
\item[Working copy]Egy másolat amin éppen változásokat végzünk a projekt érdekében. Rengeteg {\bfseries \slshape munkapéldány} lehet egy adott projektről; általában minden fejlesztőnek megvan a sajátja.
\item[Check out]Egy munkapéldány igénylése a repozitóriumból.
\item[Commit]Elküldeni a munkapéldány változtatásait a központi reporzitóriumba. ({\sl check-in} néven is ismert.)
\item[Log message]Egy magyarázat egy revízióhoz amikor kommitelsz, leírva a változásokat.
\item[Update]Kiszedni a változásokat a repozitóriumból, és a munkapéldányban alkalmazni.
\item[Conflict]Az a szituáció, amikor két fejlesztő megpróbál változásokat kommitolni ugyanazon fájl, ugyanazon területén. A CVS észreveszi a konfliktust, megjegyzi, rámutat, és a fejlesztőknek kell megoldaniuk.
\end{description}
\clearpage
\section{A GNU fejlesztő eszközök I. rész. Compiler, optimalizációk használata, speciális módokon való programfordítás, stb.}
\subsection{Bevezető}
A {\bf C/C++} programok lefordításához a legelterjedtebb fordító a GNU projekt egyik legfontosabb programja a gcc, ami a {\bf GNU Compiler Collection} rövidítése. A {\sl Compiler Collection} név jogos, hiszen nem csak C hanem C++, illetve Fortran forráskódot is le tud fordítani, sőt a 3.x verziók már a {\sl JAVA} forrásokat is le tudják fordítani, ill. {\bf java byte kód}ot is képesek előállítani.\par
A GNU programozási eszköztára lehetőséget biztosít továbbá arra, hogy a kódot futási idő, vagy a futtatható kód mérete szempontjából optimalizáljuk. Lehetőség van más architektúrákon ill. más platformokon futó program fordítására. A célkódot ui. ez a kettő együtt határozza meg. Az ilyen előre elkészített keresztfordítót általában ennek megfelelően konvencionálisan a következő módon nevezik el: {\bf arch}-{\bf host}-{\bf programnév}. {\sl (Megj.: A {\bf gcc} parancs a {\bf g++}-tól mindössze annyiban tér el, hogy a gcc C forráskódnak tekinti az inputját, ill C stílusú linkelést csinál rajta, míg a {\bf g++} C++-nak tételezi fel a forrást, és C++ stílusú linkelést hajt rajta végre.)} Példák:\index{peldak}{parancsnév példák}\par
\begin{tabular}{llll}
Architektúra & OS & Funkció & parancsnév \\
Intel 80x86 (x>3) & Linux & C Compiler & i386-linux-gcc \\
Intel 80x86 (x>5) & Win32 & Assembler & i586-mingw32msvc-as \\
Intel 80x86 (x>3) & GNU/Hurd & Linker & i386-gnu-ld \\
Intel 80x86 (x>3) & Linux($\mu$Clibc) & Preprocesszor & i386-uclibc-cpp
\end{tabular}
\\\\
Lásd még:
\begin{verbatim}$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-linux/2.95.4/specs
gcc version 2.95.4 20011002 (Debian prerelease)
\end{verbatim}
\begin{figure}
\xy *+\txt{Forráskód\\{\bf .c}\\{\bf .C .cc .cxx}\\{\bf .m}}="c" *\frm<8pt>{-},
(0,-20)*+\txt{Fejléc fájlok\\{\bf .h}}="h"  *\frm<8pt>{-},
(50,-10)*+\txt{Preprocesszor}="p" *\frm{-,},
"c";"p" **\crvs{-} ?>*\dir{>},
"h";"p" **\crvs{-} ?>*\dir{>},
(100,-10)*+\txt{Előfeldolgozott fájlok\\{\bf .i .I}}="i" *\frm{--},
"p";"i" **\crvs{-} ?>*\dir{>},
(100,-30)*+\txt{Fordító\\{\sl (compiler)}}="k" *\frm{-,},
"i";"k" **\crvs{-} ?>*\dir{>},
(50,-30)*+\txt{Assembly forrás\\{\bf .s .S}}="s"*\frm{--},
"k";"s" **\crvs{-} ?>*\dir{>},
(50,-45)*+\txt{Asszembler}="a"*\frm{-,},
"s";"a" **\crvs{-} ?>*\dir{>},
(10,-60)*+\txt{Tárgykódú fájl\\{\bf .o}}="o"*\frm<8pt>{-},
"a";"o" **\crvs{-} ?>*\dir{>},
(90,-60)*+\txt{Osztott könyvtár\\{\sl (shared object)}\\{\bf .so}}="d"*\frm<8pt>{-},
"a";"d" **\crvs{-} ?>*\dir{>},
(50,-60)*+\txt{Archív tárgykód\\/könyvtár\\{\bf .a}}="r"*\frm<8pt>{-},
(50,-80)*+\txt{Szerkesztő\\{\sl (linker)}}="l"*\frm{-,},
(90,-90)*+\txt{Futtatható fájl \\{\sl a.out}\\{\sl COFF}\\{\sl ELF}}="e"*\frm{=},
"o";"l" **\crvs{-} ?>*\dir{>},
"o";"l" **\crvs{-} ?>*\dir{>},
"d";"l" **\crvs{=} ?>*\dir{>},
"l";"d" **\crv{(70,-75)} ?>*\dir{>},
"l";"e" **\crvs{-} ?>*\dir{>},
"r";"l" **\crvs{=} ?>*\dir{>},
"l";"r" **\crv{(40,-70)} ?>*\dir{>},
"d";"e" **\crvs{=} ?>*\dir{>}
\endxy
\caption{A forrástól a futásig}
\end{figure}
\par
A kezdetek: melyik programozási nyelvet használjuk? Noss a legjobb választás a C nyelv, mert a szinte minden architektúrán le lehet fordítani, és jól optimalizálható. Ezzel szemben, ha más nyelvet használunk, akkor azt általában azért tesszük, mert szükségünk van egy nem szabványos lehetőségére. Ebből kifolyólag esetleg kevesebben értik meg a program forráskódját, ill. a felhasználónak külön fordítót kell még telepítenie, és egyéb galibákkal járhat\dots Ennek ellenére előfordulhatnak olyan kivételek, amikor mégis inkább más nyelvet célszerű használni, pl. ha a program célközönségénél már várhatóan megvan az adott nyelvhez szükséges fordító. A legtöbb programot továbbfejleszthetőnek írnak meg: Tartalmaznak egy a C-nél magasabb szintű értelmezőt, és magát a programot is ezen a nyelven írják meg. Ennek egy példája az Emacs szövegszerkesző, ami élenjár ebben a technikában.\\A szabványos kiterjeszthető interpreter a GNU rendszerekben a {\sc guile}, ami a {\bf scheme} (egy speciális, lisp változat) nyelv megvalósítása. Természetesen az egyéb scriptnyelveken is elfogadott egy GNU projekt, mint pl. a perl, vagy a python. A GUILE a teljes GNU rendszer konzisztenciájának megtartása miatt fontos.{\sl (Ennek ,,ellenére'' én is a perl nyelv alapjait fogom a későbbiekben ismertetni.)}
\par
\subsection{Kompatibilitás más C fordítókkal}
\subsubsection{Posix,Ansi,Standard C kompatibilitás és a GNU kiterjesztései}
Néhány kivételtől eltekintve a GNU fordítója, a hozzátartozó programok, és könyvtárak{\sl (libraryk)} felülről kompatibilisek a megfelelő Berkeley Unix-ban levővel, és felülről kompatibilis a Standard C-vel, amennyiben az definiálja az adott viselkedést, és felülről kompatibilis a {\sc posix}-al, amennyiben az definiálja az adott viselkedést.\par
Amikor ezek a szabványok netán ütköznek cészerű lehet felkínálni annak a lehetőségét, hogy valamelyiket betartsa a programunk, és a gcc által adott kiterjesztéseket békén hagyni. Ilyenkor a fordításnál használhatjuk a {\bf {-}-ansi}, {\bf {-}-compatible} valamint a {\bf {-}-posix} kapcsolókat.\\
A {\bf gcc} egy {\sc ansi} kompájler, ennek ellenére sok program lehet, ami nem ilyen. Ebben az esetben lehet használni a {\bf -traditional} opciót, azonban ennek van mellékhatása is, ugyanis a -fwriteable-strings opciót automatikusan bekapcsolja, aminek hatására a szövegkonstansok a {\sc text} szegmensből a {\sc data} szegmensbe átkerülnek, és így a program futása során felülírhatók lesznek.\par
Ha használjuk a GNU kiterjesztéseit, akkor esetleg átláthatóbb tisztább lesz a program, de lehet hogy nem fordul le egy nem GNU rendszeren. Bizonyos kiterjesztéseknél egyszerűen megtehető, hogy alternatívákat kínáljunk. Pl. Ha egy függvény egy inline-ként van definiálva, akkor megtehetjük, hogy az {\sc inline} kulcsszót használjuk, amit a fordító inline-ra behelyettesít ha ismeri az inline-t, egyébként pedig semmit se tesz a helyére.\\
Ha sokat javít a program futásán, akkor mindenféleképp érdemes használni a {\sc gnu} kiterjesztéseit. Ez alól kivételt képeznek a nagy és elterjedt programok (mint pl. az {\sc emacs}), amik rengeteg fajta rendszeren elérhetőek. Az ilyen kiterjesztések használata a program használóit ,,boldogtalanná'' teheti, úgyhogy ebben az esetben ellenjavalt.\par
\subsubsection{Feltételes fordítás}
Ha egy programban egy ilyen részt használunk:
\begin{verbatimtab}
#ifdef VAN_IZÉ
	csinálok_valamit(valamivel);
#else
	mást_csinálok(mással);
#endif
\end{verbatimtab}
akkor helyette javasolt a következőt használni:
\begin{verbatimtab}
if(VAN_IZÉ)
	csinálok_valamit(valamivel);
else
	mást_csinálok(mással);
\end{verbatimtab}
Ugyanis a mai fordítók már annyira modernek, hogy mindkét esetben ugyanazt a kódot generálják. Ha olyan esetbe ütközünk, ahol az állítást nem lehetne egyszerűen egy {\rm if(...)} utasításba ágyazni, mint pl. a\begin{verbatim}
HAS_REVERSIBLE_CC_MODE
\end{verbatim}
, akkor a következő {\sl workaround} használatos:
\begin{verbatim}
#ifdef REVERSIBLE_CC_MODE
#define HAS_REVERSIBLE_CC_MODE 1
#else
#define HAS_REVERSIBLE_CC_MODE 0
#endif
\end{verbatim}
\subsubsection{Sig11}
Ha egy ilyen képpel találjuk magunkat szembe:
\begin{verbatim}
Internal compiler error: cc1 got fatal signal 11
\end{verbatim}
Akkor ennek egyik oka lehet az, hogy a gcc egy nagyon bonyolult, és sokat tudó fordító, és valamit elhibáztak benne, és a gcc megpróbál egy olyan memóriaterületre írni, ahova egyébként nem lenne neki szabad. Tehát, akár az is lehet, hogy egy gcc hibába futottunk.\par
De általában a valószinűbb magyarázat (főleg, ha egy jól tesztelt stabil gcc verziót használunk), hogy a hardver a hibás. Röviden szólva a gcc az egyik legjobb {\sc ram} tesztelő program. Ha a gcc egy ilyet mond, akkor lehet még hibás a {\sc cpu}, az alaplap, vagy valamilyen cache is a {\sc ram}-on kívül.
\subsubsection{sprintf()}
Ha valaki már SunOS-on programozott, és használta rajta a sprintf() függvényt, tapasztalhatta, hogy a visszatérési értéke a string-re matató pointer. Linux rendszereken pedig (az ANSI-t követve) egy egész a visszatérési értéke, ami azt adja meg, hogy hány karaktert tett a string-be.
\subsubsection{include fájlok}
Általában, hogy milyen fájlokat kell \verb+#include+-al beilleszteni a függvények manualjaiban {\sl (2-es, 3-as szekció)} a {\sc synopsys} részben le van írva. Pl.:
\begin{verbatimtab}
SYNOPSIS
	#include <stdio.h>

	FILE *fopen (const char *path, const char *mode);
	FILE *fdopen (int fildes, const char *mode);
\end{verbatimtab}
Azonban nagyon oda kell figyelni, mert más rendszereken esetleg eltérő lehet, hogy milyen include fájlokra van szükség, ill. akár a hozzálinkelendő könyvtárakban is lehet eltérés. Pl. socket programozásnál ha egy Solaris-on dolgozunk gyakran szükség lehet az nsl könyvtár hozzászerkesztésére ({\bf -lnsl}), míg a {\sc gnu} C library tartalmazza a socketprogramozáshoz szükséges függvényeket.
\subsubsection{select(), és busy waiting}
A {\sc bsd} {\bf select(2)} manual oldala azt írja, hogy a függvényhívás mellékhatásként módosíthatj a tv ({\sc timeval}) értékét, és beírja a még hátralevő időt helyette. Illetve, hogy a későbbi verziók így fogják csinálni. Bizonyos Linux verziók már így tesznek. Bizonyos verziók nem. Így nem célszerű feltételezni, hogy a függvényhívás nem változtatja meg az értéket. Tehát a javaslat, ha így nézne ki eredetileg a kód:
\begin{verbatimtab}
	struct timeval timeout;
	timeout.tv_sec = 1; timeout.tv_usec = 0;
	while (some_condition)
		select(n,readfds,writefds,exceptfds,&timeout); 
\end{verbatimtab}
Azt cseréljük le, hogy így nézzen ki:
\begin{verbatimtab}
	struct timeval timeout;
	while (some_condition) {
		timeout.tv_sec = 1; timeout.tv_usec = 0;
		select(n,readfds,writefds,exceptfds,&timeout);
	}
\end{verbatimtab}
\subsection{Optimalizáció}
\begin{description}
\item[-Ox]A gcc meghívható a {\rm -Ox} paraméterrel, ahol x egy kis egész szám. A 0 semilyen optimalizációt sem jelent, míg a {\rm -O2} más sok, és a {\rm -O3} már nagyon sok optimalizációt. Belsőleg a gcc ezeket az opciókat {\rm -f} és {\rm -m} opciókra cseréli le. Ha nagyobb számot adunk meg, mint amekkorát a fordítónk tud, (pl. {\rm -O6}) akkor a normális működés szerint a lehető legnagyobbat használja. Ennek ellenére nem javasolt nagyobb számot használni a programunk terjesztéseiben, mert lehet, hogy később a fordítóba egy nagyobb optimalizációs lehetőség is bekerül, amivel lefordítva a kódunkat az már működésképtelenné válhat. (Konkrétan a 2.7.0 tól a 2.7.2-ig a {\rm -O2} hibásan működött.)
\item[-m486]Ha így fordítunk le egy programot, akkor az nagyobb lesz, de ennek ellenére 386-on is fut. Természetesen a 486-on pedig még gyorsabban, mert a fordításnál a 486-os processzor architektúráját figyelembe veszi. Ha még optimálisabb kódot szeretnénk, akkor érdemes esetleg speciálisan erre kihegyezett programot használni. Pl. a debian-ban adott a {\bf pentium-builder} nevű csomag, ami megfelelő környezeti változók megfelelő értékei esetén pentium-ra optimalizált kódot fordítanak.
\end{description}
\subsection{PIC}
Lásd a következő óra ide vonatkozó részét :-)
\subsection{Debug és profiling}
\subsubsection{debug infók fordítása}
Ha úgy szeretnénk lefordítani a programot, hogy a debughoz szükséges infók is belekerüljenek, akkor a {\bf -g} kapcsolót kell használnunk a fordítás során. Természetesen emiatt nem kell újrafordítanunk az egész programunkat, elég csak a debugolni kivánt részeket így fordítani.\par
Ha külön fázisban fordítjuk és szerkesztjük({\sl linkeljük}) a programot, akkor a linkernek se felejtsük el megadni a {\bf -g} kapcsolót, ahol szükség van rá. A {\sc gnu} {\bf ld}-ben már csak kompatibilitási okokból van benne.
\subsubsection{A debugra használható programok}
\begin{description}
\item[gdb]A {\sc gnu} debuggere. Egyszerű kis command line-szerű debugger. Van grafikus változata isxxgdb néven.
\item[ddd]Ez már grafikus felületen működő debugger, jóval egyszerűbb használni mint a gdb-t. ,,Kezdőknek'' javasolt.
\item[strace]Ez nem kifejezetten debugger program. Ezzel a programmal elindítva egy másikat, az strace figyeli, hogy milyen rendszerhívásokat hajt végre a program, és ezeket paraméterestül, gyerekprocesszestül, mindenestül képes listázni, akár pid-enként külön fájlokba. Másik nagy előnye, hogy semilyen extra fordítási opciót nem igényel a program fordítása során, így bármely programmal szemben használható általános hibakereső eszköz.
\end{description}
\subsubsection{profiling}
A profiling arra szolgál, hogy felderítsük, hogy a programunk, mely részére hányszor kerül a vezérlés. Ha ilyet szeretnénk tenni, akkor a programot a {\bf -p} paraméterrel kell fordítani, majd lefuttatni, ekkor készül gmon.out néven egy ,,profil'' a programól, és utána a {\bf gprof} nevű programmal lehet elemezni, hogy a program mely részén mennyi időt töltött a vezérlés, valamint, hogy hányszor került rá a vezérlés.\par
Hasonló célú eszköz a gcov is. Példa:\index{peldak}{profiling példa}
\begin{verbatim}
$ cat <<END >pelda.c
#include<stdio.h>

int main () {
  int i;
  for(i=0;i<10;i++) {
    printf("%d\n",i);
  }
  printf("A program befejezte működését\n");
}
$ gcc -fprofile-arcs -ftest-coverage pelda.c
$ ./a.out
0
1
2
3
4
5
6
7
8
9
A program befejezte működését
$ gcov pelda.c
100.00% of 6 source lines executed in file pelda.c
Creating pelda.c.gcov.
$ cat pelda.c.gcov
		#include<stdio.h>
		
		int main () {
           1      int i;
          11      for(i=0;i<10;i++) {
          10        printf("%d\n",i);
          10      }
           1      printf("A program befejezte működését\n");
           1    }

$
\end{verbatim}
\clearpage
\section{A GNU fejlesztő eszközök II. rész. Linker, linkelés, osztott könyvtár készítés}
\subsection{In medias res példa}
Következzen egy egyszerű kis program, ami az osztott könyvtárak készítését szemlélteti:\index{peldak}{Library egyszerű (duplázós) példa}
\begin{verbatimtab}
$ cat >proba.h <<'END'
#ifndef __PROBA_H
#define __PROBA_H

extern int duplaz (int x);

#endif /* __PROBA_H */
END
$ cat >proba.c <<'END'
#include<proba.h>

int duplaz (int x) {
  return x*2;
}
END
$ cat >test.c <<'END'
#include<stdio.h>
#include<proba.h>

int main () {
  int x;
  x=duplaz(5);
  printf("%d\n",x);
  exit(0);
}
END
$ cat >test2.c <<'END'
#include <dlfcn.h>
#include <stdio.h>

int main()
{
  void *proba;
  int (* duplaz)(int x);

  if(proba=dlopen("libproba.so",RTLD_LAZY))
  {
    duplaz=dlsym(proba,"duplaz");
    printf("%d\n",(*duplaz)(5));
  }
  return 0;
}
END
$ cat >Makefile <<'END'
LIBS= libproba.a
SHARED= libproba.so
OBJS= proba.o
CFLAGS= -I.
LDFLAGS= -L.
TARGETS= test tests testsp test2

all: $(TARGETS)

libproba.a: $(OBJS)
	$(AR) rvs $@ $^

libproba.so: $(OBJS)
	$(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ $^

test: test.c proba.h $(SHARED) $(LIBS)
	$(CC) $(CFLAGS) $(LDFLAGS) -lproba -o $@ $<

test2: test2.c $(SHARED) $(LIBS)
	$(CC) $(CFLAGS) $(LDFLAGS) -ldl -o $@ $<

.PHONY: runtest
runtest: test $(SHARED)
	LD_LIBRARY_PATH=$(PWD) $(PWD)/test

.PHONY: runtest2
runtest2: test2 $(SHARED)
	LD_LIBRARY_PATH=$(PWD) $(PWD)/test2

tests: test.c proba.h $(LIBS)
	$(CC) -static $(CFLAGS) $(LDFLAGS) $< -o $@ -lproba

testsp: test.c proba.h $(LIBS)
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< -Wl,-dn -lproba -Wl,-dy

.PHONY: runtests
runtests: tests
	-$(PWD)/tests

clean:
	-$(RM) $(LIBS) $(SHARED) $(OBJS) $(TARGETS)
END
$ make
cc -I.   -c -o proba.o proba.c
cc -shared -I. -L. -o libproba.so proba.o
ar rvs libproba.a proba.o
a - proba.o
cc -I. -L. -lproba -o test test.c
cc -static -I. -L. test.c -o tests -lproba
cc -I. -L. -o testsp test.c -Wl,-dn -lproba -Wl,-dy
$ make runtests
/home/pasztor/gnu/tests
10
$ make runtest
LD_LIBRARY_PATH=/home/pasztor/gnu /home/pasztor/gnu/test
10
$ ls -l test testsp
-rwxr-xr-x    1 pasztor  pasztor      5261 sze 29 15:49 test
-rwxr-xr-x    1 pasztor  pasztor      5101 sze 29 15:48 testsp
$
\end{verbatimtab}
A fenti példa egyben mutatja azt is, hogy hogyan futtassuk a programot, valamint, hogy milyen eredményt kellene kapnunk. Mellesleg elég leegyszerűsített példa is. Normál esetben ui. vhogy így kell eljárnunk egy {\bf .so} készítésénél:
\begin{verbatim}
$ gcc -fPIC -c *.c
$ gcc -shared -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0 *.o
$ ln -s libfoo.so.1.0 libfoo.so.1
$ ln -s libfoo.so.1 libfoo.so
$ LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH ; export LD_LIBRARY_PATH
\end{verbatim}
Noss, akkor vegyük sorba a ,,gyakorlati'' hibákat:
\begin{itemize}
\item A linkernek nem lett átadva soname opció. ({\bf -Wl,-soname,libfoo.so.1})
\item Egyáltalán nincs semilyen verziókezelés.
\item A ,,szokásos'' módon nem lett létrehozva a symlink a {\bf .so} fájlra.
\end{itemize}
\subsection{{\bf .so}-k verziószámozása}
A {\bf .so} fájlok általában a {\bf lib}{\sl <könyvtárnév>}{\bf .so.}{\sl <major/fő verziószám>}{\bf .}{\sl <minor/mellék verziószám>} módon vannak elnevezve. Minden osztott könyvtárhoz tartozik egy {\sl soname}, ami egy szimbolikus név, és nem maga a fájlnév. De facto szabvánnyá vált, hogy ha egy könyvtár neve {\bf libproba.so.1.2}, akkor a hozzátartozó {\sl soname} {\bf libproba.so.1}. A {\sl soname}-ra fog hivatkozni a lefordított program, így amikor a program indul, azon a néven fogja keresni a könyvtárt, amit a fordításkor a {\sl soname}-ből kiolvasott. Ezért is szokás az {\bf ln -s libproba.so.1.2 libproba.so.1} parancsal szimlinket létrehozni, mert ha pl. vmi. apró módosítást, hibajavítást végzünk a könyvtáron, akkor a {\sl minor/mellék}verziószámot növeljük, és a szimlinket kicseréljük az újra, és a programok képesek az újat használni, újrafordítás nélkül.\par
Az {\bf ln -s libproba.so.1 libproba.so} parnacsra azért van szükség, hogy amikor a {\sc gcc}-t a {\bf -lproba} paraméterrel meghívjuk, egy a proba könyvtárunkat használó program fordításakor, akkor a {\sc gcc} {\bf libproba.so} néven fogja keresni a könyvtárat (, és ebből ki fogja olvasni a {\sl soname} szimbolikus információt).
\par
Megjegyzések:
\begin{itemize}
\item A {\bf -Wl,}-vel kezdődő gcc paraméterek a linkernek ({\sc ld}) adódnak át. A fenti esetben pl. a soname-t kell így átadnunk.
\item A {\sc gcc}-nek a {\bf -fPIC} paramétert át kell adni, ha könyvtárhoz fordítunk forrásokat. PIC=Pozíció Független(Indipendent) Kód(Code)
\item A verziók számozásában még ,,mélyebbre'' is lehet menni. Pl. a {\sc gnu} libc-nél egy példaverziószám: 2.2.5, {\bf /lib/libc-2.2.5.so}, {\bf /lib/libc.so.6}, {\bf /usr/lib/libc.so}
\item Hasonlóan a {\sl soname}-hez az archív nevét is meg lehet adni szimbolikusan a .so fájlban. Ti. ha linkelni szeretnénk egy .so-hoz, akkor meg kell, hogy legyen a .a is.
\end{itemize}
\par
Gyakorlati feladatok:
\begin{itemize}
\item A fenti Makefile megfelelő módosítása.
\item Több különböző ,,funkció'' írása, ennek megfelelően a header fájl módosítása, más forrás beépítése, a Makefile hozzáigazítása, stb. {\bf ar}, {\bf ranlib} tanulmányozása.
\end{itemize}
\subsection{nm}
Ha kíváncsiak vagyunk, hogy egy függvény, melyik modulban van megvalósítva, ill. hol hivatkoznak rá, akkor az {\bf nm} nevű paranccsal ki tudjuk listázni a benne levő szimbólumokat. Pl. {\bf nm /usr/lib/libc.a}
Gyakorlati feladatok:
\begin{itemize}
\item Kikeresni a libc-ben, hogy lehet a verziószámot kideríteni
\item Programot írni, ami a libc verziószámát kiírja
\item Kikeresni néhány függvény a libc-ben, pl. fopen melyik modulban van.
\end{itemize}
\subsection{ldd}
Ha szeretnénk egy lefordított programról megtudni, hogy milyen könyvtárakhoz van hozzászerkesztve, akkor az {\bf ldd} parancs jöhet a segítségünkre.\\
Példa:\index{peldak}{Library függőségek kiderítésére (ldd) példa}
\begin{verbatim}
$ ldd test
        libproba.so => not found
        libc.so.6 => /lib/libc.so.6 (0x40018000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
$ LD_LIBRARY_PATH=. ldd test
        libproba.so => ./libproba.so (0x40014000)
        libc.so.6 => /lib/libc.so.6 (0x4001a000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
$
\end{verbatim}
\clearpage
\section{A GNU fejlesztő eszközök III. rész. {\ttfamily make}, {\ttfamily Makefile}, stb.}
\subsection{Bevezető}
A make parancs segít a programunk lefordításában. Egy nagyobb projekt sok modulból állhat, esetleg más modulokat, más paraméterekkel kell fordítani, stb. Ezen munkát megkönyítendő segít a make. A program elkészítésének ,,receptjét'' a \verb+Makefile+\footnote{A pontosság kedvéért: A make először {\tt GNUMakefile}, majd {\tt makefile} és legvégül {\tt Makefile} nevű fájlt keres. Ennek ellenére {\tt Makefile}-nak javasolt elnevezni a ,,receptet'', ti. a {\tt GNUMakefile}-t specifikusan csak a {\sc GNU} Make keresi, a {\tt Makefile} pedig a könyvtárlistázás elején fog megjelenni a fontosabb fájlokkal, mint pl. {\tt README}, {\tt INSTALL}, stb. együtt. Ha a make nem talál ezek közül egyet sem, akkor csak az implicit szabályok$_{\pageref{implicit make szabalyok}}$ lesznek elérhetők.} nevű fájl tartalmazza, és a fordítás a make parancsal történik.\par
\subsection{A make alapfogalma: target}
A make parancsnak meg kell mondani, hogy ,,mit'' csináljon. Ez a target. Hogy hogy csinálja az a {\sl makefile-ban van leírva}. Az alapértelmezett target a makefile-ban definiált első target. Általában programoknál első helyre tesznek egy {\bf all} nevű targetet, ami minden programrészletet lefordít, elkészít, stb. Gyakorlatilag végső állapotba hozza a programot. Szokás még egy {\bf install} nevű target írása is, ami a program telepítését végzi el, illetve egy {\bf clean} nevű target írása, ami a program fordítása közben keletkezett ,,mellékterméket'' eltávolítja.\par
Íme egy egyszerű példa:\index{peldak}{Makefile példa} \label{egyszeru pelda}
\begin{verbatimtab}
CFLAGS = -O2 -Wall
INSTALLPREFIX = /usr/local
INSTALLDIR = $(INSTALLPREFIX)/bin
INSTALL = install -s -p -m 0555
BINARIES = prog1 prog2
SOURCES = prog1.c prog2.c prog.c
HEADERS = prog.h
#Ez egy egyszerű Makefile 3 db forráskód,
#                         1 közös headerfájl,
#                      és 2 célprogrammal.

all: $(BINARIES)

prog1: prog1.o prog.o

prog2: prog2.o prog.o

prog1.o: prog1.c prog.h

prog2.o: prog2.c prog.h

prog.o: prog.c prog.h

.PHONY: install
install:
	$(INSTALL) $(BINARIES) $(INSTALLDIR)

.PHONY: clean
clean:
	-$(RM) -f *.o
\end{verbatimtab}
\begin{multicols}{2}
Egy példa prog1.c
\begin{verbatim}
#include<stdio.h>
#include"prog.h"

int main () {
  init();
  printf("%d\n",szam);
  return 0;
}
\end{verbatim}
\columnbreak
Egy példa prog2.c
\begin{verbatim}
#include<stdio.h>
#include"prog.h"

int main () {
  init();
  printf("%d\n",szam*2);
  return 0;
}
\end{verbatim}
\end{multicols}
\hrulefill
\begin{multicols}{2}
Egy példa prog.c
\begin{verbatim}
#include"prog.h"

int szam;

void init () {
  szam=5;
}
\end{verbatim}
\columnbreak
Egy példa prog.h
\begin{verbatim}
#ifndef __PROG_H
#define __PROG_H

extern void init ();
extern int szam;

#endif /*__PROG_H*/
\end{verbatim}
\end{multicols}

Egy szabály leírása a következőképp néz ki:
\begin{verbatimtab}
targetnév: függőségek
	parancs
	...
\end{verbatimtab}
vagy
\begin{verbatimtab}
targetnév: függőségek ; parancs
	parancs
	...
\end{verbatimtab}
A legegyszerűbb target, ahol a targetnél azt szeretnénk, hogy semilyen parancs ne hajtódjon végre: \fbox{\tt semmi: ;} Itt nagyon fontos, hogy a \verb+;+-t kitegyük. Hasznos lehet egy ilyen targetet pl. defaultnak betenni, ha azt szeretnénk, hogy egy egyszerű, a könyvtárban kiadott \verb+make+ parancs ne csináljon semmit.\par
Függőségeknél fájlneveket sorolhatunk fel. Nagyon fontos, hogy a rendszer a fájlok utolsó modosítási dátumát jól kezelje. Ti. a következőképp dolgozik a make:
\begin{enumerate}
\item Megnézi a függőségek legutolsó módosítási dátumát
\item Megnézi a célfájlt, hogy létezik-e, és hogy annak mi a módosítási dátuma
\item Ha a függőségek közt vmelyik fájl újabb, mint a target, akkor a targetet (újra) el kell készíteni.
\item Ha a targetet (újra) el kell készíteni, akkor a megadott parancsok szerint elkészíti.
\end{enumerate}
\par
\subsection{Speciális targetek}
\subsubsection{A .PHONY target}
Vannak speciális célok, amelyek nem egy fájlt hoznak létre, hanem valamilyen feladatot látnak el, pl. feltelepítik a programot, vagy a munkafájlokat törlik; mint a clean és az install targetek. Ezek \verb+.PHONY+ targetek.\par
A \verb+.PHONY+ targetként megjelölt targeteknél az előbb megadott lépéseknél az 1-3.-t mindíg kihagyja, és mindíg újra elkészíti a targetet a megadott parancsoknak megfelelően, még akkor is, ha pl. a clean-nek nincs függősége, és clean nevű fájl már létezik akármilyen dátummal.\par
Ha egy targetet \verb+.PHONY+ targetként szeretnénk definiálni, akkor azt megelőzve kezdjünk egy \verb+.PHONY+ nevű targetet és írjuk be a targetünket a \verb+.PHONY+ target függőségeként.
\subsubsection{Az üres target jelentősége}
Az üres targetek hasonlítanak picit a \verb+.PHONY+ targetekre. Itt általában nem számít a fájl tartalma, csak az utolsó hozzáférés dátuma. (Figyelem, itt már megnézi a make a fájlt) Pl. ha rendszeresen ki szeretnénk néhány megváltozott forráskódot nyomatani, akkor használhatjuk a köv. targetdefiníciót:
\begin{verbatimtab}
print: prog1.c prog2.c prog.c prog.h
	lpr -p $?
	touch print
\end{verbatimtab}
Itt lesz egy print nevű fájlunk, aminél az utolsó módosítási dátum azt jelzi, hogy mikor nyomtattunk utoljára. A \verb+$?+ pedig arra fog behelyettesítődni, amik a függőségek közül megváltoztak a print utolsó módosítása óta. Így csak a megváltozott fájlokat nyomtatja ki a szabály.
\subsubsection{.NOTPARALLEL target}
Ha ez a target szerepel a makefájlunkban, akkor a make a futása során nem fog párhuzamosítani feladatokat, még akkor sem, ha a -j kapcsolót megadtuk neki. Ha a \verb+.NOTPARALLEL+-nek megadunk valami függőséget, azt a make figyelmen kívül hagyja. Ha a make eleve párhuzamosan fut, mert pl. ez a makefájl egy rekurzív make hívás egyik példánya, attól még a többi make processzt nem fogja kilőni a rendszer.\par
Önálló feldolgozásra:
\begin{description}
\item[.SUFFIXES]A \verb+.SUFFIXES+ target függőségeként fel kell sorolnunk azon kiterjesztéseket (a kezdő ponttal együtt), amelyeknél szeretnénk, hogy a kiterjesztésekkel kapcsolatos szabály mintákat alkalmazza.\footnote{Jelen esetben semilyen tulajdonság kiterjesztéséről nincs szó. Mindössze a fájlok végén a pont után következő részt a magyar szakirodalomban a fájl kiterjesztésének hívja.} Amiatt van szükség erre, mert régebben a szabály minták (Pattern Rules) megléte előtt kiterjesztésmintákat használtak, és a make tudomására kellett hozni, hogy milyen kiterjestésekre vonatkozóan van kiterjesztésminta. Ma azonban már ellenjavalt ezeknek a használata, és helyette a sokkal általánosabb szabálymintákat használjuk.\par
\index{peldak}{Make kiterjesztés szabály példa},,Old fashion'' példa:
\begin{verbatimtab}
.c.o:
	$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
\end{verbatimtab}
Új típusú példa:\footnote{A régi típusú kiterjesztés mintáknál nem lehetett megadni függőségeket egy mintához, ha megadtnánk pl. egy {\tt izé.h} fájlt függőségként, akkor azt úgy értelmezné, hogy hogy kell az {\tt izé.h} -ból elkészíteni a {\tt .c.o-t}}
\begin{verbatimtab}
%.o: %.c foo.h
	$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
\end{verbatimtab}
\item[.DEFAULT]Ami parancsokat megadunk a \verb+.DEFAULT+ targetnek, azt minden egyes target készítésekor le fogja futtatni, amikor nem talál rá szabályt, hogy hogy kell előállítani. (Ide értendő, hogy sem explicit, sem implicit mintát nem talál rá.\footnote{Lásd még: make infó oldalainál az implicit mintakereséséi algoritmust})
\item[.PRECIOUS]Ha valamilyen targetet megadunk függőségként a \verb+.PRECIOUS+-nak, akkor azt nem fogja letörölni a make, ha annak a targetnek az előállítása közben megszakad. Példa: Ha a prog1 -et készíttetjük a make-el, és a prog1.o mint függőség készítése közben megszakadna a make futása, pl. egy {\setlength{\fboxsep}{1pt} \fbox{\sc CTRL}}-\verb+c+ hatására, akkor nem fogja a prog1.o-t letörölni.
\item[.SILENT]Ha megadunk targeteket függőségként a \verb+.SILENT+-nek, akkor azon targetek készítése közben nem fogja a make kiírni, hogy épp milyen parancsot futtat. Ha csek felsoroljuk a \verb+.SILENT+ targetet, függőségek nélkül, akkor a make úgy tesz, mintha minden target a \verb+.SILENT+ függősége lenne. Lásd még a {\sl Parancsok kezelése} $_{\pageref{parancsok kezelese}}$ részt.
\item[.IGNORE]Ha megadunk targeteket függéségként a \verb+.IGNORE+-nek, akkor azon targetek készítése közben a make nem fog leállni, ha egy adott parancs hibával\footnote{Un*x rendszerekben, minden lefuttatott parancs visszaad egy hibakódot. Ha ez 0, akkor a parancs jól lefutott, ha nem, akkor a hibakódból általában lehet következtetni a hiba jellegére, de ez minden parancsnál egyéni, hogy a hibakódba hogyan kódolja bele a hiba jellegét. Fontos, hogy ne keverjük a C programozási nyelv {\tt true}/{\tt false} kezelésével, aholis a 0 jelenti a hamis értéket.} fejezi be működését. Ha csak feltüntetjük az \verb+.IGNORE+ targetet, de nem adunk meg függőséget, akkor a make úgy tesz, mitnha minden target a \verb+.IGNORE+ target függősége lenne. Lásd még a {\sl Parancsok kezelése} $_{\pageref{parancsok kezelese}}$ részt.
\end{description}
\subsubsection{Többszörös szabályok}
Ha a \verb+:+ előtt több targetet megadunk, és függőségeket felsorolunk, akkor a make az összes target függőségeihez hozzáveszi a megadott függőséget. Példa:
\begin{verbatimtab}
kbd.o command.o files.o: command.h
\end{verbatimtab}
Ha parancsokat is megadunk, az is működik, és többszörözi a definíciót. Ha például vesszük a következő definíciót:
\begin{verbatimtab}
nagykimenet kiskimenet : rizsa.g
	generate rizsa.g -$(subst kimenet,,$@) > $@
\end{verbatimtab}
Akkor ez a definíció ekvivalens az alábbi hosszabb definícióval:
\begin{verbatimtab}
nagykimenet : rizsa.g
	generate rizsa.g -nagy > nagykimenet
kiskimenet : rizsa.g
	generate rizsa.g -kis > kiskimenet
\end{verbatimtab}
\subsubsection{Implicit szabályok}
\label{implicit make szabalyok}Az implicit szabályok a make által már eleve ismert szabályok, amiket nem kell neki külön elmondani. A fenti példában$_{\pageref{egyszeru pelda}}$ csak annyit mondtunk el a make-nek, hogy a \verb+prog.o+ függ a \verb+prog.c+-től ill \verb+prog.h+-tól, de hogy a \verb+prog.o+-t, hogy kell előállítani, azt már nem közöltük vele. Ilyenkor a make implicit szabályokat használ. Pl. egy implicit szabály, hogy hogyan kell lefordítani (kompilálni) egy {\sc C} programot:
\begin{verbatimtab}
x.o: x.c
    $(CC) -c $(CPPFLAGS) $(CFLAGS)
\end{verbatimtab}
Az implicit szabályok katalógusa megtalálható a make info oldalai közt.\footnote{Órai feladat: keresd meg, minél gyorsabban az ide vonatkozó info oldalt!}
\subsection{Szabály minták}
Ha nem egy konkrét targetet akarok megadni, hanem egy általános dologra szeretnék egy általános szabályt adni, akkor használatosak a szabály minták. Pl. ha le akarom írni, hogy hogy készül egy .pdf fájl, akkor vmi. ilyesmit használok:
\begin{verbatimtab}
%.pdf: %.tex
	pdflatex $<
	makeindex $*
	pdflatex $<
\end{verbatimtab}
\subsection{Archívumtagra hivatkozás}
Ha egy archív fájl egyik tagjára szeretnék hivatkozni targetként, vagy függőségként, akkor azt a következő szintaxis szerint adhatom meg: \verb+ARCHÍVNÉV(TAGNÉV)+\par
Például, ha szeretném a make-el közölni, hogy a \verb+libproba.a+ -ban levő \verb+proba.o+ a \verb+proba.o+-tól, függ, akkor a következő függőséget kell megadni a make-nek:
\begin{verbatimtab}
libproba(proba.o): proba.o
\end{verbatimtab}
\subsection{Változók}
A \verb+Makefile+-ban szokás változókat is használni, bizonyos dolgok egyszerűsítésére. Például előre beállítva kapunk CC változót, ami a C compiler nevét tartalmazza. De a make implicit szabályai sem közvetlenül a cc vagy gcc parancsot adják ki, hanem a CC változóból olvassák ki a parancs nevét.\par
Emiatt jónéhány változó értékét előre beállítva megkapjuk.\footnote{Órai feladat: kikeresni az info oldalakból az előre beállított változókat.}\par
Az értékadások, a targetektől függetlenül, már a make meghívásakor első lépésként lefutnak.
\subsubsection{Az értékadás módjai}
\begin{itemize}
\item Egyszerű értékadás: \verb+VÁLTOZÓ = ÉRTÉK+ Ilyenkor a változó felveszi az értéket.
\item Egyszerű értékadás, azonnali kiértékeléssel: \verb+VÁLTOZÓ := ÉRTÉK+ Ilyenkor ha az érték egy kifejezést, pl. másik változó értékét tartalmazza, az azonnal behelyetesítődik.
\item Feltételes értékadás: \verb+VÁLTOZÓ ?= ÉRTÉK+ Ha a változónak még nem volt értéke, akkor veszi csak fel a megadott értéket.
\item A változó értékének bővítése: \verb.VÁLTOZÓ += ÉRTÉK. A változó értékét megtartja, és a végéhez még hozzáírja a megadott értéket. Tipikus használat: az lefordítandó/{\sl make}elendő alkönyvtárak meghatározására.
\end{itemize}
\subsubsection{Automatikus változók}
\begin{description}
\item[{\tt \$@}]A szabály targetjének fájlneve. (Az esetleges bevezető könyvtárnévvel együtt.) Ha archívtagra hivatkozunk, akkor csak az archív fájl neve.
\item[{\tt \$\%}]Csak archívra hivatkozásnál használatos. Az archívban levő résztvevő (member) neve.
\item[{\tt \$<}]Az első függőség neve.
\item[{\tt \$?}]Az összes olyan függőség neve, ami frissebb mint a cél. Ha archívtagra hivatkozunk, akkor az azt tartalmazó fájl neve fog a felsorolásba bekerülni.
\item[{\tt \$\^}]Az összes függőség neve. Ha egy függőség a függőségek közt többször előfordul, az itt csak egyszer jelenik meg. Ha archívtagra hivatkozunk, akkor az azt tartalmazó fájl neve jelenik meg.
\item[{\tt \$+}]Ugyanaz, mint az előző. Viszont ha egy függőség a függőségek közt többször is meg van jelölve, akkor ebben a felsorolásban is többször fog előfordulni.
\item[{\tt \$*}]Szabály mintáknál az illeszkedés után megmaradt rész. Ha pl. a szabályminta \verb+a%.b+, és az \verb+eperlekvár/abroncs.b+ a targetünk, akkor a \verb+$*+ értékre \verb+eperlekvár/broncs+ lesz.
\end{description}
\subsubsection{A define direktíva}
Ha egy változónak több soron kersztül szeretnénk értéket adni (úgy, hogy a sortörés is benne legyen az értékében), akkor a define direktívát szokás használni. Szokás verbatim értékadásnak is hívni, hasonlóan a \TeX verbatim környezetéhez. Ilyenkor a változónak értékadás a következőképp megy:
\begin{verbatim}
define VÁLTOZÓNÉV
érték első sora
érték második sora
s.í.t.
endef
\end{verbatim}
\subsection{Elágazások, stb.}
A make lehetőséget ad, hogy valamilyen feltétel szerint elágazzon a \verb+Makefileunk+. Ha pl. szeretnénk ellenőrizni, hogy a C fordítónk, biztos a {\sc GNU} C fordítója, akkor a következő példa szerint tudunk eljárni:
\begin{verbatimtab}
izé: $(objects)
ifeq ($(CC),gcc)
	$(CC) -o izé $(objects) $(libraryk_a_gcc_esetén)
else
	$(CC) -o izé $(objects) $(libraryk_normál_esetre)
endif
\end{verbatimtab}
\subsubsection{include}
A make lehetőséget ad arra, hogy ne csak egy fájlból álljon az a komplex szabályrendszer, amivel egy nagyobb projektet elkészítünk, hanem szétdarabolhassuk több fájlra, és a végén a make egybeolvasztja őket. Erre szolgál a make include direktívája\footnote{Ez a {\sc GNU} make specialitása többek közt, más make várhatóan nem fogja ismerni!}.
\subsubsection{szövegek manipulálása}
A make lehetőséget ad arra, hogy egy változó, vagy konstans szöveg értékét valamilyen módosítás szerint használjuk fel. Példák:
\begin{description}
\item[{\tt \$(dirname NEVEK)}]A fájlhivatkozásból a könyvtár nevét adja vissza.\\
Pl a \verb+$(dirname izé/mizé.txt brumi)+ kifejezés a \verb+izé/ ./+ szöveget fogja megadni.
\item[{\tt \$(suffix NEVEK)}]A fájlnévhivatkozásből a fájl kiterjesztését adja vissza.\\
Pl a \verb+$(dirname izé/mizé.txt brumi)+ kifejezés a \verb+.txt+ szöveget fogja megadni.
\item[{\tt \$(basename NEVEK)}]A fájlnévhivatkozásből a fájl nevét adja vissza.\\
Pl a \verb+$(dirname izé/mizé.txt brumi)+ kifejezés a \verb+izé/mizé brumi+ szöveget fogja megadni.
\item[{\tt \$(wildcard MINTA)}]A shellben szokásos wildcardokkal megadott mintával itt is meg lehet adni mintát, és a kifejezés értéke az lesz, mintha a shell-el értékeltettük volna ki a wildcardot, vagyis a mintánkat a létező fájlok neveire fogja illeszteni, és azok közöl a létezők nevei kerülnek be az eredménybe.
\item[{\tt \$(subst MIT,MIRE,SZÖVEG)}]A megadott szövegben a megadott alrészt kicseréli a megadottra.\\
Pl a \verb+$(subst irgum,burgum,irgumburgum)+ kifejezés a \verb+burgumburgum+ szöveget fogja megadni.
\item[{\tt \$(origin VÁLTOZÓNÉV)}]Azt adja meg, hogy a változó hol vette fel az értékét. (Már feltéve, ha van értéke.) Néhány lehetséges érték: \verb+undefined+, ha soha nem lett definiálva, azaz nincs értéke; \verb+default+, ha valamilyen alapértelmezett értéke van, mint pl. a \verb+CC+ változónak, \verb+environment+ ha környezeti változó értékeként használja a make saját változójának értékéül.
\item[{\tt \$(shell PARANCS)}]Külső shell-ben lefuttatja a parancsot, és a futás eredményéül a standard kimenetre adott szöveget veszi a változó értékéül. Gyakorlatilag ugyanaz, mint amit a legtöbb shellben a backtick (\verb+`+) csinál.
\end{description}
\subsection{Parancsok kezelése}
\label{parancsok kezelese} A parancsoknál bizonyos esetben nem szeretnénk látni magát a parancsot, csak esetleg a parancs kimenetét. És ezt a szabályon belül nem az összes parancsra szeretnénk, mint ahogy azt a .SILENT targetek teszik. Ilyenkor a parancs elé egy \verb+@+ jelet kell tenni, mint az alábbi példában:
\begin{verbatimtab}
love:
	@echo "not war!"
\end{verbatimtab}
A másik ami egy paranccsal történhet, hogy hibával fut le. Ilyenkor a make megszakítja működését, és a tempfájlokat letörli. De szintén lehet olyan eset, amikor hagyni akarjuk, hogy hibával fusson le egy parancs. Tipikus példa a clean target, amit ha kétszer egymás után lefuttatunk, akkor nem lesz mit letörölnie, és másodjára már hibával futna le a clean. Ezért ilyenkor egy \verb+-+ jelet szokás a parancs elé tenni.\footnote{Mind a {\tt -}, mind a {\tt @} esetén a jeleket a kezdő tab után kell tenni!}
\begin{verbatimtab}
clean:
	-rm *.o
\end{verbatimtab}
\clearpage
\subsection{Egy komplex Makefile példa}
\index{peldak}{Makefile Komplex példa}
\begin{verbatimtab}
PHONY: default
default:
	@echo "Usage: make dir.iso [VOLNAME=volumename] [TARGDIR=targetdirectory]"


PHONY: *.iso

%.iso:
ifeq ($(origin VOLNAME), undefined)
define VOLNAME
$*
endef
endif
ifeq ($(origin TARGDIR), undefined)
define TARGDIR
.
endef
endif
	echo "volname=$(VOLNAME) - $* - targetdir=$(TARGDIR)"
	find "$*" -type d | while read x; \
	do ( cd "$$x" ; echo -ne '' | md5sum -vb `find -type f -mindepth 1 \
	   -maxdepth 1 \! -name md5sum.txt -printf '%f\n'` >md5sum.txt ) ; \
	done
	mkisofs -hide-joliet-trans-tbl -gui -l -J -L -r -T -V "$(VOLNAME)" \
	         -o "$(TARGDIR)/$*.iso" "$*"
\end{verbatimtab}
\subsubsection{A makefájl használatáról, működéséről néhány szó}
Alapértelmezett targetjének a neve \verb+default+, ez hajtódik végre, ha semmilyen paramétert nem adunk, a make-nek, csak egyszerűen elindítjuk a make parancsot. Ekkor kiírja, hogy hogyan is érdemes/lehet használni.\par
Egyébként a makefile segítségével egy .iso image generálható le. Feltételezzük, hogy a makefile-t tartalmazó könyvtár egyik alkönyvtárába összegyűjtöttük, amit a CD-re szeretnénk írni. Ekkor a make-nek a könyvtár nevét kell paraméterül megadni .iso kiterjesztéssel, ui. úgy készült a makefile, hogy a .iso kiterjesztésű targetekre van benne egy szabály minta.\par
Alapértelmezésben a .iso fájl, az aktuális könyvtárba kerül, illetve a lemez kötetcimkéje is az lesz, ami a könyvtár neve. Ezek felülbírálhatók a TARGDIR és VOLNAME változóknak történt értékadással.\par
Ha szeretnénk eltérő kötetcimkenevet akkor a következőképp kell a make-et meghívni:
\begin{verbatimtab}
$ make könyvtárnév.iso VOLNAME="Ez lesz a CDcimke"
\end{verbatimtab}
Ekkor a make előre beállítja a VOLNAME változót, és az \verb+$(origin VOLNAME)+ már nem lesz \verb+undefined+. Mint említettem, környezeti változóként is át lehet adni egy változó értékét. Ezt kétféleképp is szokás. Szokás úgy, hogy permanensen beállítjuk a shellünknek az adott környezeti változót, pl. bash használata mellett így nézne ki a példa:
\begin{verbatimtab}
$ export VOLNAME="Ez lesz a CDcimke"
$ make könyvtárnév.iso
\end{verbatimtab}
Illetve lehet úgy is, hogy csak a make kapja meg az adott környezeti változót, az adott értékkel:
\begin{verbatimtab}
$ VOLNAME="Ez lesz a CDcimke" make könyvtárnév.iso
\end{verbatimtab}
\subsection{Összefoglalás}
Röviden tekintsük át, mi lehet egy \verb+Makefile+-ban.
\begin{itemize}
\item Egy explicit szabály, ahol elmondjuk, hogy egy fájlt hogyan, és mikor készítsen el, miktől függjön, és megadjuk az elkészítéshez való parancsokat is, stb.
\item Egy implicit szabály, ahol elmindjuk, hogy egy fájlt hogyan, és mikor készítsen el, stb.
\item Változódefiníció, ahol egy változónak értéket adunk, (vagy az értékéhez hozzáteszünk,) valamilyen módon. Általában a \verb+Makefile+ egyszerűsítése és jobb áttekinthetősége miatt használjuk.
\item Egy direktíva, ami a következők közül valamelyik:
\begin{itemize}
\item Beolvastat egy másik makefilet az include direktívával.
\item Döntést hoz valamilyen változó, vagy feltétel alapján.
\item Definiál egy változót verbatim módon több soron keresztül a define direktívával.
\end{itemize}
\item Megjegyzés a \verb+Makefile+ írójának. A megjegyzés sorok a make-ben \verb+#+-al kezdődnek.
\end{itemize}
\clearpage
\section{A GNU fejlesztő eszközök IV. rész. {\ttfamily Makefile} konvenciók}
\subsection{A makefájlírás konvenciói}\label{makefilekonvenciok}
\subsubsection{A {\ttfamily make}ben használható parancsok}
A make infó oldalai közt azt találjuk, hogy ha jól hordozható \verb+Makefile+-t szeretnénk írni, akkor a következő parancsokat használjuk csak:\par
{\ttfamily cat cmp cp diff echo egrep expr false grep install-info ln ls mkdir mv pwd rm rmdir sed sleep sort tar test touch true}\par
A leírás kitér arra is, hogy a kompatibilitás jegyében semilyen karácsonyfa\footnote{túl sok extra tudással ellátott program, mint itt a shellek esetében a {\ttfamily bash}, {\ttfamily csh} vagy a {\ttfamily ksh}.} jellegű shell-t ne használjunk,\footnote{Ennek hátterében az áll, hogy a {\ttfamily make} a programokat az {\ttfamily sh -c} parancsnak argumentumul adva hívja meg a célok elkészítése érdekében.} hanem csak az alap {\ttfamily sh} lehetőségeire építsünk. A fejezet hátralévő részében ezen parancsok közül fogjuk részletezni a szöveg manipulálására szolgáló parancsokat, a többi ui. fájlkezeléssel kapcsolatos Un*x alapparancs.
\subsubsection{A {\ttfamily make} által használt parancsok, és az ezekhez kapcsolódó előre definiált változók}
A make az építkezés során a következő parancsokat használja fel:\par
{\ttfamily ar bison cc flex install ld ldconfig lex make makeinfo ranlib texi2dvi yacc}\\
Ennek megfelelően definiálja hozzájuk a következő változókat:\par
{\ttfamily \$(AR) \$(BISON) \$(CC) \$(FLEX) \$(INSTALL) \$(LD) \$(LDCONFIG) \$(LEX) \$(MAKE) \$(MAKEINFO) \$(RANLIB) \$(TEXI2DVI) \$(YACC)}\\
Ha ezen programok helyett egy másikat szeretnénk használni, pl. gyorsan szeretnénk egy programot sun környezetben lefordítani a {\sc GNU C} Compilerrel a sun saját \verb+cc+-je helyett, akkor elég a \verb+CC+ környezeti változó értékét a \verb+Makefile+ elején átdefiniálni \verb+gcc+-re.
\subsubsection{További megjegyzések}
\begin{itemize}
\item Ha szimbolikus linkeket használunk, akkor egy ún. {\sl fallback} lehetőséget definiáljunk az olyan rendszerekhez, amelyek nem támogatják a symlinkeket.
\item További programok is használhatók a \verb+Make+ változóin keresztül:\\
{\ttfamily chgrp chmod chown mknod}
\item Ezen túl csak akkor használjunk más programokat, ha tudjuk, hogy az az adott célrendszerben létezik.\footnote{Érdemes az ilyenekre felhívni az {\ttfamily INSTALL} vagy {\ttfamily README} fájlokban felhívni a figyelmet.}
\end{itemize}
\subsubsection{A fájlok telepításével kapcsolatos konvenciók}
Minden \verb+Makefile+-ban az \verb+INSTALL+ változó definiáltnak javasolt.\footnote{Láthatjuk a fentiekből, hogy a {\ttfamily Make} már előre definiálja hozzá az {\ttfamily install} programot.}\par
Ezek után javasolt még egy \verb+INSTALL_PROGRAM+ és egy \verb+INSTALL_DATA+ változó definiálása is.\footnote{pl. a programot a telepítés után futtatható jogosultságokkal telepít az {\ttfamily INSTALL\_PROGRAM}, míg az {\ttfamily INSTALL\_DATA} csak olvashatónak, esetleg a tulajdonosa által felülírhatónak, telepítí a programhoz tartozó egyéb adatfájlt.}\par
Ez esetben a telepítés valahogy így néz ki a változók használatával:
\begin{verbatimtab}
install:
	$(INSTALL_PROGRAM) izé $(bindir)/izé
	$(INSTALL_DATA) libizé.a $(libdir)/libizé.a
\end{verbatimtab}
Illetve ha még korrektebbül szeretnénk eljárni, akkor a telepítési célkönyvtárban még a \verb+DESTDIR+ változót is megadjuk prefixként, ezzel lehetővé tesszük a programunkat felhasználónak, hogy
\begin{itemize}
\item Ne egyből az éles rendszerre telepítse a programunkat, hanem csak egy alkönyvtárba
\item Könnyebben készítsen \verb+.deb+ vagy \verb+.rpm+ csomagot a programunkból
\item Egyszerűen tudja/tudjuk terjeszteni a programunkat ,,csak bináris'' formában, így megkímélve a felhasználót egy esetleges hosszú programfordítástól.
\end{itemize}
Ezek után a targetünk leírása a következőre módosul:\footnote{Javasolt konkrétan fájlnevet megadni az install parancsok második argumentumaként és nem könyvtárnevet; valamint minden egyes feltelepítendő fájlt külön parancsal telepítsünk.}
\begin{verbatimtab}
install:
	$(INSTALL_PROGRAM) izé $(DESTDIR)$(bindir)/izé
	$(INSTALL_DATA) libizé.a $(DESTDIR)$(libdir)/libizé.a
\end{verbatimtab}
A \verb+bindir+-hez hasonló változók felsorolva megtalálhatók a \verb+make+ infó oldalai közt a Könyvtár Változók\footnote{Directory Variables} pontja alatt részletezve. Egy felsorolás ezen változókról:\par
{\ttfamily prefix exec\_prefix bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir infodir lispdir includedir oldincludedir mandir man1dir man2dir ... manext man1ext man2ext ... srcdir}\\
Ha a programunk sok fájlt telepít, akkor ajánlott a fájljait külön alkönyvtárba csoportosítani. Pl. \verb+/usr/share/emacs+
\subsubsection{konvencionális targetek a {\ttfamily make}-ben}
\begin{description}
\item[all]Lefordítja a teljes programot. Ennek kell az alapértelmezett targetnek lennie. Ennek a targetnek nem kell újrafordítani a dokumentációt; az {\ttfamily info} fájlokat normál esetben tartalmazza a terjesztés, és a {\ttfamily .dvi} fájlokat csak akkor kell megépíteni, ha azt külön kérjük.\\
Alapértelmezésben a {\ttfamily make} a programokat a \verb+-g+-vel fordítja le, így a futtatható fájlok tartalmazzák a debug információkat is. Ha felhasználónak nincs rá szüksége, akkor a strip-el ezeket el lehet távolítani.
\item[install]Lefordítja a teljes programot, és felmásolja a futtatható állományokat, osztott könyvtárakat, stb. a végső helyükre a használathoz. Ha adva van egy teszt ami ellenőrizni tudja, hogy a program korrektül fel van-e telepítve, akkor ezt a tesztet is le kell futtatnia ennek a targetnek. A futtatható fájlokat ne {\sl strip}-eljük amikor telepítjük őket, erre az {\bf instal-strip} targetet használjuk.\par
A target nem változtat meg semilyen fájlt abban a könyvtárban ahol készült. Így alkalmas rá, hogy egyik felhasználó nevében leforduljanak a programok, és egy másik (pl. a rendszergazda) nevében települjenek.\par
A parancsoknak létre kell hozni minden könyvtárat ahova fájlokat telepít, ha azok a könyvtárak még nem léteztek. Lásd pl. {\ttfamily prefix}, {\ttfamily exec\_prefix} változókat.\par
Használjunk a már ismert \verb+-+ jelet a parancsok előt amikor man oldalt telepítünk, így a {\ttfamily make} figyelmen kívül hagyja a hibákat. Hasznos lehet abban az esetben ha olyan rendszerre telepítjük, amire nincs feltelepítve a Unixok man oldalrendszere.\par
Az infó oldalak telepítéséhez az \verb+infodir+ változót használjuk az \verb+$(INSTALL_DATA)+-val, és utána futtassuk az \verb+install-info+ parancsot ami frissíti az Info könyvtár `dir' fájlját és frissíti a menü bejegyzéseket az adott Info fájlról, ami része a Texinfo csomagnak. Mintapélda Info fájl telepítéséhez:\index{peldak}{Info fájlok telepítése}
\begin{verbatimtab}
$(DESTDIR)$(infodir)/foo.info: foo.info
	$(POST_INSTALL)
# There may be a newer info file in . than in srcdir.
	-if test -f foo.info; then d=.; \
	 else d=$(srcdir); fi; \
	$(INSTALL_DATA) $$d/foo.info $(DESTDIR)$@; \
# Run install-info only if it exists.
# Use `if' instead of just prepending `-' to the
# line so we notice real errors from install-info.
# We use `$(SHELL) -c' because some shells do not
# fail gracefully when there is an unknown command.
	if $(SHELL) -c 'install-info --version' \
	   >/dev/null 2>&1; then \
	   install-info --dir-file=$(DESTDIR)$(infodir)/dir \
		$(DESTDIR)$(infodir)/foo.info; \
	else true; fi
\end{verbatimtab}
Az {\bf install} target írásakor a parancsokat három csoportra szét kell osztani. A telepítés előtti, és utáni, valamint normál részre. A normális parancsoknak kell a fájlokat bemásolni a megfelelő helyre, és beállítani a módot (tulajdonost, stb.). Ez a rész nem változtathat fájlokon kivéve azokat amelyek abból a csomagból jönnek, ahova tartozik. (Vagyis strip-elve lehet telepíteni pl. a futtatható fájlokat, mert a futtatható fájl ugyanahhoz a csomaghoz tartozik, mint a hozzátartozó \verb+Makefile+.)\par
A telepítés előtti rész a normál parancsok előtt futnak le, és a telepítés utániak a normál rész után.\par
Egy tipikus példa az install utáni részre, amikor az \verb+install-info+ parancsot le kell futtatni az Info fájlok telepítése után.\par
A legtöbb programnak nincs szüksége semmilyen telepítés előtti parancsra.\par
Az installálás előtti és utáni részben csak a következő parancsokat használjuk:\par
{\ttfamily \lbrack{} basename bash cat chgrp chmod chown cmp cp dd diff echo egrep expand expr false fgrep find getopt grep gunzip gzip hostname install install-info kill ldconfig ln ls md5sum mkdir mkfifo mknod mv printenv pwd rm rmdir sed sort tee test touch true uname xargs yes}
\item[uninstall]Törli az összes telepített fájlt, azokat a másolatokat amelyeket az {\bf install} target létrehoz. Ez a szabály nem módosítja azt a könyvtárat, ahol a fordítás történik, csak azokat ahova fájlok települnek. Az uninstallációs parancsokat három kategóriába szokás sorolni, az installálási parancsokhoz hasonlóan.
\item[install-strip]Hasonló az {\bf install} targethez, de a futtatható fájlokat stripeli, amikor telepíti őket. Sok esetben ezen target definíciója az alábbi módon leegyszerűsül\footnote{Természetesen, ehhez is a konvenciók betartása szükséges}:
\begin{verbatimtab}
install-strip:
	$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \
		install
\end{verbatimtab}
\item[clean]Töröl minden fájlt az aktuális könyvtárból amelyek normál esetben a program fordítása közben keletkeznek. Ne töröljünk fájlokat amelyek konfigurációt tartalmaznak. Szintén megőrzi azokat a fájlokat, amelyeket elő lehet állítani, de normál esetben a terjesztés nem tartalmazza.\par
Törli a \verb+.dvi+ fájlokat amelyek nem részei a terjesztésnek.
\item[distclean]Töröl minden fájlt az aktuális könyvtárból amelyek a program konfigurálásakor vagy fordításakor keletkeznek. A forrás kibontása és megépítése után ha semmilyen egyéb fájlt nem csinálunk, akkor a \verb+make distclean+ csak olyan fájlokat hagy meg amelyek a terjesztésben maradnának.
\item[maintainer-clean]Letöröl mindent amit a \verb+Makefile+ segítségével újra elő lehet állítani. Tipikusan tartalmazza a {\bf distclean} által törölt fájlok törlését, továbbá: C forrás fájlokat amelyeket a {\sl Bison} állít elő, tag táblákat, Info fájlokat, stb.
\item[TAGS]Frissíti a tag fájlokat. Lásd ctags, etags.
\item[info]Legenerálja a szükséges Info fájlokat. A javasol mód ennek megtételére az alábbi mintát követni:
\begin{verbatimtab}
info: izé.info

izé.info: izé.texi fejezet1.texi fejezet2.texi
	$(MAKEINFO) $(srcdir)/izé.texi
\end{verbatimtab}
\item[dvi]Legenerálja a {\sc dvi} fájlokat a Texinfo dokumentációhoz. Példa:
\begin{verbatimtab}
dvi: izé.dvi

izé.dvi: izé.texi fejezet1.texi fejezet2.texi
	$(TEXI2DVI) $(srcdir)/izé.texi
\end{verbatimtab}
\item[dist]A terjesztés tar fájlát létrehozza. A tar fájl úgy jöjjön létre, hogy azon belül egy alkönyvtár legyen, amelynek a neve a programunk nevét és esetleg annak verziószámát tartalmazza.
\item[check]Leellenőrzi a programot. Ennél a résznél nem szabad a \verb+$(bindir)+ változó tartalmára hagyatkozni. A program megépítését és telepítését a felhasználó dolga a teszt előtt elvégezni.
\item[installcheck]
\item[installdirs]
\end{description}
\clearpage
\section{A GNU szövegfeldolgozó eszközök (sed, grep, awk), shellscriptek, és regexpek}
Munkánk során gyakran szükségünk van különböző - szöveges - fájlok feldolgozására (keresés egy fájlban, bizonyos sztringek törlése/cseréje, stb\dots)
Ezen feladatok elvégzésére C nyelvű programok írása túl időigényes lenne, vannak ennél sokkal egyszerűbb eszközök is.
Három ilyen szövegfeldolgozó (szűrő) program az \verb+awk+, a \verb+grep+ és a \verb+sed+.
Mindegyik program használatához szükségünk lesz a reguláris kifejezések ismeretére és használatára.
\subsection{Regexp alapok}
Reguláris kifejezések (regular expressions, RE) az alábbi karakterekből állíthatóak össze:
\begin{description}
\item[.]Tetszőleges karaktert helyettesít.
\item[+]Az előtte álló kifejezés egy vagy többszöri előfordulását írja elő.
\item[*]Az előtte álló kifejezés nulla vagy többszöri előfordulását írja elő.
\item[?]Az előtte álló kifejezés egy vagy nulla előfordulálst írja elő.
\item[\lbrack\rbrack]Tartományra, felsorolásra szolgáló kifejezést. Pl. \verb+[a-z]+ az angol abc kisbetűi, vagy pl. \verb+[a-f,A-F,0-9]+ hexa számjegyek.
\item[\^]Sor elejét jelző kifejezés.
\item[\$]Sor végét jelző kifejezés.
\item[()]Kifejezéseket egy kifejezéssé összefogó jel.
\end{description}
\subsection{Egyszerű helyettesítések}
A fentiek alapján néhány - egyszerű - reguláris kifejezés a következők:
\begin{description}
\item[a]Erre illeszkedik az ,,a'' betű.
\item[.a]Erre illeszkednek az ,,aa'', ,,ba'', ,,7a'', stb. sztringek.
\item[.*a]Erre illeszkedik az összes ,,a'' betűre végződő szó.
\item[.+a]Az egyedül álló ,,a'' betűn kívül minden illeszkedik rá az előző pontból.
\end{description}
\subsection{Helyettesítéshez használt eszközök}
A reguláris kifejezések önmagukban nem sokat érnek, viszont megfelelő programokat segítségül hívva hatékony eszközökké válnak.
\subsubsection{A grep szűrőprogram}
A \verb+grep+ a bemenetéről beolvasott sorok közül azokat írja ki - alapértelmezésben - a kimenetére, amelyek illeszkednek (,,matchel''-nek) a megadott reguláris kifejezésre.
\par
Néhány kapcsolója:
\begin{description}
\item[-b]Megadja a megtalált kifejezés bájt-pozícióját is.
\item[-c]Csak a sorok számát adja vissza (melyekben a kifejezést megtalálta).
\item[-f FÁJL]Az illesztési mintát (a reguláris kifejezést) a megadott fájlból veszi.
\item[-H]Kiírja annak a fájlnak a nevét, amelyben az illeszkedő sort találta.
\item[-i]Figyelmen kívül hagyja a kis- és nagybetűk közti különbséget.
\item[-l]Csak azokat a fájlneveket adja meg, amelyekben a keresett kifejezés megtalálható.
\item[-n]A szűrőn átengedett (megtalált) sorok számát adja vissza.
\item[-r]Rekurzív keresés minden alkönyvtár minden fájljában.
\item[-s]Nem jelenít meg hibaüzenetet, ha egy fájlt nem tud olvasni (nem létezik, vagy nincs rá megnyitási jogunk).
\item[-v]Azokat a sorokat keresi meg, amelyek nem tartalmazzák a megadott kifejezést
\end{description}
A \verb+GREP_OPTIONS+ környezeti változóban megadhatjuk az alapértelmezett kapcsolóinkat.
\subsubsection{A sed szövegszerkesztő}
A \verb+sed+ (Stream EDitor) a felhasználó közreműködése nélkül (nem interaktívan) módosításokat hajt végre az inputján, így nagyon jól használható például szkriptekben szöveg törlésére/cseréjére/beszúrására.
A \verb+sed+ működésének elve:
\begin{enumerate}
\item Következő sor beolvasása, ha van ilyen (ha nincs, akkor kilép).
\item A beolvasott sor feldolgozása. (,,Van-e olyan utasításom, amely alapján ezzel a sorral kell csinálnom valamit?'')
\begin{itemize}
\item ha van, akkor az utasítás végrehajtása, és az eredmény kiírása a képernyőre (,,pattern space''~$\approx$~aktuális output);
\end{itemize}
\item GOTO 1.
\end{enumerate}
\par
Parancssori argumentumai:
\begin{description}
\item[-n]Elkészíti az output-fájlt, és nem írja ki a képernyőre a feldolgozás eredményét.
\item[-e SZKRIPT]Az inputon végrehajtja a - SZKRIPT-ként - megadott utasításokat.
\item[-f SZKRIPT-FÁJL]A SZKRIPT-FÁJL-ban megadott utasítássorozatot hajtja végreaz inputon.
\end{description}
A \verb+sed+ ezeken kívül rendelkezik jópár paranccsal, közülük néhány a következő:
\begin{description}
\item[y/FORRÁS/CÉL]Kicseréli a FORRÁS-ként megadott karaktert a CÉL-ként megadott karakterre.
\item[a$\backslash$SZÖVEG]A megadott SZÖVEG-et hozzáfűzi az inputhoz.
\item[i$\backslash$SZÖVEG]A megadott SZÖVEG-et beszúrja az inputba.
\item[c$\backslash$SZÖVEG]Kicseréli az illeszkedő sorokat SZÖVEG-re.
\item[=]Kiírja az aktuális sor sorszámát.
\item[r FÁJL]A megadott FÁJL tartalmát beszúrja az outputba.
\item[w FÁJL]A megadott FÁJL-ba írja az aktuális outputot.
\item[d]Törli az aktuális outputot, és folytatja az input feldolgozását.
\item[p]Kiírja az aktuális outputot.
\item[q]Kilép a \verb+sed+-ből az input további feldolgozása nélkül.
\item[s/REG-KIF/ÚJSZÖVEG/]A megadott reguláris kifejezést keresi az inputban, és ha talál rá illeszkedőt, akkor kicseréli ÚJSZÖVEG-re.
\item[$\{$,$\}$]Utasításblokkot határoz meg.
\end{description}
\subsubsection{Az awk programozási nyelv}
Az \verb+awk+\footnote{Az elnevezés az ,,eredeti'' awk szerzőinek vezetéknevéből adódik: Al Aho, Peter Weinberger, Brian Kernighan} program tulajdonképpen egy interpreter (amely \verb+awk+ programozási nyelven megírt programjainkat értelmezi :-)). Használatával - például - egyszerű adatbázis(szerűsége)t tudunk üzemeltetni, statisztikákat, kimutatásokat, stb. készíthetünk.
\par
A részletes magyarázat előtt vegyünk egy nagyon egyszerű példát!
Számoljuk össze a \verb+/dev+ könyvtárban lévő blokkos eszközök közül azokat, amelynek neve tartalmaz számot!
\begin{verbatimtab}
$ ls -l /dev | awk '{print $1,$10}' | grep [0-9] | 
  awk '{print $1}' | grep b | wc -l
   447
\end{verbatimtab}
\par
Az \verb+awk+ programok formája a következő:
\begin{verbatimtab}
 minta { akció }
 minta { akció }
 ...
\end{verbatimtab}
Ha a programunk rövid, vagy ,,egyszer használatos'', a legegyszerűbb, ha a parancssorból futtatjuk: \verb+awk 'program' input1 input2 ...+, ahol a \verb+program+ tartalmazza a mintákat és az akciókat.
Ha hosszabb programot futtatunk (vagy többször szeretnénk használni) célszerű egy fájlba elmenteni és így futtatni: \verb+awk -f program-fájl input1 input2 ...+
\par
Az \verb+awk+ a bemenetét rekordokra bontja, ezeket a {\slshape rekordelválasztó} (Record Separator - RS nevű beépített változó) választja el egymástól. Az alapértelmezett RS az újsor karakter (\verb+\n+), így az input egy sora jelent egy rekordot. A rekordelválasztó megváltoztatása - például - így lehetséges: \verb+awk -v RS="." ...+ Ekkor a '.' karakter jelzi a rekordok végét. Ha nem a parancssorból szeretnénk megváltoztatni az értéket, akkor a programunkba kell beírni az \verb+RS="."+ sort.
A rekordok számát a - beépített - NR (Number of Records) változóban tároló tárolja.
\par
A rekordokat mezőkre darabolja az \verb+awk+, a mezőket a {\slshape mezőelválasztó} (Field Separator - FS) választja el egymástól. Alapértelmezésben ez egy tabulátor vagy space karakter(ek). Megváltoztatása vagy az RS-nél leírt módon történhet, vagy pedig parancssorból a \verb+-F+ kapcsolóval. (Például \verb+awk -F : '{print $1}' /etc/passwd+ kiírja a rendszer felhasználóinak nevét.)
A feldolgozás alatt álló rekord mezőire \$i-vel lehet hivatkozni ($1\leq i\leq NF$ (Number of Fields)), \$0 reprezentálja az egész rekordot.
\par
A reguláris kifejezések az \verb+awk+-nak is szerves részét alkotják. Használatuk a következő: \verb+awk '/REGKIF/ { akció }' input+.
\par
Nem esett még szó a lehetséges akciókról. Nézzünk meg néhány függvényt, a vezérlési szerkezeteket, változók használatát, stb., azaz a tulajdonképpeni AWK programozási nyelvet.
\begin{description}
\item[print]Mint neve is mutatja nyomtatást végez. A nyomtatandó elemeket vesszővel (,) elválasztva várja, és szóköz karakterekkel elválasztva írja a kimenetére. Megadhatunk neki számot, betűt, szavakat, mezőket, stb.
\par
Például: \verb+awk '{ print "A beolvasott rekord:",$0}' input-fájl+. Érdemes figyelni arra, hogy a kiírandó elemek közé tegyünk vesszőt, mert különben az elemeket összefűzve írja ki (ez főleg akkor lehet bosszantó, ha a kimenet egy pipe (|), és a kimeneten további szűréseket végzünk).
A print kimenete az ún. kimeneti rekord, ezeket a rekordokat az ORS (Output Record Separator) változóban megadott karakter választja el egymástól, alapértelmezésben ez az újsor karakter (megváltoztatása a ,,szokásos'' módon). Persze a FS-nek is van ,,párja'', az OFS (Output Field Separator) nevű változó, amely a kimeneti rekord mezőit választja el egymástól (alapértelmezésben szóköz).
\item[printf]Ha jobban bele szeretnénk szólni a kimeneti rekordok formájába, akkor a printf lesz segítségünkre. Használata nagyon hasonló a C printf() függvényéhez.
\par
Formája: \verb+printf form, elem1, ...+
\par
A formázó karakterek ugyanazok, mint C-ben (\verb+%c+ egy karakter, \verb+%d+ decimális egész, \dots). Amire figyelnünk kell C-ről áttérve az az, hogy a \verb+h+ (short) és \verb+l+ (long) formázókaraktereket ne használjuk, mert hibához vezet!
\par
Mind a \verb+print+, mind a \verb+printf+ esetén használhatjuk a shell-ben megszokott 
\verb+>+, \verb+>>+, \verb+<+ és \verb+|+ karaktereket. Ez azért jó, mert ha több \verb+print+ van a programunkban, akkor a különböző kimeneti rekordokat különböző fájlban tárolhatjuk el.
\par
Nézzünk az eddigiekre egy példát! Két fájlt szeretnénk kapni, az egyik tartalmazza a rendszer felhasználóinak azonosítóját, és user-id-jét, a másikba pedig mentsük el a felhasználók valódi nevét és group-id-jét (nem túl életszerű példa, de demonstrációnak talán jó).
\begin{verbatimtab}
 $ awk -F : '{
   > print $1,$3 > "username+uid"
   > print $5,$4 > "realname+gid"
   > }' /etc/passwd
 $ cat username+uid | head -3
   root 0
   daemon 1
   bin 2
\end{verbatimtab}
\item[Változók, operátorok, relációk]Hosszabb programjainkban szükségünk lesz saját változókra. Az \verb+awk+ változóit nem kell külön deklarálni, a változók típustalanok. Értékadásra az \verb+=+ szolgál.
Használhatjuk a C-ben megszokott
{\tt ++, --, *, /, \%, \&\&, ||, +=, -=, *=, /=, \%=, !} stb. operátorokat.
Hatványozásra a \verb+^+ vagy a \verb+**+ szolgál. Az ,,igaz'' és ,,hamis'' logikai értékeket a C-hez hasonlóan használhatjuk ($0$ vagy üres szó a ,,hamis'', a ,,nem hamis'' pedig igaz).
Az relációs operátorok - szokás szerint - C-szerűek:
\verb+<, >, ==, !=+ stb.
\item[Vezérlési szerkezetek]Itt is ,,kísért'' a C, nézzük!
\begin{itemize}
\item Szelekciós: \verb+if (feltétel) utasítások else utasítások+
\item Kezdőfeltételes ismétléses: \verb+while (feltétel) utasítások+
\item Végfeltételes ismétléses: \verb+do utasítások while (feltétel)+
\item Számlálásos: \verb+for (inicializálás; végfeltétel; növelés)+
\end{itemize}
Használhatjuk továbbá a \verb+break+ és \verb+continue+ kifejezéseket ciklusból kiugrásra, illetve az iteráció folytatására.
\item[Tömbök]Az \verb+awk+-ban is használhatunk tömböket. Alapvető különbség - például a C-hez képest -, hogy nem kell előre megadnunk a tömbünk méretét, valamint indexeléshez nem csak egymás utáni egész számokat használhatunk, hanem tetszőleges számokat, továbbá szavakat (betűket) is (asszociatív tömbök).
\par
Egy tömb elemének elérésére a \verb+[ ]+ szolgálnak (például $T$ nevű tömbünk ,,izé'' indexű elemére \verb+T[izé]+-vel hivatkozhatunk).
\par
A fenti tulajdonság miatt szükségünk lehet arra, hogy leellenőrizzük, hogy egy tömbnek adott indexű eleme létezik-e. Ennek módja: \verb+tömbindex in tömb+. A kifejezés $0$ (hamis) értéket ad vissza, ha nincs ilyen indexű elem, igazat egyébként.
\par
A tömbfeltöltésre is az \verb+=+ szolgál: \verb+T[izé] = "lalala"+.
\par
Többdimenziós tömbök kezelését is megengedi az \verb+awk+. Egy $n$-dimenziós tömb indexeléséhez $n$ indexre van szükségünk, így például \verb+T[3,5]+ egy $3x5$-ös mátrixot jelent. Itt kell megemlíteni a SUPSEP nevű beépített változót, amely elválasztja egymástól egy többdimenziós tömb indexeit (alapértéke $\backslash 034$). Ez azért fontos, mert az \verb+awk+ a fenti \verb+T[3,5]+ hivatkozást átalakítja \verb+T[3 SUPSEP 5]+-re, és ezt a kifejezést használja indexelésre.
\item[Függvények]Beszélhetünk beépített-, és felhasználó által definiált függvényekről. A ,,szokásos'' matematikai függvények (\verb+sin(), cos(), sqrt() ...+) az awk-ban is megtalálhatóak, érdekesek lehetnek még a {\tt length([sztring]), match(sztring, regexp), sprintf(),\\tolower(string), toupper(string), system(command), systime()}, melyek működésére a nevük utal.
\par
Ugyanakkor mi is definiálhatunk függvényeket, ezzel ,,teljes értékű'' programozási nyelvet kapva. A függvénydefiníció alakja: \verb+function fv_név(paraméterlista) { utasítások }+, és használhatjuk a \verb+return+ kifejezést függvényből való visszatérésre (értékkel is).
\end{description}
\clearpage
\subsection{Egy komplex shellscript példa}
Íme egy összetett shellscript példa:\footnote{A script megtalálható {\ttfamily allarch\_ln} és {\ttfamily allarch\_mov} néven is (symlinkek). Ill. a scriptel egy könyvtárban található egy {\ttfamily minta} nevű fájl is, aminek a tartalma a következő: {\ttfamily s/\textbackslash//\textbackslash\textbackslash\textbackslash//g}}\index{peldak}{Shell script példa}
\begin{verbatimtab}
#!/bin/bash
x=`echo "$1" | sed 's/\/$//' `
echo "$x"
[ "`basename "$0"`" = "allarch_ln"  ] && j="`dirname "$x"`/binary-$2"
[ "`basename "$0"`" = "allarch_mov" ] && j="`dirname "$x"`/binary-all"
echo "$j"
p=`dirname "$0" `
echo "$p"
subst="s/^`echo "$x/" | sed -f "$p/minta" `//"
#[ "`basename "$0"`" = "allarch_ln" ] && find "$j" -type l -print0 |\
#                                        xargs -0 -n 1 rm -f
for i in `find "$1" -name "*.deb" -type f`
do
  echo "subst = $subst "
  k=`echo "$i" | sed "$subst" `
  l=`dirname "$k"`
  m=`basename "$k"`
  [ "$l" = "." ] || dp=`echo "$l" | sed 's/[^/]\+/../g' `
  if [ "`basename "$0"`" = "allarch_ln" ]; then
    echo "dp = $dp"
    echo "ktcsin $j / $l"
    [ "$l" = "." ] || echo "linkel $i ( $dp / ../binary-all / $k ) -> $j / $l "
    [ "$l" = "." ] && echo "linkel $i ( ../binary-all / $k ) -> $j / $l "
    echo " $k == $l / $m "
    mkdir -p "$j/$l"
#   ln -s "$i" "$j/$l"
    [ "$l" = "." ] || ln -fsn $dp/../binary-all/$k $j/$l
    [ "$l" = "." ] && ln -fsn ../binary-all/$k $j/$l
    echo "ok"
  elif [ "`basename "$0"`" = "allarch_mov" ]; then
    if dpkg-deb -f "$i" Architecture |grep -q all ; then
      echo "ktcsin $j / $l"
      echo "mozgat $i ( $x / $k ) -> $j / $l "
      echo " $k == $l / $m "
      mkdir -p "$j/$l"
      mv "$i" "$j/$l"
    fi
  fi
done
\end{verbatimtab}
\clearpage
\section{Bevezetés a Perlbe}
A Perl (Practical Extraction and Report Language\footnote{vagy Pathologically Eclectic Rubbish Lister, ahogy alkotója, Larry Wall nevezte}) egy platformfüggetlen, interpretált, elsősorban szövegfeldolgozásra szánt nyelv. Tervezésekor a hatékonyságot tartották szem előtt a kód szépségével szemben. A Perl-t szokták a ,,rendszergazdák nyelve''-ként is emlegetni, nagyon hatékonyan használható például log-fájlokfeldolgozására. Megismeréséhez hasznunkra válhat a C-, awk-, shell-szkript ismeret.
\subsection{Változótípusok}
A nyelv ismertetését kezdjük a változótípusokkal! A Perl nem szab határt a változók méretére, egy tömbbe akár egy több megabájtos fájlt is betölthetünk (felső korlátot persze azért a hardver szab). Három változótípus áll rendelkezésünkre: változó, tömb, asszociatív tömb. A változónevek típusát nevüknek első karaktere határozza meg:
\begin{itemize}
\item változó: \verb+$valtnev+
\item tömb: \verb+@tombnev+, tömbelem: \verb+$tombnev[index]+
\item asszociatív tömb: \verb+%atombnev+, tömbelem: \verb+$atombnev['index']+
\end{itemize}
Mivel a változónevek a típusuk szerint külön szimbólumtáblába kerülnek, így használhatunk akár ugyanolyan nevű ,,sima'' változót, tömböt és asszociatív tömböt is egyszerre.
\par
A Perl rendelkezik jónéhány beépített változóval is, nézzünk ezekből párat!
\begin{description}
\item[\$1,\$2,\dots]Reguláris kifejezésekből kapott betűk.
\item[\$\& vagy \$MATCH]A legutolsó mintaillesztésnél az illesztett rész.
\item[\$` vagy \$PREMATCH]A legutolsó mintaillesztésnél a \$MATCH előtti rész.
\item[\$' vagy \$POSTMATCH]A legutolsó mintaillesztésnél a \$MATCH utáni rész.
\item[\$. vagy \$NR]Az utolsó beolvasott sor sorszáma.
\item[\$/ vagy \$RS]Az input rekordokat elválasztó karakter. Alapértelmezésben ez az újsor karakter.
\item[\$$\backslash$ vagy \$ORS]Az output rekordokat elválasztó karakter (amit a \verb+print+ kiír minden sor végére). Alapértelmezésben ez a változó üres.
\item[\$\$ vagy \$PID]A processz azonosítója.
\item[\$< vagy \$UID]A programot indító felhasználó valódi user id-je.
\item[\$> vagy \$EUID]A futás közbeni jogok tulajdonosa.
\item[\$0]A programot indító parancs neve.
\item[@ARGV]A parancssori argumentumok listája.
\item[\%ENV]A környezeti változók.
\end{description}
\subsection{Vezérlési szerkezetek}
A Perl utasításait ; karakter választja el egymástól, továbbá az egyszerű utasítások végrehajtásához is köthetünk feltételeket: \verb+print "Hello World!" if $nem_koszontem_meg;+ A lehetséges módosítók: if, unless, while, until.
\par
Most nézzük meg a vezérlési szerkezeteket.
\begin{itemize}
\item Szelekciós: \verb+if (feltétel) { blokk } [[elsif (feltétel) { blokk} ...] else { blokk }+
\item Szelekciós 2: \verb+unless (feltétel) { blokk } [else { blokk }]+
\item Számlálásos: \verb+for (kezdőérték;feltétel;iteráció) { blokk }+
\item Számlálásos 2: \verb+foreach változó (tömb) { blokk }+
\item Kezdőfeltételes: \verb+while (feltétel) { blokk }+
\item Végfeltételes: \verb+do { blokk } while (feltétel)+
\item Végfeltételes 2: \verb+do { blokk } until (feltétel)+
\end{itemize}
Használhatjuk a ,,szokásos'' kontroll szavakat is:
\begin{itemize}
\item next: átlép a következő iterációra.
\item last: az előző iterációs lépés.
\item redo: az aktuális iteráció ismétlése.
\item return: visszatérés.
\end{itemize}
\subsection{Operandusok}
Használhatjuk a C-ből és a shell programozásból megismert operátorok (\verb.++., \verb+--+, \verb+**+, \verb+!+, \verb+<<+, \verb+>>+, stb), de van pár ,,új'' operátor is:
\begin{description}
\item[x]Ismétlés. Például \verb+"la"x3+ eredménye \verb+"lalala"+.
\item[.]Konkatenáció. Például \verb+"Hello "."world!"+ eredménye \verb+"Hello world!"+.
\item[lt, gt, le, qe, eq, ne, cmp]Használhatóak a szövegek összehasonlítására.
\item[..]Tartomány meghatározása.
\end{description}
\subsection{Beépített függvények}
Az standard C függvények mind ,,megvannak'' a Perl-ben is, nyugodtan használhatjuk őket. Ha egyes függvények ,,gyanúsan'' viselkednek, használjuk a POSIX modult: \verb+use POSIX;+
\par
A Perl-hez ezen kívül rengeteg modul létezik (például SQL, hálózati programok, stb.), nézzünk néhány érdekesebb beépített függvényt:
\begin{description}
\item[caller]Megmondja, hogy mi hívta az aktuális programrészt.
\item[chop]Levágja az utolsó karaktert a sztring végéről. Hasznos lehet például sor vége ($\backslash$n) karakterek ,,eltüntetésére''.
\item[defined KIFEJEZÉS]Megmondja, hogy a megadott kifejezésnek van-e értéke.
\item[delete KIFEJEZÉS]Egy elem törlése egy asszociatív tömbből.
\item[each ASSZOC\_{}TÖMB]Egy asszociatív tömb elemeit iterálja. Ha ki szeretnénk írni az összes környezeti változót: \verb+while (($nev,$ertek) = each %ENV) { print "$nev = $ertek"; }+
\item[exists KIFEJEZÉS]Megmondja, hogy létezik-e az asszociatív tömb megadott eleme.
\item[my KIFEJEZÉS]A megadott változók csak az adott blokkban lesznek láthatóak.
\item[open FÁJLLEÍRÓ, KIFEJEZÉS]A kifejezésben leírt fájl megnyitása a megadott fájlleíróba.
\begin{itemize}
\item Megnyitás olvasásra: \verb+open(R,"<inputfile");+
\item Megnyitás írásra: \verb+open(R,">outfile");+
\item Megnyitás írásra és olvasásra: \verb+open(R,"file");+
\item Olvasás pipe-ból: \verb+open(R,"finger|");+
\item Írás pipe-ba: \verb+open(R,"|head");+
\end{itemize}
\item[close FÁJLLEÍRÓ]Bezárja a megadott fájl(leíró)t.
\item[print FÁJLLEÍRÓ LISTA]Lista tartalmát beleírja a FÁJLLEÍRÓ által meghatározott fájlba. Ha nincs fájlleíró megadva, akkor a stdout-ra ír.
\item[sort LISTA]Lexikografikus rendezést hajt végre a listán.
\item[undef KIFEJEZÉS]Változó megszüntetése.
\end{description}
\subsection{Mintaillesztések}
Mintaillesztésre két operátor szolgál: =\~{} az illeszkedés, !\~{} pedig a nem illeszkedés. Nézzünk pár példát:
\begin{itemize}
\item \verb+$sor =~ /izé/;+ hasonló, mint a grep.
\item \verb+$sor =~ s/izé/mizé/;+ hasonló, mint a sed-nél a csere.
\end{itemize}
Persze reguláris kifejezéseket\footnote{Az előző fejezet szerintieket, tehát: \^{}, ., \$, |, (), [], *, +, ?, \{\}} is használhatunk.
\clearpage
\section{A GNU {\scshape m4} makróprocesszor, és az {\scshape m4} makrónyelv}
\subsection{Bevezető}
A GNU ,,{\scshape m4}''\footnote{Néhány ember úgy gondolja hogy az {\scshape m4} megfelel a szenvedélyeinek. Ők először csak egyszerű problémák megoldására használják az m4-et, később egyre és egyre nagyobb kihívást látnak benne, és megtanulják, hogyan írjanak komplex {\scshape m4} makróhalmazokat. Egyszer-csak függővé válnak tőle, és a felhasználó szokásává válik mesterkélt {\scshape m4} alkalmazások írása a problémák megoldása, még akkor is, ha az {\scshape m4} szkriptek hibakeresésnek több időt szentel mint a valódi munkának. Én figyelmeztettelek! Az {\scshape m4} káros lehet a megszállott programozók egészségére!} egy implementációja a hagyományos Unix makrófeldolgozónak. A makróprocesszor dolga hogy a bemenetét a kimenetére másolja át, és terjessze ki a benne található makrókat. (Lásd pl. \verb+#include<inklúdfájl.h>+ a C előfeldolgozóban.) Ezek a makrók lehetnek beépítettek vagy a ,,felhasználó'' által definiáltak, és akárhány argumentumuk lehet.\par
Az egyszerű makrókifejtés mellett az {\scshape m4} képes beilleszteni egy megnevezett fájlt, parancsot lefuttatni, egész aritmetikai műveleteket végezni, a szöveget számos módon manipulálni, rekurzióra, stb. Akár egy előtét is lehet egy programfordító elé. (Végül-is ennek speciális esetének tekinthető, amikor az autoconf elkészíti nekünk a configure scriptet.)
\subsection{A használat alapjai}
Természetesen az {\scshape m4} használható lebutítva, az eredeti {\scshape System V} beli makróprocesszorral kompatibilisen is, ha a \verb+-G+ vagy \verb+--traditional+ kapcsolót megadjuk neki.\par
A {\scshape C}-hez hasonlóan itt is lehet a \verb+-Ikönyvtár+ vagy \verb+--include=könyvtár+ paraméterrel további include könyvtárakat adni.\par
Elérhető az is, hogy az {\scshape m4} eredeti beépített makrói megjelölsére kerüljenek oly-módon, hogy mindegyik neve elé odakerüljön az ,,\verb+m4_+'' prefixum, ha a \verb+-P+ vagy \verb+--prefix-builtins+ paramétert is megadjuk. Például az eredeti \verb+define+ helyett így \verb+m4_define+-t kell írni.\par
A {\scshape gcc} ill. {\scshape cpp}-hez hasonlóan itt is használhatóak a \verb+-DNÉV+ , \verb+-DNÉV=ÉRTÉK+ , \verb+-UNÉV+ és \verb+-UNÉV=ÉRTÉK+ paraméterek.
\subsection{Lexikai és szintaktikus konvenciók}
\begin{description}
\item[Makró nevek]Szokás szerint, egy név állhat betűkből, számjegyekből, és az \textunderscore{} karakterből, ahol a bevezető karakter nem számjegy. Ha egy névhez tartozik makródefiníció, akkor az a makró kifejtésre fog kerülni.\\Példák helyes nevekre: \verb+ize+, \verb+_tmp+, \verb+nev01+.
\item[Idézett szövegek]Az idézet szöveg egy karaktersorozat, amit az \verb+`+ kezdő és az \verb+'+ záró idézőjelek vesznek körül, ahol-is a kezdő és a záró idézőjelek a szövegben egyensúlyban vannak. A ,,sztring token'' értéke az lesz, mintha az idézőjelekből egy szintet elhagynánk. Így pl. a \verb+`'+ egy üres sztring lesz, és az \verb+``idézet''+ értéke pedig \verb+`idézet'+ lesz.\footnote{Az idézőjeleket jelentő karakter bármikor megváltoztatható. Lásd a {\tt changequote} makrót.}
\item[Egyéb tokenek]Minden karakter ami nem egy név része, vagy egy idézett sztringé, önmagában is egy token.
\item[Megjegyzések]Az {\scshape m4} alapesetben a \verb+#+ és újsor karakterek közé tett szöveget megjegyzésként tekinti. Minden karaktert ami megjegyzést határoló jelek közt van, figyelmen kívül hagy, de az egész megjegyzés (,beleértve a határolójeleit is) keresztül megy az {\scshape m4}-en és átkerül annak a kimenetére, vagyis az {\scshape m4} nem dobja el a megjegyzéseket.\\
A megjegyzéseket nem lehet beágyazni, olyan-értelemben, hogy az első újsor karakter egy \verb+#+ után lezárja a megjegyzést. A ,,megjegyzés effektus'' elkerülhető ha a bevezető megjegyzés karaktert idézőjelbe tesszük.\footnote{A megjegyzéseket határoló jelek is megváltoztathatók tetszőleges sztringre, bármikor, ha a beépített {\ttfamily changecom} makrót használjuk.}
\end{description}
\subsection{Makrók}
\subsubsection{Makró meghívása}
Egy makró meghívása egyszerűen annyi, hogy leírjuk a makró nevét \verb+név+ feltéve, hogy nincsenek argumentumai. Egyébként a \verb+név(arg1, arg2, ..., argN)+ forma használatos.\par
A makróknak tetszőleges számú argumentumuk lehet. Minden egyes argumentum egy sztring, de különböző makrók, különböző módon értelmezhetik az argumentumokat.\\
A nyitó zárójelnek közvetlenül a makró neve után kell álljon, és nem lehet közte szóköz. Ha ez nem így van, akkor a makró teljesen argumentumok nélkül hívódik meg.\par
Ha egy olyan makrót hívunk meg, amelynek nincsenek argumentumai, akkor a zárójeleket kötelező kihagyni, ugyanis a \verb+makrónév()+ hívás nem úgy értelmeződik, mintha argumentum nélkül hívtuk volna meg a makrót, hanem úgy mintha egy argumentummal hívtuk volna meg, és az az egy argumentum pedig egy üres sztring.
\subsubsection{Makró meghívásának elkerülése}
Az {\scshape m4} makrónyelv nagy fejlődése az őt megelőző makróprocesszorokhoz képest, hogy képes felismerni a makróhívásokat anélkül, hogy azt valami speciális bevezetőkarakterrel jeleznénk számára. Bár ez általában hasznos dolog, időnként nemszándékos makróhívásokat eredményezhet. Így a {\scshape GNU m4} számos mechanizmust vagy technikát kínál ara, hogy elkerüljük, hogy neveket makróhívásokként ismerjen fel.\par
Először-is tudni kell, hogy számos beépített makrót nem lehet értelmesen meghívni argumentumok nélkül. Ezen makrók bármelyikére igaz, hogyha nem követi egy nyitó zárójel, ott nem váltódik ki (,,triggerelődik'') makróhívás. Ez a legtöbb ilyen szokványos esetet megoldja, mint például az \verb+include+ és \verb+eval+ esetén.\par
Használható még a bevezetőben említett \verb+-P+ kapcsoló, ami előírja hogy a beépített makrók meghívásakor a \verb+m4_+ prefixet használjuk a makrónevekben. Ellenben ez az opció nincs hatással a felhasználó által definiált makrók neveire.\par
A legegyszerűbb módja, hogy megelőzzük egy létező makró kifejtését, ha idézőjelbe tesszük. Habár a beidézést alkalmazhatjuk az egész makrónévre, lehetőség van arra is, hogy egy üres sztringet tegyünk idézőjelbe, de ez csak a makrón belül működik. Tehát az alábbi esetekben nem kerüli el a makrókifejtést:\index{peldak}{m4 makrókifejtés elkerülése}
\begin{verbatimtab}
	`'eltérít
	eltérít`'
\end{verbatimtab}\par
Míg ezen példákban a makrókifejtés elkerülésre kerül:
\begin{verbatimtab}
	`eltérít'
	`e'ltérít
	el`tér'ít
	elté`'rít
\end{verbatimtab}\par
A makrókifejtések értékei mindig újraolvasódnak. Az alábbi példa a \verb+de+ sztringet adja, pontosan mintha az {\scshape m4}-nek a \verb+subsr(abcde, 3, 2)+-t adtuk volna bemenetül:\index{peldak}{m4 makró értelmezés újraolvasása}
\begin{verbatimtab}
	define(`x', `substr(ab')
	define(`y', `cde, 3, 2)')
	x`'y
\end{verbatimtab}\par
Az olyan idézőjelbe nem tett sztringek, amelyek valamelyik oldalán álnak egy idézőjelbe tett sztringnek ki vannak téve annak a lehetőségnek, hogy makrónevekként legyenek felismerve. Az alábbi példában az üressztring lehetővé teszi a dnl makrónak, hogy akként ismerődjön fel ami (vagyis makróként):
\begin{verbatim}
        define(`macro', `di$1')
        macro(v)`'dnl
\end{verbatim}\par
Ha nem lennének ott az idézőjelek, akkor megengedné a \verb+divdnl+ sztringet egy sorvégjellel lezárva azt.\par
Az idézés megelőzheti azt is, hogy egy makrónevet ismerjen fel, ott ahol egybevon egy kifejtett makrót az őt körülvevő makrókkal. Vagyis az alábbi példa:
\begin{verbatim}
        define(`macro', `di$1')
        macro(v)`ert'
\end{verbatim}\par
a bemenet a \verb+divert+ sztringet állítja elő. Ha az idézőjelet eltávolítanánk, akkor a \verb+divert+ makró meghívásra kerülne.
\subsubsection{Makrók argumentumai}
Amikor egy nevet lát az {\scshape m4} és ahhoz létezik makródefiníció, azt makróként kifejti. Ha a nevet egy nyitó zárójel követi, akkor előbb az argumentumokat begyűjti, mielőtt a makrót kifejtené. Ha túl kevés argumentum van megadva, akkor a hiányzó argumentumokat üressztringnek tekinti. Ha több argumentum van, akkor pedig a további argumentumokat figyelmen kívül hagyja.\footnote{Vajon gondoltak arra a fejlesztők, hogy vmi egyszerű módon ezt a tulajdonságot fel lehetne használni {\itshape megjegyzés} készítésére?}\par
Alapesetben az {\scshape m4} figyelmeztet ha a beépített makrókat nem megfelelő számú argumentummal hívjuk meg, de ezt el lehet folytatni a \verb+-Q+ parancssori opcióval. A felhasználó által definiált makrók esetén nincs az argumentumok számára vonatkozó ellenőrzés.\par
A makrókat normális esetben az argumentumgyűjtés során is kifejtésre kerülnek, legyen bennük vessző, idézőjel, vagy zárójel, így a kifejtett szöveg szintén argumentum célját látja el. Így ha feltesszük, hogy az \verb+izé+ makrónév a \verb+, b, c+ szövegre fejtődik ki, akkor a \verb+mizé(a izé, d)+ egy olyan makróhívás, ahol négy argumentum van, ezek rendre: \verb+a+, \verb+b+, \verb+c+ és \verb+d+. Hogy megértsük, hogy az első argumentum itt miért tartalmaz (könnyű)szóközt, emlékezzünk rá, hogy a bevezető idézőjellel körbe nem vett (könnyű)szóköz soha nem része az argumentumnak, ellenben a záró szóköz viszont igen.
\subsubsection{Az argumentumok idézése}
Minden argumentumból a bevezető (könnyű)szóközök eltávolításra kerülnek. Minden egyes argumentumban, az összes idézőjelbe nem tett zárójelnek kell legyen párja. Például ha az \verb+izé+ egy makró, akkor az \verb+izé(() (`(') `(')+ egy makróhívás, aminek egy argumentuma van, aminek az értéke \verb+() (() (+.\par
Általános gyakorlat, hogy a makrók minden argumentumát idézőjelek közé tegyük, kivéve ha pont azt szeretnénk, hogy az argumentumok kifejtésre kerüljenek. Ennek megfelelően a fenti példát ha áttekinthetően szeretnénk kivitelezni a zárójelekkel, akkor a nagykönyvbeli alak így néz ki: \verb+izé(`() (() (')+
\subsubsection{Makró kifejtésének menete}
Amikor argumentumok, ha vannak, mind begyűjtésre kerültek, a makró kifejtésre kerül, és a kifejtett szöveg visszakerül a bemenetre (nem bezárva idézőjelek közé), és újraolvasódik. A kifejtett szöveg egy makróhívás során további makróhívásokat eredményezhet.\par
Vegyünk egy egyszerű példát: Az \verb+izé+ a \verb+mizé+ szövegre fejtődik ki, és a \verb+mizé+ pedig a \verb+Hello world+ szövegre. Így ha a bemeneten találunk egy \verb+izé+-t, akkor az először kifejtődik \verb+mizé+-re, majd mikor újraolvasódik, akkor kifejtődik \verb+Hello world+-re.
\subsection{Definíciók}
\subsubsection{Új makró definiálása}
A makró definiálás a beépített \verb+define+ makróval megy. Melynek módja a következő:
\begin{verbatimtab}
	define(NÉV [, KIFEJTÉS])
\end{verbatimtab}\par
Ez a mód definiálja a \verb+NÉV+ nevű makrót, amit az {\scshape m4} \verb+KIFEJTÉS+-re fog kifejteni. Ha a \verb+KIFEJTÉS+ nincs megadva, akkor az üresnek számít. A define makró üres szövegre fog kifejtődni. A makródefiníció helyén egy új sor meg fog jelenni, ha a makródefiníció után jön egy új sor, amit az {\scshape m4} konzekvensen bemásol a kimenetre, de ez elkerülhető a dnl makróval.
\subsubsection{A makrók argumentumai}
A makróknak lehetnek argumentumai. Az N-edik argumentumot a \verb+$n+-el jelöljük a kifejtendő szövegben. Vagyis például a \verb+$1+ az első argumentumra fog kifejtődni.\par
A \verb+define(`exch', `$2, $1')+ makródefiníció egy olyan makrót definiál, ami a neki átadott két argumentumot felcseréli. Így például a \verb+define(exch(``kifejtendő szöveg'', ``macro''))+ makródefiníció egy \verb+macro+ nevű makrót definiál, amely kifejtve \verb+kifejtendő szöveg+-re fejtődik ki.\par
A {\scshape GNU m4} megengedi, hogy a \verb+$+ után több számjegy is álljon, lehetővé téve, hogy bármilyen számú argumentuma legyen. Ez nem teljesül az {\scshape m4} egyéb {\scshape unix} implementációira, amelyek csak egy számjegyet ismernek fel a \verb+$+ után.\par
Létezik még egy speciális eset, a \verb+$0+ argumentum, ami az éppen kifejtett makró nevére fejtődik ki. Ha azt szeretnénk hogy idézőjelbe tett szöveg megjelenjen a beágyazott szöveg részeként, akkor ne feledjük, hogy idézőjeleket beágyazhatunk az ,,idézett'' szövegbe. Így a \verb+define(`izé', `Ez az `izé' makró.')+ makródefiníció az \verb+izé+-t \verb+Ez az izé makró+ szövegre\footnote{Ne feledjük, hogy a makrónevek csak számokat, az aláhúzásjelet, és az angol abc betűit tartalmazhatják, így a fenti példákban érvénytelenek a makrónevek a magyar ékezetes betűk miatt. Azok csak az egyszerűbb szemléltetés miatt tartalmaznak ékezetet!} fejti ki.
\subsubsection{Pszeudó argumentumok}
Van egy speciális jelzés a makrónak átadott argumentumok számának jelzésére. A makró hívásakor átadott argumentumok számát a \verb+$#+-al jelölhetjük a kifejtett szövegben. Így a makró megjelenítheti, hogy hány argumentuma van.\\
Példa: \verb+define(`nargs', `$#')+ definiálja az \verb+nargs+ nevű makrót, amely arra fejtődik ki, hogy hány argumentumot adtunk neki át. Például a \verb+nargs+ \verb+0+-ra fejtődik ki, a \verb+nargs()+ 1-re fejtődik ki (, ugye mindenki emlékszik, hogy a \verb+()+-el meghívott makrónak egy üressztring átadódik paraméterül), és az \verb+nargs(arg1, arg2, arg3)+ makróhívás \verb+3+-ra fejtődik ki.\par
A \verb+$*+ szimbólum a kifejtődés során, a makrónak átadott összes paramétert visszaadja a kifejtés során, vesszővel elválasztva azokat.\footnote{Hasonlít a shell {\tt \$0}jához.} Így ha definiálunk egy makrót a következőképp \verb+define(`visszhang', `$*')+, akkor a \verb+visszhang(arg1,    arg2, arg3   , arg4)+ makróhívás a \verb+arg1,arg2,arg3   ,arg4+-re fejtődik ki.\footnote{Ne feledjük, hogy a vessző után álló bevezető szóközök nem számítanak be az argumentumba, de az argumentum végén a következő vesszőig/lezáró zárójelig tartó szóközök viszont igen.} \par
A \verb+$@+ szimbólum hasonló az előzőhöz, avval a különbséggel, hogy minden egyes argumentum idézve jelenik meg. Így ha a makródefiníciónk a következő: \verb+define(`visszhang', `$@')+, akkor a \verb+visszhang(arg1, arg2, arg3  , arg4)+ az \verb+arg1,arg2,arg3  ,arg4+ szövegre fejtődik ki. Nyilván jogos a kérdés, hogy akkor hova lettek az idézőjelek. Noss természetesen, amikor az {\scshape m4} kifejtette a makrót, visszatolta a bemenetére, és az idézőjeleket megette. Hogy lássuk a különbséget hajtsuk végre az alábbi kísérletet:\index{peldak}{m4 idézett argumentumok szemléltetése}
\begin{verbatim}
$ cat <<'END' >proba.m4
define(`vissz1', `$*')dnl
define(`vissz2', `$@')dnl
define(`ize', `Ez az `ize' makro')dnl
vissz1(ize)
vissz2(ize)
END
$ m4 proba.m4
Ez az Ez az ize makro makro
Ez az ize makro
\end{verbatim}\par
Ha a \verb+$+ után nem áll semmi olyan, amit az {\scshape m4} értelmezni tudna, akkor a \verb+$+ egyszerűen átmásolódik a kimenetre. Ha szeretnénk egy olyan makrót, amelyben valami ilyesmi szöveg van mint az \verb+$12+, akkor a \verb+$+ után írjunk egy üres idézőjelet, így: \verb+$`'12+.
\subsubsection{Makró törlése}
Egy definiált makró egyszerűen eltávolítható az \verb+undefine+ makróhívással. Viszont figyeljünk arra, hogy a makró nevét szükségszerűen zárójelbe kell tegyük, különben az {\scshape m4} kifejti a makrót, még mielőtt definiálatlanná tenné!\par
Ha az \verb+undefine+-nak olyan makrónevet adunk meg, amire vonatkozóan nincs makródefiníció, akkor az nem számít hibának. Ilyenkor az \verb+undefine+ nem csinál semmit.\footnote{Az {\tt undefine} makrót csak paraméterrel ismeri fel a makróprocesszor.}
\subsubsection{Makró átnevezése}
Lehetőség van már definiált makró átnevezésére is. Hogy ezt megtehessük, szükségünk lesz a \verb+defn+ nevű beépített makróra, ami az argumentumul kapott makrónév idézőjeles definícióját szolgáltatja. Ha az argumentuma nem egy definiált makró, akkor a kifejtése üres. Ha az argumentumul megadott makrónév egy felhasználó által definiált makró, akkor egyszerűen az idézőjeles definícióját adja vissza. Egyébként, ha egy beépített makró, akkor a kifejtés egy speciális tokent ad eredményül, ami a beépített makró belső definíciójára mutat. Ennek a tokennek csak akkor van jelentősége, ha az egy \verb+define+ makró második argumentuma (vagy egy \verb+pushdef+ makróé), egyéb környezetekben figyelmen kívül lesz hagyva.\par
Íme egy példa, hogyan nevezzük át az \verb+undefine+ makrót \verb+zap+-ra:\\
\verb+define(`zap', defn(`undefine'))+. Ilymódon a \verb+defn+ felhasználható makródefiníciók másolására, még akkor is, ha beépített makróról van szó. Még akkor is, ha az eredeti makródefiníciót eltávolítottuk, a másolat makrónév még mindig használható a definíció elérésére.\footnote{A {\tt defn} makrót csak paraméterekkel hajlandó felismerni a makróprocesszor.}
\subsubsection{Makrók ideiglenes felüldefiniálása}
Lehetőség van makrók definíciójának ideglenes felüldefiniálásra, és visszatérni az eredeti makródefinícióra egy későbbi időpontban. Ezek a műveletek a beépített\\
\verb+pushdef(NÉV [, KIFEJTÉS])+ és a \verb+popdef(NÉV)+ makrókkal tehetők meg, amelyek a \verb+define+ és \verb+undefine+ makrók analogonjai. Ebben a modellben a makrók úgy működnek mint egy verem szerű szerkezet. Egy makrót átmenetileg újradefiniálhatunk a \verb+pushdef+ makróval, ami lecseréli az épp aktuális definícióját a \verb+NÉV+ nevű makrónak, miközben a korábbi definíciót is elmenti, még mielőtt az újjal felülírná. Ha nincs korábbi definíciója a makrónak, akkor a \verb+pushdef+ pontosan úgy működik, mint a \verb+define+.\par
Ha egy makrónak már számos definíciója van (amelyből természetesen csak egy érhető el egyszerre), akkor a legfelső definíciót eltávolíthatjuk a \verb+popdef+ makróhívással. Ha nincs további definíciója a makrónak, akkor a \verb+popdef+ pontosan úgy viselkedik mint az \verb+undefine+.\par
Ha egy makrónak már van néhány definíciója, akkor a \verb+define+ pontosan csak a legfelsőt cseréli ki. Ellenben ha egy makrónak a definícióját eltávolítjuk az \verb+undefine+-al, akkor az az összes definíciót eltávolítja, nem csak a legfelsőt.
\subsubsection{Makró közvetett meghívása}
Bármilyen makró meghívható közvetett módon is az \verb+indir+ makróval, melynek szintaktikája a következő:
\begin{verbatimtab}
indir(NÉV, ...)
\end{verbatimtab}\par
Ami azt eredményezi, hogy a \verb+NÉV+ nevű makró meghívódik, és a további argumentumok átadódnak neki. Ez használható arra, hogy meghívjunk olyan makrókat, melyeknek ,,érvénytelen''\footnote{Az eredeti szöveg szerint ,,illegális''} neve van.\footnote{A {\tt define} megengedi az ilyenek létrehozását is.}\par
Ennek az lehet az értelme, hogy nagyobb makrócsomagoknak lehessenek belső privát makrói, amelyeket véletlenül nem lehet meghívni, csak az \verb+indir+ makróhíváson keresztül.
\subsubsection{Beépített makrók közvetett hívása}
Beépített makrókat közvetetten is meg lehet hívni a \verb+builtin+ makróval, amelynek a szintaktikája a következő:
\begin{verbatimtab}
	builtin(NÉV, ...)
\end{verbatimtab}\par
Ami azt eredményezi, hogy a \verb+NÉV+ nevű makró meghívódik, és a további argumentumok, pedig átadódnak neki. Ez használható akkor is, ha a \verb+NÉV+ nevű makrónak adtunk egy másik definíciót, ami elrejti az eredetit.\par
A \verb+builtin+ makrót csak paraméterekkel ismeri fel a makróprocesszor.
\subsection{Feltételek, hurkok, vezérlési szerkezetek}
Az egyszerű makrók, amelyeket egyszerű szövegre kifejtünk, esetleg argumentumai vannak, nem feltétlenül nyújtanak nekünk elég funkcionalitást. Ezért hasznos, ha futásidőben eldőlő döntéseket is meg lehet hozni. Például szükségünk van feltételekre, valamilyen ciklus szerű vezérlési szerkezetre. Így valamit egy adott számszor vagy amíg egy feltétel igaz, végre tudunk hajtani.
\subsubsection{ifdef}
Az {\scshape m4}-ben két különböző típusú feltételes elágazás van. Az egyik ilyen az \verb+ifdef+, melynek szintaktikája a következő:
\begin{verbatimtab}
	ifdef(NÉV, STRING1, opt STRING-2)
\end{verbatimtab}\par
Ez lehetővé teszi, hogy ellenőrizzük, hogy egy makró definiálva van-e már, vagy nincs. Ha a \verb+NÉV+ egy már definiált makró, akkor az \verb+ifdef+ a \verb+STRING1+-re fejtődik ki, egyébként a \verb+STRING2+-re. Ha a \verb+STRING2+ hiányzik, akkor üressztringnek veszi a makróprocesszor (hivatkozva a normális szabályokra).\par
Íme egy egyszerű példa:\\
\verb+ifdef(`izé', `az `izé' definiált', `az `izé' nem definiált')+\par
Az \verb+ifdef+ makrót csak paraméterekkel ismeri fel a makróprocesszor.
\subsubsection{ifelse}
A másik feltételes elágazási lehetőség az \verb+ifelse+, ami sokkal többet tud. Lehet használni arra is, hogy csináljunk egy hosszú megjegyzést, vagy egy if-else szerkezetre, vagy egy többágú elágazási szerkezetre, függően a megadott argumentumok számától:
\begin{verbatimtab}
	ifelse(MEGJEGYZÉS)
	ifelse(STRING1, STRING2, EGYENLŐ, opt NEMEGYENLŐ)
	ifelse(STRING1, STRING2, EGYENLŐ, ...)
\end{verbatimtab}\par
Ha csak egy argumentummal hívjuk meg, akkor az \verb+ifelse+ egyszerűen eldobja azt, és nem képződik kimenet. Ez az általános {\scshape m4} stílus, hogy bevezessünk egy blokk-megjegyzést, a \verb+dnl+ alternatívájaként. Ezt a speciális felhasználást felismeri a {\scshape GNU m4}, így amikor csak egy argumentummal hívjuk meg nem váltódik ki figyelmeztető üzenet.\par
Ha három, vagy négy paraméterrel hívjuk meg, akkor az \verb+ifelse+ az \verb+EGYENLŐ+ szöveg kerül kifejtésre, amennyiben a \verb+STRING1+ és a \verb+STRING2+ szövegek megegyeznek (karakterről karakterre), egyébként pedig a \verb+NEMEGYENLŐ+ szöveg.\par
Egy egyszerű példa: \verb+ifelse(izé, mizé, `igaz', `hamis')+\par
Egyébként az \verb+ifelse+ meghívható, több mint négy argumentummal is. Ha több mint négy argumentuma van, akkor az \verb+ifelse+ úgy működik, mint egy hagyományos \verb+case+ vagy \verb+switch+ szerkezet az egyéb hagyományos programozási nyelvekben. A működés módja ilyen esetben a következő: Ha a \verb+STRING1+ és a \verb+STRING2+ egyenlők, akkor az \verb+EGYENLŐ+ szöveg helyettesítődik, egyébként az eljárás az első három argumentum eldobásával megismétlődik. Egy példa: \verb+ifelse(izé, mizé, `harmadik', répa, retek, `hatodik', `hetedik')+\par
Az \verb+ifelse+ makrót csak paraméterekkel ismeri fel a makróprocesszor.
\subsubsection{ciklusok}
Nincs közvetlen támogatás a ciklusok létrehozására az {\scshape m4}ben, de a makrók lehetnek rekurzívak. Nincs határ a rekurziók szintjére vonatkozólag, egyéb határokat csak a hardver és az operációs rendszer szabhat.\par
A fentiek alapján a ciklusokat le lehet programozni csak a feltételes elágazás és a rekurzió segítségével. Ehhez segítségünkre lesz még a \verb+shift+ makró is, mely többek közt képes arra, hogy a makrónak átadott argumentumain iterációt hajtsunk végre. A \verb+shift+ tetszőleges számú argumentumot kaphat, és kifejtve az összes argumentumát adja vissza vesszővel elválasztva, minden egyes argumentumot idézve, és kihagyva a legelső argumentumot.\par
Így pl. a \verb+shift(izé)+ egy üressztringre fejtődik ki, az \verb+(izé, mizé, bizé)+ pedig \verb+mizé,bizé+ lesz.\par
Íme egy példa arra, hogy hogyan csináljunk meg egy olyan makrót, amely kifejtve, az argumentumul kapott paramétereket adja, fordított sorrendben:\index{peldak}{m4 argumentumok sorrendjének megfordítása}
\begin{verbatim}
define(`forditott', `ifelse($#, 0, , $#, 1, ``$1'', `forditott(shift($@)), `$1'')')
\end{verbatim}
Vagyis itt a \verb+forditott(a, b, c, d)+ makróhívás a \verb+d, c, b, a+-ra fejtődik ki.\par
Egy másik példa azt szemlélteti, hogyan készíthetünk, egy egyszerű számlálásos for ciklust az {\scshape m4} eszközeivel:\index{peldak}{m4 forloop}
\begin{verbatim}
define(`forloop',
       `pushdef(`$1', `$2')_forloop(`$1', `$2', `$3', `$4')popdef(`$1')')dnl
define(`_forloop', `$4`'ifelse($1, `$3', ,
              `define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')')dnl
\end{verbatim}\par
És néhány példa az imént definiált \verb+forloop+ makró használatára:
\begin{verbatim}
forloop(`i', 1, 6, `i ')
forloop(`i', 1, 6, `forloop(`j', 1, 7, `(i, j) ')
')
\end{verbatim}
Mely kifejtve így néz ki:
\begin{verbatim}
1 2 3 4 5 6 
(1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (1, 6) (1, 7) 
(2, 1) (2, 2) (2, 3) (2, 4) (2, 5) (2, 6) (2, 7) 
(3, 1) (3, 2) (3, 3) (3, 4) (3, 5) (3, 6) (3, 7) 
(4, 1) (4, 2) (4, 3) (4, 4) (4, 5) (4, 6) (4, 7) 
(5, 1) (5, 2) (5, 3) (5, 4) (5, 5) (5, 6) (5, 7) 
(6, 1) (6, 2) (6, 3) (6, 4) (6, 5) (6, 6) (6, 7) 

\end{verbatim}
\subsection{Bemenet vezérlése}
\subsubsection{dnl}
A beépített \verb+dnl+ makró beolvas minden karaktert az utána következő első újsorkarakterig, beleértve az adott újsor karaktert is, és ezeket kitörli/eldobja. Általában arra szokás használni, hogy egy sorba leírjunk egy makródefiníciót, és a makró definiálásakor ne kerüljön fölöslegesen újsor a kimenetre.\par
Általában a \verb+dnl+ makrót egy újsor karakter követi közvetlenül. De ha véletlenül, egy nyitózárójelet találna utána a makróprocesszor, akkor figyelmeztető üzenetet küld, de begyűjti a dnl argumentumait (és persze kifejti őket), és végrehajtódnak az evvel járó mellékhatások. Ellenben minden kifejtett karakter, egész az újsorkarakterig ekkor is el lesz dobva.
\subsubsection{changequote}
A \verb+changequote+ makró segítségével megváltoztathatjuk az idézőjelet jelző sztringet. Így például, ha a \verb+changequote([, ])+ utasítást kiadjuk, akkor az \verb+izé+ makrónkat a következőképp tudjuk definiálni: \verb+define([izé], [[izé] makró.])+\par
Ha nem csak egy egyszerű karaktert adunk meg, akkor a kezdő és a záró zárójel akármilyen hosszú is lehet.\par
Ha az idézőjeleket üressztringre változtatjuk, akkor evvel átmenetileg effektíve minden idézőjelezési mechanizmust kiiktatunk, elzárva minden lehetőséget arra, hogy szöveget idézőjelbe tegyünk.\par
Az idézőjel nem kezdődhet sem betűvel, sem aláhúzásjellel, mert az ütközne a bemenetre kerülő nevekkel. Ha mégis így tennénk, akkor avval letiltjuk az idézési mechanizmust a makróprocesszorban.
\subsubsection{changecom}
A \verb+changecom+ makró segítségével beállíthatjuk, hogy mi legyen a megjegyzések kezdését és végét jelző sztring. Ha valamelyik argumentumát elhagynánk a makrónak, akkor az eredeti alapértelmezett megjegyzést határoló jelek lépnek életbe.\par
Ha pl. C stílusú megjegyzéseket szeretnénk, akkor használhatjuk a \verb+changecom(`/*', `*/')+ parancsot.\footnote{Arra figyeljünk, hogy a megjegyzés egyszerűen átmásolódik a kimenetre, mintha idézőjelbe tett szöveg lenne. Mindössze annyi a jelentősége, hogy a megjegyzésen belül nem hajtódik végre makrókiértékelés.}
\subsection{Fájl beillesztése}
Fájlok beillesztésére két makró is szolgál az {\scshape m4}ben:
\begin{verbatimtab}
	include(FÁJLNÉV)
	sinclude(FÁJLNÉV)
\end{verbatimtab}\par
Az include makró kifejtve, gyakorlatilag az argumentumul megadott fájl tartalma. Az hibához vezet és hibaüzenetet kapunk, ha az argumentumul adott fájl nem létezik. Ilyenkor a \verb+sinclude+ makrót használjuk, mert akkor ha nem létezik a fájl, egyszerűen továbbmegy a makróprocesszor.\par
A \verb+include+-al behozott fájlokban levő makrók is kiértékelődnek, stb.\par
A beépített \verb+include+ és \verb+sinclude+ makrókat a makróprocesszor csak akkor ismeri fel, ha adunk neki argumentumot.\par
Az {\scshape m4} lehetővé teszi, hogy más (nem csak az aktuális) könyvtárból származó fájlokat is beszúrhassunk. Ha egy fájlt nem talál az aktuális munkakönyvtárban, és a megadott fájl neve nem abszolút fájlnév, akkor a fájlt a megadott keresési útban végignézi. Először a \verb+-I+ kapcsolóval megadott könyvtárakban, majd pedig a \verb+M4PATH+ környezeti változó által jelzett könyvtárakban.
\subsection{A kimenet eltérítése, visszatérítése}
Az eltérítés egy módja annak, hogy átmenetileg elmentsük a kimenetet. Az {\scshape m4} kimenetét bármikor el lehet téríteni egy átmeneti fájlba, és újrabeszúrni a kimeneti folyamba (visszatéríteni) egy későbbi időpontban.\par
A számozott eltérítések $0$-tól felfele számozódnak, és a $0$ jelenti a normális kimeneti folyamot ({\slshape stream}). A párhuzamos eltérítések számát csak a leírásukhoz szükséges memória korlátozza.Egyébként létezik egy korlát ami az összesen felhasználható memóriát együttvéve korlátozza (, és ez aktuálisan 512K). Amikor a maximumot elérné, akkor egy átmeneti fájlt megnyit a makróprocesszor, és odateszi a legnagyobb eltérítés tartalmát, evvel memóriát felszabadítva a többi eltérítés számára. Így tehát elméletileg lehetséges, hogy az eltérítések számát a maximálisan elérhető fájlleírók ({\slshape file descriptor}ok) száma korlátozza.
\subsubsection{A kimenet eltérítése}
A \verb+divert+ makró szintaxisa:
\begin{verbatimtab}
	divert(opt SZÁM)
\end{verbatimtab} \par
Ahol a \verb+SZÁM+ a használandó eltérítés száma. Ha a számot nem adjuk meg, akkor alapértelmezett értékének a $0$-t kell feltételezni. A \verb+divert+ makró kifejtése üres sztring lesz.\par
Amikor az {\scshape m4} minden bemenetét feldolgozta, akkor minden létező eltérítést visszatérít, számsorrendben. Íme egy példa:\index{peldak}{m4 eltérítés}
\begin{verbatim}
divert(1)
Ez a szöveg el van térítve
divert
Ez a szöveg nincs eltérítve
\end{verbatim} \par
Amelyet ha az m4-el értelmezetünk, akkor a következő kimenetet kapjuk:
\begin{verbatim}

Ez a szöveg nincs eltérítve

Ez a szöveg el van térítve
\end{verbatim} \par
Ha többször ugyanavval az argumentummal meghívjuk a \verb+divert+-et, akkor az nem írja felül a benne levő korábbi szöveget, hanem hozzáfűzi azt.\par
Ha a kimenetet egy nemlétező eltérítésbe küldjük, akkor az egyszerűen eldobásra kerül. Ezt használhatjuk arra, hogy elkerüljük a nemkívánatos kimenetet. Egy általános példa arra, hogy a makródefiníciók utáni újsor karaktereket elnyeljük, ha a következő módon cselekszünk:\footnote{Természetesen a makródefiníció után írt dnl is jó, de amikor már sok definíciós sor van, akkor áttekinthetetlenné teszi a {\slshape forrás}szöveget.}\index{peldak}{m4 eldobott eltérítés}
\begin{verbatim}
divert(-1)
define(`izé', ``izé' makró.')
define(`mizé', ``mizé' makró.')
divert
\end{verbatim}
\subsubsection{A kimenet visszatérítése}
Az eltérített szöveg bármikor visszatéríthető explicit módon is az \verb+undivert+ beépített makró használatával, melynek a szintaxisa a következő:
\begin{verbatimtab}
	undivert(opt SZÁM, ...)
\end{verbatimtab} \par
Ez az argumentumul adott eltérítéseket visszatéríti, abban a sorrendben, ahogy argumentumul megadtuk. Ha nem adunk meg argumentumot, akkor az összes eltérítés visszatérítődik, számsorrendben.\par
Az \verb+undivert+ makró kifejtve szintén egy üressztring lesz.\par
Amikor egy eltérített szöveget visszatérítünk, azt nem olvassa újra az {\scshape m4}\footnote{értsd: nem fogja újra átnézni makrókifejtések után}, de ahelyett, hogy egyszerűen csak átmásolná azt a kimenetére, az is lehetséges, hogy egy eltérítést egy másik eltérítésbe térítsünk vissza:\index{peldak}{m4 visszatérítés}
\begin{verbatim}
$ cat <<'END' |m4
> divert(1)
> Először ezt térítjük el
> divert`'dnl
> Ez nincs eltérítve
> divert(-1)undivert(1)divert(1)dnl
> Ez is 1-esbe van eltérítve, de vissza fog jönni
> END
Ez nincs eltérítve
Ez is 1-esbe van eltérítve, de vissza fog jönni
\end{verbatim}\par
A {\scshape GNU m4} lehetővé teszi, hogy nevén nevezhető fájlokat térítsünk vissza. Ha egy nem-numerikus argumentumot adunk meg, akkor az argumentumul megadott fájlnév tartalma lesz bemásolva, értelmezés nélkül az aktuális kimenetre, ilymódon kiegészítve a beépített \verb+include+ makrót. Hogy lássuk a pontos különbséget íme egy példa:\index{peldak}{m4 include vs undivert}
\begin{verbatim}
$ cat <<'END' >foo
> bar
> END
$ cat <<'END' |m4
> define(`bar', `BAR')
> undivert(`foo')
> include(`foo')
> END

bar

BAR

\end{verbatim}
\subsubsection{Eltérítési számok}
Az aktuális eltérítés számát a beépített \verb+divnum+ makróval lehet megtudni. A dolog személtetésére egy példa:\index{peldak}{m4 divnum}
\begin{verbatim}
$ cat <<'END' |m4
> Initial divnum
> divert(1)
> Első eltérítés: divnum
> divert(2)
> Második eltérítés: divnum
> END
Initial 0

Első eltérítés: 1

Második eltérítés: 2
\end{verbatim}
\subsubsection{Eltérített szöveg eldobása}
Ha egy eltérített szöveget szeretnénk kitörölni, akkor azt tudjuk tenni, amit abban a példában láttunk, ahol az eltérített szöveget egy másik eltérítésbe térítettünk vissza. Ha egy olyan eltérítésbe térítünk vissza, ami eldobásra kerül, akkor el tudunk dobatni eltérítéseket. Pl. ha az input feldolgozás végén szeretnénk eldobni minden eltérítés tartalmát, ahelyett, hogy implicit módon visszatérítődjenek, akkor a következő írjuk az inputfájl végére:\index{peldak}{m4 minden eltérítés eldobása}
\begin{verbatim}
divert(-1)
undivert
\end{verbatim}
\subsection{A legfontosabb makrók rövid leírása}
\begin{description}
\item[len(STRING)]szöveg hossza. Pl \verb+len(`abcdef')+ => \verb+6+
\item[index(STRING, SUBSTRING)]Szövegrész keresése a szövegben. Pl.\\
\verb+index(`ecc, pecc, kimehetsz, holnapután bejöhetsz', `pecc')+ => \verb+5+. Az első karakter indexe \verb+0+, ha nem találta a szövegben, akkor \verb+-1+ lesz a kifejtés eredménye. 
\item[regexp(STRING, REGEXP, opcionális HELYETTESÍTŐ)]Reguláris kifejezés keresése a szövegben. Ha helyettesítő szöveg nincs megadva, akkor a REGEXP első előfordulása a STRING-ben, ill. ha semelyik részére nem illeszkedik, akkor -1. Ha van HELYETTESÍTŐ megadva, akkor végrehajtódik a szövegen a helyettesítés.
\item[substr(STRING, FROM, opt LENGTH)]A szöveg egy részének kivágása.
\item[translit(STRING, KARAKTEREK, HELYETTESÍTŐ)]A shell tr parancsához hasonló karakterfordítás.
\item[pathsubst(STRING, REGEXP, HELYETTESÍTŐ)]reguláris kifejezéssel való helyettesítés.
\item[format(FORMÁTUMSZTRING, ...)]printf szerű formázások.
\item[incr(SZÁM)]szám növelése.
\item[decr(SZÁM)]szám csökkentése.
\item[ecal(KIFEJEZÉS, opt RADIX, opt SZÉLESSÉG)]egész kifejezés kiértékelése.
\item[syscmd(SHELLPARANCS)]Shell parancs végrehajtása.
\item[esyscmd(SHELLPARANCS)]Shell parancs végrehajtása, a parancs kimenete lesz a kifejtés értéke.
\item[sysval]A legutoljára végrehajtott shellparancs exitkódja.
\end{description}
\subsection{{\scshape m4}-et használó rendszerek}
A teljesség igénye nélkül néhány olyan program ami az {\scshape m4}-et használja:
\begin{itemize}
\item autoconf
\item automake
\item sendmail
\item pcb
\item fvwm
\item debian linux külső kernel modulok
\end{itemize}
\clearpage
%\section{A GNU C library bevezetés}
%\clearpage
%\section{A GNU C, C++ library, egyéb free library-k}
\chapter{II. félév}
\section{A GNU autoconfba bevezető}
Az autoconf egy eszköz arra, hogy automatikusan shellszkripteket állítsunk elő, amely konfigurálja egy program forráskódját, hogy az számos UNIX-szerű rendszerhez tudjon illeszkedni. Az autoconf által előállított szkriptek függetlenek az autoconf-tól amikor futnak, így az már nem kell hogy a programforrást felhasználó oldalán telepítve legyen.\par
Az autoconf által előállított konfigurációs szkriptek nem igényelnek kézi beavatkozást amikor futnak, normális esetben még csak egy argumentumot se kell neki adni, ami az adott rendszer típusára vonatkozik. Ehelyett az teszteli minden egyes szükséglet jelenlétét, amelyeket a szoftvercsomag igényelhet. (Minden egyes ellenőrzés előtt kiír egy egysoros üzenetet amely utal arra, hogy épp mit ellenőriz, így a felhasználó nem unatkozik míg a szkript végez.) Az eredmény jól leírja az akár hibrid, vagy személyreszabott UNIX-variánsunk minden tulajdonságát, és nem kell fájlokat karbantartanunk, ami minden egyes UNIX-variáns tulajdonságait leírja.\par
Minden egyes autoconf-ot használó szoftvercsomag, létrehoz egy konfigurációs szkriptet egy mintafájlból ({\slshape template}) ami felsorolja, hogy milyen rendszertulajdonságokat igényel, vagy tud használni. Mivel a shell kód feladata, hogy felismerjen és reagáljon egy rendszertulajdonságra, az autoconf lehetővé teszi, hogy ezt a kódot több szoftvercsomag közt megosszuk, amely tudja használni vagy igényli ezt a rendszertulajdonságot. Ha később kiderülne, hogy ez a shellkód némi igazítást igényelne valamilyen okból kifolyólag, és azt egy helyen megváltoztatjuk, akkor az összes konfigurációs szkript(,mármint minden olyan szoftvercsomag konfigurációs szkriptje, amely az adott shellkódot használta az autoconfból) újragenerálható automatikusan, hogy kihasználhassa a javított kód előnyeit.\par
\begin{figure}[h]
\xy *+\txt{Forrás fájlok}="s" *\frm<8pt>{-},
(40,0)*+\txt{autoscan}="a" *\frm{-,},
(80,0)*+\txt{configure.scan}="c" *\frm{--},
(120,0)*+\txt{configure.in}="i" *\frm{=},
"s";"a" **\crvs{-} ?>*\dir{>},
"a";"c" **\crvs{-} ?>*\dir{>},
"c";"i" **\crvs{-} ?>*\dir{>}
\endxy
\caption{Az autoscan használata}
\end{figure}
\begin{figure}[h]
\xy *+\txt{configure.in}="a" *\frm<8pt>{-},
(0,-15)*+\txt{aclocal.m4}="b" *\frm{--},
(0,-25)*+\txt{acsite.m4}="c" *\frm{--},
(0,-40)*+\txt{acconfig.h}="d" *\frm{--},
(0,-55)*\txt{config.h.top}="e" *\frm{--},
(0,-65)*\txt{config.h.bot}="f" *\frm{--},
(30,-20)="g",
(30,-50)="h",
(40,-20)="i",
(40,-50)="j",
(50,-10)*\txt{autoconf}="k" *\frm{-,},
(50,-60)*\txt{autoheader}="l" *\frm{-,},
(80,-10)*\txt{configure}="m" *\frm{=},
(80,-60)*\txt{config.h.in}="n" *\frm{=},
(0,-70)*\txt{Makefile.in}="o" *\frm<8pt>{-},
(80,-70)*\txt{Makefile.in}="p" *\frm{=},
"a";"g" **\crvs{-} ?>*\dir{>},
"b";"g" **\crvs{-} ?>*\dir{>},
"c";"g" **\crvs{-} ?>*\dir{>},
"d";"h" **\crvs{-} ?>*\dir{>},
"e";"h" **\crvs{-} ?>*\dir{>},
"f";"h" **\crvs{-} ?>*\dir{>},
"g";"i" **\crvs{-} ?>*\dir{>},
"h";"j" **\crvs{-} ?>*\dir{>},
"i";"j" **\crvs{-},
"i";"k" **\crvs{-} ?>*\dir{>},
"j";"l" **\crvs{-} ?>*\dir{>},
"k";"m" **\crvs{-} ?>*\dir{>},
"l";"n" **\crvs{-} ?>*\dir{>},
"o";"p" **\crvs{-} ?>*\dir{>}
\endxy
\caption{Az autoconf használata}
\end{figure}
Számos olyan feladat van, amely szoftvercsomagok portolhatóságához kapcsolódik, amelyeket jelenleg az autoconf nem tud. Ezek közt van, hogy automatikusan létrehozzon \verb+Makefile+okat az összes konvencionális targettel, vagy hogy helyettesítést biztosítson a nem implementált sztandard könyvtári funkciók helyett, vagy hiányzó headerfájlokat olyan rendszeren amelyen az nincs meg.\par
Az autoconf megkövetel néhány megszorítást a makrónevekkel kapcsolatban amelyek C programok \verb+#ifdef+-jénél használhatók.\par
Az autoconf megköveteli a {\scshape GNU m4}-et is a scriptek generálásához, ugyanis használ néhány olyan {\scshape GNU} kiterjesztést is, amelyet más UNIX {\scshape m4} verziók nem támogatnak. Továbbá túlcsordítja néhány {\scshape m4}-verzió belső határait is, beleértve a {\scshape GNU m4} 1.0-t is. Hogy minden rendben legyen legalább az 1.1 verziójú {\scshape GNU m4}-et kell használni, de az 1.3 verzió sokkal gyorsabb mint az 1.1 vagy 1.2 verzió.\footnote{Egy nem túl újnak mondható verzió, ami a Debian {\scshape GNU}/Linux Woody (3.0) verziójában van, és már az is 1.4-es, tehát nem egy nehezen teljesíthető feltétel.}
\begin{figure}[h]
\xy *+\txt{configure}="a" *\frm{-,},
(0,-10)*+\txt{config.h.in}="b" *\frm{--},
(0,-20)*+\txt{Makefile.in}="c" *\frm{-},
(20,-15)="d",
(40,-15)*+\txt{config.status}="e" *\frm{-,},
(40,-5)="f",
(60,0)*+\txt{config.cache}="g" *\frm{-},
(60,-8)*+\txt{config.log}="h" *\frm{-},
(55,-20)="i",
(70,-15)*+\txt{config.h}="j" *\frm{-},
(70,-25)*+\txt{Makefile}="k" *\frm{-},
(80,-20)="l",
(90,-20)*+\txt{make}="m" *\frm{=},
"a";"f" **\crvs{-} ?>*\dir{>},
"f";"g" **\crvs{-} ?>*\dir{>},
"f";"h" **\crvs{-} ?>*\dir{>},
"f";"e" **\crvs{-} ?>*\dir{>},
"b";"d" **\crvs{-} ?>*\dir{>},
"c";"d" **\crvs{-} ?>*\dir{>},
"d";"e" **\crvs{-} ?>*\dir{>},
"e";"i" **\crvs{-} ?>*\dir{>},
"i";"j" **\crvs{-} ?>*\dir{>},
"i";"k" **\crvs{-} ?>*\dir{>},
"j";"l" **\crvs{-} ?>*\dir{>},
"k";"l" **\crvs{-} ?>*\dir{>},
"l";"m" **\crvs{-} ?>*\dir{>}
\endxy
\caption{A fenti fájlok felhasználása egy programcsomag fordításakor}
\end{figure}
Az autoconf által készített konfigurációs szkriptet konvecionálisan \verb+configure+-nak hívjuk. Amikor lefuttatjuk a \verb+configure+ számos fájlt létrehoz, belehelyettesítve konfigurációs paramétereket a megfelelő értékekkel. A configure által létrehozott konfigurációs fájlok:
\begin{description}
\item[Makefile]Egy vagy több \verb+Makefile+-t létrehoz a \verb+configure+ a csomag minden egyes alkönyvtárába.
\item[config.h]Opcionálisan egy C fejlécfájlt létrehoz a \verb+configure+ amely \verb+#define+ direktívákat tartalmaz.
\item[config.status]Létrehoz egy shell-szkriptet, amelynek feladata, hogy a fenti fájlokat újralétrehozza.
\item[config.cache]Létrehoz egy shell-szkriptet, amelynek feladata, hogy a tesztek eredményeit elmentse.
\item[config.log]Létrehoz egy logfájlt, amely a futtatás alatt a fordítóprogram által adott üzeneteket tartlmazza, hogy adott esetben könnyebb legyen a hibát megkeresni, ha a \verb+configure+ hibát vét.
\end{description}\par
Hogy létrehozzuk a \verb+configure+ szkriptet, meg kell írnunk egy \verb+configure.in+ nevű bemeneti fájlt, és ezen lefuttatnunk az \verb+autoconf+ parancsot. Ha saját {\slshape feature}-teszteket írunk, az \verb+autoconf+éit kiegészítendő, akkor azokat az \verb+aclocal.m4+ és \verb+acsite.m4+ fájlokba írhatjuk. Ha szeretnénk egy C fejlécfájlt, amely \verb+#define+ direktívákat tartalmaz, akkor írhatunk egy \verb+acconfig.h+ nevű fájlt is, és terjeszthetjük a szoftvercsomagban az autoconf által generált \verb+config.h.in+ fájlt is.
\subsubsection{A {\ttfamily configure.in} fájl áttekintése}
A \verb+configure.in+ fájl az autoconf csomag {\scshape m4} makróra vonatkozó hívásokat tartalmaz. Az autoconf már jónáhány makrót tartalmaz arra, hogy a rendszert és annak adottságait teszteljük vele. Amihez nem tartalmaz támogatást az autoconf, ott használhatjuk a mintáit ({\slshape template}jeit), hogy saját ellenőrzőrutinokat írjunk.\par
A \verb+configure.in+ fájl megírását nem a nulláról kell kezdeni, lásd az idevonatkozó \verb+autoscan+ használatát szemléltető ábrát. Az \verb+autoscan+ parancsot lefuttatva egy jó kiindulópontunk van a \verb+configure.in+ megírásához.\par
Annak a sorrendje, hogy a \verb+configure.in+ milyen sorrendben hívja meg a makrókat nincs különösebb jelentősége, néhány kivételtől eltekintve:
\begin{itemize}
\item Mindig az \verb+AC_INIT+ makróval kell kezdenünk
\item Mindig az \verb+AC_OUTPUT+ makróval kell befejeznünk
\item Továbbá néhány makró helyes működése azon múlik, hogy előtte bizonyos makrókat már használnunk kell, mert felhasználnak olyan értékeket, amelyek más makrók állítanak be előtte. Az ilyen esetek szerepelnek a makrók leírásaiban.
\end{itemize}
Ezen indokok miatt egy \verb+configure.in+ váza valahogy így néz ki: \label{configurein ajanlott sorrend}
\begin{verbatim}
`AC_INIT(FÁJL)'
programok meglétének ellenőrzése
könyvtárak (library) ellenőrzése
fejlécállományok (header) ellenőrzése
típusdefiníciók ellenőrzése
struktúrák ellenőrzése
programfordító (compiler) tulajdonságainak ellenőrzése
könyvtárfunkciók ellenőrzése
rendszerszolgáltatások ellenőrzése
`AC_OUTPUT([FÁJL...])'
\end{verbatim}
\subsubsection{Néhány általános jótanács az {\ttfamily configure.in} megírására}
Lehetőleg minden makróhívást tegyünk külön sorba, mert a legtöbb makró nem tesz be extra újsor karaktereket, így a makróhívás utáni újsorkaraktertől erősen függenek. Ez a megközelítés a generált \verb+configure+ scriptet olvashatóbbá teszi, hogy nem teszünk bele egy csomó üres sort.\par
Amikor olyan makrókat hívunk meg, amelyek argumentumokat vesznek át, az {\scshape m4} szabályai szerint nem lehet szóköz a makrónév és a nyitó zárójel közt. Az argumentumok több mint egysorosak is lehetnek, ha bezárjuk őket az {\scshape m4} zárójeleivel, amely ebben a környezetben a \verb+[+ és a \verb+]+ karakter lesz. Ha egy hosszú sort írunk, amely például fájlneveket tartalmaz, akkor nyugodtan tehetünk egy visszapert a sor végére, és logikailag folytathatjuk a következő sorban. Ez nem az \verb+autoconf+ vagy az {\scshape m4} adta tulajdonság, hanem a shell szkriptek adta lehetőség.\par
Néhány makró két esetet kezel: Mi történjen, ha egy adott feltétel igaz, illetve ha hamis. Bizonyos helyeken csak akkor szeretnénk tenni valamit, ha a feltétel igaz, illetve fordítva: bizonyos helyeken csak akkor szeretnénk tenni valamit, ha a feltétel hamis. Hogy elkerüljük az igaz esetet, adjunk meg üres értéket az \verb+TEENDŐ-HA-IGAZ+ makróargumentumnak. Ha pedig a hamis ágat szeretnénk kihagyni, akkor pedig hagyjuk ki a \verb+TEENDŐ-HA-HAMIS+ argumenumot, és a hozzá tartozó, azt megelőző vesszőt.\par
Hogy áttekinthetőbbé tegyük a kódot, tegyünk a \verb+configure.in+ fájlba megjegyzéseket, amelyet az {\scshape m4} beépített \verb+dnl+ makrójával kezdünk, amely lenyeli az utánaálló szöveget egész az azt követő újsor karakterig. Így ezek a megjegyzések már nem fognak megjelenni a \verb+configure+ szkriptben.
\clearpage
\section{A GNU autoconf}
\subsection{A {\ttfamily configure} hogyan találja meg a bemenetét}
Minden \verb+configure+ scriptnek meg kell hívnia az \verb+AC_INIT+-et mielőtt bármi mást csinálna. A másik olyan makró amelynek használata kötelező az a \verb+AC_OUTPUT+, amelyet a \verb+configure+ scriptek végén kell meghívni. Az \verb+AC_INIT+ használatának szintaxisa:
\begin{description}
\item[AC\_INIT (Egyedi-fájl-a-forrás-könyvtárban)]\hspace*{\fill}\par Feldolgoz minden paranccsori argumentumot, és megtalálja a forráskód könyvtárát. Az {\slshape Egyedi-fájl-a-forrás-könyvtárban} tetszőleges fájl lehet, ami a csomag forráskönyvtárában van. A \verb+configure+ ellenőrzi eme fájl létezését, hogy a könyvtár amelyben van, valóban tartalmazza a forráskódot.
\end{description}\par
Az olyan csomagoknak, amelyek kézi konfigurációt igényelnek, vagy az \verb+install+ programot használják, valahogyan közölniük kell a \verb+configure+al, hogy hol találhatja meg az egyéb shell-szkripteket. Ez az \verb+AC_CONFIG_AUX_DIR+ makró segítségével történik, habár az alapértelmezett helyek ahol a fájlokat a szkript keresi megfelelő a legtöbb esetben.
\begin{description}
\item[AC\_CONFIG\_AUX\_DIR(DIR)]\hspace*{\fill}\par A {\slshape DIR} könyvtárból használja az \verb+install-sh+, \verb+config.sub+, \verb+config.guess+ szkripteket. Ezek segédfájlok a konfigurációhoz. A {\slshape DIR} lehet abszolút vagy relatív is a {\slshape SRCDIR}-re nézve. Az alapértelmezett az {\slshape SRCDIR} vagy az {\slshape SRCDIR/..} vagy az {\slshape SRCDIR/../..}, attól függően, hogy melyik tartalmazza legelőször az \verb+install-sh+-t. A többi fájlt nem ellenőrzi, így az \verb+AC_PROG_INSTALL+ nem igényli automatikusan a többi segédfájl közzétevését. Ez a rész az \verb+install.sh+-t is ellenőrzi, de ez már idejétmúlt, lévén a \verb+make+ programoknak van egy szabálya arra vonatkozóan, hogy csináljon \verb+install+-t belőle, ha nincs \verb+Makefile+.
\end{description}
\subsection{Kimeneti fájlok előállítása}
Minden autoconf által generált \verb+configure+ szkriptnek az \verb+AC_OUTPUT+ makró meghívásával kell végződnie. Ez az a makró ami \verb+Makefile+-okat és más opcionális fájlokat generáltat a konfigurációtól függően.
\begin{description}
\item[AC\_OUTPUT(\lbrack{}FÁJL... \lbrack{}, EXTRA-PARANCSOK \lbrack{}, INIT-PARANCSOK\rbrack\rbrack\rbrack)]\hspace*{\fill}\par Létrehozza a kimeneti fájlokat. Csak egyszer hívjuk meg ezt a makrót, és ez szerepeljen a \verb+configure.in+ fájlunk végén. A {\slshape FÁJL...} argumentum egy szóközökkel elválasztott listája a kimeneti fájloknak, ami akár üres is lehet. Ez a makró létrehoz minden olyan fájlt, amit itt felsoroltunk. Olymódon, hogy ha pl. az eredetileg felsorolt név {\slshape FÁJL} volt, akkor azt a {\slshape FÁJL.in} nevű fájlból hozza létre belehelyettesítve a kimeneti változók értékeit. A makró létre is hozza a {\slshape FÁJL}hoz tartozó könyvtárat, ha az előtte nem létezett. (De az adott könyvtár szüleit már nem!) Általában \verb+Makefile+okat generálunk így, de más fájlokat is létrehozhatunk ilymódon.\par
Ha korábban használtuk az \verb+AC_CONFIG_HEADER+, \verb+AC_LINK_FILES+ vagy \verb+AC_CONFIG_SUBDIRS+ makróhívásokat, akkor az ezek argumentumaiból következő fájlok is itt kerülnek létrehozásra.\par
Egy \verb+AC_OUTPUT+ makróhívás tipikusan valahogy így szokott kinézni:\\
\verb+AC_OUTPUT(Makefile src/Makefile man/Makefile X/Imakefile)+\par
A bemeneti fájlok neveit felül lehet bírálni, olymódon, hogy a fájl nevéhez kettőspontal elválasztva hozzáírjuk, hogy mi legyen a bemeneti fájl vagy fájlok (ekkor is kettőspont a határolójel) neve. Példák:
\begin{verbatim}
AC_OUTPUT(Makefile:templates/top.mk lib/Makefile:templates/lib.mk)
AC_OUTPUT(Makefile:templates/var.mk:Makefile.in:templates/rules.mk)
\end{verbatim}
Ha adunk meg {\slshape EXTRA-PARANCSOK}at, akkor azok beillesztődnek a \verb+config.status+-ba, hogy leffuttatódjanak az egyéb feldolgozások után. Ha {\slshape INIT-PARANCSOK}at is megadunk, akkor azok a {\slshape EXTRA-PARANCSOK} elé illesztődnek, és a shell változók értékei, a parancs-, és a zárójel- helyettesítések végrehajtódnak rajtuk a \verb+configure+-ban. Így például felhasználhatő arra, hogy a \verb+configure+-ból változók értékeit átadjuk az {\slshape EXTRA-PARANCSOK}nak. Ha az \verb+AC_OUTPUT_COMMANDS+ makrót meghívjuk, akkor a akkor a parancsok amelyeket annak adunk pont azelőtt futnak le, hogy az ezen makrónak adott parancsokra kerülne a sor.
\item[AC\_OUTPUT\_COMMANDS (EXTRA-PARANCSOK \lbrack{}, INIT-PARANCSOK\rbrack{})]\hspace*{\fill}\par
Olyan további shell parancsok adhatók meg itt, amelyek a \verb+config.status+ szkript végén fognak lefutni, illetve olyan parancsok amelyek a \verb+configure+-ból inicializálnak változóértéket. Ezt a makrót több alkalommal is meg lehet hívni. Ime egy a valóságtól elrugaszkodott példa:\par
\begin{verbatim}
ize=27
AC_OUTPUT_COMMANDS([echo ez egy extra $ize, sít.], ize=$ize)
AC_OUTPUT_COMMANDS([echo ez egy másik, extra, apróság], [echo init apróság])
\end{verbatim}
\end{description}
Ha a \verb+make+t futtatjuk alkönyvtárakon, akkor azt úgy tegyük, hogy a \verb+MAKE+ változó tartalmát beállítjuk \verb+make+-re. A legtöbb \verb+make+ verzió beállítja a \verb+MAKE+ értékét a \verb+make+ program nevére plussz a neki átadott opciókra. De számos verzió pedig nem veszi bele a parancssorban átadott változók értékeit, így azok nem kerülnek automatikusan átadásra. Néhány régi \verb+make+ verzió ilyen. Az alábbi makró lehetővé teszi, hogy akár ezekkel a régi verziókkal is használható legyen művünk.
\begin{description}
\item[AC\_PROG\_MAKE\_SET]\hspace*{\fill}\par
Ha a \verb+make+ előre beállítja a \verb+MAKE+ változót, akkor a \verb+SET_MAKE+ kimeneti változót üresre állítja. Egyébként a \verb+SET_MAKE+ változó a \verb+MAKE=make+ sztringet fogja tartalmazni. Ez a makró az \verb+AC_SUBST+ makrót használja a \verb+SET_MAKE+ beállítására.\par
Hogy eme makró lehetőségét kihasználjuk, tegyünk egy ilyen sort a \verb+Makefile.in+be, ahol az lefuttatja a \verb+MAKE+et a többi könyvtárra:
\begin{verbatim}
@SET_MAKE@
\end{verbatim}
\end{description}
\subsection{{\ttfamily Makefile}beli helyettesítések}
Minden egyes könyvtárnak, amelyben van valami lefordítani való, vagy telepíteni való, tartalmaznia kell egy \verb+Makefile.in+t, amelyból a \verb+configure+ \verb+Makefile+-t csinál abba a könyvtárba. Hogy létrejöjjön a \verb+Makefile+ a \verb+configure+ egy egyszerű változóhelyettesítést végrehajt a fájlokon, olymódon, hogy minden egyes \verb+@VÁLTOZÓ@+ előfordulást a \verb+Makefile.in+ben lecserél arra az értékre amelyet a \verb+configure+ megállapított. Ezen változókat, melyek helyettesítésre kerülnek a kimeneti fájlokban, kimeneti változóknak hívjuk. Általában ezek olyan shell változók, amelyet a \verb+configure+ szkript állít be. Ahhoz, hogy a \verb+configure+ behelyettesítse ezeket a változókat a kimeneti fájlokban az \verb+AC_SUBST+ makrót kell meghívni a helyettesítendő változó nevét argumentumul adva.\par
Egy szoftvercsomagot amely egy \verb+configure+ szkriptet használ egy \verb+Makefile.in+el kell terjeszteni és nem \verb+Makefile+-al, mert a \verb+configure+ fogja majd a megfelelő értékeket behelyettesíteni, így a felhasználónak csak annyi a dolga, hogy a helyi rendszernek megfelelően konfigurálja a csomagot mielőtt lefordítja, és telepíti.
\subsection{Kimeneti változók}
Bizonyos kimeneti változók értéke mindig előre be van állítva az autoconf makróinak köszönhetően. Bizonyos autoconf makrók pedig további kimeneti változókat állítanak be amelyek az adott makrók leírásában szerepelnek. Ime azon kimeneti változók amelyek értéke előre be van állítva, magyarázattal együtt:
\begin{description}
\item[bindir]Annak a könyvtárnak a neve, ahova a felhasználó által futtatható állományokat telepíteni kell.
\item[configure\_input]Egy megjegyzés, amely jelzi, hogy a fájl automatikusan lett generálva a \verb+configure+ szkript által, és megadja a bemeneti fájl nevét. A \verb+AC_OUTPUT+ hozzávesz egy megjegyzés sort minden egyes általa létrehozott \verb+Makefile+ elejéhez, amely ennek a változónak a tartalma lesz. Más fájlok esetén külön hivatkozni kell erre a változóra, hogy a megjegyzés megjelenjen a bemeneti fájl elején. Például, ha van egy (bemeneti) shell szkriptünk, akkor annak az eleje valahogy így kell kinézzen a cél érdekében:
\begin{verbatim}
#!/bin/sh
# @configure_input@
\end{verbatim}
Ezen sor megléte emlékezteti a fájlt szerkesztő embert, hogy azt a \verb+configure+ szkripttel fel kell dolgoztatnia.
\item[datadir]Annak a könyvtárnak a neve, ahova a csak olvasható, architektúra-független adatokat kell elhelyezni.
\item[exec-prefix]Az architektúra-függő fájlok telepítési prefixuma.
\item[includedir]Annak a könyvtárnak a neve, ahova a C fejlécállományokat kell telepíteni.
\item[infodir]Annak a könyvtárnak a neve, ahova az info formátumú dokumentációt kell telepíteni. (Lásd Makefile konvenciók rész)
\item[libdir]Annak a könyvtárnak a neve, ahova a tárgykódú könyvtárakat kell telepíteni.
\item[libexecdir]Annak a könyvtárnak a neve, ahova a más programok által futtatott futtatható programokat kell telepíteni.
\item[localstatedir]Annak a könyvtárnak a neve, ahova a gépre nézve egyedi, módosítható adatokat kell telepíteni.
\item[mandir]A felsőszintű könyvtárnév ahova a man formátumú dokumentációt kell telepíteni.\footnote{Ezen belül a dokumentáció szekciója szerinti alkönyvtárba kell a kézikünyv-oldalt betenni.}
\item[oldincludedir]Annak a könyvtárnak a neve, ahova a C fejlécfájlokat kell telepíteni a nem-gcc fordítók számára.
\item[prefix]Az architektúra-független fájlok telepítési prefixuma.
\item[sbindir]Annak a könyvtárnak a neve, ahova az adminisztrátor által használt futtatható programokat kell telepíteni.
\item[sharedstatedir]Annak a könyvtárnak a neve, ahova a módosítható architektúra-független adatokat kell telepíteni.
\item[srcdir]Annak a könyvtárnak a neve, amely az adott \verb+Makefile+hoz tartalmazza a forráskódot.
\item[sysconfdir]Annak a könyvtárnak a neve, ahova a csak olvasható gépre nézve egyedi adatokat kell tenni.
\item[top\_srcdir]A csomag forráskódjának legfelső szintű könyvtárának a neve. Ha a legfelső szintű könyvtárban van, akkor ugyanaz lesz mint az \verb+srcdir+
\item[CFLAGS]A debuggolási és optimalizációs opciók, amelyeket a C fordítónak át kell adni. Ha ez nincs beállítva a \verb+configure+ futtatásánál, akkor az alapértelmezett értéke az \verb+AC_PROG_CC+ makró meghívásánál állítódik be (, vagy nem ha nem hívjuk azt meg). A \verb+configure+ használja ezt az értéket, amikor programokat fordít, hogy ellenőrizze a C (fordító) lehetőségeit.
\item[CPPFLAGS]A fejléc állományok keresési könyvtára és egyéb különféle opciók a C preprocesszor és fordító számára. Ha nincs beállítva környezeti változóként, amikor a \verb+configure+ fut, akkor az alapértelmezett értéke üres lesz. A \verb+configure+ használja ezt az értéket, amikor programokat fordít vagy preprocesszál, hogy ellenőrizze a C lehetőségeit.
\item[CXXFLAGS]Ugyanaz lényegében mint a \verb+CFLAGS+, csak ez a C++ fordítóra vonatkozik. Itt az alapértelmezett érték az \verb+AC_PROG_CXX+ makróhívásnál állítódik be. A \verb+configure+ használja ezt ez értéket a C++ fordító tulajdonságainak tesztelésére.
\item[FFLAGS]Mint a fenti \verb+CFLAGS+ csak a Fortran 77 fordítóra vonatkozik, és az alapértelmezett érték a \verb+AC_PROG_F77+ makró meghívásánál állítódik be. A \verb+configure+ használja ezt az értéket a Fortran 77 tulajdonságainak tesztelésére.
\item[DEFS]\verb+-D+ opciók, amelyeket a C fordítónak át kell adni. Ha az \verb+AC_CONFIG_HEADER+ makrót meghívjuk, akkor a configure inkább a \verb+-DHAVE_CONFIG_H+ra seréli a \verb+@DEFS@+ sztringet. Ez a változó nincs definiálva, amikor a \verb+configure+ a saját tesztjeit futtatja, csak amikor a kimeneti fájljait hozza létre.
\item[LDFLAGS]A {\slshape strip}elésre és egyéb vegyes a szerkesztőnek ({\slshape linker}) átadandó opciókat tartalmazza. Ha nincs környezeti változóban beállítva, amikor a \verb+configure+ fut, akkor az értéke üres lesz. A \verb+configure+ használja ennek az értékét, amikor programokat szerkeszt össze a C tulajdonságainak tesztelésekor.
\item[LIBS]A szerkesztőnek átadandó \verb+-l+ és \verb+-L+ opciók.
\end{description}
\subsection{Konfigurációs fejlécállományok}
Amikor egy szoftvercsomag több mint egy néhány C preprocesszor szimbólumot tesztel, akkor a parancssor, amelyben \verb+-D+ opciókat adunk át meglehetősen hosszúra nyúlhat. Ez kétféle problémát okoz: Egyrészt, vizuálisan nem lesz áttekinthető a \verb+make+ kimenete, ha hibát keresünk benne. És a komolyabbik hiba, pedig az, hogy a paranccsor hosszabbra nyúlhat, mint az operációs rendszer által engedélyezett maximális hossz. Hogy ezt a nehézséget leküzdjük, alternatívaként szóba jöhet, hogy a \verb+configure+ script létrehozzon egy C fejlécfájlt, amely ezen \verb+#define+ direktívákat fogják tartalmazni. Ha ilyen jellegű kimenetet szeretnénk, akkor azt az \verb+AC_CONFIG_HEADER+ makró meghívásával jelezhetjük, amelyet közvetlenül az \verb+AC_INIT+ után kell használnunk.\par
A szoftvercsomagnak be kell illesztenie egy \verb+#include+ direktívával ezt a fejlécfájlt, mielőtt bármilyen egyéb fejlécfájllal foglalkozna, hogy a deklarációk inkonzisztenciáját megelőzzük. (Például, ha megpróbálná a \verb+const+ szót újradefiniálni.)\par
A fejlécállomány beillesztésére a \verb+#include <config.h>+-t javasolt használni a \verb+#include "config.h"+ helyett, és még így a fordítónak (csak az előfeldolgozó résznek) át kell adni a \verb+-I.+ ill. \verb+-I..+ opciókat, attól függően, hogy melyik könyvtár tartalmazza a \verb+config.h+-t. Ilymódon ha a forráskönyvtár konfigurálta magát, más build-könyvtárak szintén konfiguráltak lehetnek, anélkül, hogy külön meg kellene keresniük a \verb+config.h+-t a forráskönyvtárból.\footnote{Példa: tfh. van egy x szoftverem, amely részként használja az y-t, ami szintén autoconf-os. Ha x {\ttfamily configure}-ja tud mindent, amit y-é, és a {\ttfamily config.h}-t megfelelően elkészíti, akkor nem kell az y részben külön {\ttfamily ./configure}-ni.}
\begin{description}
\item[AC\_CONFIG\_HEADER (LÉTREHOZANDÓ-FEJLÉC)]\hspace*{\fill}\par
Beállítja az \verb+AC_OUTPUT+ makrót, hogy amikor a fájlokat létrehozza, akkor a szóközökkel elválasztva felsorolt {\slshape LÉTREHOZANDÓ-FEJLÉC} fájlokat is hozza létre, amelyek tartalmazzák a \verb+#define+ állításokat, és a generált fájlokban a \verb+@DEFS@+-t a \verb+-DHAVE_CONFIG_H+ra cserélje a \verb+DEFS+ értéke helyett. A szokásos név, ami a {\slshape LÉTREHOZANDÓ-FEJLÉC} szokott lenni, a \verb+config.h+\par
Ha a {\slshape LÉTERHOZANDÓ-FEJLÉC} már létezik és tartalma azonos avval, amit az \verb+AC_OUTPUT+ beletenne, akkor nem foglalkozik vele. Így elkerülhetővé válik az, hogyha a konfigurációban bekövetkezik néhány apró változás, (ami nem változtatná meg a \verb+config.h+-t) szükségtelenül újrafordítani tárgykódokat, amelyek függenek ettől a fejlécfájltól.\par
Általában a bemeneti fájl neve {\slshape LÉTREHOZANDÓ-FEJLÉC.in}, habár ez felülbírálható hogyha kettőspontal elválasztva felsoroljuk a bemeneti fájlok nevét. Példák:
\begin{verbatim}
AC_CONFIG_HEADER(defines.h:defines.hin)
AC_CONFIG_HEADER(defines.h:defs.pre:defines.h.in:defs.post)
\end{verbatim}
\end{description}
\subsection{Konfigurációs fejléc minták}
Ha a programnak tartalmaznia kell egy minta fejlécfájlt, amely úgy néz ki, mint a végső fejlécfájl, beleértve a kommenteket, és a \verb+#define+-ok alapértelmezett értékeit. Például, ha a \verb+configure.in+-ben ezek a makróhívások vannak:
\begin{verbatim}
AC_CONFIG_HEADER(conf.h)
AC_CHECK_HEADERS(unistd.h)
\end{verbatim}
Akkor a \verb+config.h.in+-be valami ilyesminek kellene lennie:
\begin{verbatim}
/* Értéke legyen 1 ha van unistd.h. */
#define HAVE_UNISTD_H 0
\end{verbatim}
Egyéb megoldásként szóba jöhet, hogyha a kód \verb+#ifdef+ direktívákkal dönt \verb+#if+ helyett, hogy az alapértelmezett értéket \verb+#undef+-eljük ahelyett, hogy a változónak egy értéket definiálnánk. Tehát, egy olyan rendszeren ahol van \verb+unistd.h+, akkor a \verb+configure+ meg fogja változtatni a második sort \verb+#define HAVE_UNISTD_H 1+-re. Az egyéb rendszereken pedig megjegyzésbe kerül a sor:
\begin{verbatim}
/* Definiálódik ha van unistd.h */
#undef HAVE_UNISTD_H
\end{verbatim}
\subsection{Az {\ttfamily autoheader} használata a konfigurációs fejléc minták létrehozására}
Az autoheader program létre tud hozni egy ilyen mintafájlt amely C \verb+#define+ állításokat tartalmaz, a \verb+configure+nak. Ha a \verb+configure.in+ meghívja az \verb+AC_CONFIG_HEADER(FÁJL)+ makrót, akkor az \verb+autoheader+ létrehozza a \verb+FÁJL.in+ nevű fájlt, ha pedig több argumentum is meg volt adva, akkor az elsőt használja. Egyéb esetben pedig az autoheader \verb+config.h.in+-t hoz létre.\par
Ha az \verb+autoheader+-nek adunk egy argumentumot, akkor azt a fájlt fogja nézni a \verb+configure.in+ helyett, és a fejlécfájlt a sztandard kimenetre fogja kiírni a \verb+config.h.in+ helyett. Ha az \verb+autoheader+-nek argumentumul egy \verb+-+ -t adunk meg, akkor a sztandrd bemenetét fogja olvasni a \verb+configure.in+ helyett, és a fejlécfájlt pedig a sztandard kimenetére fogja írni.\par
Az \verb+autoheader+ elolvassa a \verb+configure.in+-t (, vagy amit adunk neki), és az alapján kitalálja, hogy milyen C előfeldolgozó szimbólumokat definiálhat. Az \verb+acconfig.h+ban található megjegyzéseket, \verb+#define+ és \verb+#undef+ állításokat átmásolja amely az \verb+autoconf+ telepítésével jön. Ha az aktuális könyvtárban is van \verb+acconfig.h+, akkor azt is használja. Ha az \verb+AC_DEFINE+-al további szimbólumokat is létrehozunk, akkor kötelezően létre kell hoznunk ezt a fájlt, az ehhez tartozó bejegyzésekkel. Azokhoz a szimbólumokhoz, amelyeket az \verb+AC_CHECK_HEADERS+, \verb+AC_CHECK_FUNCS+, \verb+AC_CHECK_SIZEOF+, \verb+AC_CHECK_LIB+ makróhívások definiálnak, az \verb+autoheader+ generál megjegyzéseket és \verb+#undef+ állításokat saját maga, ahelyett, hogy ezeket egy fájlból másolná, lévén a lehetséges szimbólumok jól körülírhatók.\par
A fájl, amit az \verb+autoheader+ létrehoz jórészt \verb+#define+ és \verb+#undef+ állításokat tartalmaznak, és a hozzájuk tartozó megjegyzéseket. Ha a \verb+./acconfig.h+ tartalmazza a \verb+@TOP@+ szöveget, akkor az \verb+autoheader+ a \verb+@TOP@+ szöveget tartalmazó sor előtti sorokat átmásolja a generált fájl elejére. Hasonló módon, ha az \verb+./acconfig.h+ tartalmazza a \verb+@BOTTOM@+ szöveget, akkor az \verb+autoheader+ átmásolja a \verb+@BOTTOM@+ szöveget tartalmazó sor utáni sorokat a generált fájl végére. Egyik, vagy akár mindkét szöveg elhagyható.\footnote{Természetesen ilyenkor a hozzá tartozó rész nem lesz átmásolva.}\par
Egy alternatív módszer hogy hasonlót érjünk el, hogy ha csinálunk \verb+FILE.top+ nevű fájlt (vagyis általában ennek a neve \verb+config.h.top+ lesz) és/vagy \verb+FILE.bot+ nevű fájlt az aktuális könyvtárba. Ha ezek léternek akkor az \verb+autoheader+ átmásolja őket a kimenetének az elejére, illetve a végére.\footnote{Ezek használata ellenjavalt, mert az M\$-DOS rendszereken nem lehet két pont a fájlok nevében, valamint két további fájl, hogy telezsúfolja a könyvtárat.}
\subsection{Az alapértelmezett prefix}
A \verb+configure+ beállít egy prefixet, hogy hova települjenek a fájlok. Ennek az alapértelmezése a \verb+/usr/local+ könyvtárra mutat. A \verb+configure+ scriptet használó személy ezt beállíthatja más helyre is, ha a \verb+--prefix+ illetve \verb+--exec-prefix+ opciókat használja. Ezt a beállítást két módon is lehet módosítani, mint láttuk az egyik lehetőség, a \verb+configure+ script futtatásakor. A másik lehetőség, hogy a \verb+configure+ script alapértelmezését változtassuk meg, már a létrehozásakor. (Vagyis amikor kigeneráljuk a \verb+configure.in+ fájlból.) Ez az alábbi makróhívással tehető meg:
\begin{description}
\item[AC\_PREFIX\_DEFAULT(PREFIX)]\hspace*{\fill}\par Beállítja az alapértelmezett telepítési prefixet {\slshape PREFIX}re a \verb+/usr/local+ helyett.
\end{description}
Hasznos lehet az is, ha a \verb+configure+ kitalálja a telepítési prefixet egy hozzákapcsolódó, már telepített program nevéből. Ha így szeretnénk cselekedni, akkor erre az \verb+AC_PREFIX_PROGRAM+ makrót használhatjuk az alábbi módon:
\begin{description}
\item[AC\_PREFIX\_PROGRAM(PROGRAM)]\hspace*{\fill}\par Ha a felhasználó nem adott meg telepítési prefixet (, amit ettől függetlenül bármikor felülbírálhat a \verb+--prefix+ opcióval a \verb+configure+ futtatásakor), akkor megpróbálja kitalálni az értékét az alapján, hogy megnézi a \verb+PATH+-ban hogy a {\slshape PROGRAM} hol található. Ha a {\slshape PROGRAM} megtalálható, akkor a prefixet a {\slshape PROGRAM}-ot tartalmazó könyvtár szülőkönyvtárára állítja, egyébként nem változtatja meg a \verb+Makefile.in+-ben a prefix értékét.\par
Például, ha a {\slshape PROGRAM} a \verb+gcc+ és a \verb+PATH+ alapján megtalálja a \verb+configure+ script a \verb+/usr/local/gnu/bin/gcc+ nevű fájlt, akkor beállítja a prefixet a \verb+/usr/local/gnu+ könyvtárra.
\end{description}
Az egyszerűbb érthetőség kedvéért íme, egy szemléltető példa:
\begin{verbatimtab}
$$ cat <<'END' >Makefile.in
> # Ez egy Makefile lesz, és a köv sorban, látható lesz az előző sorbeli megjegyzés
> # @configure_input@
> bindir=@bindir@
> datadir=@datadir@
> exec_prefix=@exec_prefix@
> includedir=@includedir@
> infodir=@infodir@
> libdir=@libdir@
> libexecdir=@libexecdir@
> localstatedir=@localstatedir@
> mandir=@mandir@
> oldincludedir=@oldincludedir@
> prefix=@prefix@
> sbindir=@sbindir@
> sharedstatedir=@sharedstatedir@
> srcdir=@srcdir@
> sysconfdir=@sysconfdir@
> top_srcdir=@top_srcdir@
> CFLAGS=@CFLAGS@
> CPPFLAGS=@CPPFLAGS@
> 
> .PHONY: test
> test:
>         @echo "bindir=$(bindir)"
>         @echo "datadir=$(datadir)"
>         @echo "exec_prefix=$(exec_prefix)"
>         @echo "includedir=$(includedir)"
>         @echo "infodir=$(infodir)"
>         @echo "libdir=$(libdir)"
>         @echo "libexecdir=$(libexecdir)"
>         @echo "localstatedir=$(localstatedir)"
>         @echo "mandir=$(mandir)"
>         @echo "oldincludedir=$(oldincludedir)"
>         @echo "prefix=$(prefix)"
>         @echo "sbindir=$(sbindir)"
>         @echo "sharedstatedir=$(sharedstatedir)"
>         @echo "srcdir=$(srcdir)"
>         @echo "sysconfdir=$(sysconfdir)"
>         @echo "top_srcdir=$(top_srcdir)"
>         @echo "CFLAGS=$(CFLAGS)"
>         @echo "CPPFLAGS=$(CPPFLAGS)"
> END
$ cat <<'END' >configure.in
> AC_INIT(Makefile.in)
> AC_OUTPUT(Makefile)
> END
$ autoconf
$ ./configure 
creating cache ./config.cache
updating cache ./config.cache
creating ./config.status
creating Makefile
$ make
bindir=/usr/local/bin
datadir=/usr/local/share
exec_prefix=/usr/local
includedir=/usr/local/include
infodir=/usr/local/info
libdir=/usr/local/lib
libexecdir=/usr/local/libexec
localstatedir=/usr/local/var
mandir=/usr/local/man
oldincludedir=/usr/include
prefix=/usr/local
sbindir=/usr/local/sbin
sharedstatedir=/usr/local/com
srcdir=.
sysconfdir=/usr/local/etc
top_srcdir=.
CFLAGS=
CPPFLAGS=
$ head Makefile
# Generated automatically from Makefile.in by configure.
# Ez egy Makefile lesz, és a köv sorban, látható lesz az előző sorbeli megjegyzés
# Generated automatically from Makefile.in by configure.
bindir=${exec_prefix}/bin
datadir=${prefix}/share
exec_prefix=${prefix}
includedir=${prefix}/include
infodir=${prefix}/info
libdir=${exec_prefix}/lib
libexecdir=${exec_prefix}/libexec
$ CFLAGS=-O2 ./configure --prefix=/opt
loading cache ./config.cache
creating ./config.status
creating Makefile
$ make
bindir=/opt/bin
datadir=/opt/share
exec_prefix=/opt
includedir=/opt/include
infodir=/opt/info
libdir=/opt/lib
libexecdir=/opt/libexec
localstatedir=/opt/var
mandir=/opt/man
oldincludedir=/usr/include
prefix=/opt
sbindir=/opt/sbin
sharedstatedir=/opt/com
srcdir=.
sysconfdir=/opt/etc
top_srcdir=.
CFLAGS=-O2
CPPFLAGS=
$ cat <<'END' >configure.in
> AC_INIT(Makefile.in)
> AC_PREFIX_DEFAULT(/usr/opt)
> AC_OUTPUT(Makefile)
> END
$ autoconf
$ ./configure 
loading cache ./config.cache
creating ./config.status
creating Makefile
$ make 
bindir=/usr/opt/bin
datadir=/usr/opt/share
exec_prefix=/usr/opt
includedir=/usr/opt/include
infodir=/usr/opt/info
libdir=/usr/opt/lib
libexecdir=/usr/opt/libexec
localstatedir=/usr/opt/var
mandir=/usr/opt/man
oldincludedir=/usr/include
prefix=/usr/opt
sbindir=/usr/opt/sbin
sharedstatedir=/usr/opt/com
srcdir=.
sysconfdir=/usr/opt/etc
top_srcdir=.
CFLAGS=
CPPFLAGS=
\end{verbatimtab}
\subsection{Verziószámok}
Az alábbi makrókkal lehet verziószámmal kapcsolatos műveleteket végezni a \verb+configure+ szkriptekben.
\begin{description}
\item[AC\_PREREQ(VERZIÓ)]\hspace*{\fill}\par Evvel a makróval meg lehet győződni arról, hogy megfelelően új verziójú autoconfot használunk. Ha az éppen használt autoconf verziója régebbi, mint a {\slshape VERZIÓ}, akkor kiír egy hibaüzenetet, és nem készíti el a \verb+configure+ szkriptet az \verb+autoconf+. Például:
\begin{verbatim}
AC_PREREQ(1.8)
\end{verbatim}
Ez a makró hasznos lehet, ha a \verb+configure.in+ egy az autoconf kiadások közti nem magától értetődő viselkedésbeli különbségre épít. Ha frissiben hozzáadott makrók miatt szeretnénk használni, akkor az \verb+AC_PREREQ+ kevésbé hasznos, mert az autoconf enélkül is megmondja a felhasználónak, ha egy makrót nem talál. Ugyanez történik akkor is, ha a \verb+configure.in+t egy olyan régebbi \verb+autoconf+al dolgoztatjuk fel, amelyik még az \verb+AC_PREREQ+et sem ismerte.
\item[AC\_REVISION(KIADÁS-INFÓ)]\hspace*{\fill}\par A \verb+configure+ szkriptbe bemásolja a {\slshape KIADÁS-INFÓ} kiadási bélyeget, a dollár jelek vagy a dupla-idézőjel eltávolításával. Ez a makró lehetővé teszi, hogy egy kiadási bélyeget tegyünk a \verb+configure.in+ből a \verb+configure+ba, anélkül, hogy az {\scshape RCS} vagy a {\scshape CVS} megváltoztatná azt, amikor {\slshape check in}eljük\footnote{A commit ,,szinonímája''}. Ilymódon megállíptható, hogy milyen kiadású \verb+configure.in+ből lett generálva a \verb+configure+ szkript.\par
Jó ötlet lehet, hogy ezt a makrót az \verb+AC_INIT+ előtt hívjuk meg, így a kiadási szám, közelebb van a \verb+configure.in+ és a \verb+configure+ fájl tetejéhez. Hogy ezt megtehessük, az \verb+AC_REVISION+ kimenete egy \verb+#!/bin/sh+ résszel kezdődik, mint ahogy egy normális \verb+configure+ szkriptnek kell. Például, ha ez a sor van a \verb+configure.in+ben:
\begin{verbatim}
AC_REVISION($Revision: 1.30 $)dnl
\end{verbatim}
Akkor az egy ilyen sort eredményez a \verb+configure+ban:
\begin{verbatim}
#!/bin/sh
# From configure.in Revision: 1.30
\end{verbatim}
\end{description}
\subsection{Kész tesztek}
Figyelem, ebben a fejezetben nem abban a sorrendben jön a tesztek leírása, mint ahogyan azt a \verb+configure.in+ben kellene írnunk az ajánlás$_{\pageref{configurein ajanlott sorrend}}$ szerint.
\subsubsection{Programok létének ellenőrzése}
Ezek a makrók arra szolgálnak, hogy ellenőrizzük, hogy létezik-e egy bizonyos program. Akár arra is felhasználhatjuk, hogy több különböző alternatív lehetőség közül válasszunk egyet, és hogy a döntésünk mellett milyen egyéb teendőnk van. Ha a keresett programra nincs külön előre gyártott makró, és a keresett prograram semilyen különleges tulajdonságát nem kell ellenőrizni, akkor használhatjuk az általános programellenörző makrókat.\par
Az alábbi makrók egyedi programokat ellenőriznek, és bizonyos esetekben azok megfelelő tulajdonságait:
\begin{description}
\item[AC\_DECL\_YYTEXT]\hspace*{\fill}\par Definiálja az \verb+YYTEXT_POINTER+-t, ha az \verb+yytext+ \verb+char *+-nak van definiálva \verb+char []+ helyett. A \verb+LEX_OUTPUT_ROOT+ kimeneti változót is beállítja a lexer által generált alapfájlnévre, ami általában \verb+lex.yy+ szokott lenni, de időnként más is lehet. Ezen eredmények erősen függnek attól, hogy \verb+lex+et vagy \verb+flex+et használunk.
\item[AC\_PROG\_AWK]\hspace*{\fill}\par Ellenőrzi a \verb+mawk+, \verb+gawk+, \verb+nawk+ és az \verb+awk+ programok meglétét, ebben a sorrendben, és beállítja az \verb+AWK+ kimeneti változót arra, amelyet elsőnek találja meg. Azért a \verb+mawk+al kezdi a sort, mert állítólag ez a leggyorsabb implementáció.
\item[AC\_PROG\_CC]\hspace*{\fill}\par Meghatározza a használandó {\scshape C} fordítót. Ha a \verb+CC+ környezeti változó nincs eleve beállítva, akkor ellenőrzi a \verb+gcc+t és sikertelen esetben a \verb+cc+vel is megpróbálkozik. A \verb+CC+ kimeneti változó értékét a talált fordító nevére beállítja.\par
Ha a {\scshape GNU C} fordítót használjuk, akkor a \verb+GCC+ környezeti változót is beállítja \verb+yes+re, különben üresen hagyja. Ha a \verb+CFLAGS+ nem volt eredetileg beállítva, akkor beállítja azt \verb+-g -O2+re {\scshape GNU C} esetén (illetve \verb+-O2+re az olyan rendszereken, ahol a \verb+-g+t nem fogadja el a gcc) vagy \verb+-g+-re az egyéb fordítók esetén.\par
Ha a {\scshape C} fordító olyan végrehajtható állományt generál, ami nem képes futni azon a rendszeren, ahol a \verb+configure+ szkript éppen fut, akkor a \verb+cross_compiling+ környezeti változót \verb+yes+re állítja, egyébként \verb+no+ra. Másszóval, ellenőrzi, hogy az a rendszer ahol a programot fordítjuk, mint ahol futtatni fogjuk.\par
Lássunk egy példát, hogy is működik ez a makró:
\begin{verbatim}
$ cat <<'END' >Makefile.in
> CFLAGS= @CFLAGS@
> CC= @CC@
> cross_compiling= @cross_compiling@
> 
> .PHONY: test
> test:
>         @echo "CFLAGS=$(CFLAGS)"
>         @echo "CC=$(CC)"
>         @echo "cross_compiling=$(cross_compiling)"
> END
$ cat <<'END' >configure.in
> AC_INIT(Makefile.in)
> AC_PROG_CC
> AC_SUBST(cross_compiling)
> AC_OUTPUT(Makefile)
> END
$ autoconf
$ ./configure
creating cache ./config.cache
checking for gcc... gcc
checking whether the C compiler (gcc  ) works... yes
checking whether the C compiler (gcc  ) is a cross-compiler... no
checking whether we are using GNU C... yes
checking whether gcc accepts -g... yes
updating cache ./config.cache
creating ./config.status
creating Makefile
$ make
CFLAGS=-g -O2
CC=gcc
cross_compiling=no
\end{verbatim}
\item[AC\_PROG\_CC\_C\_O]\hspace*{\fill}\par Ellenőrzi, hogy a fordító elfogadja-e egyszerre a \verb+-c+ és \verb+-o+ paramétereket, és ha nem, akkor a \verb+NO_MINUS_C_MINUS_O+t definiálja.\footnote{Ha valaki tudja, hogy mi értelme van egy C makró definiáltságában ellenőrizni a C fordító egy tulajdonságát, az ossza meg velem!}
\item[AC\_PROG\_CPP]\hspace*{\fill}\par Beállítja a \verb+CPP+ kimeneti változót arra a parancsra, amely képes futtatni a C előfeldolgozót. Ha a \verb+$CC -E+ nem működne, akkor a \verb+/lib/cpp+re állatja. Csak akkor általánosan hordozható a \verb+CPP+ futtatása, ha a fájlnak \verb+.c+ kiterjesztése van.\par
Ha az aktuálisan használt nyelv a {\scshape C}, akkor számos más makró használja közvetve a \verb+CPP+ értékét, például a \verb+AC_TRY_CPP+, \verb+AC_CHECK_HEADER+, \verb+AC_EGREP_HEADER+ vagy az \verb+AC_EGREP_CPP+.
\item[AC\_PROG\_CXX]\hspace*{\fill}\par Meghatározza a használandó {\scshape C++} fordítót. Ellenőrzi a \verb+CXX+ illetve a \verb+CCC+ környezeti változókat (ebben a sorrendben), hogy be vannak-e állítva, és ha igen, akkor a \verb+CXX+-et erre az értékre állítja. \dots Lásd alábbi táblázat.
\item[AC\_PROG\_CXXCPP]\hspace*{\fill}\par Beállítja a \verb+CXXCPP+ kimeneti változó értékét arra a parancsra, ami képes a {\scshape C++} előfeldolgozót futtatni. \dots Szintén hasonlóképp viselkedik mint az \verb+AC_PROG_CPP+: Ha a \verb+$CXX -E+ nem megy, akkor \verb+/lib/cpp+, illetve ez is csak akkor hordozható, ha a fájlnak, amin használjuk \verb+.c+, \verb+.C+ vagy \verb+.cc+ kiterjesztése van.
\item[AC\_PROG\_F77]\hspace*{\fill}\par A használandó Fortran 77 fordítót határozza meg. \dots\par
Eltérések a \verb+AC_PROG_CC+hez képest:\par
\begin{tabular}{rccc}
 & {\tt AC\_PROG\_CC} & {\tt AC\_PROG\_CXX} & {\tt AC\_PROG\_F77} \\
ellenőrzött környezeti változó & {\tt CC} & {\tt CXX}, {\tt CCC} & {\tt F77} \\
kipróbálandó fordító & {\tt gcc}, {\tt cc} & {\tt c++}, {\tt g++}, {\tt gcc}, {\tt CC}, {\tt cxx}, {\tt cc++} & {\tt g77}, {\tt f77}, {\tt f2c} \\
beállított környezeti változó & {\tt GCC} & {\tt GXX} & {\tt G77} \\
fordítóhoz paraméterei & {\tt CFLAGS} & {\tt CXXFLAGS} & {\tt FFLAGS}
\end{tabular}
A \verb+cross_compiling+ ellenőrzést mindhárom makró elvégzi.
\item[AC\_PROG\_F77\_C\_O]\hspace*{\fill}\par Ellenőrzi, hogy a fordító elfogadja-e egyszerre a \verb+-c+ és \verb+-o+ paramétereket, és ha nem, akkor az \verb+F77_NO_MINUS_C_MINUS_O+t definiálja.
\item[AC\_PROG\_GCC\_TRADITIONAL]\hspace*{\fill}\par A \verb+CC+ kimeneti változóhoz hozzáteszi a \verb+-traditional+ kapcsolót is, ha a {\scshape GNU C} fordítót használjuk, és az {\slshape ioctl}ek nem működnek enélkül megfelelően. Ez általában akkor történik meg, ha a fix fejlécállományokat nem telepítettünk fel egy régi rendszerre. Lévén az újabb {\scshape GNU C} verziók már kijavítják a fejlécállományokat automatikusan, ez egyre kevésbé jelentős probléma.
\item[AC\_PROG\_INSTALL]\hspace*{\fill}\par Beállítja a \verb+INSTALL+ kimeneti változót egy a {\scshape BSD} \verb+install+ programjával kompatibilis program nevére, ha talál egy ilyet a \verb+PATH+ban. Egyébként a \verb+DIR/install-sh -c+ lesz az értéke, aholis a {\slshape DIR} a már említett \verb+AC_CONFIG_AUX_DIR+ makró által meghatározott érték. Ez a makró beállítja az \verb+INSTALL_PROGRAM+ és \verb+INSTALL_SCRIPT+ változókat az \verb+${INSTALL}+ értékre és az \verb+INSTALL_DATA+ környezeti változó értékét \verb+${INSTALL} -m 644+ re.\par
\dots\par
Ha saját plussz tulajdonságokkal felruházott \verb+install+ programot szeretnénk használni, akkor ne ezt a makrót használjuk, hanem egyszerűen írjuk be a nevét a \verb+Makefile.in+ünkbe.
\item[AC\_PROG\_LEX]\hspace*{\fill}\par Ha talál \verb+flex+-et akkor a \verb+LEX+ kimeneti változó értékét \verb+flex+re állítja és a \verb+LEXLIB+et pedig \verb+-lfl+re, ha ez a könyvtár ({\slshape library}) a rendes helyén megtalálható. Egyébként beállítja a \verb+LEX+et \verb+lex+re és a \verb+LEXLIB+et \verb+-ll+re.
\item[AC\_PROG\_LN\_S]\hspace*{\fill}\par Ha az \verb+ln -s+ működik az aktuális fájlrendszeren (mind az operációs rendszer, mind a használt fájlrendszer támogatja a szimbolikus linkeket), akkor az \verb+LN_S+ környezeti változót \verb+ln -s+re állítja, egyébként \verb+ln+re.\par
Ha ez aktuális könyvtártól eltérő könyvtárba teszünk linket, akkor a működése eltér attól függően, hogy \verb+ln+ vagy \verb+ln -s+t használunk-e. Hogy biztonságos módon hozzunk létre linkeket az \verb+$(LN_S)+ használatával, vagy mindig próbáljuk kitalálni, hogy épp melyik változat van érvényben, vagy mindíg abból a könyvtárból hívjuk meg a ahol a linket létre kell hozni. Vagyis ehelyett:
\begin{verbatim}
        $(LN_S) izé /x/mizé
\end{verbatim}
használjuk ezt:
\begin{verbatim}
        (cd /x && $(LN_S) izé mizé)
\end{verbatim}
\item[AC\_PROG\_RANLIB]\hspace*{\fill}\par A \verb+RANLIB+ kimeneti változót beállítja \verb+ranlib+re ha talál \verb+ranlib+et, egyébként nem csinál semmit.
\item[AC\_PROG\_YACC]\hspace*{\fill}\par Ha talál \verb+bison+t, akkor a \verb+YACC+ kimeneti változó értékét \verb+bison -y+ra állítja. Egyébként ha \verb+byacc+ot talál, akkor \verb+byacc+ra állítja, és végső elkeseredésében pedig \verb+yacc+ lesz az értéke.
\end{description}
Az alább következő makrók arra valók, hogy olyan programokat ellenőrizzünk, amelyeket a fenti makrókkal nem tudtunk ellenőrizni. Ha a program egyéb viselkedési módjait is ellenőrizni szeretnénk (mint pl. az \verb+AC_PROC_CC_C_O+ makró csinálja), akkor saját makrókat kell írnunk. Alapértelmezésben az alábbi makrók a \verb+PATH+ környezeti változót ellenőrzik. Ha szeretnénk a keresett programot olyan helyen is keresni, ami a \verb+PATH+ban nincs feltüntetve, akkor egy módosított \verb+PATH+t is átadhatunk, valahogy így:
\begin{verbatim}
AC_PATH_PROG(INETD, inetd, /usr/libexec/inetd,
  $PATH:/usr/libexec:/usr/sbin:/usr/etc:etc)
\end{verbatim}
\begin{description}
\item[AC\_CHECK\_FILE(FÁJL, \lbrack, TEENDŐ-HA-VAN \lbrack,\\TEENDŐ-HA-NINCS\rbrack\rbrack)]\hspace*{\fill}\par
Ellenőrzi, hogy a {\slshape FÁJL} létezik-e a rendszerben. Ha megtalálta, akkor végrehajtja a {\slshape TEENDŐ-HA-VAN} résznek megfelelő teendőket, egyébként pedig a {\slshape TEENDŐ-HA-NINCS} részben előírt teendőket, ha azok adottak.
\item[AC\_CHECK\_FILES(FÁJLOK, \lbrack, TEENDŐ-HA-VAN \lbrack,\\TEENDŐ-HA-NINCS\rbrack\rbrack)]\hspace*{\fill}
Végrehajtja egyszer az \verb+AC_CHECK_FILE+-t minden egyes felsorolt {\slshape FÁJLOK} fájlra. Továbbá definiál \verb+HAVEFILE+-t minden egyes megtalált fájlhoz, és beállítja 1-re.
\item[AC\_CHECK\_PROG(VÁLTOZÓ, ELLENŐRZENDŐ-PROGRAM,] 
\item[ÉRTÉK-HA-VAN \lbrack,ÉRTÉK-HA-NICS \lbrack, PATH, \lbrack REJ \rbrack\rbrack\rbrack)]\hspace*{\fill}\par
Ellenőrzi az {\slshape ELLENŐRZENDŐ-PROGRAM} létezését a \verb+PATH+ban. Ha megtalálta, akkor beállítja a {\slshape VÁLTOZÓ}t az {\slshape ÉRTÉK-HA-VAN} értékre, egyébként az {\slshape ÉRTÉK-HA-NINCS} értékre, ha az adott. Mindig kihagyja a keresésből a {\slshape REJ} fájlt (aminek egy abszolút fájlnévnek kell lennie), még akkor is, hogy ha ezt találja meg elsőnek a keresési \verb+PATH+ban, és beállítja a {\slshape VÁLTOZÓ} értékét az {\slshape ELLENŐRZENDŐ-PROGRAM}-ra, ami nem a {\slshape REJ}. Ha a {\slshape VÁLTOZÓ} értéke már be van állítva, akkor nem csinál semmit. Ez a makró meghívja az \verb+AC_SUBST+ makrót is a {\slshape VÁLTOZÓ}-ra.
\item[AC\_CHECK\_PROGS(VÁLTOZÓ, ELLENŐRZENDŐ-PROGRAMOK \lbrack,]
\item[ÉRTÉK-HA-NINCS \lbrack, PATH\rbrack\rbrack)]\hspace*{\fill}\par
Ellenőrzi, minden egyes az {\slshape ELLENŐRZENDŐ-PROGRAMOK}ban listázott (white-spaceszel elválaszott lista) program létezését a \verb+PATH+ban. Ha megtalálta, akkor beállítja a {\slshape VÁLTOZÓ} értékét a talált program nevére. Egyébként folytatja az ellenőrzést a listában szereplő következő program után. Ha egyik programot se találta meg, akkor a {\slshape VÁLTOZÓ} értékét {\slshape ÉRTÉK-HA-NINCS}re állítja. Illetve, ha ez nincs megadva, akkor a {\slshape VÁLTOZÓ} értéke nem változik. Ez a makró is meghívja az \verb+AC_SUBST+ makrót a {\slshape VÁLTOZÓ}ra.
\item[AC\_CHECK\_TOOL(VÁLTOZÓ, ELLENŐRZENDŐ-PROGRAM \lbrack,]
\item[ÉRTÉK-HA-NINCS \lbrack, PATH\rbrack\rbrack)]\hspace*{\fill}\par
Hasonló az \verb+AC_CHECK_PROG+hoz, de először az {\slshape ELLENŐRZENDŐ-PROGRAM}ot egy az \verb+AC_CANONICAL_HOST+ által megállapított prefixel (és egy azt követő minusz jellel) ellenőrzi. Így például, ha a \verb+configure+ parancsot így adtuk ki: \verb+./configure --host=i386-gnu+, akkor az \verb+AC_CHECK_TOOL(RANLIB, ranlib, :)+ makróhívás beállítja a \verb+RANLIB+et \verb+i386-gnu-ranlib+re ha létezik ilyen a \verb+PATH+ban, vagy \verb+ranlib+re, ha legalább az létezik a \verb+PATH+ban, vagy \verb+:+ra, ha az sem.
\item[AC\_PATH\_PROG(VÁLTOZÓ, ELLENŐRZENDŐ-PROGRAM \lbrack,]
\item[ÉRTÉK-HA-NINCS \lbrack, PATH\rbrack\rbrack)]\hspace*{\fill}\par
Hasonló az \verb+AC_CHECK_PROG+hoz, de a {\slshape VÁLTOZÓ} a program teljes útvonalát veszi fel értékül, ha az {\slshape ELLENŐRZENDŐ-PROGRAM}ot megtalálta.
\item[AC\_PATH\_PROGS(VÁLTOZÓ, ELLENŐRZENDŐ-PROGRAMOK \lbrack,]
\item[ÉRTÉK-HA-NINCS \lbrack, PATH\rbrack\rbrack)]\hspace*{\fill}\par
Hasonló az \verb+AC_CHECK_PROGS+hoz, de a {\slshape VÁLTOZÓ} a program teljes útvonalát veszi fel értékül, ha az {\slshape ELLENÖRZENDŐ-PROGRAMOK} egyikét megtalálta.
\end{description}
\subsubsection{Könyvtárak ({\slshape library}k) ellenőrzése}
\begin{description}
\item[AC\_CHECK\_LIB(LIBRARY, FÜGGVÉNY \lbrack,TEENDŐ-HA-VAN \lbrack,]
\item[TEENDŐ-HA-NINCS \lbrack, EGYÉB-LIBRARYK\rbrack\rbrack\rbrack]\hspace*{\fill}\par
Az aktuális nyelvtől függően, megpróbál meggyőződni arról, hogy a {\scshape C}, {\scshape C++}, {\scshape Fortran 77}ben elérhető a {\slshape FÜGGVÉNY} a {\slshape LIBRARY}ban, egy tesztprogramon keresztül, amit ehhez szerkeszt. A {\slshape LIBRARY} az alapneve a könyvtárnak, ha pl. a \verb+-lmp+ -vel szeretnénk hozzászerkeszteni az \verb+mp+ könyvtárat, akkor legyen \verb+mp+ az argumentum.\par
A {\slshape TEENDŐ-HA-VAN} shell parancsok listája, amelyet akkor futtat le, ha a könyvtárhoz való szerkesztés sikerült. Ha ez nem definiált, akkor az alapértelmezett teendő hozzáveszi a \verb+-lLIBRARY+-t a \verb+LIBS+hez és definiálja a \verb+HAVE_LIBLIBRARY+ szimbólumot, ahol minden csupa nagybetűs.\par
Ha a {\slshape LIBRARY} hozzászerkesztése feloldatlan szimbólumokat eredményezne, mert további könyvtárakat is meg kell adni a szerkesztéshez, akkor azokat az {\slshape EGYÉB-LIBRARYK} argumentumként adjuk meg szóközökkel szeparálva, pl. így \verb+-lXt -lX11+. Egyébként a makró hibásan detektálhatja egy könyvtár létezését, mert a tesztprogram összeszerkesztése mindig hibára vezet a feloldatlan szimbólumok miatt.
\item[AC\_HAVE\_LIBRARY(LIBRARY \lbrack, TEENDŐ-HA-VAN \lbrack,]
\item[TEENDŐ-HA-NINCS \lbrack, EGYÉB-LIBRARYK\rbrack\rbrack\rbrack]\hspace*{\fill}\par
Ez a makró ekvivalens avval mintha az \verb+AC_CHECK_LIB+-et hívtuk volna meg a {\slshape FÜGGVÉNY} paraméterként \verb+main+-t megadva. Továbbá a {\slshape LIBRARY} írható \verb+izé+, \verb+-lizé+, vagy \verb+libizé.a+ alakban. Mindegyik esetben a fordító a \verb+-lizé+ paramétert fogja megkapni. A {\slshape LIBRARY} nem lehet shellbeli változó, hanem azt betű szerint érti. Ez a makró már idejétmúltnak tekintendő.
\item[AC\_SEARCH\_LIBS(FÜGGVÉNY, PRÓBA-LIBEK \lbrack, TEENDŐ-HA-VAN \lbrack,]
\item[TEENDŐ-HA-NINCS \lbrack, EGYÉB-LIBRARYK\rbrack\rbrack\rbrack]\hspace*{\fill}\par
Hasonló a fentiekhez. A teszt megpróbálja kitalálni, hogy a {\slshape FÜGGVÉNY} melyik libraryban van. Először további könyvtár nélkül, majd az {\slshape PRÓBA-LIBEK}ben felsoroltakat próbálja az \verb+AC_TRY_LINK_FUNC+ makró hozzászerkeszteni a példaprogramhoz. A többi argumentum kezelése, és alapértelmezései, hasonlóak a fentiekhez.\footnote{Például használhatjuk arra, hogy ha hálózatos programot írunk, ki tudjuk találni, hogy az {\ttfamily nsl} library-t hozzá kell-e szerkeszteni a socket() hívás miatt a programhoz.}
\end{description}
\subsubsection{Könyvtári függvények ellenőrzése}
Speciális könyvtári függvények tulajdonságainak ellenőrzése:
\begin{description}
\item[AC\_FUNC\_ALLOCA]
\item[AC\_FUNC\_CLOSEDIR\_VOID]
\item[AC\_FUNC\_FNMATCH]
\item[AC\_FUNC\_GETLOADAVG]
\item[AC\_FUNC\_GETMNTENT]
\item[AC\_FUNC\_GETPGRP]
\item[AC\_FUNC\_MEMCMP]
\item[AC\_FUNC\_MMAP]
\item[AC\_FUNC\_SELECT\_ARGTYPES]
\item[AC\_FUNC\_SETPGRP]
\item[AC\_FUNC\_SETVBUF\_RESERVED]
\item[AC\_FUNC\_STRCOLL]
\item[AC\_FUNC\_STRFTIME]
\item[AC\_FUNC\_UTIME\_NULL]
\item[AC\_FUNC\_VFORK]
\item[AC\_FUNC\_VPRINTF]
\item[AC\_FUNC\_WAIT3]
\end{description}
Általános függvényekkel kapcsolatos tesztek:
\begin{description}
\item[AC\_CHECK\_FUNC(FÜGGVÉNY \lbrack, TEENDŐ-HA-VAN \lbrack, TEENDŐ-HA-NINCS\rbrack\rbrack]
\item[AC\_CHECK\_FUNCS(FÜGGVÉNY \dots\lbrack, TEENDŐ-HA-VAN \lbrack, TEENDŐ-HA-NINCS\rbrack\rbrack]
\item[AC\_REPLACE\_FUNCS(FÜGGVÉNY \dots)]
\end{description}
\subsubsection{Fejléc állományok meglétének ellenőrzése}
Speciális fejlécek ellenőrzése:
\begin{description}
\item[AC\_DECL\_SYS\_SIGLIST]
\item[AC\_DIR\_HEADER]
\item[AC\_HEADER\_DIRENT]
\item[AC\_HEADER\_MAJOR]
\item[AC\_HEADER\_STDC]
\item[AC\_HEADER\_SYS\_WAIT]
\item[AC\_MEMORY\_H]
\item[AC\_UNISTD\_H]
\item[AC\_USG]
\end{description}
Általános fejlécellenőrző makrók:
\begin{description}
\item[AC\_CHECK\_HEADER(FEJLÉCFÁJL \lbrack, TEENDŐ-HA-VAN \lbrack, TEENDŐ-HA-NINCS\rbrack\rbrack)]
\item[AC\_CHECK\_HEADERS(FEJLÉCFÁJL \dots \lbrack, TEENDŐ-HA-VAN \lbrack, TEENDŐ-HA-NINCS\rbrack\rbrack)]
\end{description}
\subsubsection{Struktúrák, illetve a tagjainak ellenőrzése}
\begin{description}
\item[AC\_HEADER\_STAT]
\item[AC\_HEADER\_TIME]
\item[AC\_STRUCT\_ST\_BLKSIZE]
\item[AC\_STRUCT\_ST\_BLOCKS]
\item[AC\_STRUCT\_ST\_RDEV]
\item[AC\_STRUCT\_TM]
\item[AC\_STRUCT\_TIMEZONE]
\end{description}
\subsubsection{Típusdefiníciók ellenőrzése}
Speciális típusdefiníciók ellenőrzése:
\begin{description}
\item[AC\_TYPE\_GETGROUPS]
\item[AC\_TYPE\_MODE\_T]
\item[AC\_TYPE\_OFF\_T]
\item[AC\_TYPE\_PID\_T]
\item[AC\_TYPE\_SIGNAL]
\item[AC\_TYPE\_SIZE\_T]
\item[AC\_TYPE\_UID\_T]
\end{description}
Általános típusdefiníció ellenörző makrók:
\begin{description}
\item[AC\_CHECK\_TYPE(TÍPUS, ALAPÉRTELMEZÉS)]
\end{description}
\subsubsection{Programfordító fordítási tulajdonságainak ({\slshape karakterisztikájának}) tesztelése}
\begin{description}
\item[AC\_C\_BIGENDIAN]
\item[AC\_C\_CONST]
\item[AC\_C\_INLINE]
\item[AC\_C\_CHAR\_UNSIGNED]
\item[AC\_C\_LONG\_DOUBLE]
\item[AC\_C\_STRINGIZE]
\item[AC\_CHECK\_SIZEOF(TÍPUS \lbrack, KERESZT-MÉRET\rbrack)]
\item[AC\_INT\_16\_BITS]
\item[AC\_LONG\_64\_BITS]
\item[AC\_F77\_LIBRARY\_LDFLAGS]
\end{description}
\subsubsection{Rendszerszolgáltatások ellenőrzése}
\begin{description}
\item[AC\_CYGWIN]
\item[AC\_EXEEXT]
\item[AC\_OBJEXT]
\item[AC\_MINGW32]
\item[AC\_PATH\_X]
\item[AC\_PATH\_XTRA]
\item[AC\_SYS\_INTERPRETER]
\item[AC\_SYS\_LONG\_FILE\_NAMES]
\item[AC\_SYS\_RESTARTABLE\_SYSCALLS]
\end{description}
\subsubsection{Unix változatokra vonatkozó ellenőrzések}
\begin{description}
\item[AC\_AIX]
\item[AC\_DYNIX\_SEQ]
\item[AC\_IRIX\_SUN]
\item[AC\_ISC\_POSIX]
\item[AC\_MINIX]
\item[AC\_SCO\_INTL]
\item[AC\_XENIX\_DIR]
\end{description}
\subsection{Hogyan írjunk saját teszteket}
\clearpage
\section{A GNU automake}
\subsection{Bevezető}
Az \verb+automake+ egy olyan eszköz amely elkészíti helyettünk a \verb+Makefile.in+ fájlt a \verb+Makefile.am+ alapján. Minden egyes \verb+Makefile.am+ alapvetően egy sor makródefiníció a {\scshape make} számára. A generált \verb+Makefile.in+ megfelel a {\scshape GNU Makefile} szabványainak.$_{\pageref{makefilekonvenciok}}$\par
A {\slshape GNU Makefile Szabványok Dokumentuma} nagy, komplikált és hajlamos a változásra. Az \verb+automake+ célja, hogy ne a Makefile karbantartásával menjen el a programozó ideje (hanem az legyen az az \verb+automake+ karbantartójának gondja).\par
Egy tipikus \verb+automake+ bemeneti fájl egyszerűen néhány makró definicíóból áll. Minden egyes ilyen fájlból készül egy \verb+Makefile.in+. Így a projekt minden egyes könyvtárának tartalmaznia kell egy \verb+Makefile.am+ fájlt.\par
Az \verb+automake+ a projektre vonatkozóan számos kötöttséggel jár; például avval, hogy feltételezi, hogy \verb+autoconf+ot is használunk, valamint ránkkényszerít néhány megszorítást a configure.in tartalmával kapcsolatban.\par
Az \verb+automake+nek szüksége van a {\scshape perl}re is hogy legenerálja a \verb+Makefile.in+-t, de ez csak a projtekből disztributálandó fájlt elkészítő gépen szükséges (vagyis ahol, az \verb+automake+ parancsal a \verb+Makefile.in+-t elkészítjük).
\subsection{Általános működés}
Az \verb+automake+ elolvssa a \verb+Makefile.am+ fájlt és generál belőle egy \verb+Makefile.in+t. Számos makró és target amit a \verb+Makefile.am+ben definiálunk arra utasíthatja az \verb+automake+et, hogy specializáltabb kódot készítsen. Például a \verb+bin_PROGRAMS+ makró definíciója olyan hatással van a targetekre, hogy lefordítsák és összeszerkesszék a generálandó programot.\par
A \verb+Makefile.am+ben szereplő makródefiníciók és targetek pontosan (betűről betűre) átmásolódnak a generált \verb+Makefile.in+be.\par
Figyelem a {\scshape GNU Make} kiterjesztéseit nem ismeri fel az automake. Ha ezeket a kiterjesztéseket használjuk a \verb+Makefile.am+-ben akkor hibához és nemvárt viselkedéshez vezethet!\par
Ha egy targetet definiálunk a \verb+Makefile.am+ben és létezik olyan target amit ugyanilyen néven az automake is létrehozna alapértelmezésben, akkor a ,,miénk'' fog érvényre jutni. Habár ez egy támogatott tulajdonság, általában jobb kerülni (mert időnként a generált szabályok nagyon finnyásak lehetnek).\par
Hasonlóképpen ha a \verb+Makefile.am+ben definiálunk egy makrót, akkor az az \verb+automake+ által alapértelmezetten generáltat felülbírálja. Vedd figyelembe, hogy az \verb+automake+ által generált makrók a saját belső használatára készülnek, és a nevük a későbbi \verb+automake+ kiadásokban változhat.\par
Amikor makró definíciókat vizsgálunk, akkor tudnunk kell, hogy az automake rekurzívan megvizsgálja a hivatkozott makró definícióját. Például, ha az \verb+automake+ egy ilyen részlettel találkozik:
\begin{verbatim}
xs = a.c b.c
izé_SOURCES = c.c $(xs)
\end{verbatim}
Akkor az \verb+a.c+, \verb+b.c+ és \verb+c.c+ fájlokat veszi a \verb+izé_SOURCES+ tartalmául.\par
Az \verb+automake+ lehetővé teszi olyan megjegyzések írását is ami {\bfseries nem} másolódik át a kimenetére. Minden \verb+##+el kezdődő sort teljesen figyelmenkívül hagy az \verb+automake+. Például érdemes lehet a \verb+Makefile.am+ első sorát így kezdeni:
\begin{verbatim}
## Dolgoztasd fel ezt a fájlt az automake-el, hogy készítsen belőle egy Makefile.in-t.
\end{verbatim}
\subsection{Könyvtár mélységek}
Az \verb+automake+ három különböző könyvtárhierarchiát támogat: \verb+flat+, \verb+shallow+ és \verb+deep+.\par
A ,,flat'' csomag minden fájlját egyszerűen egy könyvtárban tartja. A \verb+Makefile.am+ ebben az esetben nem definiálja a \verb+SUBDIRS+ makrót. Például ilyen a \verb+termutils+ csomag, vagy a múlt órán bemutatott \verb+fdist+.\par
A ,,deep'' csomag esetén a forráskódok alkönyvtárakban helyezkednek el, a legfelső szintű könyvtár leginkább csak konfigurációs információt tartalmaz. A \verb+cpio+ jó példa egy ilyen csomagra, csakúgy mint a {\scshape GNU} \verb+tar+. A felső szintű \verb+Makefile.am+ egy ,,deep'' csomagnál tartalmaz egy \verb+SUBDIRS+ makrót (illetve annak definícióját), de nem tartalmaz más makrókat amelyek a készítendő objektumokra vonatkoznának.\par
A ,,shallow'' csomag olyan, ahol a fő forrás a legfelső szintű könyvtárban találhatő, még számos más része (tipikusan könyvtárak{\slshape /libraryk}) pedig alkönyvtárakban.
\subsection{Szigor}
Habár az \verb+automake+t arra tervezték hogy a {\scshape GNU} csomagok karbantartói használják, tesznek arra vonatkozóan is erőfeszítéseket, hogy azoknak is hasznos legyen akik nem szeretnék az összes {\scshape GNU} konvenciót követni.\par
Emiatt az \verb+automake+ három szintet támogat a ,,szigorúságot'' illetően, attól függően hogy mennyire szeretnénk, hogy az automake a szabványoknak való megfelelést ellenőrizze. Az érvényes szigorúsági szintek:
\begin{description}
\item[foreign]Az \verb+automake+ csak azokat a funkciókat ellenőrzi, amelyek abszolút szükségesek a megfelelő működéshez. Például a {\scshape GNU} Szabványok előírják a \verb+NEWS+ fájl létezését, ez nem szükséges ebben a módban. A név abból a tényből származik, hogy az \verb+automake+t arra szánták, hogy a {\scshape GNU} programokhoz használják; így ezek a görcsös szabályok nem szükségesek a működéshez.
\item[gnu]Az \verb+automake+ annyi ellenőrzést végez, amennyit csak lehet, hogy betartassa a {\scshape GNU} előírásait. Ez az alapértelmezett.
\item[gnits]Az \verb+automake+ a még iratlan ,,Gnits szabványok''nak való megfelelőséget ellenőrzi. Ezek a {\scshape GNU} szabványokon alapulnak, de sokkal részletesebbek. Ameddig el nem készül a Gnits és nem publikálják, addig javallott nem ezt használni.
\end{description}
\subsection{Az egyésges nevezéktani séma}
Az \verb+automake+ makrók (innentől {\slshape változó}ként hivatkozunk rájuk) általában egy általános nevezéktani sémát követnek, ami egyszerűvé teszi, hogy eldöntsük, hogy a programok hogyan készülnek, és hogyan települnek. Ez a séma támogatja például azt, hogy a \verb+configure+ parancs futásakor dőljön el, hogy minek kell lefordulnia.\par
A \verb+make+ futásakor a megfelelő változókat használjuk arra, hogy meghatározzuk mely objektumokat kell megépíteni. Ezeket a változókat hívjuk ,,elsődleges változóknak''. Például a \verb+PROGRAMS+ nevű elsődleges változó tartalmaz egy listát azokról a programokról amelyeket le kell fordítani, és össze kell szerkeszteni.\par
A változók egy másik részét arra használjuk, hogy meghatározzuk, hogy az elkészült objektumokat hova telepítsük. Ezeket a változókat az elsődleges változók után nevezzük el, de megmarad prefixként a szabványos könyvtár, amit telepítő könyvtárnak használnánk. A szabványos könyvtárnevek meg vannak határozva a {\slshape GNU} szabványokban. Az automake kiterjeszti ezt a \verb+pkglibdir+, \verb+pkgincludedir+ és a \verb+pkgdatadir+el. Ezek hasonlók a nem\verb+pkg+s változathoz, csak még a \verb+@PACKAGE@+ hozzáadódik a végéhez. Például a \verb+pkglibdir+t \verb+$(libdir)/@PACKAGE@+ként definiálja.\par
Minden egyes elsődleges változóhoz létezik egy további változó, ahol a nevét az \verb+EXTRA_+ prefixummal jelöljük meg az elsődleges változathoz képest. Ezt a változót arra használjuk, hogy felsoroljunk objektumokat amelyeket talán megépítünk, talán nem, függően attól, hogy a \verb+configure+ hogyan döntött. Ezt a változó azért kell, mert az \verb+automake+nek statikusan tudnia kell a teljes listáját azon objektumoknak amelyet lehet hogy meg kell építenie, és olyan \verb+Makefile.in+t kell generálnia hozzá, ami minden esetben működik. Például a \verb+cpio+ eldönti a \verb+configure+ futtatásakor, hogy mely programokat kell megépítenie. Ezek közül bizonyos programokat a \verb+bindir+be és bizonyosakat a \verb+sbindir+be kell telepítenie:
\begin{verbatim}
EXTRA_PROGRAMS = mt rmt
bin_PROGRAMS = cpio pax
sbin_PROGRAMS = @PROGRAMS@
\end{verbatim}
Ha egy elsődleges változót prefix nélkül definiálunk (például \verb+PROGRAMS+) az hibát jelent.\par
Az általános \verb+dir+ utótag lemarad amikor változóneveket konstruálunk, így pl. \verb+bin_PROGRAMS+-t kell írni és nem \verb+bindir_PROGRAMS+-t.\par
Nem minden fajta objektumot lehet bármelyik könyvtárba telepíteni. Az \verb+automake+ figyeli az ilyen próbálkozásokat és hibát jelez. Az \verb+automake+ diagnosztizálja azt is, ha könyvtárneveket elgépelünk.\par
Néha a szabványos könyvtára kevésnek bizonyulnak, még akkor is, ha azokat némileg feljavítja az \verb+automake+. Különösen hasznos lehet, ha objektumokat valamilyen előre definiált alkönyvtárba szeretnénk telepíteni. Evégett az \verb+automake+ lehetővé teszi, hogy kiterjesszük a lehetséges telepítési könyvtárakat. Legyen adott egy prefix (például \verb+zar+) amit érvényesnek tekint, ha a hasonló nevű változóhoz a \verb+dir+t hozzáadjuk, és az definiált (vagyis \verb+zardir+).\par
Például, ameddig a html támogatás nem része az \verb+automake+nek addig megtehetjük, hogy ezt használjuk a nyers html dokumentáció telepítésére:
\begin{verbatim}
htmldir = $(prefix)/html
html_DATA = automake.html
\end{verbatim}
A speciális \verb+noinst+ prefix azt jelzi, hogy a kérdéses objektumokat egyáltalán nem kell telepíteni.\par
A speciális \verb+check+ prefix azt jelzi, hogy a kérdéses objektumokat nem lehet elkezdeni építeni ameddig a \verb+make check+ parancs le nem futott.\par
A lehetséges elsődleges nevek: \verb+PROGRAMS+, \verb+LIBRARIES+, \verb+LISP+, \verb+SCRIPTS+, \verb+DATA+, \verb+HEADERS+, \verb+MANS+ és \verb+TEXINFOS+.
\subsubsection{Hogyan származtatjuk a változók neveit}
Megesik, hogy egy \verb+Makefile+ változónév valamilyen a felhasználó által megadott szövegből származik. Például programneveket újraírunk \verb+Makefile+ makrónevekké. Az \verb+automake+ kanonizálja ezt a szöveget így annak nem kell követnie a \verb+Makefile+ makróelnevezési szabályokat. Minden karaktert a névben kivéve a betűket, számokat és az aláhúzásjelet aláhúzásjellé változtat amikor makróhivatkozásokat készít. Például ha a programot \verb+izé-mizének+ hívják, akkor a származtatott változónév \verb+izé_mizé_SOURCES+ lesz és nem \verb+izé-mizé_SOURCES+.
\subsection{Példák}
\subsubsection{Teljes}
Tegyük fel, épp most fejeztem be az \verb+fdist+ megírását. Szeretném az \verb+autoconf+ot használni a hordozhatósági keretmunkák végett, de a \verb+Makefile.in+ csak ad-hoc módon lett összedobálva, és bolondbiztosat szeretnék helyette.\par
Az első lépés hogy a \verb+configure.in+t frissítsem ennek megfelelően, hogy az \verb+automake+ által igényelt részek is belekerüljenek. A legegyszerűbb módja, hogy ezt megtegyük, az az \verb+AM_INIT_AUTOMAKE+ makróhívás hozzáadása az \verb+AC_INIT+ után:
\begin{verbatim}
AM_INIT_AUTOMAKE(fdist, 0.1)
\end{verbatim}
Mivel a programba nem tettem semmit, ami megnehezítené a dolgom (például, nem használja a gettextet, helyette vegyesen angolul és magyarul káromkodik, és nem is akar osztott könyvtárat készíteni), evvel a résszel kész vagyunk. (Természetesen még az \verb+AC_CONFIG_HEADER+t le kell cserélni \verb+AM_CONFIG_HEADER+re.)\par
Most újragenerálhatom a \verb+configure+omat, de mielőtt ezt megtenném, az \verb+autoconf+al közölnöm kell hogyan talája meg az általam használt új makrót. A legegyszerűbb módja ennek az \verb+aclocal+ program meghívása, ami generál egy \verb+aclocal.m4+ fájlt nekem. De ha netán már lett volna egy ilyen fájlom, mert némi csicsázó makrót itt írtam volna meg magamnak, akkor az \verb+aclocal+ lehetővé teszi számomra, hogy a saját makróimat inkább az \verb+acinclude.m4+be tegyem, így csak át kell neveznem a ,,saját'' \verb+aclocal.m4+emet \verb+acinclude.m4+re, majd a többi:
\begin{verbatim}
$ mv aclocal.m4 acinclude.m4
$ aclocal
$ autoconf
\end{verbatim}
Itt az ideje, hogy megírjam a \verb+Makefile.am+-et az \verb+fdist+hez. Lévén az \verb+fdist+ egy felhasználói program, oda szeretném telepíteni, ahova a felhasználói programok mennek. Továbbá feltételezhetjük, hogy lesz némi Texinfo dokumentációja. Ha a \verb+configure.in+ scriptem használná az \verb+AC_REPLACE_FUNCS+ot is, akkor a \verb+@LIBOBJS@+hoz hozzá kellene szerkesztenem. Így az egész így nézne ki, amit bele kell írjak a \verb+Makefile.am+be:
\begin{verbatim}
bin_PROGRAMS = fdist
fdist_SOURCES = fdist.c fdist.h md5.c md5.h
fdist_LDADD = @LIBOBJS@

info_TEXINFOS = fdist.texi
\end{verbatim}
Most lefuttathatom az \verb+automake --add-missing+ parancsot, ami legenerálja a Makefile.in-t és begyűjti a szükséges segéd fájlokat, amire szükségem lehet, és kész is vagyok.
\subsubsection{Hello}
A {\scshape GNU hello}\footnote{url:{\ttfamily ftp://prep.ai.mit.edu/pub/gnu/hello-1.3.tar.gz}} híres az egyszerűségéről és a sokoldalúságáról. Ez a rész bemutatja, hogyan lehet a {\scshape GNU hello} csomagot automakessé tenni. Az alábbi példák a béta verzióból származnak.\par
Természetesen a {\scshape GNU hello} valamivel többet tud mint a tradícionális kétsoros változat. A {\scshape GNU hello} nemzetköziesítve van, opciófeldolgozást csinál, és van kézikönyve és egy tesztkörnyezete. A {\scshape GNU hello} egy ,,deep'' csomag.\par
Ime a \verb+configure.in+ hozzá:
\begin{verbatim}
dnl Dolgoztasd fel az autoconf-al, hogy kapj egy configure scriptet.
AC_INIT(src/hello.c)
AM_INIT_AUTOMAKE(hello, 1.3.11)
AM_CONFIG_HEADER(config.h)
dnl Az elérhető nyelvek
ALL_LINGUAS="de fr es ko nl no pl pt sl sv"

dnl Checks for programs.
AC_PROG_CC
AC_ISC_POSIX

dnl Checks for libraries.

dnl Checks for header files.
AC_STDC_HEADERS
AC_HAVE_HEADERS(string.h fcntl.h sys/file.h sys/param.h)

dnl Checks for library functions.
AC_FUNC_ALLOCA

dnl Check for st_blksize in struct stat
AC_ST_BLKSIZE

dnl internationalization macros
AM_GNU_GETTEXT
AC_OUTPUT([Makefile doc/Makefile intl/Makefile po/Makefile.in \
           src/Makefile tests/Makefile tests/hello],
   [chmod +x tests/hello])
\end{verbatim}
Az \verb+AM_+ makrókat az \verb+automake+ biztosítja, a nagyja pedig \verb+autoconf+ makró.\par
Íme a felső szintű \verb+Makefile.am+:
\begin{verbatim}
EXTRA_DIST = BUGS ChangeLog.O
SUBDIRS = doc intl po src tests
\end{verbatim}
Mint látható az igazi munka itt az alkönyvtárakban folyik. A \verb+po+ és az \verb+intl+ könyvtárakat automatikusan hozza létre a \verb+gettextize+ használata, amelyre most nem térek ki.\par
Íme a \verb+doc/Makefile.am+:
\begin{verbatim}
info_TEXINFOS = hello.texi
hello_TEXINFOS = gpl.texi
\end{verbatim}
Ez a rész a {\scshape GNU hello} kézikönyvének építéséhez, telepítéséhez és terjesztéséhez szükséges.\par
A \verb+test/Makefile.am+:
\begin{verbatim}
TESTS = hello
EXTRA_DIST = hello.in testdata
\end{verbatim}
A \verb+hello+ egy a \verb+configure+ által generált script, és ez az egyetlen teszt eset. A \verb+make check+ ezt a tesztet fogja futtatni.\par
És végül a \verb+src/Makefile.am+, ahol az igazi munka folyik:
\begin{verbatim}
bin_PROGRAMS = hello
hello_SOURCES = hello.c version.c getopt.c getopt1.c getopt.h system.h
hello_LDADD = @INTLLIBS@ @ALLOCA@
localedir = $(datadir)/locale
INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\"
\end{verbatim}
\subsubsection{etags}
Íme egy másik trükkös példa. Bemutatja, hogy generáljunk két programot (az \verb+ctags+ot és az \verb+etags+ot), ugyanabból a közös forrás fájlból (\verb+etags.c+). A nehéz része az \verb+etags.c+ minden fordításakor más opciókat kell a preprocesszornak átadni.
\begin{verbatim}
bin_PROGRAMS = etags ctags
ctags_SOURCES =
ctags_LDADD = ctags.o

etags.o: etags.c
        $(COMPILE) -DETAGS_REGEXPS -c etags.c

ctags.o: etags.c
        $(COMPILE) -DCTAGS -o ctags.o -c etags.c
\end{verbatim}
Figyeljük meg, hogy a \verb+ctags_SOURCES+t üresnek definiáltuk, ilymódon nem lesz implicit érték behelyettesítve. Az implicit érték egyébként amit az \verb+etags+ generálásához használ az \verb+etags.o+.\par
A \verb+ctags_LDADD+ot arra használjuk, hogy a ctags.o belekerüljön a szerkesztéskor a parancssorba. A \verb+ctags_DEPENDENCIES+t az \verb+automake+ generálja.\par
A fenti szabályok nem fognak működni, ha a fordító nem fogadja el egyszerre a \verb+-c+ és a \verb+-o+ kapcsolókat. A legegyszerűbb javítás ha a evvel együtt koholt függőségeket is bemutatunk (ami amiatt kell, hogy ne okozzon problémát két párhuzamosan futó \verb+make+):
\begin{verbatim}
etags.o: etags.c ctags.o
        $(COMPILE) -DETAGS_REGEXPS -c etags.c

ctags.o: etags.c
        $(COMPILE) -DCTAGS -c etags.c && mv etags.o ctags.o
\end{verbatim}
Ezek az explicit szabályok nem működnek, ha a deANSIfikációt is bekapcsoljuk. Ha ezt is támogatni szeretnénk, akkor a következő kell:
\begin{verbatim}
etags._o: etags._c ctags.o
        $(COMPILE) -DETAGS_REGEXPS -c etags.c

ctags._o: etags._c
        $(COMPILE) -DCTAGS -c etags.c && mv etags._o ctags.o
\end{verbatim}
\clearpage
%\section{A GNU libtool}
%\clearpage
%\section{Egy GNU program szerkezete, felépítése, konvenciói...}
%\clearpage
\section{A digitális hitelesítés alapjai}
\subsection{Kódolási típusok}
Már elég korán az emberiség történetében felmerült, hogy információkat olyan formában juttassanak el valahova, hogy aki közben esetleg elolvassa, az ne tudja kinyerni belőle a ,,titkos'' információt. Sokféle módszert kitaláltak, de mi csak a ,,digitálisan'' tárolt információk kódolásának egy részét tekintjük át.\par
A titkosítási algoritmusok alapvetően két csoportra oszthatók:
\begin{description}
\item[szimmetrikus kulcsú titkosítások]Ugyanazt a közös ,,titkot'' kell ismerni a kódolt információ visszanyeréséhez, és eltitkosításához is (például egy jelszót). Nagy adatmennyiség esetén is viszonylag nehezen fejthető vissza. Ilyen pl. a {\scshape des}, {\scshape 3des}, {\scshape Blowfish}. A {\scshape des}-t pl. az ssh 1-es protokollban használták az adatfolyam elkódolására, használata a kriptografikus gyengesége miatt ellenjavalt. A {\scshape 3des} ennek olyan módosítása, ahol a kódolandó adatfolyam egy kódolás-dekódolás-kódolás hármason megy át, 3 különböző kulccsal. A {\scshape Blowfish} egy blokkos jellegű, gyors titkosítási algoritmus.
\begin{figure}[h]
\xy *+\txt{Eredeti,\\titkosítatlan adat}="a" *\frm{-,},
(40,0)*+\txt{Titkosító kulcs}="k" *\frm<8pt>{-},
(80,0)*+\txt{Kódolt adat}="e" *\frm{-,},
"a";"e" **\crv{(40,10)} ?>*\dir{>},
"e";"a" **\crv{(40,-10)} ?>*\dir{>}
%"e";"k" **\crvs{-} ?>*\dir{>},
%"k";"a" **\crvs{-} ?>*\dir{>}
\endxy
\caption{szimmetrikus kulcsú titkosítások sémája}
\end{figure}
\item[asszimetrikus kulcsú titkosítások]A titkosítotáshoz itt is szükség van egy kulcsra, de a visszakódoláshoz már egy másik kulcs kell. Ez a két kulcs egymásból nem számítható ki. Az ilyen jellegű algoritmusok arra a tényre támaszkodnak, hogy a nagy számok prímfaktorizációja nehezen megoldható. A két kulcs szerepe teljesen ,,szimmetrikus'', olyan értelemben, hogy ha az egyikkel kódoljuk el az adatot akkor a másikkal tudjuk dekódolni. Nem érdemes nagy mennyiségű, kis entrópiájú adatot ilymódon elkódolni, mert avval csak azok dolgát könnyítjük meg, aki megpróbálja a nem ismert kulcsot kitalálni. (Általában a kulcspár egyik felét közzé szokták tenni.) Ilyen titkosítási algoritmusok pl. RSA, DSA, El Gammal.\par
\begin{figure}[h]
\xy *+\txt{Eredeti,\\titkosítatlan adat}="a" *\frm{-,},
(40,8)*+\txt{kulcs1}="k" *\frm<8pt>{-},
(40,-8)*+\txt{kulcs2}="l" *\frm<8pt>{-},
(80,0)*+\txt{Kódolt adat}="e" *\frm{-,},
"a";"e" **\crv{(40,10)} ?>*\dir{>},
"e";"a" **\crv{(40,-10)} ?>*\dir{>}
\endxy
\caption{asszimmetrikus kulcsú titkosítások sémája}
\end{figure}
Ezt a típusú kódolást többféleképpen is lehet alkalmazni. Az egyik cél, hogy úgy küldjünk valakinek információt, hogy azt senki más ne tudja elolvasni, csak a címzett. A másik amire még lehet használni, hogy valaki úgy adjon közre információt, hogy avval ,,hitelesen'' bizonyítja, hogy azt az információt ő tette közzé. De ezt a két lehetőséget akár kombinálhatjuk is. Nézzünk konkrét példákat:\par
András generál magának egy kulcspárt. A kulcspár egyik felét megtartja magának, ez lesz a privát kulcsa; a kulcspár másik felét közzéteszi, ez lesz a publikus kulcsa. Ha szeretnék Andrásnak üzenni, úgy hogy csak ő tudja elolvasni, akkor az András által közzétett kulccsal eltitkosítom az üzenetem, így azt csak András tudja visszafejteni az ő privát kulcsával.\par
Nézzünk egy másik példát, ahol Béla szeretne közzetenni információt úgy, hogy biztosak lehessünk benne, hogy azt Béla tette közzé. Ekkor Béla a privát kulcsával elkódolja az információt, és az ilymódon elkódolt információt teszi közzé. Ezt az elkódolt információt viszont bárki visszanyerheti, hiszen, Béla a publikus kulcsát közzétette, és mi pedig biztosak lehetünk benne, hogy az információt Béla tette közzé, hiszen Béla privát kulcsa egyedül Bélának van meg, és azt tudjuk, hogy csak Béla privát kulcsával kódolhatták el az infót, hiszen a dekódoláshoz Béla publikus kulcsa kellett.\par
Végül nézzünk egy olyan példát, ahol Béla szeretne információt eljuttatni Andrásnak, úgy hogy csak András tudja elolvasni ezt, és András biztos lehessen benne, hogy Bélától származik a kódolt információ: Ekkor Béla az üzenetét elkódolja a saját privát kulcsával (ezt az átmeneti ,,információt'', most hívjuk {\scshape izé}nek), és az így kapott eredményt elkódolja András publikus kulcsával. Ezt a legvégső fázisban kapott információt elküldi Andrásnak. Andrásnak most az a dolga, hogy a (feltehetően) Bélától kapott információt a saját privát kulcsával elkódolja (ami ebben az esetben épp ,,dekódolás''). Ekkor András megkapja {\scshape izé}t, amiről feltételezi, hogy Béla küldte neki. András most {\scshape izé}t elkódolja Béla publikus kulcsával, aminek eredményéül megkapja Béla eredeti üzenetét titkosítatlanül, és biztos lehet benne, hogy az {\scshape izé} Bélától származik, hiszen azt Béla publikus kulcsával tudta dekódolni.
\begin{figure}[h]
\xy *+\txt{Béla eredeti,\\kódolatlan üzenete}="a" *\frm{-,},
(35,10)*+\txt{Béla privát\\kulcsa}="b" *\frm<8pt>{-},
(35,-10)*+\txt{Béla publikus\\kulcsa}="c" *\frm<8pt>{-},
(65,0)*+\txt{izé}="d" *\frm{-,},
(100,10)*+\txt{András privát\\kulcsa}="e" *\frm<8pt>{-},
(100,-10)*+\txt{András publikus\\kulcsa}="f" *\frm<8pt>{-},
(140,0)*+\txt{Titkosított üzenet,\\amit András megkap}="g" *\frm{-,},
"a";"d" **\crv{(35,10)} ?>*\dir{>},
"d";"a" **\crv{(35,-10)} ?>*\dir{>},
"g";"d" **\crv{(100,10)} ?>*\dir{>},
"d";"g" **\crv{(100,-10)} ?>*\dir{>}
\endxy
\caption{titkos üzenet küldésének sémája}
\end{figure}
\end{description}\par
Mint azt említettem, nagy mennyiségű (és kis entrópiájú) adatra nem érdemes asszimetrikus kulcsú titkosítást használni, mert evvel támadási felületet nyújtunk a kulcspár ismeretlen felének visszafejtéséhez. A gyakorlatban, pl. az ssh program az asszimetrikus kulcsú titkosítást arra használja, hogy a szerver és a kliens egy (nem túl) rövid, random, nagy entrópiájú titkosítási kulcsban megeggyezzen, és a tényleges adatfolyam pedig {\scshape 3des} vagy {\scshape Blowfish}el lesz elkódolva. (Lásd ssh kézikönyv -c opció: cipher kiválasztása.)\par
Az ssh az asszimetrikus kulcsú kódolásokat arra is használja, hogy a felhasználó azonosítást ezen keresztül oldja meg: A kliens oldalon nem egy jelszót kell begépelnünk, hanem egy kulcs privát felével kell rendelkeznünk, valamint a túloldalra el kell juttatnunk a kulcs publikus felét. Ekkor a szerver eljuttat a kliensünknek egy random adatot, amit a privát kulcsal el kell kódolnia, és visszaküldenie (Challange-Response). A szervernek az ellenőrzéshez annyi feladata van, hogy a választ a publikus kulcsunkal elkódolva, összehasonlítsa, hogy megegyezik-e az eredetileg küldött ,,random'' adattal. (megj: szintén ajánlatos viszonylag kevés, nagy entrópiájú adatot küldenie a szervernek.)
\subsection{Kivonatolási algoritmusok}
Ha valaki közzé szeretne tenni valamilyen információt (amelyre nem áll fenn, az, hogy kevés, és nagy entrópiájú), akkor nem egy asszimetrikus kulcsú titkosítást fog az adat elkódolására használni. Helyette nem az eredeti üzenetét kódolja el, hanem készít az üzenetéről egy ,,kivonatot'', és a kivonatot az üzenet mellé teszi a privát kulcsával elkódolva. Mivel a kulcspár publikus felét ismerjük, így össze tudjuk hasonlítani, hogy az üzenetre saját magunk által számított kivonat egyezik-e avval, amit a kulcspár publikus felével visszakapunk.\par
Egy ilyen kivonattól általában a következőket várjuk el: legyen rövid, ,,jól reagáljon'' a változásokra (vagyis, ha az eredeti üzeneten, akár egy bitet is megváltoztatunk, akkor már kapjunk eltérő kivonatot), és lehetőleg legyen nagy az entrópiája. Ilyen kivonatolási algoritmusok:
\begin{description}
\item[md5]1992-ben fejlesztette ki az RSA megalkotásában is részt vevő Ron Rivest. 128 bit hosszúságú kivonatot készít. (RFC 1321)
\item[sha1]Amerikai szövetségi információ feldolgozási szabvány. 160 bit hosszúsági kivonatot készít.
\end{description}
\subsection{gpg/pgp}
Mivel az SMTP protokoll (a telnethez hasonlóan) nem biztosította annak lehetőségét, hogy úgy juttasson el egy levelet a célhoz, hogy közben ne lehessen azt elolvasni, ezért egy felsőbb réteg beli megoldást hoztak létre. Ez volt a PGP (Pretty Good Privacy), amely egy nyilt forráskódó, (jobbára) ,,szabadon használható'' megoldás volt. Azonban használt szabadalommal védett megoldásokat (pl. az idea és rsa kódolásokat. megj.: az rsa-ra vonatkozó korlátozás már lejárt, az idea-ra vonatkozó 2007-ben fog), emiatt szükség volt egy teljesen szabad megoldásra. Ez a teljesen szabad megoldás az FSF által készített {\scshape GnuPG} volt. Az OpenPGP-ről az RFC 2440 szól.\par
Eddig ugyan nem esett szó arról, hogy hogyan lehet megbizonyosodni arról, hogy egy kulcs publikus fele valóban a tulajdonosához tartozik. Ha valakivel szeretnénk privát levelezést folytatni, vagy a levelei hitelességéről meggyőződni, akkor a legbiztosabb mód, ha személyesen találkozunk az illetővel, elkérjük a személyi igazolványát, és a publikus kulcsának ,,újjlenyomatát'' (fingerprint\footnote{Minden kulcshoz tartozik egy kivonatszerű újjlenyomat, amely a kulcsot azonosítja.}). Pl. ha valaki a Debian projektbe szeretne bekerülni, akkor rendelkeznie kell, egy olyan kulccsal, amit egy már aktív Debian fejlesztő hitelesített, pl. ilyen személyes találkozás útján. A pgp-nél az X.509-el ellentétben ez a bizalmi rendszer nem egy hierarchikus, fába rendezhető módon van megoldva, hanem egy ún. bizalmi hálón alapul: Mindenki egyenrangú, a bizalom ,,szintje'' pedig azon múlik, hogy hanyadik lépésben találunk valaki kulcsához egy azt hitelesítő ,,ismerőst''\footnote{Akik már ilyen személyes találkozás módján meggyőződtek arról, hogy a személyhez feltételezett kulcs valóban az adott személyhez tartozik, azok ,,hitelesítik'' egymás kulcsát}.\par
A gpg a Debian projektben is fontos szerepet tölt be. A debian csomagok elkészültekor a debian csomaghoz tartozó {\ttfamily ChangeLog}ot (valamint az elkészült bináris csomag kivonatát) ill. forráscsomagról szóló fájlt gpg-vel alá kell írni a csomag készítőjének, majd a kapott fájlokat az incoming.debian.org anonymous ftp sitejára feltölteni. Így azon országok tehetséges fejlesztői elől sincs elzárva a lehetőség a Debian projekthez való hozzájáruláshoz, ahol az adott ország törvényei korlátozzák az erős titkosítást használó programok használatát\footnote{Vagyis nem ssh/scp-vel kell feltölteni a fájlokat, és mégis hellytálló módon meg lehet győződni a fájlok hitelességéről.} polgárai számára. De pl. a Debian (és más kereskedelmi disztrubúciók) által kiadott hibajegyeket is egy arra jogosult ember hitelesíti, és úgy küldi ki a hibajegyekkel foglalkozó levelezési listára, így ellenőrizhető, hogy nem egy átverésről van szó, amelyben egy trójai program feltelepítését kéri tőlünk, egy idegen rosszindulatú \dots ember.\par
\subsection{Gyakorlati feladatok órára}
\begin{itemize}
\item ssh kulcspár generáltatása
\item ssh kulcsos azonosítás beállítása
\item gpg kulcs(pár) generáltatása (akinek még nincs)
\item gpg kulcs publikus felének exportálása, importálása
\item más gpg kulcsának aláírása, az aláírt kulcs exportálása, visszaimportálása
\end{itemize}
\clearpage
\section{Bevezető a program telepíthető csomagba összeállításába}
\subsection{A debian csomagolással kapcsolatos dokumentumok}
Ha debian csomagot szeretnénk készíteni, akkor a {\bfseries maint-guide}, {\bfseries debian-policy}, {\bfseries doc-base}, {\bfseries developers-reference} csomagokat érdemes feltenni, mert ezekből a Debiannal kapcsolatos minden infrastruktúrális kérdésünkre választ kaphatunk.
\begin{description}
\item[maint-guide]Viszonylag rövid alapozó összeállítás arról, hogy hogyan kezdjünk el debian csomagot készíteni. Mi is ezen fogunk véigmenni (csak magyarul).
\item[debian-policy]Az éppen aktuális disztribúció szabályzata. Korábban (a potato idején) ezek az infók a {\bfseries packaging-manual} csomagban voltak. A {\bfseries debian-policy} részei a {\slshape woody} \footnote{A debian disztribúciók a Toy Story című rajzfilm szereplői után kapják a nevüket:\\bo $\rightarrow$ a pásztorlányka, buzz $\rightarrow$ buzz lightyear, az űrhalyós, rex $\rightarrow$ a dínó, hamm $\rightarrow$ a malac, slink(y) $\rightarrow$ a kutyus, potato $\rightarrow$ krumpliuraság, woody $\rightarrow$ a serif, sarge $\rightarrow$ a katona} idején:
\begin{description}
\item[Debian Policy Manual]A debian csomagokkal kapcsolatos szabályok
\item[FHS]Filesystem Hierarchy Standard, a Debianban már a korai idők óta\footnote{Már a Linux Filesystem Standard előtt létezett} ez a szabványgyújtemény írja le, hogy milyen típusú fájlnak hol kell elhelyezkednie. Pl. A konfigurációs fájlok a {\ttfamily /etc}-be, a rendszer elindításához szüks. felhasználói binárisok a {\ttfamily /bin}-be, sít.
\item[Virtuális csomagok listája]A teljes lista a disztribúcióban szereplő virtuális csomagnevekről.
\item[libc6 migráció]Egy dokumentum, ami arról szól, hogy hogyan oldhatjuk meg, hogy a régi libc5-re írt programjaink a libc6-ot (AKA glibc2) is támogassák.
\item[Debconf specifikáció]A debconf csomagkonfigurációs rendszer használatáról szóló dokumentáció
\item[Debian Java Policy]Egy tervezett policy a Debianba csomagolt Java csomagok kezelési módjáról.
\item[Debian Mime Policy]Ez a policy leírja, hogy mit kell tenni, hogy a {\scshape mime} rendszert használjuk a {\scshape \bfseries Debian GNU/Linux} disztribúciónkban, valamint a {\scshape mime} adatbázisba való beregisztrálás szabályait.
\item[Debian Menu Policy]Ez a kézikönyv leírja, hogy a {\scshape \bfseries Debian GNU/Linux} disztrónk Debian menüjébe hogyan tehetünk be elemeket, valamint a menü fejezeteinek hiearchikus struktúráját.
\item[Debian Perl Policy]Ez a kézikönyv leírja, hogy a Perl rendszernek milyen igényei vannak a {\scshape \bfseries Debian GNU/Linux} disztrónkban, leírva a fordítását és telepítését az olyan csomagoknak, amelyek adnak illetve használnak, Perlt és Perl modulokat.
\item[Debian Policy Process Description]A Debian Policy fejlesztés menetét leíró dokumentum.
\end{description}
\item[doc-base]Ez a dokumentum leírja mi az a doc-base és hogyan használhatjuk a Debian rendszerünk online kézikönyveinek karbantartására.
\item[developers-reference]A debian fejlesztők kézikönyve a debian szervezeti dolgairól, úgy mint: hogyan lehetünk maintainerek; a debian levelező listái, szerverei, és egyéb gépei; a debian (csomag)archívum; csomagok feltöltése; NMU-k; portolási infók; a csomagok élete; hibák kezelése és követése; a jövendőbeli fejlesztőkkel való kommunikáció; a debian karbantartó eszközeinek áttekintése
\end{description}
\subsection{Előkészületek a csomagoláshoz}
Ahhoz, hogy csomagokat építsünk a {\bfseries build-essential} csomagra lesz szükségünk, ami jóformán egy metacsomag\footnote{olyan csomag, amelynek a tartalma szinte üres, viszont függ más csomagoktól. Így ha a csomagot feltelepítjük, akkor az apt hozza magával a csomag függőségeit. Pl. ha valaki egy alap X grafikus rendszert szeretne telepíteni, akkor elég az x-window-system-core csomagot feltennie, és az hozza magával az X szervert, alapfontokat, és néhány nélkülözhetetlen alapprogramot}. Ezen függőségekből néhány fontosabb csomag, ill. néhány további olyan csomag, ami hasznunkra válik, de a {\bfseries build-essential} nem hozza magával:
\begin{description}
\item[binutils]Ez a csomag szükséges hogy asszembláljunk, és összeszerkesszünk tárgykódú fájlokat. (A {\bfseries gcc} csomag, ami build-essential függ a {\bfseries gcc-2.95}től, ami pedig a {\bfseries binutils}tól.)
\item[cpp]A C előfeldolgozója. Bizonyos, akár nem C-ben írt programok is használhatják. (A {\bfseries binutils}hoz hasonló úton ez is jön a {\bfseries build-essential} függőségein keresztül.)
\item[cpio]Egy a {\ttfamily tar}-hoz hasonló archiváló eszköz.
\item[file]Ez egy olyan program, amely belenéz fájlokba, és bizonyos jellemzők alapján megpróbálja kitalálni, hogy a fájl belsejében milyen adat/program\footnote{Program esetén, hogy dinamikusan, vagy statikusan linkelt-e, illetve, milyen architektúrára való, strip-elve van-e, stb.} van.
\item[gcc]A {\scshape GNU C} fordító
\item[libc6-dev]A {\scshape C} könyvtár, a hozzászerkesztéshez szükséges archív, valamint a hozzátartozó fejlécfájlok.
\item[make]A {\scshape GNU Make}.
\item[patch]Fájlok módosítására használatos eszköz. A diff-el tudunk készíteni szöveges fájlok különbségéről szóló szöveges fájlt, amely leírja a különbséget. A patch pedig képes arra, hogy egy ilyen fájl alapján módosítsa az eredeti fájlt egy új/javított verzióra.
\item[perl]A perl interpreter. Nem hozza magával a build-essential, ellenben nagyon nehéz lenne nélküle.
\end{description}
Ezek eddig olyan csomagok voltak, amelyek akkor is hasznosak, vagy szükségesek lehetnek, ha nem debian csomagot szeretnénk készíteni, hanem egy átlagos programot lefordítani. Nézzünk néhány olyan csomagot, ami debian csomag fejlesztésében lesz a segítségünkre\footnote{Ne felejtsük, hogy a csomagkészítés végén a changes és dsc fájlokat hitelesítenünk kell, ezért a gpg is javallott.}:
\begin{description}
\item[dh-make]Ha már van egy programcsomagunk, amiből debian csomagot szeretnénk készíteni, akkor ez segítségünkre lesz, hogy ne nulláról kelljen indulnunk. Előregyártott templatek alapján debianizálja a programcsomagunkat, amihez már alig kell hozzányúlnunk. Ha csomagot szeretnénk készíteni, ez nem szükséges, de nagyban megkönnyíti evvel a mechanizmussal a kezdeti munkánkat.
\item[debhelper]Ha a {\bfseries dh-make}t használjuk, akkor erre is mindenképp szükségünk lesz, mert a {\bfseries dh-make} által debianizált debian csomag használja a {\bfseries debhelper}ben levő egyszerűsítéseket. Ebben a csomagban olyan mechanizmusok vannak elkészítve, amelyek bizonyos feladatokat automatizálnak, ill. megkönnyítik a policy-k betartását. Példa: \verb+dh_compress+: a 4kbyte-nál nagyobb doksikat \verb+gzip -9+el tömöríti, \verb+dh_strip+: a csomagban található bináris futtathatókat strip-eli, a policynek megfelelően.
\item[devscripts]A csomagok fejlesztőinek munkáját megkönnyíti. Pl. a \verb+dch+ segít a parancssorból {\bfseries ChangeLog} bejegyzések elkészítésében, vagy az \verb+uupdate+ és \verb+uscan+ segíti a csomagunk {\slshape upstream}jének követését.
\item[fakeroot]A csomagkészítés bizonyos fázisainál rootnak kell lennünk. Pl. a rendszerbe feltelepülő bináris programok a root tulajdonába kell kerüljenek a .deb archívban, hogy ne módosíthassák a felhasználók a rendszer alapköveit pl. trójaiakra. Mivel azonban egy fordítás általában nem igényel root jogosultságokat csak a telepítés, a fakeroot lehetővé teszi, hogy az archívkezelő programok azt higgyék a fájlokról, hogy root tulajdonában vannak, egy előtöltött az eredeti C könyvtár hívásait lefedő fakeroot könyvtáron (library) keresztül. Így lehetőség van arra, hogy a csomagkészítés egyik fázisában se legyen szükség root jogosultságokra.
\item[lintian]A policy betartásának ellenőrzésére tartalmaz bizonyos automatizmusokat. Mielőtt egy csomagot a hivatalos debian archívba feltöltenénk, előtte mindenképp ellenőrizzük a lintiannal.
\end{description}
Ha minden szükséges fejlesztőeszköz fenn van, akkor az alábbiakat ne felejtsük el ellenőrizni:
\begin{itemize}
\item Ellenőrizzük, hogy nincs-e az általunk becsomagolandó csomag már eleve benne a debianban.
\item Nézzünk utána a WNPP\footnote{Work Needing for Prospective Packages, {\ttfamily http://www.debian.org/devel/wnpp/}}-ben, illetve a debian-devel levelezőlista archívumában, hogy nem próbálkozik-e más is a mi programunkat becsomagolni. (Természetesen, ha saját fejlesztésű csomagról van szó, akkor ez az első két lépés kihagyható.)
\item A programnak {\bfseries kell} legyen licensze. Lehetőleg feleljen meg a DFSG\footnote{Debian Free Software Guidelines, {\ttfamily http://www.debian.org/social\_contract\#guidelines}}nek. Ha nem így lenne, akkor még mindig kerülhet a {\slshape contrib} vagy a {\slshape non-free} szekciókba. Ha a programnak valami egyedi licensze lenne, ami felett nem tudunk itélkezni, akkor a debian-legal levelezőlistán érdeklődhetünk, hogy nálunk okosabbaknak mi a licenszről a véleményük.
\item Ellenőrizzük, hogy a program ne legyen feleslegesen setuid root-os, a legjobb ha sem setuid sem setgid se semmi nem kell neki.
\item A program nem egy démon, vagy valami, ami feleslegesen valamelyik \verb+/sbin+ könyvtárba akar kerülni...
\item A programnak legyen egy végrehajtható bináris alakja a fordítás végén
\item Lehetőleg legyen jól dokumentált. A policy kiköti, hogy minden végrehajtható bittel ellátott programhoz, ami vmilyen \verb+bin+ könyvtárba kerül, kapcsolódjon egy kézikönyv oldal.
\item Próbáljuk felvenni a kapcsolatot a program készítőjével, hogy egyetért-e avval, hogy mi becsomagoljuk a debianba a programját\footnote{Ha megfelelő licenszet tett rá, akkor nem igazán áll módjában ellenkezni, de azért jobb a békesség.}. Ez azért is fontos, mert nem árt ha a program {\slshape upstream}jével jó a kapcsolatunk. Könnyen lehet, hogy egy az upstreamben levő (pl. programozási) hibát a BTS-en keresztül nekünk jelentenek.
\item Lehetőleg ismerjük azt a programot, amit becsomagolunk, és legyen vele némi saját tapasztalatunk.
\end{itemize}
\subsection{A programcsomag előkészítése}
Miután letöltöttük a programcsomagot, győződjünk meg róla, hogy az a mi rendszerünkön rendesen lefordul, elkészül, és használható program lesz belőle. Pl. gyakorlásképp letölthetjük a szokásos állatorvosi lovunkat az fdist-et. Lépjünk be a programunk könyvtárába, és olvassunk el minden idevonatkozó dokumentációt: \verb+README*+, \verb+INSTALL*+, \verb+*.lsm+, \verb+*.html+. Ezekben meg kell találjunk minden szükséges útmutatást, hogy a programot le tudjuk fordítani, és fel tudjuk telepíteni. Ez a rész programról programra változhat, de a legtöbb modern programnak van egy \verb+./configure+ szkriptje, ami a forráskódot konfigurálja és meggyőződik róla, hogy a fordításához minden szükséges előfeltétel a rendelkezésre áll. Miután konfiguráltuk a programot azt általában a \verb+make+ parancsal tudjuk lefordítani. Néhány támogatja a \verb+make check+ parancsot, amely néhány önellenőrzést hajt végre. A célkönyvtárba telepítést a legtöbb esetben a \verb+make install+ parancs végzi.\par
Most probáljuk meg lefordítani és futtatni a programot, hogy meggyőződjünk róla, hogy minden rendben működik, és nem ront el semmi mást a telepítés vagy futtatás hatására.\par
Bizonyos esetekben a \verb+make uninstall+t is használhatjuk a telepített fájlok eltávolítására, és a \verb+make clean+t (vagy még jobb a \verb+make distclean+) a készítő könyvtár kitisztítására.
\subsubsection{A {\ttfamily dh\_make} előtt}
A csomagolást lehetőleg egy teljesen tiszta forráskönyvtáron végezzük, de a legjobb, ha frissen kibontott forráskönyvtárral kezdünk.\par
A csomag helyes elkészültéhez a program nevét csupa kis betűvel kell venni, és a forráskönyvtárnak a {\slshape csomagnév}-{\slshape verzió} formát kell követnie.\par
Ha a program neve több mint egy szó, írjuk egybe, vagy használjunk egy rövidítést. Például, ha a csomagunk neve ,,Jancsi kicsi editora Xre'', akkor hívhatjuk {\bfseries jancsikex}nek, vagy {\bfseries jle4x}nek, vagy amit csak akarunk. Lehetőleg valami elfogadható hosszkorlátot válasszunk, pl. max. 20 karaktert.\par
Ellenőrizzük a program pontos verzióját is (ami a csomag verzióban is szerepelni fog). Ha a programunkat nem {\bfseries X.Y.Z} módon verziószámozzák, hanem pl. dátummal, akkor tegyünk a verziószám elé egy ,,0.0''-t (csak azért, hogy ha az upstream egyszer úgy dönt, hogy kiad egy aranyos verziószámot, pl. 1.0-t, akkor fel legyünk rá készülve). Így ha a kiadásunk vagy pillanatképünk (snapshot) dátuma 2003. Április 23., akkor legyen a verziósztringünk {\bfseries 0.0.20030423}. Bizonyos programokat egyáltalán nem számoznak. Ebben az esetben vegyük fel a kapcsolatot az upstream karbantartójával, hogy kiderítsük milyen verziókövetési módszert használ.
\subsubsection{A {\ttfamily dh\_make} futtatása}
Álljunk a program forráskönyvtárába, majd adjuk ki a megfelelően felparaméterezett \verb+dh_make+ parancsot. Pl. valahogy így:
\begin{verbatim}
[pasztor@clyde ~/fdist-0.2]$ dh_make -e pasztor@fsn.hu ../fdist-0.2.tar.gz 

Type of package: single binary, multiple binary, or library? [s/m/l] s

Maintainer name : unknown
Email-Address   : pasztor@fsn.hu 
Date            : Wed, 23 Apr 2003 02:10:58 +0200
Package Name    : fdist
Version         : 0.2
Type of Package : Single
Hit <enter> to confirm: 
Done. Please edit the files in the debian/ subdirectory now. fdist
uses a configure script, so you probably don't have to edit the Makefiles.
[pasztor@clyde ~/fdist-0.2]$
\end{verbatim}
A karbantartó nevét, és e-mailcímét automatikusan megpróbálja a program kitalálni. A nevet a \verb+/etc/passwd+ alapján (ill. NIS, vagy LDAP adatbázis alapján). Az e-mailcímet pedig a {\bfseries felhasználónév@gépnév} módon, ahol a gépnevet a \verb+/etc/mailname+-ből veszi. Viszont könnyen előfordulhat, hogy nem, vagy nem csak olyan gépen készítjük a csomagjainkat, ahol ezek jól be vannak állítva, vagy az következik belőle, amit mi szeretnénk a csomagban viszontlátni, ezért javasolt a névre a \verb+DEBFULLNAME+ környezeti változót beállítani\footnote{Név gyanánt lehetőleg olyat adjunk meg, ami csak az angol abc betűit tartalmazza. Hasznos dolog a vezetéknevünket csupa nagybetűvel írni, mert nem mindenütt tudják, hogy mi magyarok a vezetéknevünket írjuk előre, és esetleg megsértődünk, ha egy e-mailben, amikor valaki kapcsolatot akar felvenni velünk ,,Hi Gyorgy'' helyett, ,,Hi Pasztor''-t ír}, valamint az e-mailcímre a \verb+DEBEMAIL+ környezeti változót, akár a \verb+~/.bashrc+ ill. \verb+~/.bash_profile+ fájljainkban (feltéve, hogy bash-t használunk, de természetesen mindenki értse ide, a neki valót). Így az előzőt ,,eltakarítandó'' vmi. ilyet teszek:
\begin{verbatim}
[pasztor@clyde ~/fdist-0.2]$ cd..
[pasztor@clyde ~]$ rm -r fdist-0.2
[pasztor@clyde ~]$ export DEBFULLNAME="PASZTOR Gyorgy"
[pasztor@clyde ~]$ export DEBEMAIL="pasztor@fsn.hu"   
[pasztor@clyde ~]$ tar xzf fdist-0.2.tar.gz 
[pasztor@clyde ~]$ cd fdist-0.2
[pasztor@clyde ~/fdist-0.2]$ dh_make -s -n -c gpl -f ../fdist-0.2.tar.gz 
Maintainer name : PASZTOR Gyorgy
Email-Address   : pasztor@fsn.hu 
Date            : Wed, 23 Apr 2003 02:28:57 +0200
Package Name    : fdist
Version         : 0.2
Type of Package : Single
Hit <enter> to confirm: 
Done. Please edit the files in the debian/ subdirectory now. fdist
uses a configure script, so you probably don't have to edit the Makefiles.
[pasztor@clyde ~/fdist-0.2]$ 
\end{verbatim}
Némi magyarázat az újonnan hozzáadott paraméterekkel kapcsolatban:
\begin{description}
\item[-c gpl]A debian/copyright fájlt rendesen kitölti, feltételezve, hogy a program licensze gpl. A \verb+dh_make+ {\bfseries gpl}, {\bfseries lgpl}, {\bfseries artistic} és {\bfseries bsd} licenszekhez rendelkezik előgyártott template-tel.
\item[-n]Natív debian csomag készüljön: A natív debian csomagoknál a program írója (upstream author), és a debian csomag karbantartója ugyanaz a személy, és csak egy natív (kötőjelet nem tartalmazó) verziószám kapcsolódik a csomaghoz. A nem natív csomagoknál ez a két személy különböző, és sok egyéb adminisztratív eltérés van, pl. a csomag verziószáma az {\bfseries eredetiverzió-debianalverzió} módon áll össze.
\item[-s]Egyszerű bináris csomag készüljön. Így nem kérdez, hogy egyszerű bináris, többes bináris, vagy könyvtár jellegű csomagot építsen.
\end{description}
Fontos, hogy ha egy csomagot egyszer már debianizáltunk, akkor többször már ne adjuk ki a csomag forrásában a \verb+dh_make+ parancsot.
\subsection{A forráskód módosítása}
Általában a programok a \verb+/usr/local+ könyvtárba telepítik magukat, ellenben a debian csomagok nem használhatják azt a könyvtárat\footnote{Lásd: FHS \cite{debian-policy}}, mert az a rendszeradminisztrátor saját használatára van fenntartva. Így a programunk build-rendszerébe bele kell nyúlnunk a Makefileoknál kezdve\footnote{Az {\bfseries fdist}re, és általában az autoconf+automake-s programokra ez nem igaz.}. Ha egy autoconfot és automake-et használó programmal van dolgunk, akkor ne felejtsük el, hogy a \verb+Makefile+-t hiába piszkáljuk, mert azt a \verb+./configure+ futtatása generálja.\par
A legtisztább dolog, ha felvesszük az upstreammel a kapcsolatot, és egy olyan \verb+Makefile+ja van a programnak, ami támogatja a \verb+DESTDIR+ használatát.
\subsection{A {\ttfamily debian/} alkönyvtár}
A \verb+control+ fájl: Ez a fájl tartalmaz infót a forráscsomagról: Név, kategória, prioritás, karbantartó, szabványkövetési verzió, stb. Valamint a forráscsomagból készülő bináris csomagokról: csomagnév, architektúra, függőségek, leírás, stb. Az fdist control fájlját vhogy így készítettem el:
\begin{verbatim}
Source: fdist
Section: net
Priority: optional
Maintainer: PASZTOR Gyorgy <pasztor@fsn.hu>
Build-Depends: debhelper (>> 3.0.0)
Standards-Version: 3.5.2

Package: fdist
Architecture: any
Depends: ${shlibs:Depends}
Description: A very little program to broadcast files on a network
 A very little program, which can be server and client decided an its
 paramters. The server wait for some client, and then broadcast a file for
 them. All parameters are get from a konfig file. The server is able to
 reread its config file at a sighup, etc.
\end{verbatim}
\par
A \verb+copyright+ fájl: Ez a fájl a program licenszeléséről szóló infót tartalmazza. Minden a forráscsomagból készült bináris csomagba bekerül {\ttfamily /usr/share/doc/{\slshape csomagnév}/copyright} néven. A mi esetünkben ezt a \verb+dh_make+ kitöltötte, mert közöltük vele, hogy a program GPL-es.\par
A \verb+changelog+ fájl: A debian csomag élettörténete. Ha pl. egy a BTS-ben jelentett hibát kijavítunk és ide írjuk, hogy \verb+Closes: #nnnnnn+, akkor a csomag feltöltése után a hibajegy lezáródik a BTS-ben.\par
A \verb+rules+ fájl: Egy makefile, amelyben bizonyos nevű targeteknek kötelezően lennie kell. Ez írja le, hogyan készüljön el a csomag.
\subsection{Egyéb fájlok a {\ttfamily debian/} alkönyvtárban}
A \verb+README.Debian+ fájl: Hasznos rövid információkat lehet idetenni a debian csomaggal kapcsolatban. Pl. pár szóban leírhatjuk, ha valami plusz teendő van a csomag használatához, pl. mailman esetén ide pár sorban leírhatjuk, hogy az adminisztrációs felület működéséhez milyen alias-t kell az apache konfigurációjába beírni.\par
A \verb+conffiles+ fájl: Azon fájlok felsorolása, amelyek a csomagban konfigurációs fájlok. A konfigurációs fájlokról is készül MD5 lenyomat, és a frissítésnél ez összehasonlítódik a fájlrendszeren levővel és ha úgy tűnik változott, akkor rákérdez a rendszer, hogy az újat tegye-e fel, vagy megtartsa a régit, vagy mutassa a különbséget, stb. Illetve ha a csomagot letöröljük, akkor a konfigurációs fájlokat nem törli a rendszer.\par
A \verb+dirs+ fájl: Azon létrehozandó könyvtárak neve, amelyet a make install nem hozna létre, ellenben hiányukban panaszkodna. Jelentősége csak akkor van, ha a \verb+dh_installdirs+ debhelpert használjuk a csomagépítés megfelelő fázisában.\par
A \verb+manpage.1.ex+ fájl: Egy rövid, üres példa kézikönyv oldal, aminek mentén el lehet indulni a csomaghoz tartozó programok dokumentálásában, és nem from scratch kell kézikönyvoldalt írni hozzá.\par
A \verb+menu.ex+ fájl: Példa menübejegyzés, hogy ne from scratch kelljen megírni, ha használni akarjuk a \verb+dh_installmenu+ debhelpert.\par
A \verb+watch.ex+ fájl: Az upstream programverzió elérhetőségét ha egy watch fájlban leírjuk, akkor az \verb+uscan+ és \verb+uupdate+ parancsokkal könnyebben követni tudjuk az upstream programverziót.\par
A \verb+ex.doc-base+ fájl: Ha doc-base néven csinálunk ilyen fájlt, akkor a doc-base rendszerbe beépül a programunk dokumentációja. A \verb+dh_installdoc+ debhelpert kell használjuk hozzá, viszont a \verb+dh_installdoc+ debhelper sok más feladatot is elvégez.\par
A \verb+postinst.ex+, \verb+preinst.ex+, \verb+postrm.ex+ és \verb+prerm.ex+ fájlok: A \verb+dh_installdeb+ debhelper fogja a helyére tenni ezeket. Példák arra nézve, hogy mit tegyen a csomag a település/eltávolítás előtt/után.
\subsection{A végkifejlet}
\subsubsection{A csomag megépítése}
\begin{verbatim}
[pasztor@clyde ~/fdist-0.2]$ dpkg-buildpackage -rfakeroot -k69A2F424
dpkg-buildpackage: source package is fdist
dpkg-buildpackage: source version is 0.2
dpkg-buildpackage: source maintainer is PASZTOR Gyorgy <pasztor@fsn.hu>
dpkg-buildpackage: host architecture is i386
 fakeroot debian/rules clean
dh_testdir
dh_testroot
rm -f build-stamp 
...
...
...
dh_md5sums
dh_builddeb
dpkg-deb: building package `fdist' in `../fdist_0.2_i386.deb'.
 signfile fdist_0.2.dsc

You need a passphrase to unlock the secret key for
user: "PASZTOR Gyorgy (fsn) <pasztor@fsn.hu>"
1024-bit DSA key, ID 69A2F424, created 2001-12-28

                  
 dpkg-genchanges
dpkg-genchanges: including full source code in upload
 signfile fdist_0.2_i386.changes

You need a passphrase to unlock the secret key for
user: "PASZTOR Gyorgy (fsn) <pasztor@fsn.hu>"
1024-bit DSA key, ID 69A2F424, created 2001-12-28

                  
dpkg-buildpackage: full upload; Debian-native package (full source is included)
[pasztor@clyde ~/fdist-0.2]$ cd ..
[pasztor@clyde ~]$ lintian -i fdist_0.2.dsc      
[pasztor@clyde ~]$ lintian -i fdist_0.2_i386.changes 
E: fdist: binary-without-manpage fdist
N:
N:   Each binary in /usr/bin, /usr/sbin, /bin, /sbin, or /usr/games, must
N:   have a manual page.
N:   
N:   Note, that though the `man' program has the capability to check for
N:   several program names in the NAMES section, each of these programs
N:   must have its own manual page (a symbolic link to the appropriate
N:   manual page is sufficient) because other manual page viewers such as
N:   xman or tkman don't support this.
N:   
N:   Refer to Policy Manual, section 13.1 for details.
N:
\end{verbatim}
\clearpage
\section{debhelperek használata}
Mint azt láttuk a \verb+dh_make+ által ,,inicializált'' csomag debhelper-függő lesz. Nem véletlen, hogy az újabb fejlesztőeszközökben igyekeznek az egyre újabb technikákat beszivárogtatni a fejlesztők kezébe, ugyanis a debhelperek, valóban hasznos segítséget nyújtanak, és sokkal átláthatóbbá teszik a \verb+debian/rules+ fájl elkészítését is. Ezért tekintsük át a főbb debhelperek múködését:
\begin{description}
\item[dh\_testdir]Ellenőrzi a (forrás)könyvtárat a csomag építése előtt. Meggyőződik arról, hogy egy szabályos debian forráscsomagban vagyunk, létezik {\ttfamily debian/control}, stb. Valamint argumentumban további ellenőrzendő fájlokat is megadhatunk. Ha nem lenne valami jó, akkor hibakóddal lép ki, és mivel a {\ttfamily debian/rules} egy {\slshape Makefile}, ezért nem fog továbbmenni, hanem itt megáll.
\item[dh\_testroot]Meggyőződik arról, hogy a csomagot valóban root-ként kezdtük fordítani. (Természetesen ha a {\bfseries fakeroot}al indítottuk, az is megfelel.) Ha nem, akkor hibakóddal kilép.
\item[dh\_clean]Ez a debhelper felelős azért, hogy egy csomag építése után kitisztuljon a munkakönyvtár. Eltávolítja a csomagok build-könyvtárát, és más fájlokat is letöröl pl. {\ttfamily debian/substvars}, {\ttfamily debian/files}, \verb+*~+, \verb+*.orig+, stb. Részletekért lásd a kézikönyv oldalát.\par
Azonban a \verb+-k+ opcióját kiemelném, mert ha ezt megadjuk neki akkor nem törli a {\ttfamily debian/files}-t, aminek akkor lehet jelentősége, ha több mint egy bináris csomag épül a forráscsomagunkból.
\item[dh\_installdirs]Ez a debhelper felelős azért, hogy az alkönyvtárakat elkészítse a csomag build-könyvtáraiban. Minden a paraméterében megadott könyvtárnevet a control rekordban található első csomag build-könyvtárában hoz létre, illetve ha használjuk a \verb+-p+, \verb+-i+, \verb+-a+ kapcsolók valamelyikét, akkor az annak megfelelő első csomag build-könyvtárában. A {\ttfamily debian/{\slshape csomag}.dirs} fájlban tudjuk megadni a létrehozandó könyvtárakat. A könyvtárneveket könnyű-szóközzel kell elválasztani\footnote{Ebből következően a létrehozandó könyvtár nevében nem lehet szóköz}.
\item[dh\_installdocs]A csomag build-könyvtáraiba feltelepíti a dokumentációt.\par
A csomag {\ttfamily usr/share/doc/{\slshape csomagnév}} könyvtárába feltelepíti a dokumentációt. Automatikusan ideteszi a {\ttfamily debian/copyright} fájlt. Ha több bináris csomag készül, és más-más copyright fájlokat kell hozzájuk telepíteni, akkor használhatjuk a {\ttfamily debian/{\slshape csomag}.copyright} fájlneveket.\par
Hasonlóan járhatunk el a {\ttfamily README.Debian} fájlok illetve a {\ttfamily debian/TODO} fájlok esetén is. Azt azonban tudnunk kell, hogy a célhelyen a {\ttfamily TODO} fájlból {\ttfamily TODO.Debian} lesz, hogy az esetleges eredeti (upstream) szoftvercsomag {\ttfamily TODO} fájlját ne írja felül.\par
A {\ttfamily debian/{\slshape csomag}.docs} fájlban további feltelepítendő dokumentációt sorolhatunk fel.\par
A csomag generál automatikusan parancsokat is a \verb+postinst+ és \verb+prerm+ scriptekbe, hogy a {\ttfamily /usr/doc/{\slshape csomag}} szimbolikus kötés automatikusan meglegyen, illetve eltávolodjon a {\ttfamily /usr/share/doc/{\slshape csomag}} könyvtárra.\par
Ha léteznek {\ttfamily debian/{\slshape csomag}.doc-base} fájlok, akkor a {\slshape doc-base} vezérlő fájlok is feltelepülnek, illetve a csomag \verb+postinst+ és \verb+prerm+ scriptjeibe bekerülnek a megfelelő parancsok, hogy ezek a dokumentációk a csomag telepítése folyamán a debian {\slshape doc-base} rendszerébe bekerüljenek.\par
Ha egy csomag több dokumentációt is szeretne beregisztrálni a {\slshape doc-base} rendszerbe, akkor a {\ttfamily debian/{\slshape csomag}.doc-base.{\bfseries *}} minta használandó a fájlok neveire.
\item[dh\_installexamples]Ez a debhelper fájlokat telepít a {\ttfamily usr/share/doc/{\slshape csomag}/examples} könyvtárba. Minden fájlnév, amit a {\ttfamily debian/examples} illetve {\ttfamily debian/{\slshape csomag}.examples} fájlokban felsorultunk feltelepít a fent nevezett könyvtárba.
\item[dh\_installmenu]Ez a debhelper program felelős azért, hogy a debian menü csomaghoz tartozó fájlok a csomag build-könyvtárába bekerüljenek. Automatikusan generál \verb+postinst+ és \verb+postrm+ scriptrészleteket, hogy a debian menü csomag interfészén keresztül a debian menübe beregisztrálja a program saját magát. A csomaghoz tartozó menüadatokat a {\ttfamily debian/{\slshape csomag}.menu} nevű fájlba kell elhelyezni, és a {\ttfamily usr/lib/menu/{\slshape csomag}} néven kerül be a build-könyvtárba\footnote{Ha pedig a {\ttfamily debian/{\slshape csomag}.menu-method} nevű fájl létezik, akkor az a {\ttfamily etc/menu-methods/{\slshape csomag}} fájlba kerül a build-könyvtárba.}. Lásd a menufile kézikönyv oldalt a tartalom formátumával kapcsolatban, illetve a debian-menu policy-t\cite{debian-policy}.
\item[dh\_installman]A csomag build-könyvtáraiba feltelepíti a man oldalakat. Megadható, hogy mely kézikönyvoldalakat kell feltelepítenie. A telepítéskor figyelembe veszi a szekciót is a fájl kiterjesztésében található szám alapján, illetve a fájlban található \verb+.TH+ sor alapján. A kézikönyv oldal nyelvének megállapítása szintén támogatott, amennyiben valamilyen {\ttfamily .{\slshape ll}.n} vagy {\ttfamily .{\slshape ll\_LL}.n} kiterjesztése van a kézikönyvoldalnak.\par
Ha a \verb+dh_installman+ úgy tünik, hogy rosz helyre telepíti a kézikönyvoldalt, akkor az azért van, mert a fájlban hibás a \verb+.TH+-t tartalmazó sor. Ebben az esetben javítsuk ki a kézikönyvoldalt.
\item[dh\_undocumented]Ez a debhelper a dokumentálatlan man oldalakat jelzi olymódon, hogy a megjelölt néven és szekcióban létrehozza a kézikönyvlapot, pontosabban egy az undocumented kézikönyvlapra mutató szimbolikus kötést. A létrehozandó kézikönyvoldalak nevét a {\ttfamily debian/{\slshape csomagnév}.undocumented} fájlban kell felsorolni, illetve argumentumban is megadható a szokásos módon, és a szokásos \verb+-p+, \verb+-i+ ill. \verb+-a+ kapcsoló felhasználásával.\par
Ez a módszer erősen ellenjavallott a policy szerint. A javasolt eljárás egy debian csomag készítésénél, a megadott példafájl alapján elkészíteni a program leírását.
\item[dh\_installinfo]Ez a debhelper felelős azért, hogy a programunkhoz tartozó info oldalak feltelepüljenek a csomagba, valamint hogy azok a csomag telepítése során regisztrálódjanak az info adatbázisába.\par
A szokásos módon lehet paraméterben illetve {\ttfamily debian/{\slshape csomagnév}.info} módon is a tudtára adni, hogy milyen info dokumentumokat kell feltelepíteni a build-könyvtárakba. Valamint a szokásos módon lehet használni a \verb+-p+, \verb+-i+ és \verb+-a+ kapcsolókat.\par
A fentiekből következik az is, hogy a \verb+prerm+ ill. \verb+postinst+ scriptekbe való regisztrációval kapcsolatos részleteket ő is beleteszi.
\item[dh\_installchangelogs]Függően attól, hogy a csomagunk natív debian csomag-e feltelepíti a {\ttfamily debian/changelog} fájlt a build-könyvtár {\ttfamily usr/share/doc/{\slshape csomagnév}/changelog} név alá. Illetve ha nem egy natív debiancsomagról van szó, akkor a\\
{\ttfamily usr/share/doc/{\slshape csomagnév}/changelog.Debian} fájlnév alá. Természetesen, ha létezik {\ttfamily debian/{\slshape csomagnév}.changelog}, akkor inkább azt telepíti.\par
Ha nem egy natív debiancsomagról van szó, akkor megadhatjuk paraméterben az upstream changelog fájljának a nevét, amit a build-könyvtárban\\
{\ttfamily usr/share/doc/{\slshape csomagnév}/changelog} néven helyez el. Figyeljük meg, hogy ebben az esetben ez nem ütközik, az ugyanabban a könyvtárban levő {\ttfamily changelog.Debian}-al, hanem ott lesz mind a két changelog.\par
Ez a debhelper arra is figyel (a kiterjesztés alapján), hogyha az eredeti changelog egy html fájl, akkor azt a html2text-el egyszerű szövegre konvertálja előbb, és azt helyezi el {\ttfamily changelog} néven az említett könyvtárba.\par
Hatása módosítható a \verb+-k+ kapcsolóval, amikoris megtartja az eredeti changelog fájl nevét és nem nevezi át {\ttfamily changelog}-ra. Hasznos lehet, ha az eredeti csomag changelogjának valami szokatlan neve van, vagy a csomag hivatkozik ilyen néven a changelog fájljára.
\item[dh\_link]A csomag build könyvtáraiban szimbolikus kötéseket csinál. A szokásos módon a {\ttfamily debian/{\slshape csomagnév}.links} néven elhelyezünk egy fájlt, amelynek minden sorában két fájlnevet sorolunk fel: Az eredeti fájlét, illetve a hozzátartozó szimbolikus kötés nevét.\par
Mindig a teljes nevét adjuk meg a fájloknak, a \verb+dh_link+ gondoskodik arról, hogy a szimbolikus kötés a debian policynek \cite{debian-policy} megfelelően jöjjön létre.\par
Az újabb verziókban már arra is képes, hogy a nem általa létrehozott szimbolikus kötéseket is leelenőrizze, és a policy-nek nem megfelelőket kijavítsa.
\item[dh\_strip]Ez a debhelper felelős azért, hogy strip-eljen minden futtatható programot, osztott és statikus könyvtárat (library), amelyek nem hibakeresésre használatosak. Feltételezi, hogy az olyan fájlok, amelyeknek a neve a {\ttfamily lib*\_g.a}-hoz hasonló, azok debugra használatos statikus könyvtárak, és nem strip-eli őket.\par
Ha a {\ttfamily DEB\_BUILD\_OPTIONS} környezeti változó tartalmazza a nostrip szót, akkor a Debian policy-nek megfelelően semmit sem fog strip-elni.
\item[dh\_compress]Ez a debhelper azért felelős, hogy minden olyan fájl, amelyre a policy előírja, hogy tömörítettnek kell lennie, össze legyen tömörítve, illetve hogy az ilyen fájlokra mutató szimbolikus kötések javítva legyenek az új tömörített fájlokra.\par
Alapértelmezésben a Debian Policy\cite{debian-policy}-nek megfelelő fájlokat tömöríti össze. Nevezetesen minden fájlt a {\ttfamily usr/share/info}, {\ttfamily usr/share/man}, {\ttfamily usr/X11R6/man} könyvtárakban, valamint a {\ttfamily usr/share/doc} alatt levő minden 4 kilobájtnál nagyobb fájlt (kivéve a {\ttfamily copyright} fájlt, {\ttfamily .html} fájlokat, valamint azokat amelyek a nevük alapján már tömörítettnek tűnnek), és minden {\ttfamily changelog} fájlt.\par
A {\ttfamily debian/{\slshape csomagnév}.compress} fájl ezesetben feltételezett, hogy egy shellscript, amelynek az outputja szolgáltatja az összetömörítendő csomagokat. A shellscriptet a csomag build-könyvtárában futattja le a rendszer. Ha bizonyos fájlok összetömörítését el akarjuk kerülni, akkor inkább a \verb+-X+ kapcsolót használjuk, mint ezt a lehetőséget.
\item[dh\_fixperms]Kijavítja a fájlok és könyvtárak jogosultságait egy a Debian Policynek megfelelő változatra. Így a {\ttfamily usr/share/doc} alatt levő fájlokat 644 módúra javítja, kivéve az examples könyvtárban levőkét. Kijavítja a man oldalakat adó fájlok módját is 644-re. Minden fájlt a root tulajdonába vesz és a csoporttól illetve az egyéb felhasználóktól elvesz minden írási jogosultságot. Az osztott könyvtárakról leveszi a futtathatási jogot, ha valamelyikre véletlenül be lett volna állítva. A {\ttfamily bin/} és a {\ttfamily etc/init.d} könyvtárakban levő fájlokra beállítja a futtathatósági bitet. Végül eltávolít minden setuid illetve setgid bitet a csomagban levő összes fájlról\footnote{Vagyis ha valaki mégis setuid-es vagy setgid-es fájlt akar egy csomagban elhelyezni, akkor azt a {\ttfamily dh\_fixperms} után kézileg be kell a megfelelő fájlokra állítani.}.
\item[dh\_installdeb]A csomag {\ttfamily DEBIAN} könyvtárába való fájlokat előkészíti, és a helyükre teszi, a megfelelő jogosultságokkal.\par
Az alábbi fájlokat teszi a {\ttfamily debian/} könyvtárból a {\ttfamily DEBIAN} könyvtárba:
\begin{itemize}
\item {\slshape csomagnév}.postinst
\item {\slshape csomagnév}.preinst
\item {\slshape csomagnév}.postrm
\item {\slshape csomagnév}.prerm
\item {\slshape csomagnév}.shlibs
\item {\slshape csomagnév}.conffiles
\end{itemize}
Az újabb verziók esetében már nem kell külön feljegyezni a {\ttfamily etc/} könyvtárban levő fájlokat, azok automatikusan a {\ttfamily conffiles}ba számítanak.
\item[dh\_gencontrol]Ez a debhelper generálja és helyezi el a {\ttfamily DEBIAN} könyvtárakba a {\ttfamily control} fájlokat.
\item[dh\_md5sums]Legenerálja a {\ttfamily DEBIAN/md5sums} fájlt (illetve fájlokat több bináris csomag esetén), amelyek a csomagban levő fájlok md5 kivonatai. Természetesen minden a {\ttfamily DEBIAN} könyvtárban levő fájl kimarad a listázásból. Az md5sum fájl, a megfelelő tulajdonossal, és jogosultságokkal jön létre.\par
Alapértelmezésben a konfigurációs fájlok md5-kivonatai kimaradnak ebből a listázásból, de ha a \verb+-x+ opciót megadjuk, akkor azok is belekerülnek. Megjegyzendő, hogy ez az információ redundáns, mert ezek már máshol is eltárolódnak egy debiancsomagban.
\item[dh\_builddeb]Egyszerűen meghívja a \verb+dpkg+-t, hogy készítse el a debian csomagot, vagy csomagokat.
\end{description}
A sokat emlegetett általános kapcsolóknál általában argumentumban megadhatók a telepítendő/regisztrálandó menüelemek/manoldalak/infóoldalak, stb. Viszont könnyen előfordulhat, hogy a forráscsomagból több bináris csomag generálódik, és más más csomagokba másnak kell kerülnie, illetve jó lenne az átfedést elkerülni. Ezek szabályozására a \verb+-a+ kapcsoló hatásával azt érhetjük el, hogy az összes architektúrafüggő csomagunkra hatni fog a szóban forgó debhelper. A \verb+-i+ kapcsolóval az architektúrafüggetlen csomagukra tudunk hatni, illetve a {\ttfamily -p{\slshape csomagnév}} kapcsolóval a megadott csomagra tudunk hatni. Az általános debhelper paraméterezések a {\bfseries debhelper(1)} kézikönyvoldalban találhatók.
\clearpage
\section{Mire figyeljünk a csomagolásnál, a csomag elkészítése, felépítése, ellenőrzése (lintian)}
\clearpage
\addcontentsline{toc}{chapter}{Jegyzékek}
\addcontentsline{toc}{section}{Ábrajegyzék}
\listoffigures
\printindex{peldak}{Példák jegyzéke}
\addcontentsline{toc}{section}{Irodalomjegyzék}
\begin{thebibliography}{9}
\bibitem{vimtutor}Vi IMproved tutorial
\bibitem{cvsbook}CVSBook, http://cvsbook.red-bean.com/
\bibitem{gccman}{\scshape GCC} kézikönyv
\bibitem{makeinfo}{\scshape GNU Make} info oldalak
\bibitem{m4info}{\scshape GNU M4} info oldalak
\bibitem{autoconfinfo}{\scshape GNU autoconf} info oldalak
\bibitem{automakeinfo}{\scshape GNU automake} info oldalak
\bibitem{maint-guide}debian {\bfseries maint-guide} csomag, Josip Rodin
\bibitem{debian-policy}debian {\bfseries debian-policy} csomag, Julian Gilbey, Manoj Srivastava, továbbá: Ian Jackson, Christian Schwarz, David A. Morris
\bibitem{doc-base}debian {\bfseries doc-base} csomag, Christian Schwarz, Adam Di Carlo
\bibitem{developers-reference}debian {\bfseries developers-reference} csomag, Adam Di Carlo, Christian Schwarz valamint Ian Jackson
\end{thebibliography}
\end{document}
