Вот минимальное воспроизведение вашей проблемы в Ubuntu 20.04.
$ g++ --version
g++ (Ubuntu 9.3.0-10ubuntu2) 9.3.0
...
$ cat main.cpp
#include <cstdlib>
int main ()
{
return EXIT_SUCCESS;
}
$ export CPLUS_INCLUDE_PATH="/usr/include"; g++ -c main.cpp
In file included from main.cpp:1:
/usr/include/c++/9/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
75 | #include_next <stdlib.h>
| ^~~~~~~~~~
compilation terminated.
Обратите внимание, что export CPLUS_INCLUDE_PATH="/usr/include"
здесь имеет тот же эффект, что и ваши идентичные настройки в вашем .bashrc
.
Ошибка не возникает, если мы удалим этот параметр среды:
$ export CPLUS_INCLUDE_PATH=; g++ -c main.cpp; echo Done
Done
Эффект от этого параметра среды согласно Руководству G CC: 3.21 Влияние переменных среды G CC это то же самое, что:
$ g++ -isystem /usr/include -c main.cpp
In file included from main.cpp:1:
/usr/include/c++/9/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
75 | #include_next <stdlib.h>
| ^~~~~~~~~~
compilation terminated.
, что соответственно воспроизводит ошибку.
Параметр -isystem
задокументирован в Руководстве по G CC : 3.16 Параметры для поиска в каталоге
общее решение вашей проблемы: Не запускайте компиляцию g++
любым способом, который имеет эффект g++ ... -isystem /usr/include ...
Вы можете избежать запуска команды g++
таким образом, потому что опция -isystem /usr/include
не нужна. /usr/include
- это каталог поиска по умолчанию для препроцессора. Вам не нужно указывать ему искать там файлы системных заголовков - либо через настройки среды, либо через конфигурацию VS Code, либо любым другим способом.
См. Порядок поиска препроцессора по умолчанию для C ++: -
$ echo | g++ -x c++ -E -Wp,-v -
ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/9"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/include/c++/9
/usr/include/x86_64-linux-gnu/c++/9
/usr/include/c++/9/backward
/usr/lib/gcc/x86_64-linux-gnu/9/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include ### <- There it is ###
End of search list.
...
Итак, ваш комментарий:
Я почти уверен, что весь экспорт .bashr c уже является грязным обходным путем
включен деньги 1 . Но что еще хуже, настройка .bashrc
:
export CPLUS_INCLUDE_PATH="/usr/include"
превращает проблему в постоянную функцию вашего bash профиля .
Каким образом произошла ошибка?
Различие, которое вносит -isystem /usr/include
в порядок поиска препроцессора, можно увидеть здесь:
$ echo | g++ -x c++ -isystem /usr/include -E -Wp,-v -
ignoring duplicate directory "/usr/include/x86_64-linux-gnu/c++/9"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"
ignoring duplicate directory "/usr/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/include ### <- Was previously last, now is first ###
/usr/include/c++/9
/usr/include/x86_64-linux-gnu/c++/9
/usr/include/c++/9/backward
/usr/lib/gcc/x86_64-linux-gnu/9/include
/usr/local/include
/usr/include/x86_64-linux-gnu
End of search list.
...
Как видите, обнаружено /usr/include
теперь как дублированный каталог в порядке поиска <...>
; второе вхождение - которое было последним , ранее - удаляется, а первое вхождение сохраняется, идя первое в порядке поиска.
Теперь вызовите диагностику c:
/usr/include/c++/9/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
75 | #include_next <stdlib.h>
| ^~~~~~~~~~
Директива препроцессора #include_next
не является стандартной директивой, это расширение G CC, задокументированное в руководстве G CC: 2.7 Заголовки оболочки
В то время как #include <stdlib.h>
означает:
Включить первый файл с именем stdlib.h
, обнаруженный в порядке поиска <...>
, начиная с начала
#include_next <stdlib.h>
означает:
Включить следующий обнаруженный файл с именем stdlib.h
в порядок поиска <...>
, начиная с каталога сразу после того, как файл обрабатывается сейчас.
Единственный каталог в порядке поиска <...>
, содержащий stdlib.h
, - это /usr/include
. Таким образом, если #include_next <stdlib.h>
обнаружен препроцессором в любом файле в любом каталоге dir
в порядке поиска <...>
, а /usr/include
- первый в порядке поиска <...>
, может не быть каталогом позже dir
в порядке поиска <...>
, где будет найдено <stdlib.h>
. Итак, ошибка.
#include_next <foobar.h>
может работать, только если порядок поиска <...>
помещает каталог, содержащий <foobar.h>
, после того, который содержит файл, содержащий директиву. Как правило, просто не связывайтесь с порядком поиска <...>
.
Только что обсуждаемая проблема была предметом отчета об ошибке регрессии, поднятого против G CC 6.0 . Как вы можете видеть, разрешение было WONTFIX
.
[1] Все ваши
.bashrc
экспорта в том виде, в каком они были опубликованы, как вы подозреваете, являются плохой практикой.
Нет необходимости сообщать препроцессору о каких-либо каталогах поиска в порядке поиска по умолчанию. Вы можете только ошибиться.
Каталоги, которые не будут найдены по умолчанию должны быть указаны с помощью -I dir
параметров, указанных в командная строка (обычно вводится через параметры конфигурации сборки), чтобы эти нестандартные параметры были видны в журналах сборки для устранения неполадок. «Невидимых рук» следует избегать в системах сборки в максимально возможной степени.