</p>
<h3 id="14.2.1.examplemakefile">14.2.1. Przykładowy plik Makefile</h3>
<p>
-
+ Na podstawie dwóch plików z poprzedniego podrozdziału utworzyłem
+ przykładowy plik <em>Makefile</em>. Plik ten tworzy znany nam
+ rownież plik <em>myprog</em>, który nie robi nic więcej poza
+ wyświetleniem napisu <em>Hello, World!</em>.
+ </p>
+<pre class="code-block">
+xf0r3m@laptop-7bf2993:~/prog/C$ cat Makefile
+
+OBJS=aux.o main.o
+all: myprog
+myprog: $(OBJS)
+ $(CC) -o myprog $(OBJS)
+</pre>
+ <p>
+ W pierwszej linii znajduje się definicja makra, która w tym
+ przypadku wskazuje na dwie nazwy plików obiektowych
+ (<code class="code-inline">OBJS=aux.o main.o</code>). W następnej
+ linii znajduje się bowiem reguła
+ (<code class="code-inline">all:</code>) reguły jak już wcześniej
+ wspomniano określają sposób w jaki ma zostać zbudowany cel. W tym
+ przypadku reguła <code class="code-inline">all:</code> wskazuje
+ mogłoby się wydawać, że na nasz plik końcowy. Jest to poczęści
+ prawda, ale zwróćmy uwagę na to, że poza
+ <code class="code-inline">myprog</code> nie znajduje się nic innego.
+ W jaki sposób narzędzie <em>make</em> ma wiedzieć jak zbudować ten
+ ten program. Odpowiedź kryje się w linii niżej, bowiem
+ <code class="code-inline">myprog</code> jest <strong>celem</strong>,
+ a co za tym idzie zależnością dla
+ <code class="code-inline">all:</code>. W przypadku celu
+ <code class="code-inline">myprog:</code> widzimy już jakieś konkrety:
+ pierwszym jest odwołanie się do makra, jest ono rozwiązywane do
+ nazw zapisanych na początku pliku <em>Makefile</em>, w pliku nie
+ znajduje się żadne inne elementy systemu <em>Make</em> tak więc
+ ten cel jest o tych plików uzależniony. Warto dodać, że
+ <em>Make</em> zakłada, że plki źródłowe znajdują się w tym samym
+ katalogu co pliki <em>Makefile</em>. Uruchomienie polecenia
+ <em>make</em> w tym katalogu prezentuje się następująco.
+ </p>
+<pre class="code-block">
+xf0r3m@laptop-7bf2993:~/prog/C$ make
+cc -c -o aux.o aux.c
+cc -c -o main.o main.c
+cc -o myprog aux.o main.o
+</pre>
+ <p>
+ Poza tym co sami zapisaliśmy w pliku <em>Makefile</em> to nie
+ wszystkie czynności jakie są wykonywane przez system <em>Make</em>.
+ W <em>Makefile</em> użyliśmy plików obiektowych, zatem skąd narzędzie
+ ma wiedzieć o tym, że ma wykorzystać pliki kodu źródłowego
+ (<em>.c</em>), aby utworzyć pliki obiektowe (<em>.o</em>). Za tego
+ typu czynności odpowiadają <strong>reguły wbudowane</strong>. Przez
+ co osoby zajmujące się utworzeniem plików <em>Makefile</em> mogą
+ od razu operować na właściwych plikach.
+ </p>
+ <p>
+ Ostatnia linia pliku <em>Makefile</em> jest odpowiedzialna za
+ zbudowanie właściwego pliku wykonywalnego naszego programu.
+ Po wcześniejszym przygotowaniu plików obiektowych z plików
+ źródłowych odwołanie się do makra
+ <code class="code-inline">$(OBJS)</code> staje się zwykłym
+ podstawieniem argumentów do polecenia. Ta linia jest zwykłym
+ poleceniem utworzonym na podstawie makr pliku <em>Makefile</em>.
+ Każde polecenie w pliku <em>Makefile</em> musi zostać
+ wprowadzone w nowej linii i poprzedzone
+ znakiem tabulacji równym czterem znakom spacji.
+ Makro <code class="code-inline">$(CC)</code> jest zmienną, która
+ przechowywuje nazwę programu kompilatora C, w wiekszości przypadku
+ jej wartość będzie ustawiona na <em>cc</em>.
+ </p>
+ <p>
+ Jednym z najczęstszych błędów, jakie możemy doświadczyć na początku
+ tworzenia plików <em>Makefile</em> jest:
+ </p>
+<pre class="code-block">
+xf0r3m@laptop-7bf2993:~/prog/C$ make
+Makefile:5: *** brakujący separator. Stop.
+</pre>
+ <p>
+ Wynika to najczęściej ze złego ustawienia szerokości tabulacji w
+ naszym edytorze. Ja korzystam z 2 spacji na 1 tab, ze względu na
+ wytyczne <em>Makefile</em> musiałem zmienić swoje ustawienia.
+ </p>
+ <h3 id="14.2.2.updatemakedeps">14.2.2. Aktualizacjia zależności</h3>
+ <p>
+ Program make został zaprojektowany w taki sposób aby do realizacji
+ określonego celu była wymagana jak najmniejsza ilość kroków. Tak
+ więc nie uświadczymy ponownego budowania programu w momencie
+ ponownego wydania polecenia <em>make</em>. Aczkolwiek jedną z zasad
+ systemu <em>Make</em> jest to, że cele zawsze powinny być budowane
+ wraz ze swoimi zależnościami. Taki komunikat otrzymamy gdy
+ wydamy polecenie <em>make</em> jeszcze raz.
+ </p>
+<pre class="code-block">
+xf0r3m@laptop-7bf2993:~/prog/C$ make
+make: Nie ma nic do zrobienia w 'all'.
+</pre>
+ <p>
+ Natomiast jeśli chociażby zmienimy datę, któregoś z plików kodu
+ źródłowego za pomocą prostego polecenia <em>touch</em>. Wówczas plik
+ obiektowy będzie starszy niż plik źródłowy i <em>Make</em> dokona
+ budowy naszego programu ponownie.
+ </p>
+<pre class="code-block">
+xf0r3m@laptop-7bf2993:~/prog/C$ touch aux.c
+xf0r3m@laptop-7bf2993:~/prog/C$ make
+cc -c -o aux.o aux.c
+cc -o myprog aux.o main.o
+</pre>
+ <p>
+ Z tą róźnicą, że zaktualizowany zostanie wyłącznie ten plik, który
+ został zmieniony oraz ponownie zostanie zbudowany końcowy plik
+ wykonywalny.
+ </p>
+ <h3 id="14.2.3.makecommandargs">14.2.3. Argumenty i opcje wiersza poleceń programu make</h3>
+ <p>
+ Uzupełniając wywołanie programu <em>make</em> o różne opcje oraz
+ argumenty możemy zmusić go do wykonani kilku przydatnych czynności.
+ Najprostrzym przykładem może być zmiana wartości makra <em>CC</em>,
+ wskazując inny niż domyślny kompilator.
+ </p>
+<pre class="code-block">
+$ make CC=clang
+</pre>
+ <p>
+ Tak utworzone makra mogą być przydatne w trakcie testów. Szczególnie
+ takie jak <em>CFLAGS</em> oraz <em>LDFLAGS</em>. Innym przypadkiem
+ może być użycie programu <em>make</em> dla najprostrzych programów
+ wówczas podajemy nazwe pliku bez rozszerzenia jako argument,
+ a program zbuduje nam końcowy plik wynikowy o podanej nazwe. Zwróćmy
+ uwagę, że nie ma potrzeby przygotowania pliku <em>Makefile</em>.
+ </p>
+<pre class="code-block">
+$ make foo
+cc foo.o -o foo
+</pre>
+ <p>
+ Tego typu uruchmianie narzędzia <em>make</em> bedzie sprawdzać się
+ w przypadku programów zapisanych w jednym pliku lub programów, w
+ których jezykiem nie jest C. Jest to drobre rozwiązanie gdy dopiero
+ rozpoczynamy pracę z danym językiem i nie wiem jeszcze jak działa
+ kompilator czy inne narzędzia z nim związane. Jeśli nawet zbudowanie
+ celu się niepowiedzie to i tak otrzymamy informację zwrotną co jest
+ nie tak.
+ </p>
+ <p>
+ Po za zmianami makr, możemy wykorzystać kilka przydatnych opcji
+ takich jak:
+ </p>
+ <ul>
+ <li><strong>-n</strong> - wypisuje polecenia wymagane do zbudowania
+ programu, ale nie pozwala na ich wykonanie (taki <em>dry-run</em>).
+ </li>
+ <li><strong>-f <em>plik</em></strong> - nakazuje narzędziu
+ <em>make</em> odczytać dane z podane pliku zamiast z pliku
+ <em>Makefile/makefile</em>.</li>
+ </ul>
+ <h3 id="14.2.4.makestdmacrosandvars">14.2.4. Standardowe makra i zmienne</h3>
+ <p>
+ System <em>make</em> posiada wiele predefiniowanych zmiennych oraz
+ makr. Sama różnica między makrami i zmiennymi jest trudna do
+ określenia. Dlatego też przyjęło się, że makra są niezmienne przez
+ cały okres trwania jakiegoś procesu. W tym przypadku nazwiemy tak
+ wszystko co nie zmieni się od momemntu rozpoczęcia procesu
+ budowania celów zawartych w pliku <em>Makefile</em>.
+ </p>
+ <p>
+ Najczęsciej wykorzystywane makra to między innymi:
+ </p>
+ <ul>
+ <li><strong>CFLAGS</strong> - opcje kompilatora C. <em>Make</em>
+ przekazuje je kompilatorowi w czasie tworzenia kodu obiektowego z
+ plikików <em>.c</em>.</li>
+ <li><strong>LDFLAGS</strong> - opcje przekazywane do konsolidatora w
+ czasie tworzenia pliku wykonywalnego z plików obiektowych.</li>
+ <li><strong>LDLIBS</strong> - w przypadku gdy niechcemy łączyć opcji
+ nazw bibliotek ze ścieżką wyszukiwania zapisaną w makrze
+ <em>LDFLAGS</em>, to można umieszcząć je w tym makrze.</li>
+ <li><strong>CC</strong> - nazwa kompilatora języka C. Domyślnie jest
+ to <em>cc</em>.</li>
+ <li><strong>CPPFLAGS</strong> - opcje <em>preprocesora</em> języka
+ C. Jeżeli w którymś momencie system <em>make</em> będzie wywoływał
+ preprocesor, to przekaże mu podane w tym makrze opcje.</li>
+ <li><strong>CXXFLAGS</strong> - opcje kompilatora języka C++.</li>
+ </ul>
+ <p>
+ Poza makrami w narzędziu <em>make</em> możemy korzystać ze zmiennych.
+ Zmienne mogą zmienić się podczas budowania zdefiowanych celów w
+ <em>Makefile</em>. Najczęściej jednak będziemy się spotykać ze
+ zmiennymi zdefiniowanymi automatycznie w obrębie reguł celów. Oto
+ trzy z nich:
+ </p>
+ <ul>
+ <li><strong>$@</strong> - wewnątrz reguły, zmienna opisuje nazwę jej
+ celu.</li>
+ <li><strong>$<</strong> - wewnątrz reguły, zmienna opisuje
+ pierwszą zależność celu.</li>
+ <li><strong>$*</strong> - zmienna rozwijana jest w <em>nazwę
+ podstawową</em> aktualnego celu. Wczasie tworzenia celu
+ <em>foo.o</em>, ta zmienna przechowuje nazwę <em>foo</em>.</li>
+ </ul>
+ <h3 id="14.2.5.makecommoncomptarget">14.2.5. Typowe cele kompilacji</h3>
+ <p>
+ W plikach <em>makefile</em> odpowiedzialnych za pokierowanie systemu
+ <em>make</em> faktycznych programów użytkowych możemy spotkać wiele
+ innych celów realizujących zadania niekoniecznie związane z
+ kompilacją. Są one predefiniowane przez <em>make</em> i oto kilka z
+ nich:
+ </p>
+ <ul>
+ <li><strong>clean</strong> - ten cel usuwa wszystkie pliki obiektowe
+ oraz pliki wykonywalne, dzięki temu będziemy mogli rozpocząć
+ proces kompilacji od nowa.</li>
+ <li><strong>distclean</strong> - cel podobny do <em>clean</em>,
+ ale usuwa on wszystko co nie jest częścią oryginalnej dystrybucji
+ w tym i plik <em>makefile</em>.</li>
+ <li><strong>install</strong> - ten cel powoduje skopiowanie
+ wszystkich plików, które w <em>Makefile</em> zostały oznaczone
+ jako nięzbędne do zainstalowania w systemie. Operacja jest
+ uznawana za dość niebezpieczną warto w tym przypadku zastosować
+ opcję <em>-n</em>, która pozowoli nam zobaczyć co dokładnie
+ będzie kopiowane do naszego systemu.</li>
+ <li><strong>test</strong> lub <strong>check</strong> - cel pozwala
+ sprawdzić czy po skompilowaniu wszystko działa jak należy.</li>
+ <li><strong>depend</strong> - cel ten tworzy zależności
+ wywołują kompilator ze specjalną opcją -M nakazującą mu sprawdzenie
+ kodu. Cel ten nie jest już powszechnie używany, aczkolwiek mogą
+ zdarzyć się projekty, które będą wymagać wywołanie tego celu.</li>
+ <li><strong>all</strong> - najczęściej pierwszy cel w pliku
+ <em>Makefile</em>. W wielu projektach będziemy spotykać się z
+ potrzebą wywołanie tego celu, a nie samego pliku wykonywalnego.
+ Wiele projektów składa się z wielu plików wykonywalnych i często
+ nie ma tego jednego głównego. Natomiast użycie celu <em>all</em>.
+ </li>
+ </ul>
+ <h3 id="14.2.6.makefilesstyles">14.2.6. Organizowanie pliku Makefile</h3>
+ <p>
+ Istnieje wiele róznych stylów tworzenia plików <em>Makefile</em>,
+ mimo tego stosowanych jest kilka ogólnych zasad. W pierwszej
+ częsci pliku, najcześciej spotykane są (jako definiecje makr)
+ opcje bibliotek oraz plików nagłówkowych po grupowanych wg.
+ określonych pakietów.
+ </p>
+<pre class="code-block">
+MYPACKAGE_INCLUDES=-I/usr/local/include/mypackage
+MYPACKAGE_LIB=-L/usr/local/lib/mypackage -lmypackage
+PNG_INCLUDES=-I/usr/local/include
+PNG_LIB=-L/usr/local/lib -lpng
+</pre>
+ <p>
+ Następnie zapisywane są makra z opcjami kompilatora oraz opcje
+ konsolidatora każde z opcji zapisywane jest w osobnym makrze.
+ </p>
+<pre class="code-block">
+CFLAGS=$(CFLAGS) $(X_INCLUDES) $(PNG_INCLUDES)
+LDFLAGS=$(LDFLAGS) $(X_LIB) $(PNG_LIB)
+</pre>
+ <p>
+ Po tych opcjach zapisywana jest hierarchia makr opisujących pliki
+ obiektowe. Hierarchia ze względu na zależności.
+ </p>
+<pre class="code-block">
+UTIL_OBJS=util.o
+BORING_OBJS=$(UTIL_OBJS) boring.o
+TRITE_OBJS=$(UTIL_OBJS) trite.o
+PROGS=boring trite
+</pre>
+ <p>
+ W pozostałej częsci plików występują już cele, które składają główne
+ pliki wykonywalne. Jeśli trzeb przygować regułę dla pliku obiektowego
+ należy ją umieścić zaraz nad regułą programu pliku wykonywalnego.
+ Jeśli z tego pliku obiektowego korzysta więcej plików wykonywalnych
+ niż ten jednen to trzeba je przenieść nad nie wszystkie.
</p>
</div>
<p style="margin: 15px; padding: 0; outline: 0;">