231

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.

1

11 Answers 11

277
`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
Sign up to request clarification or add additional context in comments.

8 Comments

What do the `s mean? I'm finding it difficult to search for this.
I guess the C preprocessor is cpp instead of cc1? On my debian jessie $(gcc -print-prog-name=cpp) -v (correctly) gives one more path, which is /usr/include/x86_64-linux-gnu
If you want that to not hang waiting for input, redirect input from /dev/null, so `gcc -print-prog-name=cc1` -v < /dev/null .
@SteveJorgensen yep! Or press Ctrl+D, which sends "end of file" in Unix-talk.
|
51

In addition, gcc will look in the directories specified after the -I option.


2 Comments

@totaam: Check your font! This answer uses "-I" (capital "eye") not "-l" (lowercase "ell").
-I is for <anglebracketed.h> whereas -iquote is for "quotedfiles.h"
39

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

8 Comments

I think this would be more helpful if you just said "use the -v option".
Well if you use "-v" without a C file that includes a non-existent system header you will not cause gcc to iterate through all the include paths. The key to my answer is bogus.h listed as a system header.
without temporary files: echo "#include <bogus.h>" | gcc -v -x c -
gcc -v -E - < /dev/null or cpp -v < /dev/null are enough. You just have to get the preprocessor to run, it doesn't matter what input it sees. (The search paths are printed during startup, before it even looks at its input.)
@zwol Thanks for that, it's a lot more straight forward, and imho deserves to be a separate answer on its own.
|
20

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.

5 Comments

That's fine for your current version of gcc. The actual directories it looks in depends on the options specified when gcc was built. See Shmoopty answer for a better solution.
PS: My C++ header files are in: /usr/include/c++/4.0.0
@Martin: You're old school. Mine are in /usr/include/c++/4.2 :)
is this done recursively? i. e. if i had a lib in /usr/include/subdir/, would it be picked up?
@Base64__ Yes, you can arrange header files in subdirectories under /usr/include and they will be found.
15

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.)

Comments

11
g++ -print-search-dirs
gcc -print-search-dirs

1 Comment

These commands print the default search paths for link libraries and internal components of the compiler; they don't tell you anything about header files.
9

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

Comments

1

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

1 Comment

As you note it works for additional user specified directories, but it won’t work for the standard include paths, which is OP’s question.
1

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.

Comments

1

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.

Comments

0

I am unfamiliar with the state of GNU C++ (or of C++ in general) over a decade ago. I know trhat I took my first CS class in 2018 and back then this question didn't have a straight forward answer. I think that is largely to to the vast array of distros and how they worked, rather than how GNU C++ worked. Anyway, today (in 2025) I can say that most all distros that are widely used are going to put their standard library header files (or rather all C++ header files as far as I am aware) in the same place.

/usr/include/c++/{ver}

Replace {ver} w/ the major ver — for example: gcc v15.2.0 will be in /usr/include/c++/15._

Other Option

The other option you have is to ask GCC, which doesn't require as complicated of a CLI command as many of the other answers show. Just execute the following.

gcc -E -v -

The -E informs GCC that it isn't to compile files, or link libraries. The -v tells GCC to list subprocesses or software that has running (or rather that its using). The - tells GCC to read input from stdin instead of from files like it normally does.

The result is a list of logs from stdin, some are processes, some are environment variables, but the lot of it is irrelevant, what is important to you is the end where it displays the directories GCC searches for header files/libraries.

  // THERE WILL BE A BUNCH OF IRRELLIVANT STUFF HERE, AND THEN 
  // BELOW WILL BE THE SWEET DATA YOU WERE LOOKING FOR

  #include "..." search starts here:
  #include <...> search starts here:
   /usr/lib/gcc/x86_64-redhat-linux/15/include
   /usr/local/include
   /usr/include
  End of search list.
Comments don't do anything in cmd output, but I added them as a way of showing that they are not part of the printed GCC stdin logs.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.