]> gitweb.morketsmerke.org Git - mmdev.git/commitdiff
Kontynuowanie tworzenia rozdziału 14. Podrozdział 14.3.
authorxf0r3m <jakubstasinski@protonmail.com>
Sun, 28 Apr 2024 16:03:33 +0000 (18:03 +0200)
committerxf0r3m <jakubstasinski@protonmail.com>
Sun, 28 Apr 2024 16:03:33 +0000 (18:03 +0200)
articles/terminallog/Linux.Podstawy.html

index dfc9632e4d918e7765ee5322bb272315bed723e9..a2ecbde866edd8ddd448aa7ef0cdd59e6aea51ee 100644 (file)
@@ -11883,7 +11883,278 @@ xf0r3m@laptop-5cfe659:~$ cc -c -I/opt/pt/include netstats.c
         </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>$&lt;</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;">