這裏是你的問題 方案的MVCE:
的main.c
#include <hw.h>
#include <stdio.h>
int main(void)
{
puts(HW);
return 0;
}
hw.h
#ifndef HW_H
#define HW_H
#define HW "Hello World"
#endif
的Makefile
srcs := main.c
objs := $(addprefix tmp/,$(srcs:.c=.o))
pch := tmp/hw.h.gch
CPPFLAGS += -I.
.PHONY: all clean
all: hw
tmp:
mkdir -p tmp
tmp/%.o: %.c | $(pch)
gcc -c $(CPPFLAGS) -o [email protected] $<
$(pch): hw.h | tmp
gcc -c $(CPPFLAGS) -o [email protected] $<
ifdef ENFORCE_PCH
echo "#error Debug." >> $^
endif
hw: $(objs)
gcc -o [email protected] $^
clean:
sed -i '/^#error/d' hw.h
rm -fr hw tmp
該項目輸出tmp
中的中間文件。 .o
文件去那裏 和PCH hw.h.gch
。
生成並運行它:
$ make && ./hw
mkdir -p tmp
gcc -c -I. -o tmp/hw.h.gch hw.h
gcc -c -I. -o tmp/main.o main.c
gcc -o hw tmp/main.o
Hello World
到目前爲止好。但是它真的使用了PCH嗎?讓我們看看:
$ make clean
sed -i '/^#error/d' hw.h
rm -fr hw tmp
$ make ENFORCE_PCH=true
mkdir -p tmp
gcc -c -I. -o tmp/hw.h.gch hw.h
echo "#error Debug." >> hw.h
gcc -c -I. -o tmp/main.o main.c
In file included from main.c:1:0:
./hw.h:5:2: error: #error Debug.
#error Debug.
^
Makefile:15: recipe for target 'tmp/main.o' failed
make: *** [tmp/main.o] Error 1
不,它沒有。我們知道,因爲,隨着ENFORCE_PCH
定義,我們 上漲的#error
指令的hw.h
結束後產生 好tmp/hw.h.gch
。所以如果前者是隨後的#include
-ed任何地方 而不是後者,構建就會中斷。它只是做了。
這就是它應該的。 GCC手冊3.21 Using Precompiled Headers, 段。 3:
當在編譯中看到#include時,將搜索預編譯頭文件。 當它搜索包含的文件(請參閱搜索路徑)時,編譯器會在每個目錄中查找 預編譯頭文件,然後在該目錄中查找包含文件 。搜索的名稱是#include附帶的'.gch' 中指定的名稱。如果預編譯的頭文件不能使用,它將被忽略。
所以,對於包括搜索路徑.
,該指令#include <hw.h>
會導致 gcc
使用./hw.h
之前檢查的PCH ./hw.h.gch
,並且有 沒有./hw.h.gch
,它將使用./hw.h
。
它可能會出現,從剛纔引述的文件,在添加tmp
到包括搜索路徑 - CPPFLAGS += -Itmp -I.
- 應引起 tmp/hw.h.gch
在優先使用./hw.h
。但實際上它沒有區別。 該文件省略了重要的資格。第二句話應該改爲:
,因爲它搜索所包含的文件(見搜索路徑)編譯器會在每個目錄 編譯頭看起來爲包含文件中 之前該目錄和如果找到包含文件 ,將使用預編譯頭文件作爲首選項。
被發現和使用的,PCH必須是匹配的報頭的兄弟。並考慮 這是你想要的。否則,a/foo.h.gch
不匹配的同級頭可能 發現時,有一個b/foo.h.gch
用來感謝-Ia
,具有匹配b/foo.h
,該 可以找到並感謝以後-Ib
使用。顯然,後者是更健全的選擇。
有了這種認識,不難看到一個解決辦法:如果你真的想編譯和使用 一個PCH,這不是它的源頭的兄弟姐妹,確保給它一個假匹配的頭 那是兄弟姐妹。您可以根據自己的情況進行安排,例如
Makefile文件(固定)
srcs := main.c
objs := $(addprefix tmp/,$(srcs:.c=.o))
pch := tmp/hw.h.gch
# Seek headers in tmp first...
CPPFLAGS += -Itmp -I.
.PHONY: all clean
all: hw
tmp:
mkdir -p tmp
tmp/%.o: %.c | $(pch)
gcc -c $(CPPFLAGS) -o [email protected] $<
$(pch): hw.h | tmp
# Make phony header in tmp...
echo "#error You should not be here" > $(basename [email protected])
gcc -c $(CPPFLAGS) -o [email protected] $<
ifdef ENFORCE_PCH
echo "#error Debug." >> $^
endif
hw: $(objs)
gcc -o [email protected] $^
clean:
sed -i '/^#error/d' hw.h
rm -fr hw tmp
看得出來,PCH從tmp
使用:
$ make clean
sed -i '/^#error/d' hw.h
rm -fr hw tmp
$ make ENFORCE_PCH=true && ./hw
mkdir -p tmp
# Make phony header in tmp...
echo "#error You should not be here" > tmp/hw.h
gcc -c -Itmp -I. -o tmp/hw.h.gch hw.h
echo "#error Debug." >> hw.h
gcc -c -Itmp -I. -o tmp/main.o main.c
gcc -o hw tmp/main.o
Hello World
你可以發佈你嘗試編譯線之一獲得GCC看'gch'當它在不同的文件夾中? – user657267
@ user657267當然:'INC + = .tmp/$ {OS_TYPE}/$ {CPU_TYPE}/$ {REL_TYPE}'。 'gcc $ {INC} -c $ {INPUT} -o $ {OUTPUT}'。不是最有用的,但是我的'Makefile'非常冗長,並且回聲了在構建過程中使用的'include'路徑,並且我可以確認頭文件通常從該路徑中解析出來,除了'.gch'文件。 – DevNull
對不起,我的意思是它在執行時實際擴展到的東西。 – user657267