ers:
I'm trying to combine precompiled headers with dependency generation (-MM). Final goal is to generate dependency file for make. Not able to combine them together with -fpch-deps. The motivation is to speed up (incremental) builds for a huge code base that take hours to build.
Using GCC 9.3.1, "C" code. same results with GCC10 (Redhat builds)
src/a.c:
#include "h.h"
int main(int argc, char **argv) { printf("hello\n") ; }
include/h.h
#include <stdio.h>
Testing with something like:
mkdir obj
gcc include/h.h -o obj/h.h.gch
# Compile against PCH
gcc -I obj src/a.c
# Validation:
# Next line will print hello - showing PCH-based build works.
obj/a.out
# Build dependecy from pch - fail
gcc -MM -I obj -fpch-deps a.c -Winvalid-pch
GCC message is fatal error: h.h: no such file or directory
, implying that it did not search for the obj/h.h.gch.
Any help, am I misinterpreting/misusing the '-fpch-deps'
Already verified:
You have this directory tree:
$ tree
.
├── include
│ └── h.h
├── obj
└── src
└── a.c
So the commands:
$ gcc include/h.h -o obj/h.h.gch
$ gcc -I obj src/a.c
must be run in .
to work and the latter will output ./a.out
,
not ./obj/a.out
The command:
$ gcc -MM -I obj -fpch-deps a.c -Winvalid-pch
cc1: fatal error: a.c: No such file or directory
could not work unless you:
$ cd src
Where it will still fail as you observed:
$ gcc -MM -I obj -fpch-deps a.c -Winvalid-pch
a.c:1:10: fatal error: h.h: No such file or directory
1 | #include "h.h"
| ^~~~~
Why that happens can be seen with:
$ gcc -v -MM -I obj -fpch-deps a.c -Winvalid-pch
...[cut]...
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include"
ignoring nonexistent directory "obj"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-linux-gnu/13/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
a.c:1:10: fatal error: h.h: No such file or directory
1 | #include "h.h"
| ^~~~~
compilation terminated.
There is no h.h
in the current directory and:
ignoring nonexistent directory "obj"
There is no directory obj
under src
.
If -I obj
is not to be ignored then you must:
$ cd .. # up from src
and then run:
$ gcc -v -MM -I obj -fpch-deps src/a.c -Winvalid-pch
...[cut]...
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
obj
/usr/lib/gcc/x86_64-linux-gnu/13/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
End of search list.
src/a.c:1:10: fatal error: h.h: No such file or directory
1 | #include "h.h"
| ^~~~~
compilation terminated.
Include-directory obj
is now found, but header h.h
remains not found,
notwithstanding that:
$ ls obj
h.h.gch
That is because there:
gcc
will not match any precompiled header to a
header file that it cannot find.gcc
will not consider a header file to be matched by a precompiled header
file that is not in the same directory as the header file.GCC Manual: 3.22 Using Precompiled Headers:
A precompiled header file is searched for when #include is seen in the compilation. As it searches for the included file (see Search Path in The C Preprocessor) the compiler looks for a precompiled header in each directory just before it looks for the include file in that directory. The name searched for is the name specified in the #include with ‘.gch’ appended. If the precompiled header file cannot be used, it is ignored.
For instance, if you have #include "all.h", and you have all.h.gch in the same directory as all.h, then the precompiled header file is used if possible, and the original header is used otherwise.
So if you do:
$ mv obj/h.h.gch include/
then:
$ gcc -MM -I include -fpch-deps src/a.c -Winvalid-pch
a.o: src/a.c include/h.h
will succeed, and there you have the make
dependency line for a.o
.
You can check that pre-compiled header is live with:
$ gcc -H -I include src/a.c
! include/h.h.gch
src/a.c
But if you then were to do:
$ mv include/h.h include/hide-h.h
then once again:
$ gcc -MM -I include -fpch-deps src/a.c -Winvalid-pch
src/a.c:1:10: fatal error: h.h: No such file or directory
1 | #include "h.h"
| ^~~~~