我正在进行一个大型Makefile
项目,我想整理一下。它构建了数十个子项目,每个子项目包含大约100个.cpp
和.h
个文件。我已经对它进行了设置,以便能够为多个操作系统(Linux,OSX / Mac,QNX等)和多个体系结构(debug
构建release
和x86/i386
构建, x64/amd64
,armhf
,arm64/aarch64
)并行。这是因为它是一个庞大的项目,使其快速构建的唯一方法是与多个工具链并行。
我有一个主规则,所有项目都遵循在构建时将中间对象(即:.o
文件)存储在临时目录中。因此,为Linux,arm64,发布模式构建test.c
;将在当前工作目录的以下子目录中构建目标文件:
.tmp/Linux/arm64/release
此功能在我的版本中没有问题,但是使用此设置,我似乎无法正确使用预编译的头文件(即:.GCH
文件)与GCC。通过我的设置,我有stdafx.h
/ stdafx.cpp
对。使用GCC,我可以轻松地创建stdafx.h.gch
文件。但是,如果文件与源文件位于同一路径,则项目似乎只使用它(加速构建)。如果预编译头是中间对象路径(即:.tmp/Linux/arm64/release
),则不会检测或使用它。即使我明确地将include路径添加到包含gch
文件的中间对象路径,它也会失败。包括文件名本身的完整路径会导致它被视为无效的链接描述文件,并被忽略。
因此,我的第一个解决方法是制定一条规则,强制所有OS / arch构建等待初始预编译的头生成,而不是基于每个OS / arch构建gch
。但是,如果我使用发布模式设置构建gch
并尝试make
调试版本,我会收到以下警告:
warning: stdafx.h.gch: created with -gnone, but used with -gdwarf-2
首先,我不知道这对我的构建是否会产生严重后果,其次,不同的操作系统可能会为gch
代传递不同的编译时定义标志,因此这不是“一个大小”就我所见,适合所有“用例”。
如何解决这个问题,以便预编译的标头位于$PWD
以外的位置,GCC可以检测到它?我目前正在使用gcc v5.3.1。
谢谢。
答案 0 :(得分:3)
这是您问题的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
<强>生成文件强>
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 $@ $<
$(pch): hw.h | tmp
gcc -c $(CPPFLAGS) -o $@ $<
ifdef ENFORCE_PCH
echo "#error Debug." >> $^
endif
hw: $(objs)
gcc -o $@ $^
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
- 任何地方
而不是后者,构建中断。它只是做了。
这就是它应该的样子。 GCC手册3.21 Using Precompiled Headers, 段。 3:
在编译中看到#include时,会搜索预编译的头文件。 在搜索包含的文件(请参阅搜索路径)时,编译器会查找 在查找包含文件之前,每个目录中的预编译头 那个目录。搜索到的名称是#include中指定的名称,带有'.gch' 追加。如果无法使用预编译的头文件,则会将其忽略。
因此,在包含搜索路径.
的情况下,指令#include <hw.h>
将会导致
gcc
在使用./hw.h.gch
之前检查PCH ./hw.h
,并且确实如此
没有./hw.h.gch
,它会使用./hw.h
。
从刚刚引用的文档中可能看出,将tmp
添加到包含搜索路径 - CPPFLAGS += -Itmp -I.
- 可能会导致
tmp/hw.h.gch
优先使用./hw.h
。但事实上它没有任何区别。
文档省略了重要的资格。第二句应该是:
在搜索包含的文件(请参阅搜索路径)时,编译器会查找 在查找包含文件之前,每个目录中的预编译头 该目录,如果包含文件,将使用预编译头作为首选项 找到了。
要找到并使用,PCH必须是匹配标头的兄弟。并考虑
这就是你想要的。否则,a/foo.h.gch
可能没有匹配的兄弟标头
感谢-Ia
,当b/foo.h.gch
与匹配的b/foo.h
匹配时,{
可以通过以后的-Ib
找到并使用。显然,后者是更健全的选择。
有了这种洞察力,不难看出解决方案:如果你真的想编译和使用 PCH不是其源头的兄弟,请务必给它一个 phony 匹配头 那个是一个兄弟姐妹。您可以根据需要安排,例如
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 $@ $<
$(pch): hw.h | tmp
# Make phony header in tmp...
echo "#error You should not be here" > $(basename $@)
gcc -c $(CPPFLAGS) -o $@ $<
ifdef ENFORCE_PCH
echo "#error Debug." >> $^
endif
hw: $(objs)
gcc -o $@ $^
clean:
sed -i '/^#error/d' hw.h
rm -fr hw tmp
请参阅tmp
使用PCH:
$ 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
答案 1 :(得分:0)
如果您将编译器强制设置为-include tmp/pch.h
或-include-pch tmp/pch.h.gch
,则pch.h
中的保护块将阻止其再次被包含。
# Makefile
SOURCES := main.cpp
OBJECTS := $(SOURCES:%.cpp=tmp/%.o)
PCH_H := tmp/pch.h
PCH := $(PCH_H).gch
$(PCH) : *.h
$(COMPILE.cpp) -x c++-header src/pch.h -o $@
$(OBJECTS) : tmp/%.o : src/%.cpp $(PCH)
$(COMPILE.cpp) -include $(PCH_H) $< -o $@
注意:
.gch
.pch
或 .gch
-include pch.h
或-include-pch pch.h.pch
-include-pch