How does cpp preprocessor pick up header from subdirectories - c++

I want to begin my question with a disclaimer that I am beginner with c++.
My question is how does the preprocessor know which directories to look for when looking for header file.
I know that it searches in some specific predefined locations and whatever we pass as -I in the g++ compilation step. However what confuses me is some standard headers are picked up even if they are not in those locations.
I referred to the question at Finding out what the GCC include path is and I followed the steps there.
$ /usr/include % echo | cpp -Wp,-v
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/4.9/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.9/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "<stdin>"
But I tried to locate the iostream and I see
$ locate iostream
/usr/include/c++/4.8/iostream
it is located at /usr/include/c++/4.8/iostream , but the search path ends at /usr/include . If it were any other header file, I would have to include it as
#include <c++/4.8/iostream>, but in all the programs I use #include <iostream> .
PS: The reason I am asking this question is because I accidentally deleted /usr/include/c++/4.9 directory, it used to work before deleting. But it is not picking up usr/include/c++/4.8/cstddef . I want to understand the procedure for picking up correct include paths of c++ preprocessor.
Thanks

They're compiled in. Make sure you specify the correct language.
$ echo | cpp -Wp,-v -x c++
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.9.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.9.2/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-redhat-linux/4.9.2/../../../../include/c++/4.9.2
/usr/lib/gcc/x86_64-redhat-linux/4.9.2/../../../../include/c++/4.9.2/x86_64-redhat-linux
/usr/lib/gcc/x86_64-redhat-linux/4.9.2/../../../../include/c++/4.9.2/backward
/usr/lib/gcc/x86_64-redhat-linux/4.9.2/include
/usr/local/include
/usr/include
End of search list.
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "<stdin>"

Related

Permanently and reliably set gcc include path globally

System: LMDE4, 64bit, gcc-8.3.0, VS Code
Target File: https://github.com/opencv/opencv/blob/master/samples/cpp/videocapture_camera.cpp
Now as the title says, this starts pissing me off. Nothing is working to fix such a simple issue. And NO I don't want to always use "-I" to tell pretty obvious things to the compiler. Here is what I've done so far.
in c_cpp_properties.json of VS Code:
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/include/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "gnu++14",
"intelliSenseMode": "clang-x64",
"browse": {
"path": [
"/usr/include/"
]
}
}
],
"version": 4
}
in .bashrc:
#C Include
export C_INCLUDE_PATH="/usr/include"
export C_INCLUDE_PATH=$C_INCLUDE_PATH:"/usr/include/opencv2"
#C++ Include
export CPLUS_INCLUDE_PATH="/usr/include"
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:"/usr/include/c++/8/"
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:"/usr/include/opencv2"
#C/C++ Include
export CPATH="/usr/include"
I am pretty sure that all the .bashrc exports are already a dirty workaround and still I get the following message on compile:
In file included from /usr/include/c++/8/bits/stl_algo.h:59,
from /usr/include/c++/8/algorithm:62,
from /usr/include/opencv2/core/base.hpp:55,
from /usr/include/opencv2/core.hpp:54,
from ~/LearnDummy/helloworld.cpp:1:
/usr/include/c++/8/cstdlib:75:15: fatal error: stdlib.h: Datei oder Verzeichnis nicht gefunden
#include_next <stdlib.h>
^~~~~~~~~~
compilation terminated.
Well fine... stdlib.h is unknown (Jesus!)... find /usr -name stdlib.h gives me
/usr/include/stdlib.h
/usr/include/c++/8/stdlib.h
/usr/include/c++/8/tr1/stdlib.h
/usr/include/x86_64-linux-gnu/bits/stdlib.h
/usr/include/i386-linux-gnu/bits/stdlib.h
In addition VS Code already knows(!) where the file is once I click on "Go to Definition" and still gcc is blind. How do I get realiably rid of this?
Here is a minimal repro of your problem on 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.
Note that export CPLUS_INCLUDE_PATH="/usr/include" here has the same effect as your
identical setting in your .bashrc.
The error does not occur if we remove that environment setting:
$ export CPLUS_INCLUDE_PATH=; g++ -c main.cpp; echo Done
Done
The effect of that environment setting, as per the GCC Manual: 3.21 Environment Variables Affecting GCC
is the same as:
$ 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.
which accordingly reproduces the error.
The -isystem option is documented in the GCC Manual: 3.16 Options for Directory Search
The general solution to your problem is: Don't run a g++ compilation in any way
that has the effect of g++ ... -isystem /usr/include ...
You can avoid running a g++ command in such a way because the option
-isystem /usr/include is unnecessary. /usr/include is a default search directory
for the preprocessor. You don't need to tell it to look for system header files there -
either via environment settings, or via a VS Code configuration, or any other way.
See the preprocessor's default search order for 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.
...
So your comment:
I am pretty sure that all the .bashrc exports are already a dirty workaround
is on the money1. But what's worse, the .bashrc setting:
export CPLUS_INCLUDE_PATH="/usr/include"
turns the problem into a persistent feature of your bash profile.
How does the error happen?
The difference that is made to the preprocessor's search order by -isystem /usr/include
can be seen here:
$ 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.
...
As you see, /usr/include is detected now as a duplicated directory in the <...> search
order; the second occurrence - which was last, previously - is deleted and the first occurrence is
retained, coming first in the search order.
Now recall the diagnostic:
/usr/include/c++/9/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
75 | #include_next <stdlib.h>
| ^~~~~~~~~~
The preprocessor directive #include_next is not a standard directive, it is
a GCC extension, documented in the GCC manual: 2.7 Wrapper Headers
Whereas #include <stdlib.h> means:
Include the first file called stdlib.h discovered in the <...> search order, starting from the start
#include_next <stdlib.h> means:
Include the next file called stdlib.h discovered in the <...> search order, starting from the
directory right after that of the file being processed now.
The only directory in the <...> search order that contains stdlib.h is /usr/include. So,
if #include_next <stdlib.h> is encountered by the preprocessor in any file in any directory dir in the <...>
search order, while /usr/include is first in the <...> search order, there can be no directory
later than dir in the <...> search order where <stdlib.h> will be found. And so the error.
#include_next <foobar.h> can only work if the <...> search order places the directory containing
<foobar.h> after the one that contains the file that contains the directive. As a rule of thumb,
just don't mess with the <...> search order.
The problem just discussed was the subject of a regression bug-report raised against GCC 6.0.
As you can see there, the resolution was WONTFIX.
[1] All of your .bashrc exports as posted are, as you suspect, poor practice.
It isn't necessary to tell the preprocessor about any search directories in
its default search order. You can only make things wrong.
Directories that will not be found by default should be specified by
-I dir options specified on the commandline (typically injected via parameters
of the build configuration), so that these non-default options are visible in build logs
for trouble shooting. "Invisible hands" are to be avoided in build systems to the
utmost practical extent.

Does g++ not take header files from the first include path it exists in?

I'm trying to build a third party tool. I'm not very familiar with the C++ build tools, and I'm not sure how this should be resolved.
dcp2icc.src/dcp2icc.cpp line 6 is:
#include "dng_camera_profile.h"
dng_sdk_1_2/dng_sdk/source/dng_camera_profile.h line 39:
#include "dng_hue_sat_map.h"
There are two dng_hue_sat_map.h files:
$ ls -l dng_sdk_1_2/dng_sdk/source/dng_hue_sat_map.h fixes/dng_sdk/dng_hue_sat_map.h
-r--r--r-- 1 user users 3141 Apr 9 2008 dng_sdk_1_2/dng_sdk/source/dng_hue_sat_map.h
-rw-r--r-- 1 user users 3124 Oct 31 2015 fixes/dng_sdk/dng_hue_sat_map.h
Finally, this is the command which gets run:
g++ -o build/dcp2icc/dcp2icc.o -c -m32 -O2 -iquote- -DUNIX_ENV=1 -D_FILE_OFFSET_BITS=64 -DkBigEndianHost=0 -Idcp2icc.src -Ifixes/dng_sdk -Idng_sdk_1_2/dng_sdk/source -INone dcp2icc.src/dcp2icc.cpp
I expected that because -Ifixes/dng_sdk comes before -Idng_sdk_1_2/dng_sdk/source, fixes/dng_sdk/dng_hue_sat_map.h would be used, but this is not the case:
In file included from dng_sdk_1_2/dng_sdk/source/dng_camera_profile.h:39:0,
from dcp2icc.src/dcp2icc.cpp:6:
dng_sdk_1_2/dng_sdk/source/dng_hue_sat_map.h:129:8: error: extra qualification 'dng_hue_sat_map::' on member 'operator==' [-fpermissive]
bool dng_hue_sat_map::operator== (const dng_hue_sat_map &rhs) const;
^~~~~~~~~~~~~~~
How does g++ choose which file to use when the header file exists in two include locations? Does it matter which sequence the includes are in, and if so, how?
man g++ simply has this to say:
-I dir
Add the directory dir to the list of directories to be searched for header files. Directories named by -I are searched before the standard system include directories. If the directory dir is a standard system include directory, the option is ignored to ensure that the default search order for system directories and the special treatment of system headers are not defeated . If dir begins with "=", then the "=" will be replaced by the sysroot prefix; see --sysroot and -isysroot.
The GCC spec says the following, which as far as I can tell is the opposite of what I'm seeing:
You can specify multiple -I options on the command line, in which case the directories are searched in left-to-right order.
You're using the #include "..." form, rather than the #include <...> form.
The file dng_sdk_1_2/dng_sdk/source/dng_camera_profile.h is including "dng_hue_sat_map.h". #include "..." first searches relative to the file doing the including, so it first searches in dng_sdk_1_2/dng_sdk/source, regardless of -I options.

How to generate *.f90 files from *.F90 files in gfortran?

I have a small fortran program with some pre-processor directives written in a *.F90 file. Now, I would like to generate a *.f90 fortran file from it, which removes all the extra code in the *.F90 file corresponding to the other non-activated directives.
In pgifortran, all I have to do is :
pgf90 -F file_name.F90
And that is it! It produces a *.f90 file having the lines relevant to the active directives.
How can I do this in gfortran?
GNU Fortran options
See https://gcc.gnu.org/onlinedocs/gfortran/Preprocessing-Options.html for full details, but you may observe that the option -E preprocesses foo.F90 to stdout (you can, of course, pipe it to e.g. foo.f90).
The -E option is valid for the GNU compiler front-ends in general, and works for C, C++ and Fortran.
While preprocessing is enabled by default for files with the extentions .fpp, .FPP, .F, .FOR, .FTN, .F90, .F95, .F03 or .F08, you can enable it manually with -cpp. You can also disable it manually with -nocpp.
Example Program
program main
implicit none
#ifdef USER_MACRO
print*,'USER_MACRO was defined'
#endif
#ifdef __GFORTRAN__
print*,'I am GNU Fortran (aka gfortran)!'
#endif
#ifdef __GNUC__
print*,'I am GNU C (or its preprocessor)!'
#endif
end program main
Result from GNU C preprocessor (cpp)
$ cpp -E fpp.F90
# 1 "fpp.F90"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 324 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "fpp.F90" 2
program main
implicit none
print*,'I am GNU C (or its preprocessor)!'
end program main
Result from GNU Fortran
$ gfortran -E fpp.F90
# 1 "fpp.F90"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "fpp.F90"
program main
implicit none
print*,'I am GNU Fortran (aka gfortran)!'
print*,'I am GNU C (or its preprocessor)!'
end program main
Obviously, you can see how user-defined symbols are preprocessed, too:
$ gfortran -E -DUSER_MACRO fpp.F90
# 1 "fpp.F90"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "fpp.F90"
program main
implicit none
print*,'USER_MACRO was defined'
print*,'I am GNU Fortran (aka gfortran)!'
print*,'I am GNU C (or its preprocessor)!'
end program main
Result from Intel Fortran
In case it is of interest, Intel compilers support the same options as GCC:
$ ifort -E -DUSER_MACRO fpp.F90
# 1 "fpp.F90"
program main
implicit none
print*,'USER_MACRO was defined'
# 8
# 11
end program main
Preprocessing with IBM XL Fortran
The IBM XL Fortran man pages have the full details, but it is important to note that preprocessor symbols must be provided via -WF,-DUSER_MACRO instead of -DUSER_MACRO.

Why does Eclipse think clang doesn't support std::atomic

I have an eclipse c++ project that uses some c++11 features. It uses cmake for building so it is setup in eclipse as a project with existing makefiles.
It builds fine with the makefiles either in eclipse or from the command line. But I get syntax errors with atomic_bool saying the symbol can't be resolved. I have added -std=c++11 under 'C/C++ General -> Preprocessor Include Pattern -> Providers -> CDT GCC Built-in Compiler Settings' and I have the toolchain in eclipse set to MacOSX GCC.
Note: other c++11 things like thread or shared_ptr don't give any syntax errors.
The errors come from the <atomic> header where there is the preprocessor if statement
#if !__has_feature(cxx_atomic)
#error <atomic> is not implemented
#else
...
Everything below the #else is grayed out. So apparently __has_feature(cxx_atomic) evaluates to 0 according to eclipse. But if I check it from the command line it shows that it should evaluate to true.
$ echo '__has_feature(cxx_atomic)' | g++ -x c++ -std=c++11 -E -
# 1 "<stdin>"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 188 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2
1
Why does __has_feature(cxx_atomic) evaluate to false in Eclipse but not if I check the compiler itself?
Try a Enabling "Build output parser".
http://www.eclipse.org/forums/index.php/t/501479/
I encountered this issue too, other C++11 features are supported, but atomic does not.

Where does gcc look for C and C++ header files?

On a Unix system, where does gcc look for header files?
I spent a little time this morning looking for some system header files, so I thought this would be good information to have here.
`gcc -print-prog-name=cc1plus` -v
This command asks gcc which C++ preprocessor it is using, and then asks that preprocessor where it looks for includes.
You will get a reliable answer for your specific setup.
Likewise, for the C preprocessor:
`gcc -print-prog-name=cpp` -v
In addition, gcc will look in the directories specified after the -I option.
You can create a file that attempts to include a bogus system header.
If you run gcc in verbose mode on such a source, it will list all the system include locations as it looks for the bogus header.
$ echo "#include <bogus.h>" > t.c; gcc -v t.c; rm t.c
[..]
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i686-apple-darwin9/4.0.1/include
/usr/include
/System/Library/Frameworks (framework directory)
/Library/Frameworks (framework directory)
End of search list.
[..]
t.c:1:32: error: bogus.h: No such file or directory
The CPP Section of the GCC Manual indicates that header files may be located in the following directories. From the Search Path page:
GCC looks in several different places for headers. On a normal Unix system, if you do not instruct it otherwise, it will look for headers requested with #include in:
/usr/local/include
libdir/gcc/target/version/include
/usr/target/include
/usr/include
For C++ programs, it will also look in /usr/include/g++-v3, first.
To get GCC to print out the complete set of directories where it will look for system headers, invoke it like this:
$ LC_ALL=C gcc -v -E -xc - < /dev/null 2>&1 |
LC_ALL=C sed -ne '/starts here/,/End of/p'
which will produce output of the form
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/5/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
If you have -I-family options on the command line they will affect what is printed out.
(The sed command is to get rid of all the other junk this invocation prints, and the LC_ALL=C is to ensure that the sed command works -- the "starts here" and "End of search list" phrases are translated IIRC.)
g++ -print-search-dirs
gcc -print-search-dirs
The set of paths where the compiler looks for the header files can be checked by the command:-
cpp -v
If you declare #include "" , the compiler first searches in current directory of source file and if not found, continues to search in the above retrieved directories.
If you declare #include <> , the compiler searches directly in those directories obtained from the above command.
Source:- http://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art026
One could view the (additional) include path for a C program from bash by checking out the following:
echo $C_INCLUDE_PATH
If this is empty, it could be modified to add default include locations, by:
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/include
These are the directories that gcc looks in by default for the specified header files ( given that the header files are included in chevrons <>);
1. /usr/local/include/ --used for 3rd party header files.
2. /usr/include/ -- used for system header files.
If in case you decide to put your custom header file in a place other than the above mentioned directories, you can include them as follows:
1. using quotes ("./custom_header_files/foo.h") with files path, instead of chevrons in the include statement.
2. using the -I switch when compiling the code.
gcc -I /home/user/custom_headers/ -c foo.c -p foo.o
Basically the -I switch tells the compiler to first look in the directory specified with the -I switch ( before it checks the standard directories).When using the -I switch the header files may be included using chevrons.
My system has gcc9 by default and I have built a gcc12 from source and I think the accepted answer is not correct, that is gcc -print-prog-name=cc1plus -v doesn't give the real include search path.
My build configuration is
Configured with: /home/tian/playground/gcc_build_play/objdir/../gcc-12.1.0/configure --prefix=/home/tian/GCC-12.1.0 --disable-multilib
And no matter where I mv the gcc12 directoy in my machine. It can always include its own c++ header files correctly.
If I type ./gcc -print-prog-name=cc1plus -v, in the original installed directory, it gives:
tian#tian-B250M-Wind:~/GCC-12.1.0/bin$ `./gcc -print-prog-name=cc1plus` -v
ignoring nonexistent directory "/home/tian/GCC-12.1.0/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/home/tian/GCC-12.1.0/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0
/home/tian/GCC-12.1.0/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0/x86_64-pc-linux-gnu
/home/tian/GCC-12.1.0/lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0/backward
/home/tian/GCC-12.1.0/lib/gcc/x86_64-pc-linux-gnu/12.1.0/include
/usr/local/include
/home/tian/GCC-12.1.0/include
/home/tian/GCC-12.1.0/lib/gcc/x86_64-pc-linux-gnu/12.1.0/include-fixed
/usr/include
End of search list.
mv my gcc12 to ~/Desktop/, run again, gives:
tian#tian-B250M-Wind:~/Desktop/GCC-12.1.0/bin$ `./gcc -print-prog-name=cc1plus` -v
ignoring nonexistent directory "/home/tian/GCC-12.1.0/include/c++/12.1.0"
ignoring nonexistent directory "/home/tian/GCC-12.1.0/include/c++/12.1.0/x86_64-pc-linux-gnu"
ignoring nonexistent directory "/home/tian/GCC-12.1.0/include/c++/12.1.0/backward"
ignoring nonexistent directory "/home/tian/GCC-12.1.0/lib/gcc/x86_64-pc-linux-gnu/12.1.0/include"
ignoring nonexistent directory "/home/tian/GCC-12.1.0/include"
ignoring nonexistent directory "/home/tian/GCC-12.1.0/lib/gcc/x86_64-pc-linux-gnu/12.1.0/include-fixed"
ignoring nonexistent directory "/home/tian/GCC-12.1.0/x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/include
End of search list.
If that's true, then I compile a program with ./g++, it should use c++ header files in /usr/include or /usr/local/include. But it's not.
Experiment is omitted here. You can try using mv to rename any header file of gcc12 your test program use or add some garbage code to the header file. Then you will see the gcc12 ./g++ is complaining about the gcc12 c++ header file, not my system gcc9's c++ header files in /usr/include or /usr/local/include.
So in both places ./g++ can find its gcc12 c++ headers files correctly.
So I guess gcc and g++ are finding headers in relative directory, relative to /path_to_gcc12/bin/gcc.
Try./g++ -g -Wall --verbose -o test test.cpp gives the real include path:
tian#tian-B250M-Wind:~/Desktop/GCC-12.1.0/bin$ ./g++ -g -Wall --verbose -o test test.cpp
Using built-in specs.
COLLECT_GCC=./g++
COLLECT_LTO_WRAPPER=/home/tian/Desktop/GCC-12.1.0/bin/../libexec/gcc/x86_64-pc-linux-gnu/12.1.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /home/tian/playground/gcc_build_play/objdir/../gcc-12.1.0/configure --prefix=/home/tian/GCC-12.1.0 --disable-multilib
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 12.1.0 (GCC)
COLLECT_GCC_OPTIONS='-g' '-Wall' '-v' '-o' 'test' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
/home/tian/Desktop/GCC-12.1.0/bin/../libexec/gcc/x86_64-pc-linux-gnu/12.1.0/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -iprefix /home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/12.1.0/ -D_GNU_SOURCE test.cpp -quiet -dumpbase test.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -g -Wall -version -o /tmp/ccrg0qhG.s
GNU C++17 (GCC) version 12.1.0 (x86_64-pc-linux-gnu)
compiled by GNU C version 12.1.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../x86_64-pc-linux-gnu/include"
ignoring duplicate directory "/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0"
ignoring duplicate directory "/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0/x86_64-pc-linux-gnu"
ignoring duplicate directory "/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0/backward"
ignoring duplicate directory "/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/12.1.0/include"
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring duplicate directory "/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/12.1.0/include-fixed"
ignoring nonexistent directory "/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../x86_64-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0
/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0/x86_64-pc-linux-gnu
/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/12.1.0/../../../../include/c++/12.1.0/backward
/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/12.1.0/include
/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/x86_64-pc-linux-gnu/12.1.0/include-fixed
/usr/local/include
/home/tian/Desktop/GCC-12.1.0/bin/../lib/gcc/../../include
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
So I think my guess is correct.