# 第9章 使用预编译的头文件

预编译头文件`(PCH)`是一些编译器支持的一种性能特性，用于编译稳定的代码体，并将代码的编译状态存储在二进制文件中。在后续的编译期间，编译器将加载存储的状态，并继续编译指定的文件。每次后续编译都更快，因为稳定的代码不需要重新编译。

qmake支持在一些平台和构建环境上使用预编译的标头，包括：

* Windows
* nmake
* VisualStudio项目(VS2008及更高版本)
* macOS、iOS、tvOS和watchOS
* Makefile
* Xcode
* Unix
* GCC 3.4及以上
* clang

## 向项目添加预编译头 <a href="#toc20479" id="toc20479"></a>

预编译的标头必须包含在整个项目中都是稳定的和静态的代码。一个典型的预编译的头可能是这样的：

```
// Add C includes here
#if defined __cplusplus
// Add C++ includes here
#include <stdlib>
#include <iostream>
#include <vector>
#include <QApplication> // Qt includes
#include <QPushButton>
#include <QLabel>
#include "thirdparty/include/libmain.h"
#include "my_stable_class.h"
...
#endif
```

<mark style="background-color:yellow;">注：一个预编译的头文件需要分离的C包含和C++包含，因为C文件的预编译的头文件可能不包含C++代码。</mark>

### 项目选项 <a href="#toc28895" id="toc28895"></a>

要使项目使用预编译的头文件，您只需要在项目文件中定义`PRECOMPILED_HEADER`变量：

```
PRECOMPILED_HEADER = stable.h
```

qmake将处理其余的部分，以确保创建和使用预编译的头文件。您不需要在`HEADERS`中包含预编译的头文件，因为如果配置支持预编译的头文件，那么qmake就会这样做。

针对Windows的`MSVC`和`g++`特性(specs)默认启用`precompile_header`。

使用此选项，在使用预编译头时，可以在项目文件中触发条件块以添加设置。例如：

```
precompile_header:!isEmpty(PRECOMPILED_HEADER) {
    DEFINES += USING_PCH
}
```

要对`MSVC` nmake目标上的C文件使用预编译头，请将`precompile_header_c`添加到`CONFIG`变量中。如果标头也用于C++，并且它包含C++的关键字`include`，请附上`#ifdef__cplusplus`。

## 关于可能问题的说明 <a href="#toc17867" id="toc17867"></a>

在某些平台上，预编译头文件的文件名后缀与其他对象文件的相同。例如，以下声明可能会导致生成两个同名的不同对象文件：

```
PRECOMPILED_HEADER = window.h
SOURCES = window.cpp
```

为了避免类似这样的潜在冲突，请为预编译的头文件提供独特的名称。

## 示例项目 <a href="#toc2341" id="toc2341"></a>

您可以在Qt发行版的`examples/qmake/precompile` 目录中找到以下源代码：

#### `mydialog.ui` <a href="#toc98" id="toc98"></a>

下图显示了Qt Creator设计模式下的mydialog.ui文件。您可以在“编辑”模式下查看该代码。

![IMG\_256](/files/1VKJcKh3NSHnshGXpvjn)

### stable.h <a href="#toc4313" id="toc4313"></a>

```
/* Add C includes here */
#if defined __cplusplus
/* Add C++ includes here */
# include <iostream>
# include <QApplication>
# include <QPushButton>
# include <QLabel>
#endif
```

### myobject.h <a href="#toc3779" id="toc3779"></a>

```
#include <QObject>
class MyObject : public QObject
{
public:
MyObject();
~MyObject();
};
```

### myobject.cpp <a href="#toc27642" id="toc27642"></a>

```
#include <iostream>
#include <QDebug>
#include <QObject>
#include "myobject.h"
MyObject::MyObject()
: QObject()
{
std::cout << "MyObject::MyObject()\n";
}
```

### util.cpp <a href="#toc1923" id="toc1923"></a>

```
void util_function_does_nothing()
{
// Nothing here...
int x = 0;
++x;
}
```

### main.cpp <a href="#toc15386" id="toc15386"></a>

```
#include <QApplication>
#include <QPushButton>
#include <QLabel>
#include "myobject.h"
#include "mydialog.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyObject obj;
MyDialog dialog;
dialog.connect(dialog.aButton, SIGNAL(clicked()), SLOT(close()));
dialog.show();
return app.exec();
}
```

### precompile.pro <a href="#toc32115" id="toc32115"></a>

```
TEMPLATE = app
LANGUAGE = C++
CONFIG += cmdline precompile_header
# Use Precompiled headers (PCH)
PRECOMPILED_HEADER = stable.h
HEADERS = stable.h \
mydialog.h \
myobject.h
SOURCES = main.cpp \
mydialog.cpp \
myobject.cpp \
util.cpp
FORMS = mydialog.ui
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tyw66.gitbook.io/qmake_manual_cn/yong-hu-shou-ce/di-9-zhang-shi-yong-yu-bian-yi-de-tou-wen-jian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
