C/C++: Kompilacja projektów cz. 3 - automatyzacja kompilacji z GNU Make

W poprzedniej części podzieliliśmy kompilację programu na trzy etapy. Pierwsze dwa odpowiadały za skompilowanie bibliotek arrayio.o sort.o, zaś trzeci za kompilację i linkowanie docelowej aplikacji app.exe. Cały proces budowy pliku wykonywalnego zaczął się przez to komplikować. Tym razem zobaczymy jak możemy zautomatyzować ten proces za pomocą narzedzia GNU Make.

Problemy z ręczną kompilacją

Wykonując ćwiczenie z poprzedniej części od razu dało się zauważyć jeden problem. Zbudowanie projektu wymagało wywołania kompilatora gcc aż trzy razy. Nie jest to jednak jedyna wada przeprowadzania całego procesu kompilacji ręcznie. Oprócz tego mogą się pojawić dodatkowe problemy dotyczące tego jakie pliki i w jakiej kolejności skompilować.

W naszym prostym przykładzie jeżeli zmienimy zawartość pliku app.c to nie musimy kompilować jeszcze raz plików arrayio.c sort.c. Z kolei zmiana któregokolwiek z tych plików wymaga nie tylko jego ponownej kompilacji ale i ponownego linkowania pliku app.exe. Da się jeszcze nad tym zapanować.

Wyobraźmy sobie jednak bardziej złożony projekt, w którym występują wielopoziomowe zależności. Np. załóżmy, że nasz plik sort.o korzysta z funkcji zawartych w pliku util.o. Sytuację taką przedstawia poniższy rysunek:

Teraz załóżmy, że treść pliku util.o uległa zmianie. Musimy ponownie skompilować plik sort.c tak, żeby zmiany znalazły się w pliku sort.o, a następnie jeszcze raz zbudować plik app.exe. Powoli zaczynamy tracić kontrolę nad kompilacją projektu.

GNU Make

Jak widać kompilacja nawet niezbyt złożonego projektu aż prosi się o zautomatyzowanie. Na szczęście możemy posłużyć się do tego gotowymi narzędziami. Jednym z nich jest program GNU Make.

GNU Make w systemie Windows możemy zainstalować na kilka sposobów. Ja przedstawię dwa z nich:

  1. Ściągamy ze strony projektu GNU Win32 plik instalacyjny i uruchamiamy instalację. Niestety instalator nie modyfikuje poprawnie zmiennej systemowej PATH. Musisz więc ręcznie dodać do niej ścieżkę z plikiem make.exe (znajduje się on w folderze bin w miejscu, w które podaliśmy podczas instalacji). Jeżeli nie wiesz jak ustawić zmienną PATH to pokazujemy to przy okazji demonstracji instalowania pakietu MinGW na naszym kursie o podstawach programowania (poniżej znajdziesz odpowiedni film, a pełny kurs jest dostępny na platformie Udemy). 
  2. Druga opcja to użycie wersji programu Make dołączonej do pakietu MinGW. Jeżeli używasz kompilatora gcc pod Windowsem to pewnie masz zainstalowany już ten pakiet. Jeżeli nie to poniżej znajdziesz film z instrukcją jego instalacji. Uwaga! W pakiecie MinGW program Make ma nazwę mingw32-make i taką nazwą należy zastąpić wszystkie wywołania programu make w dalszej części tego artykułu.

Tworzymy plik Makefile

Program Make do zautomatyzowania kompilacji posługuje się specjalnymi plikami o nazwie Makefile. Zawierają one informacje o tym jak poprawnie zbudować dany projekt. Zobaczymy teraz jak to działa.

Utwórzmy w folderze z plikami źródłowymi plika o nazwie Makefile (bez rozszerzenia). Wypełniamy go następującą zawartością:

all: arrayio.o sort.o
	gcc -o app.exe app.c arrayio.o sort.o

arrayio.o: arrayio.c
	gcc -c -o arrayio.o arrayio.c

sort.o: sort.c
	gcc -c -o sort.o sort.c

clean:
	del arrayio.o sort.o

Za nim omówimy sobie znaczenie poszczególnych poleceń wykonajmy kompilację. Robimy to wywołując w konsoli polecenie:

make all

W konsoli powinniśmy zobaczyć wykonujące się kolejno kompilacje plików arrayio.c, sort.c app.c. W efekcie powinien powstać nam działający program app.exe. 

Teraz spróbujmy ponownie wywołać polecenie make all. Okaże się, że kompilacja plików arrayio.c sort.c nie nastąpi.

Na koniec przetestujmy wykonanie polecenia make clean. Powinno ono usunąć pliki arrayio.o sort.o. (Uwaga – polecenie zadziała tylko w środowisku Windows. Pod Linuxem należy zmienić komendę del na rm).

Działanie ćwiczenia przedstawia poniższy screen:

Jak to wszystko działa?

Po wywołaniu instrukcji make all program Make wywoła komendę umieszczoną w pliku Makefile w sekcji all. Wcześniej sprawdzi on jednak czy wszystkie pliku umieszczone w linii za słowem all są utworzone. Jeżeli nie to wywołane zostaną tworzone je komendy zdefiniowane w dalszej części pliku Makefile. 

Jeżeli pliki istnieją, to nie zostaną ponownie zbudowane. Dzięki temu skraca się czas kompilacji. 

Dodatkowo możemy definiować inne komendy np. tak jak w naszym przykładzie komendę clean. Definiowane przez nas komendy to po prostu wywołania powłoki (konsoli) systemu operacyjnego.

Modyfikacja plików źródłowych

Wykonajmy jeszcze jedno ćwiczenie:

  1. Ponownie skompilujmy program wywołując komendę make all.
  2. Upewnijmy się, że pliki arraio.sort.c nie będą kompilowane po ponownym wywołaniu make all.
  3. Zmodyfikujmy zawartość pliku arrayio.c np. tak, żeby funkcja print_array wypisywała elementy tablicy w odwróconej kolejności (spróbuj to zrobić samodzielnie).
  4. Ponownie wywołajmy komendę make all.

Tym razem przed budową pliku app.exe zostanie ponownie przeprowadzona kompilacja pliku arrayio.c. Z czego to wynika?

Program Make przed wykonaniem każdej komendy sprawdza, czy umieszczone przy niej pliki źródłowe nie zostały zmodyfikowane od ostaniej kompilacji. Jeżeli modyfikacja nastąpiła to odpowiednie komendy kompilujące kod są wykonywane.

W naszym przypadku procedura ta wygląda następująco:

  1. Program Make przed wykonaniem komendy all sprawdza komendy budujące pliki arrayio.o oraz sort.o.
  2. Przed wykonaniem komendy budującej plik arrayio.o sprawdzana jest zawartość pliku arrayio.c. Wynika to z czwartego wiersza pliku Makefile.
  3. Ponieważ plik arrayio.c został zmodyfikowany to zostaje wywołana komenda z piątego wiersza pliku Makefile.
  4. Program sprawdza stan pliku sort.c. Ponieważ nie został on zmodyfikowany komenda z wiersza ósmego nie jest wywoływana.
  5. Teraz komenda all (zdefiniowana w wierszu drugim) może zostać wywołana.
Realizację ćwiczenia przedstawia kolejny rysunek:

Co dalej?

Jak widać program GNU Make może nam znacznie ułatwić proces budowania projektu. Rozwiązanie, które wykorzystaliśmy nie jest jednak idealne. Oto dwa przykładowe problemy:

  1. Jeżeli chcielibyśmy zmienić kompilator z gcc na jakiś inny (np. kompilator cl) to należałoby zmodyfikować nasz plik Makefile w trzech miejscach. 
  2. Komenda make clean zadziała tylko w systemie Windows. Dla Linuxa musielibyśmy przygotować osobny plik.

Jeżeli chodzi o problem pierwszy to program Make obsługuje specjalny język, w którym możemy definiować coś na kształt zmiennych i posługiwać się nimi w takich sytuacjach.

Co do problemu drugiego to istnieją lepsze narzędzia do automatycznej kompilacji np. program CMake, które pozwalają tworzyć skrypty wieloplatformowe. Mimo to warto poznać działanie programu GNU Make i składnię plików Makefile. Po pierwsze, są one często wykorzystywane do kompilacji programów typu open source. Po drugie, wiele opartych na środowisku Eclipse narzędzi do tworzenia oprogramowania na mikrokontrolery korzysta z GNU Make do przeprowadzenia kompilacji.

Chociaż poznaliśmy dopiero wierzchołek możliwości programu GNU Make to w kolejnej części cyklu skupimy się na razie na lepszym wyjaśnieniu na czym w zasadzie polega proces linkowania.

Maciej Kraszewski

Maciej Kraszewski

Inżynier, menedżer R&D i nauczyciel akademicki. Uwielbiam zajmować się tworzeniem nowych technologii, zdobywaniem nowej wiedzy i dzieleniem się swoim doświadczeniem z innymi. Specjalizuję się w zagadnieniach przetwarzania obrazu i widzenia maszynowego.
Szukasz dobrych materiałów o projektowaniu elektroniki?

Załóż darmowe konto na naszej platformie i odbierz pakiet materiałów edukacyjnych.

Zakładając konto zgadzasz się na przesyłanie Ci treści marketingowych przez IT20 sp. z o.o. zgodnie z dostępną na stronie Polityką Prywatności. Możesz wycofać zgodę w każdej chwili.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Szukasz dobrych materiałów o projektowaniu elektroniki?

Załóż darmowe konto na naszej platformie i odbierz pakiet materiałów edukacyjnych.

Zakładając konto zgadzasz się na przesyłanie Ci treści marketingowych przez IT20 sp. z o.o. zgodnie z dostępną na stronie Polityką Prywatności. Możesz wycofać zgodę w każdej chwili.

Zaprojektuj PCB

Jak przejść od zera do projektowania profesjonalnych obwodów drukowanych?

Programowanie w języku C

Jak przejść od napisania pierwszego programu komputerowego do wykorzystania zaawansowanych metod programowania?

Projektowanie układów elektronicznych

Jak działają i jak projektować poprawnie działające układy elektroniczne?
Zapisz się na listę mailową i odbierz swoje bonusy!

Więcej treści na temat elektroniki i robotyki, darmowe e-booki i dostęp do minikursów on-line. Otrzymasz to wszystko zapisując się na naszą listę mailową.