gcc / g ++: „Nie ma takiego pliku lub katalogu”

87

g++ daje mi błędy w formularzu:

foo.cc:<line>:<column>: fatal error: <bar>: No such file or directory
compilation terminated.

To samo dzieje się podczas kompilowania programów w C z gcc.

Dlaczego?


Uwaga: to pytanie zadawano już wiele razy, ale za każdym razem było to specyficzne dla sytuacji pytających. Celem tego pytania jest pytanie, które inni mogą zostać zamknięci jako duplikaty raz na zawsze; FAQ .

Sebastian Mach
źródło
4
Fajny dodatek do FAQ. Dzięki Ci!
sbi

Odpowiedzi:

117

Twój kompilator właśnie próbował skompilować plik o nazwie foo.cc. Po naciśnięciu numeru wiersza linekompilator znajduje:

#include "bar"

lub

#include <bar>

Kompilator następnie próbuje znaleźć ten plik. W tym celu wykorzystuje zestaw katalogów do przeglądania, ale w tym zestawie nie ma pliku bar. Aby uzyskać wyjaśnienie różnicy między wersjami instrukcji include, zajrzyj tutaj .

Jak powiedzieć kompilatorowi, gdzie go znaleźć

g++ma opcję -I. Umożliwia dodanie ścieżek wyszukiwania dołączania do wiersza poleceń. Wyobraź sobie, że twój plik barznajduje się w folderze o nazwie frobnicatewzględem foo.cc(załóżmy, że kompilujesz z katalogu, w którym foo.ccsię znajduje):

g++ -Ifrobnicate foo.cc

Możesz dodać więcej ścieżek włączania; każdy, który podajesz, odnosi się do bieżącego katalogu. Kompilator Microsoftu ma opcję korelacji, /Iktóra działa w ten sam sposób, lub w Visual Studio foldery można ustawić na stronach właściwości projektu, w sekcji Właściwości konfiguracji-> C / C ++ -> Ogólne-> Dodatkowe katalogi dołączane.

Teraz wyobraź sobie, że masz wiele wersji barw różnych folderach, biorąc pod uwagę:


// A/bar
#include<string>
std::string which() { return "A/bar"; }

// B/bar
#include<string>
std::string which() { return "B/bar"; }

// C/bar
#include<string>
std::string which() { return "C/bar"; }

// foo.cc
#include "bar"
#include <iostream>

int main () {
    std::cout << which() << std::endl;
}

Priorytet z #include "bar"jest skrajnie lewy:

$ g++ -IA -IB -IC foo.cc
$ ./a.out
A/bar

Jak widać, gdy kompilator zaczął rozglądać się za pośrednictwem A/, B/oraz C/, że zatrzymał się na pierwszym lub skrajnej lewej przeboju.

Dotyczy to obu form include <>i incude "".

Różnica między #include <bar>i#include "bar"

Zwykle #include <xxx>najpierw sprawdza foldery systemowe, a najpierw #include "xxx"bieżące lub niestandardowe foldery.

Na przykład:

Wyobraź sobie, że masz następujące pliki w folderze projektu:

list
main.cc

z main.cc:

#include "list"
....

W tym celu kompilator umieści #includeplik listw folderze projektu, ponieważ obecnie się kompiluje main.cci ten plik znajduje się listw bieżącym folderze.

Ale z main.cc:

#include <list>
....

a następnie g++ main.ccTwój kompilator najpierw zajrzy do folderów systemowych, a ponieważ <list>jest to standardowy nagłówek, będzie #includeto plik o nazwie listdostarczonej z platformą C ++ jako część biblioteki standardowej.

To wszystko jest nieco uproszczone, ale powinno dać ci podstawowe pojęcie.

Szczegóły dotyczące <>/ ""-priorities i-I

Zgodnie z dokumentacją gcc , priorytet dla include <>"normalnego systemu uniksowego" jest następujący:

 /usr/local/include
 libdir/gcc/target/version/include
 /usr/target/include
 /usr/include

W przypadku programów w języku C ++ będzie również szukać najpierw w katalogu / usr / include / c ++ / version. W powyższym celu jest to nazwa kanoniczna systemu, dla którego skonfigurowano GCC do kompilowania kodu; […].

Dokumentacja podaje również:

Możesz dodać do tej listy za pomocą opcji wiersza poleceń -Idir. Wszystkie katalogi nazwane -I są przeszukiwane, w kolejności od lewej do prawej, przed katalogami domyślnymi . Jedynym wyjątkiem jest sytuacja, gdy katalog jest już przeszukiwany domyślnie. W takim przypadku opcja jest ignorowana, a kolejność wyszukiwania katalogów systemowych pozostaje niezmieniona.

Aby kontynuować nasz #include<list> / #include"list"przykład (ten sam kod):

g++ -I. main.cc

i

#include<list>
int main () { std::list<int> l; }

i rzeczywiście, nadaje -I.priorytet folderowi .nad zawartością systemu i otrzymujemy błąd kompilatora.

Sebastian Mach
źródło
9
Chcę tylko, abyś zauważył, że to trochę dziwne, że nazywasz swój kompilator „swoim kompilatorem”, ponieważ pytanie i odpowiedź mają tego samego autora.
But
27
@Jeffrey: Może autor pytania chciał dopasować tutaj ogólny format. Nie wiem, zapytaj go.
Sebastian Mach,
1
Ta odpowiedź jest zła, #include <>wygląda w katalogach wymienionych -Iprzed domyślnymi katalogami systemowymi
Jonathan Wakely
5
Wyobraź sobie, że pasek plików znajduje się w folderze o nazwie frobnicate, w stosunku do foo.cc ”, podane w katalogach katalogi-I są względne w stosunku do katalogu, w którym uruchamiasz gcc, a nie względem kompilowanego pliku. Różnica jest znacząca, jeśli to zrobiszg++ -Ifrobnicate blah/foo.cc
Jonathan Wakely
3
Czy ustawienia PATHzmiennej środowiskowej (w systemach Linux) wpływają na sposób wyszukiwania plików przez kompilator?
Matt Phillips