Modułowe budowanie programów, plik Makefile

Transkrypt

Modułowe budowanie programów, plik Makefile
Modułowe budowanie programów, plik Makefile
Po co konstrukcja modułowa?
Konstrukcja wielomodułowa programów - podział na klasy, moduły:
● Zapewnia logiczną strukturę i poprawia czytelność programu.
● Niezależne moduły mogą być oddzielnie testowane i po kompilacji wykorzystywane w różnych
programach.
● Umożliwia wykorzystywanie w programie w języku C/C++ procedur napisanych w innych
językach programowania.
● Zwiększa szybkość kompilacji w trakcie modyfikowania programu.
Programy wielomodułowe w C/C++
Kod dużych projektów programistycznych dzieli się na wiele modułów, gdy programowanie w jednym
pliku źródłowym:
● sprawia problemy edycyjne;
● utrudnia szukanie błędu;
● znacznie wydłuża czas kompilacji (używane jest dużo zasobów procesora i pamięci);
● utrudnia dystrybucje;
● uniemożliwia współpracę w grupie programistycznej.
Aby rozbić jeden większy moduł na mniejsze, należy przenieść część kodu do innych (najlepiej
powiązanych tematycznie nazwą) plików i utworzyć pliki nagłówkowe, zawierające niezbędne deklaracje.
Pliki źródłowe – rozszerzenia *.c, *.cpp – zawierają definicje funkcji, definicje zmiennych globalnych
Pliki nagłówkowe – rozszerzenia *.h, *.hpp - zawierają deklaracje funkcji, makrodefinicje (#define ...)
oraz deklaracje zmiennych globalnych.
Program make
Make jest narzędziem automatycznie określającym, które fragmenty kodu wymagają ponownej kompilacji
i wykonuje ich kompilacje.
Plik makefile (Makefile) - opisuje relacje pomiędzy plikami w projekcie oraz polecenia służące do
uaktualniania poszczególnych plików; wywołanie:
make
make -f makefile_name
make nazwa_reguly
W pliku Makefile:
Plik Makefile składa się z: reguł, dyrektyw, definicji makr i poleceń. Reguły, dyrektywy i definicje makr
powinny rozpoczynać się w pierwszej kolumnie tekstu, natomiast polecenia muszą być poprzedzone co
najmniej jednym znakiem pustym.
Reguły w pliku Makefile mają następującą budowę:
zbiór_uakt1 [zbiór_uakt2 [...]] : {{sciezki}}[zbiór_uzal1 [zbiór_uzal2 [...]]]
polecenie
Reguły opisują nam zależności między plikami (innymi regułami), a polecenia są poleceniami systemu,
które wykonują nam daną regułę.
jeden_plik :
g++ -Wall -pedantic -o program main.cpp
Reguła jeden_plik nie jest zależna od żadnych innych reguł i po prostu kompiluje nam ona plik main.cpp.
Mamy dwa rodzaje reguł:
1. Reguły jawne, w których wymieniamy konkretne nazwy plików(reguł). Każda z nich opisuje inny
plik projektu. Jak mamy 100 klas to musimy do każdej z nich sami napisać osobną regułę i po
dodaniu każdego kolejnego pliku źródłowego trzeba do niego dodawać kolejną regułę. Jest to dość
kłopotliwe, ale dla małych projektów można tak używać pliku Makefile.
Przykład (z dwóch plików obiektowych robimy plik wykonywalny):
funkcja : main.o funkcja.o
g++ -o funkcja main.o funkcja.o
2. Reguły niejawne, w których pewien wzorzec jest automatycznie rozwijany w nazwę pliku
Przykład (reguła ta z każdego pliku źródłowego o rozszerzeniu *.cpp zrobi nam plik obiektowy o takiej
samej nazwie):
%.o : %.cpp
g++ -Wall -pedantic -c $<
$< - jest to makrodefinicja pre definiowana (oznacza zbiór uzależniający) – w to miejsce będziemy mieli
wstawione odpowiednie nazwy plików źródłowych, np. main.cpp, owoc.cpp, ...
Jest też makrodefinicja $@, która oznacza zbiór uzależniany, np. main.o, owoc.o czy skelp (jako plik
wykonywalny).