c-GCC-多个预编译的标头和特定路径
作者:互联网
背景
我有一个正在处理的大型Makefile项目,我想整理一下.它构建了几十个子项目,每个子项目包含大约100个.cpp和.h文件.我已经对其进行设置,以便它能够为多种操作系统(Linux,OSX / Mac,QNX等)和多种体系结构(x86 / i386,x64 / amd64,armhf,arm64 / aarch64)构建调试版本并发布版本在平行下.这是因为这是一个庞大的项目,而使其快速构建的唯一方法是与多个工具链并行.
我有一个主要规则,那就是所有项目在构建时都应遵守将中间对象(即.o文件)存储在临时目录中的原则.因此,为Linux,arm64,发布模式构建test.c;将在当前工作目录的以下子目录中构建目标文件:
.tmp/Linux/arm64/release
问题
此功能在我的版本中可以正常工作,但是使用此设置,我似乎无法在GCC中正确使用预编译的标头(即.GCH文件).通过我的设置,我有一个stdafx.h / stdafx.cpp对.使用GCC,我可以很容易地创建一个stdafx.h.gch文件.但是,如果文件与源文件位于同一路径,则该项目似乎仅使用它(这会加快构建速度).如果预编译的头文件位于中间对象路径(即.tmp / Linux / arm64 / release)中,则不会检测到或使用该头文件.即使我将包含路径显式添加到包含gch文件的中间对象路径中,它也会失败.包含文件名本身的完整路径会导致将其视为无效的链接描述文件,并被忽略.
因此,我的第一个解决方法是制定一条规则,以强制所有OS / arch构建在初始预编译头生成时等待,而不是在每个OS / arch基础上构建gch.但是,如果我使用发布模式设置构建gch并尝试进行调试构建,则会收到以下警告:
warning: stdafx.h.gch: created with -gnone, but used with -gdwarf-2
首先,我不知道这是否会对我的构建产生严重的后果,其次,不同的操作系统可能会为gch生成传递不同的编译时定义标志,因此这不是“一刀切”的用例,因为据我所知.
题
如何解决此问题,以便预编译的标头位于$PWD以外的位置,并且GCC可以检测到它?我目前正在使用gcc v5.3.1.
谢谢.
解决方法:
这是您的问题的MVCE
场景:
main.c
#include <hw.h>
#include <stdio.h>
int main(void)
{
puts(HW);
return 0;
}
w
#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-include
而不是后者,构建中断.它只是做了.
这就是应该的. GCC手册3.21 Using Precompiled Headers,
段3:
A precompiled header file is searched for when #include is seen in the compilation.
As it searches for the included file (see Search Path) 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 can’t be used, it is ignored.
因此,给定包含搜索路径.,指令#include< hw.h>会引发
gcc在使用./hw.h之前先检查PCH ./hw.h.gch
没有./hw.h.gch,它将使用./hw.h.
从刚刚引用的文档中可以看出,将tmp添加到包含搜索路径-CPPFLAGS = -Itmp -I. -应该引起
优先于./hw.h使用的tmp / hw.h.gch.但是实际上,这没有什么区别.
该文档省略了至关重要的条件.第二句话应改为:
As it searches for the included file (see Search Path) the compiler looks for a
precompiled header in each directory just before it looks for the include file in
that directory and will use the precompiled header for preference if the include file
is found.
要找到并使用,PCH必须是匹配头的同级.并考虑
这就是你想要的.否则,没有匹配的同级标头的a / foo.h.gch可能是
当存在b / foo.h.gch并具有匹配的b / foo.h时,感谢-Ia找到并使用了该命令,
后来的-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 $@ $<
$(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
标签:gcc,makefile,precompiled-headers,linux,c-4 来源: https://codeday.me/bug/20191118/2029866.html