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).