gcc / g ++: “Немає такого файлу чи каталогу”


87

g++ видає мені помилки у формі:

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

Це те саме при складанні C-програм з gcc.

Чому так?


Зверніть увагу: це запитання вже задавали багато разів, але кожного разу воно було специфічним для ситуації, що вимагала запитання. Мета цього запитання - поставити питання, яке можна раз і назавжди закрити як дублікати ; FAQ .


4
Гарне доповнення до поширених запитань. Дякую тобі!
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. У наведеному вище ціль - це канонічна назва системи GCC, налаштованої на компіляцію коду для; [...].

У документації також зазначено:

Ви можете додати до цього списку за допомогою опції командного рядка -Idir. Всі каталоги з іменем -I шукаються в порядку зліва направо перед каталогами за замовчуванням . Єдиним винятком є ​​випадки, коли каталог за замовчуванням вже шукається. У цьому випадку параметр ігнорується, а порядок пошуку системних каталогів залишається незмінним.

Щоб продовжити наш #include<list> / #include"list"приклад (той самий код):

g++ -I. main.cc

і

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

і справді, -I.пріоритети папки .над системою включають, і ми отримуємо помилку компілятора.


9
Просто хочу, щоб ви помітили, що це якось дивно, коли ви називаєте свій компілятор "своїм компілятором", оскільки питання та відповідь має одного і того ж автора.
Взуття

27
@ Джеффрі: Можливо, автор запитання мав на меті відповідати загальному формату тут. Не знаю, запитай його.
Себастьян Мах,

1
Ця відповідь помилкова, #include <>виглядає в папках, перелічених -Iдо системних папок за замовчуванням
Джонатан Уейклі

5
" Уявіть, що рядок вашого файлу знаходиться в папці з ім'ям frobnicate, відносно foo.cc ", дані, вказані з, -Iвідносяться до каталогу, в якому ви запускаєте gcc, а не щодо файлу, що компілюється. Різниця суттєва, якщо ви це зробитеg++ -Ifrobnicate blah/foo.cc
Джонатан Уейклі

3
Чи PATHвпливають налаштування вашої змінної середовища (в системах Linux) на те, як компілятор взагалі шукає файли?
Matt Phillips
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.