2013-08-05 51 views
3

编译器如何知道何时不需要重新编译代码的某些部分,特别是在大型项目中?编译器如何知道何时不重新编译?


例如,假设在C++中我们有两个C++文件和两个头文件。头文件相互依赖。 (它们使用在其他文件中指定的类)。

编译器是否总是需要解析头文件(也可能是用于方法实现的C++文件)以获取类信息以生成两个C++文件?


我一直以为,当你在命令提示符下运行编译器,其输出的目标文件后立即关闭 - 所以这将是不可能的缓存抽象语法树或中间代码。大多数C++编译器是否知道某个文件何时不需要输出到目标文件,因此会被跳过?

+4

这通常是构建系统的工作(例如,做),而不是编译器的。 –

+0

这是例如使与生成文件 – hamon

+0

的帮助下通常它是做了检查提出的,这是相当复杂的,告诉哪些文件依赖于哪些其他文件... – xanatos

回答

3

我知道的所有编译器都会编译每个源文件,他们会告诉 。总是。并且他们为他们编译的每个源文件生成对象 的新版本。

只编译需要的工作通常是留给 构建系统(make或其他)。知道需要重新生成哪些对象 取决于每个源文件包含的内容,可以直接使用 或间接;大多数编译器都可以选择以某种格式输出此信息,或者是作为一个独立的 调用,而构建系统(至少可用的) 使用此信息来确定依赖关系。

0

我不知道他们是如何实现的(因为许多人不......不要问我为什么),但我很确定这很容易。您可以在中间(obj)文件中保存源文件和正在编译的每个相关文件的名称和散列,以及正在使用的编译选项,编译器的散列(或其内部版本)以及编译结果(ok/error)。下一次用户尝试重新编译文件时,编译器会检查是否已经存在中间文件,检查所有哈希是否相同,如果编译选项相同,并且编译器相同......如果所有内容都是同样,它给出了预先保存的错误消息,并且不做任何事情而退出。

中间文件会稍大一些(可能每个都有一个kb)。

+1

我从来没有听说过这样做的编译器或构建系统。通常的编译系统依赖于编译器输出来确定依赖关系,以及文件上的时间戳以确定哪些文件实际需要重新编译。 –

+0

实际上听起来像'ccache'。如果仅仅是因为时钟同步,分布式构建比本地构建要困难一些。 – MSalters

0

如上所述,编译器会编译每个要求编译的文件。需要make等工具来决定需要编译的内容。

make之一设置规则。每个规则都有一个目标,依赖关系列表,如果这些依赖关系未得到满足,则会运行命令。例如,

target.o : target.c 
    gcc -c -o target.o target.c 

在大多数文件系统上,每个文件都有一个时间戳。如果target.o具有比target.c更新的时间戳(规则依赖性),那么make不会在下面运行gcc命令。这是因为首先编辑源文件,然后将源文件编译成目标文件。

但是,如果依赖源文件比目标文件更新,那么我们知道源文件在编译发生后编辑,而另一个编译按顺序编辑。因此make将执行该规则的构建命令。

它当规则依赖于其他的规则,但同样的原则也适用得到了很多更加复杂。