Zrozumienie składni pliku Makefile: typowe problemy i rozwiązania (w tym „brakujący operator” i „nie znaleziono punktu wejścia”)

Zrozumienie Skladni Pliku Makefile Typowe Problemy I Rozwiazania W Tym Brakujacy Operator I Nie Znaleziono Punktu Wejscia



Podobnie jak plik kodu zawiera jedną lub więcej linii kodu, aby było to opłacalne, podstawowy plik makefile jest tworzony przy użyciu zmiennych, reguł i celów. Poza tym istnieją również inne czynniki, które są niezbędne do utworzenia kompletnego pliku makefile bez żadnych problemów. W tym przewodniku omówimy podstawową składnię pliku makefile i typowe problemy podczas pisania pliku makefile oraz przedstawimy rozwiązania tych problemów.

Zrozumienie podstawowej składni Makefile

Aby rozpocząć tworzenie pliku makefile, wyjaśniamy podstawowe właściwości pliku makefile na przykładzie kodu makefile. Aby otrzymać plik wykonywalny, konieczne jest uwzględnienie w treści pliku makefile następujących właściwości składni:







Zmienny s: Podstawowe dane przechowujące obiekty niezbędne do użycia w pliku makefile. Zmienne te są wykorzystywane do określenia kompilatora, flag, plików źródłowych, plików obiektowych i plików docelowych. W poniższym przykładowym pliku makefile znajduje się w sumie pięć zmiennych: CXX (do ustawienia kompilatora C++), CXXFLAGSc (flagi kompilatora), TARGET (do ustawienia docelowej nazwy pliku wykonywalnego), SRCS (do ustawienia pliku z kodem źródłowym) , OBJS (zawierający pliki obiektowe generowane za pośrednictwem pliku kodu źródłowego).



Cele: Oczekiwany wynik do zbudowania ze źródła. Może to być plik docelowy lub dowolna nazwa symboliczna: „all” to domyślny cel, który należy zbudować za pomocą zmiennej „TARGET”, „$TARGET” zależy od zmiennych „OBJS”, a „clean” target usuwa cel i pliki obiektowe z katalogu roboczego.



Reguły i polecenia budowania: Zestaw podstawowych instrukcji do wykonania w celu utworzenia celu z pliku źródłowego lub zależności. Na przykład reguła „%.o: %.cpp” wyświetla, że ​​plik z rozszerzeniem „cpp” służy do utworzenia pliku obiektowego z rozszerzeniem „o”, podczas gdy oba pliki mają tę samą nazwę. Z drugiej strony polecenie kompilacji $(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS) służy do łączenia ze sobą pliku obiektowego i nowego pliku docelowego. W ten sam sposób polecenie build $(CXX) $(CXXFLAGS) -c $< -o $@ kompiluje plik źródłowy do pliku obiektowego.





Zależności: Zależności są zawsze obecne, gdy chcesz utworzyć plik makefile. Na przykład cel „all” zależy od zmiennej „TARGET”, podczas gdy „TARGET” zależy od zmiennej „OBJS”. Jednocześnie zmienna „OBJS” jest zależna od pliku źródłowego poprzez zmienną „SRCS”.

Uwagi: Instrukcje zrozumiałe dla człowieka są zwykle używane do wyjaśnienia celu linii kodu w przypadku, gdy używasz pliku po długim czasie. W poniższym pliku makefile używamy komentarzy zaczynających się od znaku „#”, aby wyjaśnić każdą linię.



CXX = g++
CXXFLAG = -std =c++ jedenaście -Ściana
CEL = nowy
SRCS = main.cpp
OBJS = $ ( SRCS:.cpp=.o )
wszyscy: $ ( CEL )
$ ( CEL ) : $ ( OBJS )
$ ( CXX ) $ ( CXXFLAG ) -O $ ( CEL ) $ ( OBJS )
% .O: % .cpp
$ ( CXX ) $ ( CXXFLAG ) -C $ < -O $ @
czysty:
rm -F $ ( CEL ) $ ( OBJS )

Typowe problemy i rozwiązania

Podczas pisania dowolnego pliku makefile konieczne jest rozważenie każdego drobnego szczegółu, aby na końcu uzyskać pożądany wynik. Użytkownicy często napotykają pewne typowe problemy podczas tworzenia pliku makefile. W tej sekcji omówimy te problemy i zaproponujemy możliwe rozwiązania w następujący sposób:

1: Nieużywanie zmiennych

Używanie zmiennych w pliku makefile jest koniecznością, ponieważ jest wymagane do ustawienia kompilatorów, celu, plików źródłowych itp. Najczęstszym problemem, jaki można napotkać, jest nieużywanie żadnej zmiennej w pliku makefile. Dlatego upewnij się, że w poprzednim przykładowym pliku makefile wykorzystano podstawowe zmienne, takie jak CXX, CXXFLAGSc (flagi kompilatora), TARGET, SRCS i OBJS.

2: Problem z brakującym separatorem

Podczas pisania pliku makefile należy bardzo uważnie rozważyć zasady wcięć, ponieważ użycie spacji zamiast tabulatora doprowadzi do problemu „brakującego separatora” podczas wykonywania instrukcji „make”. Na przykład dodajemy spację na początku reguły w linii 13 i usuwamy tabulator.

$ ( CEL ) : $ ( OBJS )
$ ( CXX ) $ ( CXXFLAG ) -O $ ( CEL ) $ ( OBJS )

Po wykonaniu zapytania „make” w linii 13 pojawia się błąd „brakującego separatora” i plik przestaje działać. Aby uniknąć tego problemu, użyj „tabulacji” zamiast spacji.

robić

Aby uniknąć tego problemu, użyj „tabulacji” zamiast spacji, jak pokazano na poniższym obrazku:

$ ( CEL ) : $ ( OBJS )
$ ( CXX ) $ ( CXXFLAG ) -O $ ( CEL ) $ ( OBJS )

3: Problem „Nie znaleziono punktu wejścia”.

Ten błąd występuje najczęściej z powodu pliku źródłowego, a nie pliku makefile, na przykład w przypadku pominięcia funkcji „main()” w pliku kodu źródłowego. Na przykład zastępujemy definicję funkcji main() prostą deklaracją funkcji zdefiniowanej przez użytkownika.

#include
int pokaż ( ) {
znak v;
std::cout << 'Wprowadź wartość: ' ;
std::cin >> W;
std::cout << W << std::endl;
powrót 0 ;
}

Po wykonaniu instrukcji „make” w wierszu poleceń systemu Windows napotykamy „niezdefiniowane odniesienie do „WinMain””. Dzieje się tak, ponieważ kompilator nie znajduje żadnego punktu wejścia, aby rozpocząć wykonywanie pliku C++. Aby rozwiązać ten problem, zamień „pokaż” na „główny”.

4: Użycie nieprawidłowych rozszerzeń

Czasami użytkownik może niechcący użyć niewłaściwych rozszerzeń pliku źródłowego, który ma zostać użyty w pliku makefile. Użycie niewłaściwego rozszerzenia spowoduje błędy w czasie wykonywania, tj. brak reguły wyznaczającej cel. Tworzymy plik makefile do zbudowania pliku wykonywalnego i obiektowego dla pliku C++. W siódmej linii podajemy plik źródłowy z rozszerzeniem „c”.

CXX := g++
CXXFLAGI := -std =c++ jedenaście -Ściana
CEL = nowy
SRCS = main.c
OBJS = $ ( SRCS:.cpp=.o )
Wszyscy: $ ( CEL )
$ ( CEL ) : $ ( OBJS )

Uruchomienie instrukcji „make” prowadzi nas do błędu „Brak reguły do ​​utworzenia elementu docelowego „main.c”. Aby uniknąć tego problemu, upewnij się, że używasz prawidłowego rozszerzenia pliku źródłowego.

robić

5: Brakujące zależności

Pisząc plik makefile, powinieneś uwzględnić wszystkie zależności pliku źródłowego, aby uzyskać żądane dane wyjściowe. Na przykład nasz plik kodu C++ wykorzystuje plik „myheader.h” jako swoją zależność. Dlatego wspominamy o tym w pliku kodu C++ w następujący sposób:

#include
#include „mój nagłówek.h”
int pokaż ( ) {
znak v;
std::cout << 'Wprowadź wartość: ' ;
std::cin >> W;
std::cout << W << std::endl;
powrót 0 ;
}

W pliku makefile celowo ignorujemy użycie pliku „myheader.h” w regule kompilacji zapisanej w linii 9.

% .O: % .cpp
$ ( CXX ) $ ( CXXFLAG ) -C $ < -O $ @

Teraz podczas korzystania z instrukcji „make” napotykamy błąd „Nic nie można zrobić dla „wszystkich”.

robić

% .O: % .cpp mój nagłówek.h
$ ( CXX ) $ ( CXXFLAG ) -C $ < -O $ @

Aby uniknąć tego problemu i pomyślnie uruchomić kod źródłowy, wspomnij o nazwie pliku „myheader.h” w dziewiątym wierszu pliku makefile, jak pokazano poniżej:

Wniosek

W tym przewodniku dokładnie wyjaśniliśmy składnię pliku makefile, używając jego niezbędnej zawartości, takiej jak zmienne, polecenia kompilacji, reguły itp. Przykładowy kod został dołączony w celu lepszego wyjaśnienia składni. Na koniec omówiliśmy kilka typowych problemów i ich rozwiązań, które użytkownik może napotkać podczas tworzenia pliku makefile.