2016-05-13 105 views
3

背景


我有一個大Makefile項目我的工作,我想整理一下。它建立了幾十個子項目,每個都包含約100 .cpp.h文件。我已經設置好它,以便能夠爲多個操作系統(Linux,OSX/Mac,QNX等)以及多個體繫結構(x86/i386x64/amd64armhf,arm64/aarch64)並行構建debugrelease版本。這是因爲它是一個龐大的項目,而使其快速構建的唯一方法是與多個工具鏈並行。GCC - 多個預編譯的頭和具體路徑

我有一個主規則,所有項目,用於存儲中間對象服從:建設時臨時目錄(即.o文件)。因此,針對Linux,arm64,release模式構建test.c;將建立在以下子目錄中的目標文件在當前工作目錄:

.tmp/Linux/arm64/release 

問題


此功能沒有問題的作品在我的版本,但這種設置,我似乎無法正確使用GCC的預編譯頭文件(即:.GCH文件)。隨着我的設置,我有一個stdafx.h/stdafx.cpp對。使用GCC,我可以輕鬆創建一個stdafx.h.gch文件。但是,如果該文件與源文件位於同一路徑中,該項目似乎只會使用它(加速構建)。如果預編譯的頭是旅店中間對象路徑(即:.tmp/Linux/arm64/release)它不會檢測或使用。即使我明確地添加包含路徑,其將包含gch文件中的中間對象路徑,它失敗。包括文件名本身的完整路徑導致它被視爲無效的鏈接器腳本,並被忽略。

因此,我的第一個解決方法是制定一個規則,強制所有操作系統/構建版本在初始預編譯頭文件生成上等待,而不是在每個操作系統/基礎上構建一個gch。但是,如果我建gch與釋放模式設置,並試圖make調試版本,我得到以下警告:

warning: stdafx.h.gch: created with -gnone, but used with -gdwarf-2 

首先,我不知道是否有嚴重的後果,對我的身材,和第二,不同的操作系統可能會通過不同的編譯時間定義爲標誌的gch產生,所以這不是一個「一刀切」的使用情況,據我可以看到。


問題


我怎樣才能解決這個讓預編譯的頭是在一個位置以外的$PWD,它可以通過GCC檢測?我目前正在使用gcc v5.3.1。

謝謝。

+0

你可以發佈你嘗試編譯線之一獲得GCC看'gch'當它在不同的文件夾中? – user657267

+0

@ user657267當然:'INC + = .tmp/$ {OS_TYPE}/$ {CPU_TYPE}/$ {REL_TYPE}'。 'gcc $ {INC} -c $ {INPUT} -o $ {OUTPUT}'。不是最有用的,但是我的'Makefile'非常冗長,並且回聲了在構建過程中使用的'include'路徑,並且我可以確認頭文件通常從該路徑中解析出來,除了'.gch'文件。 – DevNull

+0

對不起,我的意思是它在執行時實際擴展到的東西。 – user657267

回答

2

這裏是你的問題 方案的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 
+0

做得很好。謝謝。 – DevNull