gcc / g ++: "Keine solche Datei oder kein solches Verzeichnis"

87

g++ gibt mir Fehler der Form:

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

Dies gilt auch für das Kompilieren von C-Programmen mit gcc.

Warum ist das so?


Bitte beachten Sie: Diese Frage wurde schon oft gestellt, aber jedes Mal war sie spezifisch für die Situation des Fragestellers. Der Zweck dieser Frage ist es, eine Frage zu haben, die andere ein für alle Mal als Duplikate von schließen können. eine FAQ .

Sebastian Mach
quelle
4
Schöne Ergänzung zu den FAQ. Danke!
sbi

Antworten:

118

Ihr Compiler hat gerade versucht, die genannte Datei zu kompilieren foo.cc. Beim Erreichen der Zeilennummer linefindet der Compiler:

#include "bar"

oder

#include <bar>

Der Compiler versucht dann, diese Datei zu finden. Zu diesem Zweck werden eine Reihe von Verzeichnissen zum Durchsuchen verwendet, in dieser Gruppe befindet sich jedoch keine Datei bar. Eine Erklärung des Unterschieds zwischen den Versionen der include-Anweisung finden Sie hier .

Wie man dem Compiler sagt, wo er es findet

g++hat eine Option -I. Sie können der Befehlszeile Include-Suchpfade hinzufügen. Stellen Sie sich vor , dass Ihre Datei barin einem Ordner mit dem Namen frobnicate, bezogen auf foo.cc(vorausgesetzt , dass Sie aus dem Verzeichnis kompilieren , wo foo.ccbefindet):

g++ -Ifrobnicate foo.cc

Sie können weitere Include-Pfade hinzufügen. Jedes von Ihnen angegebene ist relativ zum aktuellen Verzeichnis. Der Compiler von Microsoft verfügt über eine Korrelationsoption /I, die auf die gleiche Weise funktioniert. In Visual Studio können die Ordner auf den Eigenschaftenseiten des Projekts unter Konfigurationseigenschaften-> C / C ++ -> Allgemein-> Zusätzliche Einschlussverzeichnisse festgelegt werden.

Stellen Sie sich nun vor, Sie haben mehrere Versionen barin verschiedenen Ordnern:


// 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;
}

Die Priorität mit #include "bar"ist ganz links:

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

Wie Sie sehen, wenn der Compiler gestartet Suche durch A/, B/und C/hielt es an dem ersten oder am weitesten links stehenden Hit.

Dies gilt für beide Formen include <>und incude "".

Unterschied zwischen #include <bar>und#include "bar"

Normalerweise #include <xxx>werden zuerst Systemordner und zuerst #include "xxx"aktuelle oder benutzerdefinierte Ordner angezeigt.

Z.B:

Stellen Sie sich vor, Sie haben die folgenden Dateien in Ihrem Projektordner:

list
main.cc

mit main.cc:

#include "list"
....

Zu diesem Zweck erstellt Ihr Compiler #includedie Datei listin Ihrem Projektordner, da sie derzeit kompiliert wird main.ccund sich diese Datei listim aktuellen Ordner befindet.

Aber mit main.cc:

#include <list>
....

Anschließend g++ main.ccüberprüft Ihr Compiler zuerst die Systemordner. Da <list>es sich um einen Standardheader handelt, wird #includedie Datei mit dem Namen verwendet list, die mit Ihrer C ++ - Plattform als Teil der Standardbibliothek geliefert wird.

Dies ist alles etwas vereinfacht, sollte Ihnen aber die Grundidee geben.

Details zu <>/ ""-priorities und-I

Laut der gcc-Dokumentation hat include <>auf einem "normalen Unix-System" folgende Priorität :

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

Bei C ++ - Programmen wird zuerst auch in / usr / include / c ++ / version nachgeschaut. Oben ist Ziel der kanonische Name des Systems, für das GCC zum Kompilieren von Code konfiguriert wurde. [...].

In der Dokumentation heißt es außerdem:

Sie können dieser Liste mit der Befehlszeilenoption -Idir hinzufügen. Alle mit -I benannten Verzeichnisse werden in der Reihenfolge von links nach rechts vor den Standardverzeichnissen durchsucht . Die einzige Ausnahme ist, wenn das Verzeichnis bereits standardmäßig durchsucht wird. In diesem Fall wird die Option ignoriert und die Suchreihenfolge für Systemverzeichnisse bleibt unverändert.

Um unser #include<list> / #include"list"Beispiel fortzusetzen (gleicher Code):

g++ -I. main.cc

und

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

In der Tat enthält die -I.Priorisierung des Ordners .über das System und wir erhalten einen Compilerfehler.

Sebastian Mach
quelle
9
Ich möchte Sie nur darauf aufmerksam machen, dass es etwas seltsam ist, wenn Sie Ihren Compiler als "Ihren Compiler" bezeichnen, da die Frage und die Antwort denselben Autor haben.
Schuh
28
@ Jeffrey: Vielleicht wollte der Autor der Frage hier zum allgemeinen Format passen. Keine Ahnung, frag ihn.
Sebastian Mach
1
Diese Antwort ist falsch, #include <>sieht in den Verzeichnissen mit -Ivor Standard-Systemverzeichnissen aufgeführt
Jonathan Wakely
5
" Stellen Sie sich vor, Ihre Dateileiste befindet sich in einem Ordner mit dem Namen frobnicate, relativ zu foo.cc ". Die angegebenen Verzeichnisse beziehen sich auf das Verzeichnis, -Iin dem Sie gcc ausführen, und nicht auf die zu kompilierende Datei. Der Unterschied ist signifikant, wenn Sie dies tung++ -Ifrobnicate blah/foo.cc
Jonathan Wakely
3
PATHBeeinflussen die Einstellungen Ihrer Umgebungsvariablen (auf Linux-Systemen), wie der Compiler überhaupt nach Dateien sucht?
Matt Phillips