gcc -I dir: add a header search path (fix "No such file or directory" for #include)
- tool
- C
- command
- gcc
- flag
- -I dir
- default
- the directory of the current file (for #include "...") and the system include directories
gcc -Iinclude main.c adds the directory include to the list of places the preprocessor searches for header files, so #include <mylib/math.h> finds include/mylib/math.h. Directories given with -I are searched before the standard system directories, in the order they appear on the command line. Without it, a header that is not next to the source file or in a system directory fails with fatal error: mylib/math.h: No such file or directory (GCC) or fatal error: 'mylib/math.h' file not found (Clang).
Without and with -I
The example uses Clang 20 from the Zig 0.15.1 toolchain (installed from PyPI with uv); cc below is that compiler, and GCC accepts the same options:
cc() { uv run -q --no-project --python 3.13 --with ziglang==0.15.1 python -m ziglang cc -fno-color-diagnostics "$@"; }
mkdir -p include/mylib src
cat > include/mylib/math.h <<'EOF'
#pragma once
int add(int a, int b);
EOF
cat > src/math.c <<'EOF'
#include <mylib/math.h>
int add(int a, int b) { return a + b; }
EOF
cat > src/main.c <<'EOF'
#include <stdio.h>
#include <mylib/math.h>
int main(void) { printf("2 + 3 = %d\n", add(2, 3)); return 0; }
EOF
echo "== without -I"
cc src/main.c src/math.c -o app1; echo "exit: $?"
echo "== with -Iinclude"
cc -Iinclude src/main.c src/math.c -o app2 && ./app2Output
== without -I
src/math.c:1:10: fatal error: 'mylib/math.h' file not found
1 | #include <mylib/math.h>
| ^~~~~~~~~~~~~~
1 error generated.
src/main.c:2:10: fatal error: 'mylib/math.h' file not found
2 | #include <mylib/math.h>
| ^~~~~~~~~~~~~~
1 error generated.
exit: 1
== with -Iinclude
2 + 3 = 5Each source file that includes the header fails on its own without -I. With -Iinclude both compile, link and run. The path is relative to the directory where the compiler is started, not to the source file.
Search order
| Order | #include "file.h" | #include <file.h> |
|---|---|---|
| 1 | Directory of the file that contains the #include | - |
| 2 | Directories from -iquote, left to right | - |
| 3 | Directories from -I, left to right | Directories from -I, left to right |
| 4 | Directories from -isystem, then the standard system directories | Same |
| 5 | Directories from -idirafter | Same |
Related options: -iquote dir (only for the quoted form), -isystem dir (treated like a system directory, so warnings from those headers are suppressed), -idirafter dir (searched last), -nostdinc (ignore the standard directories), and the environment variables CPATH and C_INCLUDE_PATH, which act like -I and -isystem.
Typical uses
gcc -Iinclude -Ithird_party/json/include -c src/main.c -o build/main.o
gcc -I"$(brew --prefix openssl)/include" -c tls.c # Homebrew libraries on macOS
gcc $(pkg-config --cflags libcurl) -c net.c $(pkg-config --libs libcurl) # let pkg-config supply -I and -lpkg-config --cflags prints the right -I (and -D) options for installed libraries; prefer it over hard-coded paths. In CMake, target_include_directories(app PRIVATE include) generates -I for you.
Pitfalls
-Ifixes compile-time header lookup only. If the header is found but the function lives in a library that is not linked, the error moves to the linker as undefined reference; add the source file or-lname(and-L dir).- Do not add
-I/usr/includeor other system directories: it changes the search order of system headers and can break#include_nextin the C library. - Two directories with a header of the same name: the first
-Iwins, which can silently pick an old copy. Prefer prefixed includes such as<mylib/math.h>, as in the example. - For multi-file builds and object files, see compile multiple C files.
FAQ
What is the difference between -I and -L?
-I adds a directory for header files, used by the preprocessor for #include. -L adds a directory for libraries, used by the linker together with -lname. A missing -I gives a 'file not found' error at compile time; a missing -L or -l gives undefined reference errors at link time.
Should I use #include "file.h" or #include <file.h>?
Quotes for headers of your own project: they are searched first in the directory of the including file, then in the -iquote and -I paths. Angle brackets for system and library headers: they skip the current directory and search the -I paths, then the system directories.
How do I see where the compiler searches for headers?
Run gcc -v -E -x c /dev/null (or clang the same way). The output lists the #include "..." and #include <...> search directories in order, including those added with -I.