gcc / g ++: «Нет такого файла или каталога»

87

g++ дает мне ошибки формы:

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

То же самое и при компиляции C-программ с использованием gcc.

Почему это?


Обратите внимание: этот вопрос задавали много раз раньше, но каждый раз он относился к ситуации, в которой спрашивает. Цель этого вопроса состоит в том, чтобы задать вопрос, который другие могут быть закрыты как дубликаты раз и навсегда; FAQ .

Себастьян Мах
источник
4
Хорошее дополнение к FAQ. Спасибо вам!
sbi

Ответы:

117

Ваш компилятор только что попытался скомпилировать файл с именем foo.cc. При достижении номера строки lineкомпилятор находит:

#include "bar"

или

#include <bar>

Затем компилятор пытается найти этот файл. Для этого он использует набор каталогов, но в этом наборе нет файла bar. Объяснение разницы между версиями оператора include см . Здесь .

Как сообщить компилятору, где его найти

g++есть возможность -I. Он позволяет добавлять пути поиска в командную строку. Представьте, что ваш файл barнаходится в папке с именем frobnicateотносительно foo.cc(предположим, что вы компилируете из каталога, в котором foo.ccон находится):

g++ -Ifrobnicate foo.cc

Вы можете добавить больше включаемых путей; каждый, который вы указываете, относится к текущему каталогу. Компилятор Microsoft имеет параметр корреляции, /Iкоторый работает таким же образом, или в Visual Studio папки можно установить на страницах свойств проекта в разделе Свойства конфигурации-> C / C ++ -> Общие-> Дополнительные каталоги включения.

Теперь представьте, что у вас есть несколько версий barв разных папках, учитывая:


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

Приоритет с #include "bar"крайним левым:

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

Как видите, когда компилятор начал просмотр A/, B/и C/он остановился при первом или крайнем левом ударе.

Это верно как для форм, так include <>и для incude "".

Разница между #include <bar>и#include "bar"

Обычно #include <xxx>он сначала просматривает системные папки, а #include "xxx"затем - текущие или пользовательские папки.

Например:

Представьте, что у вас в папке проекта есть следующие файлы:

list
main.cc

с main.cc:

#include "list"
....

Для этого ваш компилятор поместит #includeфайл listв папку вашего проекта, потому что он в настоящее время компилируется main.ccи этот файл находится listв текущей папке.

Но с main.cc:

#include <list>
....

а затем g++ main.ccваш компилятор сначала изучит системные папки, и, поскольку <list>это стандартный заголовок, он найдет #includeфайл с именем, listкоторый поставляется с вашей платформой C ++ как часть стандартной библиотеки.

Все это немного упрощено, но должно дать вам основную идею.

Подробная информация о <>/ ""-приоритетах и-I

Согласно документации gcc , приоритет для include <>"нормальной системы Unix" следующий:

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

Для программ на C ++ он также сначала будет искать в / usr / include / c ++ / version. В приведенном выше примере target - это каноническое имя системы, для которой GCC был настроен для компиляции кода; [...].

В документации также указано:

Вы можете добавить в этот список параметр командной строки -Idir. Все каталоги, названные -I, ищутся в порядке слева направо перед каталогами по умолчанию . Единственное исключение - когда dir уже ищется по умолчанию. В этом случае опция игнорируется, и порядок поиска для системных каталогов остается неизменным.

Чтобы продолжить наш #include<list> / #include"list"пример (тот же код):

g++ -I. main.cc

а также

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

и действительно, -I.папка имеет приоритет .над системой, и мы получаем ошибку компилятора.

Себастьян Мах
источник
9
Просто хочу, чтобы вы заметили, что это довольно странно, что вы называете свой компилятор «своим компилятором», поскольку у вопроса и ответа один и тот же автор.
Shoe
27
@ Джеффри: Возможно, автор вопроса намеревался вписать здесь общий формат. Не знаю, спроси его.
Себастьян Мах
1
Этот ответ неверен, #include <>смотрит в каталогах, перечисленных -Iперед системными каталогами по умолчанию
Джонатан Уэйкли,
5
« Представьте, что ваша файловая панель находится в папке с именем frobnicate относительно foo.cc », указанные с помощью dirs -Iотносятся к каталогу, в котором вы запускаете gcc, а не относительно компилируемого файла. Разница значительна, если вы это сделаетеg++ -Ifrobnicate blah/foo.cc
Джонатан Уэйкли
3
Влияют ли настройки вашей PATHпеременной окружения (в системах Linux) на то, как компилятор вообще ищет файлы?
Мэтт Филлипс,