189

When I compile a very simple source file with gcc I don't have to specify the path to standard include files such as stdio or stdlib.

How does GCC know how to find these files?

Does it have the /usr/include path hardwired inside, or it will get the paths from other OS components?

activedecay
  • 10,129
  • 5
  • 47
  • 71
Raxvan
  • 6,257
  • 2
  • 25
  • 46

5 Answers5

277

In order to figure out the default paths used by gcc/g++, as well as their priorities, you need to examine the output of the following commands:

  1. For C:
echo | gcc -xc -E -v -
  1. For C++:
echo | gcc -xc++ -E -v -

The credit goes to Qt Creator team.

Here's a breakdown of the flags:

  • -x selects the language, C or C++ respectively

  • -E makes gcc to run the preprocessor only, so no compilation takes place

  • -v prints all the commands run, which is the key to dumping the standard paths

  • - is the "input file" to preprocess, as a convention - stands for stdin (or stdout, depending on the context);

    echo | feeds an empty string to gcc so effectively we preprocess an empty file generated on the fly

Here's a nice explaining it in more detail: https://explainshell.com/explain?cmd=echo+%7C+gcc+-xc+-E+-v+-

Ihor Kaharlichenko
  • 5,944
  • 1
  • 26
  • 32
  • 17
    `cpp -v /dev/null -o /dev/null` – Nehal J Wani Mar 17 '17 at 12:07
  • @NehalJWani - good advice, but it doesn't work for Renesas's rx-elf-gcc cross-compiler. `rx-elf-cpp.exe: error: /dev/null: No such file or directory` – AJM Mar 11 '22 at 12:08
  • 1
    @Ihor - what does the - at the end of the command line do? I've seen questions about these dashes elesewhere on Stack Overflow, but their meaning varies by command. As far as I can tell when experimenting with Cygwin, it means gcc will do nothing and ignore all input except Ctrl-C. But gcc in an actual Bash shell might behave very differently. – AJM Mar 11 '22 at 13:43
  • 1
    `-` refers to `stdin` here. So you could also do: `echo | gcc -xc++ -E -v -` and `echo | gcc -xc++ -E -v -` – Nehal J Wani Mar 11 '22 at 16:10
  • How does this work? And why does it not work without the last dash? And why is there an `-E` when there's no file to compile? – palapapa Mar 29 '23 at 13:58
  • 1
    @palapapa, I've updated the answer, hope it helps – Ihor Kaharlichenko Mar 30 '23 at 14:26
  • @IhorKaharlichenko I noticed that you have added `echo |` but it worked without it. It even works without `-E`. Does that mean they are unnecessary? – palapapa Mar 30 '23 at 15:14
  • 1
    @palapapa, I suppose it depends on the version of GCC. I tried omitting some of the flags from the above set, and even though there was some output each time, none of them contained the `include ... search starts here` piece which is the one we are looking for. Running on Ubuntu 22.04, GCC 11.3.0 – Ihor Kaharlichenko Apr 03 '23 at 13:36
51

There is a command with a shorter output, which allows to automatically cut the include pathes from lines, starting with a single space:

$ echo | gcc -Wp,-v -x c++ - -fsyntax-only
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2
 /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/x86_64-redhat-linux
 /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/backward
 /usr/lib/gcc/x86_64-redhat-linux/4.8.2/include
 /usr/local/include
 /usr/include
End of search list.

The credit goes to the libc++ front-page.

abyss.7
  • 13,882
  • 11
  • 56
  • 100
13

To summarise the other answers:

For C++:

c++ -xc++ /dev/null -E -Wp,-v 2>&1 | sed -n 's,^ ,,p'

For C:

cc -xc /dev/null -E -Wp,-v 2>&1 | sed -n 's,^ ,,p'

Johan Boulé
  • 1,936
  • 15
  • 19
5

Though I agree with Ihor Kaharlichenko’s answer for considering C++ and with abyss.7’s answer for the compactness of its output, they are still incomplete for the multi-arch versions of gcc because input processing depends on the command line parameters and macros.

Example:

echo | /opt/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-g++ -specs=nano.specs -mcpu=cortex-m4 -march=armv7e-m -mthumb -mfloat-abi=soft -x c++ -E -Wp,-v\ - -fsyntax-only yields

⋮
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../arm-none-eabi/include/newlib-nano                                                                                                              
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include/c++/9.2.1                                                                        
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include/c++/9.2.1/arm-none-eabi/thumb/v7e-m/nofp                                         
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include/c++/9.2.1/backward                                                               
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/include                                                                                                            
 /opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/include-fixed                                                                                                      
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include                                                                                  
⋮

whereas echo | /opt/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-g++ -x c++ -E -Wp,-v - -fsyntax-only yields

⋮
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include/c++/9.2.1                                                                        
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include/c++/9.2.1/arm-none-eabi                                                          
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include/c++/9.2.1/backward                                                               
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/include                                                                                                            
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/include-fixed                                                                                                      
/opt/gcc-arm-none-eabi-9-2019-q4-major/bin/../lib/gcc/arm-none-eabi/9.2.1/../../../../arm-none-eabi/include                                                                                  
⋮

The former invocation utilizes newlib (see lines 1 and 3 of the output), the latter goes with the standard includes. The common files at the end of the list are an example for the usage of include_next.

Bottom line: Always consider all macros and compiler options when printing the include directories.

hermannk
  • 745
  • 8
  • 12
0

Just run the following to list the default search paths:

$(gcc -print-prog-name=cc1) -v
Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
Daniele Testa
  • 1,538
  • 3
  • 16
  • 34
  • 1
    This doesn't list the include paths. Only programs path and libraries path – kayahr Jun 20 '19 at 09:56
  • `cc1` usually can't be called directly because it is an internal command which is not on the PATH. Maybe you want to edit your answer to describe where to find the file. – kayahr Jun 21 '19 at 09:31
  • bash: syntax error near unexpected token `-v' – mireazma Mar 09 '21 at 16:54