c makefile tutorial
W tym samouczku C ++ Makefile omówimy główne aspekty narzędzia Make i Makefile, w tym jego zalety i zastosowania w C ++:
W każdym projekcie C ++ jednym z ważnych celów jest uproszczenie budowania projektu, tak abyśmy otrzymali wszystkie zależności i pliki projektu w jednym miejscu i wykonali je za jednym razem, tak aby uzyskać pożądane dane wyjściowe za pomocą jednego polecenia.
c # pytania do wywiadu i odpowiedzi dla doświadczonych z przykładami
Jednocześnie za każdym razem, gdy którykolwiek z plików projektu jest modyfikowany, nie musimy mieć kłopotów z ponownym budowaniem całego projektu, tj. Za każdym razem, gdy plik lub dwa są modyfikowane w projekcie, przebudowujemy tylko te zmienione pliki, a następnie kontynuujemy z wykonaniem.
=> Przeczytaj serię szkoleń Easy C ++.
To są dokładnie funkcje, do których odnosi się narzędzie „make” i „makefiles” w C ++. W tym samouczku omówimy wszystkie główne aspekty plików makefile, a także ich zastosowania w C ++.
Czego się nauczysz:
Make Tool
Make jest narzędziem UNIX i służy jako narzędzie upraszczające budowanie plików wykonywalnych z różnych modułów projektu. Istnieją różne reguły, które są określone jako pozycje docelowe w pliku makefile. Narzędzie make odczytuje wszystkie te zasady i odpowiednio się zachowuje.
Na przykład, jeśli reguła określa jakąkolwiek zależność, to narzędzie make uwzględni tę zależność na potrzeby kompilacji. Polecenie make jest używane w makefile do budowania modułów lub do czyszczenia plików.
Ogólna składnia make to:
%make target_label #target_label is a specific target in makefile
Na przykład , jeśli chcemy wykonać polecenia rm w celu wyczyszczenia plików, piszemy:
% make clean #here clean to etykieta_celu określona dla poleceń rm
C ++ Makefile
Plik makefile to nic innego jak plik tekstowy, który jest używany lub do którego odwołuje się polecenie „make” do budowania celów. Plik makefile zawiera również informacje, takie jak zależności na poziomie źródła dla każdego pliku, a także zależności kolejności kompilacji.
Zobaczmy teraz ogólną strukturę pliku makefile.
Plik makefile zazwyczaj zaczyna się od deklaracji zmiennych, po których następuje zestaw wpisów docelowych do tworzenia określonych celów. Tymi celami mogą być .o lub inne pliki wykonywalne w języku C lub C ++ oraz .class w Javie.
Możemy również mieć zestaw pozycji docelowych do wykonywania zestawu poleceń określonych przez etykietę docelową.
Tak więc ogólny plik makefile jest taki, jak pokazano poniżej:
# comment target: dependency1 dependency2 ... dependencyn command # (note: the in the command line is necessary for make to work)
Poniżej pokazano prosty przykład pliku makefile.
# a build command to build myprogram executable from myprogram.o and mylib.lib all:myprogram.o mylib.o gcc –o myprogram myprogram.o mylib.o clean: $(RM) myprogram
W powyższym pliku makefile określiliśmy dwie etykiety docelowe, pierwsza to etykieta „all” do zbudowania pliku wykonywalnego z plików myprogram i mylib. Druga etykieta docelowa „wyczyść” usuwa wszystkie pliki o nazwie „myprogram”.
Zobaczmy inną odmianę pliku makefile.
# the compiler: gcc for C program, define as g++ for C++ CC = gcc # compiler flags: # -g - this flag adds debugging information to the executable file # -Wall - this flag is used to turn on most compiler warnings CFLAGS = -g -Wall # The build target TARGET = myprogram all: $(TARGET) $(TARGET): $(TARGET).c $(CC) $(CFLAGS) -o $(TARGET) $(TARGET).c clean: $(RM) $(TARGET)
Jak pokazano w powyższym przykładzie, w tym pliku makefile używamy zmiennej „CC”, która zawiera wartość kompilatora, którego używamy (w tym przypadku GCC). Inna zmienna „CFLAGS” zawiera flagi kompilatora, których będziemy używać.
Trzecia zmienna „TARGET” zawiera nazwę programu, dla którego musimy zbudować plik wykonywalny.
Zaletą tej odmiany makefile jest to, że po prostu musimy zmienić wartości zmiennych, których użyliśmy, ilekroć nastąpi zmiana w kompilatorze, flagach kompilatora lub nazwie programu wykonywalnego.
Przykład Make And Makefile
Rozważmy przykład programu z następującymi plikami:
- Main.cpp: Główny program sterownika
- Point.h: Plik nagłówkowy dla klasy punktów
- Point.cpp: Plik implementacji CPP dla klasy punktów
- Square.h: Plik nagłówkowy dla klasy square
- Square.cpp; Plik implementacji CPP dla klasy square
Z podanymi powyżej plikami .cpp i .h, musimy skompilować te pliki osobno, aby wygenerować pliki .o, a następnie połączyć je w plik wykonywalny o nazwie main.
Więc następnie kompilujemy te pliki osobno.
- g ++ -c main.cpp: generuje main.o
- g ++ -c point.cpp: generuje punkt. o
- g ++ -c square.cpp: generuje square.o
Następnie łączymy razem pliki obiektowe, aby wygenerować plik wykonywalny main.
g ++ -o main main.o point.o square.o
Następnie musimy zdecydować, które z plików będziemy musieli przekompilować i zregenerować, gdy niektóre części programu zostaną zaktualizowane. W tym celu będziemy mieć plik wykres zależności który pokazuje różne zależności dla każdego z plików implementacji.
Poniżej znajduje się wykres zależności dla powyższych plików.
Na powyższym wykresie zależności widzimy plik wykonywalny „main” w katalogu głównym. Plik wykonywalny „main” składa się z plików obiektowych, a mianowicie. main.o, point.o, square.o, które są generowane przez kompilację odpowiednio main.cpp, point.cpp i square.cpp.
Wszystkie implementacje cpp używają plików nagłówkowych, jak pokazano na powyższym wykresie. Jak pokazano powyżej, main.cpp odwołuje się zarówno do point.h, jak i square.h, ponieważ jest programem sterownika i używa klas point i square.
Następny plik point.cpp odwołuje się do point.h. Trzeci plik square.cpp odwołuje się do square.h, jak również do point.h, ponieważ będzie również potrzebował punktu do narysowania kwadratu.
Z powyższego wykresu zależności jasno wynika, że za każdym razem, gdy zmieni się plik .cpp lub .h, do którego odwołuje się plik .cpp, musimy ponownie wygenerować ten plik .o. Na przykład, gdy plik main.cpp się zmieni, musimy ponownie wygenerować plik main.o i ponownie połączyć pliki obiektowe, aby wygenerować główny plik wykonywalny.
Wszystkie powyższe wyjaśnienia, które podaliśmy, będą działać płynnie, jeśli w projekcie jest niewiele plików. Kiedy projekt jest ogromny, a pliki są duże i zbyt wiele, ich ponowne odtworzenie staje się trudne.
W związku z tym idziemy do tworzenia plików i używamy do tworzenia narzędzia do budowania projektu i generowania pliku wykonywalnego.
Widzieliśmy już różne części pliku make. Zauważ, że plik powinien nosić nazwę „MAKEFILE” lub „makefile” i powinien zostać umieszczony w folderze źródłowym.
Teraz zapiszemy plik makefile dla powyższego przykładu.
Zdefiniujemy zmienne przechowujące wartości kompilatora i flag kompilatora, jak pokazano poniżej.
CC = g++ CFLAGS = -wall -g
Następnie tworzymy pierwszy cel w naszym pliku makefile, czyli plik wykonywalny main. Więc piszemy cel z jego zależnościami.
main: main.o point.o square.o
Zatem polecenie wygenerowania tego celu to
$(CC) $(CFLAGS) –o main main.o point.o square.o
Uwaga: Powyższe polecenie właściwie tłumaczy się na g ++ -wall –g –o main main.o point.o square.o
Naszym następnym celem będzie wygenerowanie plików obiektowych, main.o, point.o, square.o
Teraz, aby wygenerować main.o, cel zostanie zapisany jako:
Main.o: main.cpp point.h square.h
Polecenie dla tego celu to:
$(CC) $(CFLAGS) –c main.cpp
Następny plik point.o można wygenerować za pomocą poniższego polecenia:
$(CC) $(CFLAGS) –c point.h
W powyższym poleceniu pominęliśmy point.cpp. Dzieje się tak, ponieważ make już wie, że pliki .o są generowane z plików .cpp, więc wystarczy .h (plik dołączany).
Podobnie square.o można wygenerować za pomocą następującego polecenia.
$(CC) $(CFLAGS) –c square.h point.h
Cały plik makefile dla tego przykładu będzie wyglądał tak, jak pokazano poniżej:
# Makefile for Writing Make Files Example # ***************************************************** # Variables to control Makefile operation CC = g++ CFLAGS = -Wall -g # **************************************************** # Targets needed to bring the executable up to date main: main.o Point.o Square.o $(CC) $(CFLAGS) -o main main.o Point.o Square.o # The main.o target can be written more simply main.o: main.cpp Point.h Square.h $(CC) $(CFLAGS) -c main.cpp Point.o: Point.h Square.o: Square.h Point.h
Widzimy więc, że mamy kompletny plik makefile, który kompiluje trzy pliki C ++, a następnie generuje wykonywalny plik main z plików obiektowych.
Zalety plików Makefiles
- W przypadku dużych projektów użycie plików makefile pomaga nam przedstawić projekt w systematyczny i efektywny sposób.
- Pliki Makefiles sprawiają, że kod źródłowy jest bardziej zwięzły i łatwy do odczytania i debugowania.
- Pliki Makefiles automatycznie kompilują tylko te pliki, które zostały zmienione. W związku z tym nie musimy ponownie generować całego projektu, gdy niektóre jego części są modyfikowane.
- Narzędzie Make pozwala nam skompilować wiele plików jednocześnie, dzięki czemu wszystkie pliki można skompilować w jednym kroku.
Wniosek
Pliki Makefile są dobrodziejstwem dla rozwoju oprogramowania. Korzystając z pliku makefile w C ++, możemy tworzyć rozwiązania w krótszym czasie. Również w przypadku modyfikacji części projektu plik makefile rekompiluje i ponownie generuje tylko tę część bez konieczności ponownego generowania całego projektu.
C ++ Makefile umożliwia nam systematyczne i wydajne reprezentowanie projektu, dzięki czemu jest on bardziej czytelny i łatwy do debugowania.
W tym samouczku C ++ Makefile omówiliśmy szczegółowo makefile i narzędzia do tworzenia. Omówiliśmy również, jak napisać makefile od podstaw.
=> Sprawdź idealny przewodnik szkoleniowy C ++ tutaj.
rekomendowane lektury
- 70+ NAJLEPSZYCH samouczków C ++ do nauki programowania w C ++ ZA DARMO
- Dev C ++ IDE: instalacja, funkcje i programowanie w C ++
- Pełne omówienie C ++
- Obiekty plików VBScript: CopyFile, DeleteFile, OpenTextFile, odczyt i zapis pliku tekstowego
- Samouczek obsługi plików w języku Python: jak tworzyć, otwierać, czytać, pisać
- Polecenia systemu plików Unix Touch, Cat, Cp, Mv, Rm, Mkdir (część B)
- 12 najlepszych IDE i edytorów kodu Pythona w 2021 roku
- 15 najlepszych darmowych edytorów kodu zapewniających doskonałe wrażenia z kodowania