为什么Delphi决定不必要地重新编译某些文件

时间:2013-04-28 06:36:21

标签: delphi build compilation makefile delphi-2006

当我构建项目时,我希望看到所有单元在编译过程中重新编译。当我“制作”项目时,我希望只重新编译源更改的那些单元。当我在完整构建后立即制作时,我希望看到链接发生而没有别的。

出于某种原因,德尔福已经开始重新编译某些单位了。我注意到的主要内容是idIOHandler.pas - Indy的一部分。它有时会编译其他人 - 总是Indy中的某个单位。我在Indy源文件夹中搜索了带有棘手日期戳的文件是徒劳的。

(偶尔我会看到相反的问题 - 我知道我已经更改过的源单元没有重新编译。我把它归结为我的PC和存放源的服务器之间的时间差异。)

这不是一个大问题,但我很想听到解释。

3 个答案:

答案 0 :(得分:3)

这完全取决于Delphi如何决定某些东西需要重新编译。

我已经看到一个的事情导致这种情况(在完全非Delphi环境中)。由于某种原因,文件在将来会被给定日期,依赖于它们的文件将始终重新编译。

例如,假设由于某种原因,myprog.c在2027年被赋予了一个日期。当您第一次编译它(到myprog.o)时,结果将在2013年的今天给出。

下一次时间,myprog.c上的日期位于myprog.o之后,因此重新编译。

不确定这是否会导致您的问题,但可能值得研究。

您需要注意的另一件事。如果您的设备依赖于接口已更改的另一个设备,则会重新编译该设备。另请参阅this answer另一个问题,但它也为此提供相关信息。

我倾向于在大多数时间做完整版本,因为我不信任计算机 - 我对它们进行编程,因此我知道它们有多么狡猾: - )

答案 1 :(得分:2)

不幸的是,Delphi编译器及其依赖项的源代码是封闭源代码,所以这个问题需要推测。但是,如果您有兴趣避免让Indy单元重新编译,您当然可以只将DCU文件放在库路径中,并从搜索路径(项目级别)和库路径(全局IDE级别)中删除Indy源文件。组态。如果您确实在映射的网络驱动器上编译源代码,那么我认为你疯了。我建议你查看mercurial和这个很酷的功能,你可以克隆repos并将所有源代码的副本完全保存在你正在构建的同一台计算机上。这很酷。

无论如何,编译器......到目前为止我所观察到的是:

  1. 对您(以及对我来说)的重新编译实际上实际上可能只是对Interface部分的扫描,实际上是构建依赖关系树的方式。与C(makefile)或Java(ant或maven)样式构建环境不同,至少在代码的接口部分设置编译器松散是找出特定模块的所有依赖关系的唯一方法。我认为即使从搜索路径中删除Indy单元,您仍然可以看到编译器进度显示IdIOHandler.pas的“编译”,但在这种情况下,它将要做的是加载编译的表示您的pascal单元的接口部分来自DCU文件,然后决定要读取的其他文件。有时IDE进度将在单元上显示“编译”,但不会在最后修改DCU文件。

  2. 在经历了一场重大变革之后,为了重构或修复一个大项目,我发现了以下几点:a。即使不是不可能猜测下一个语法错误将破坏编译的位置也很困难。湾编译器在单元A中打破致命错误,然后在单元B中途,然后再在单元A上,然后在单元C上,然后再在单元B上,则表明编译器与基于C编译器的心理模型完全不同在makefile上会是这样的:首先我们编译单元A,然后我们编译单元B,然后我们编译单元D.我所有的证据表明真正的过程比这更令人费解,并且在编译器团队中的某个人内部会在文件A上调用“单次传递”,其他文件内容的“扫描”或内存中其他文件内部表示的扫描(而不是物理文件内容的解析)导致“编译”不是全部或全部或一次性的东西,而不是一个大的内存免费为所有人,并且编译器的单元评估顺序由接口构建的一些内存树驱动,然后是每个单元的实现子句。在现实世界的应用程序中预测这个大型循环图的行为超出了我的技能。

答案 2 :(得分:1)

正如Warren所说,单位编译顺序是非常不可预测的(从人的角度来看,我确信编译器是确定性的),接口和实现是单独的编译阶段(因为解析实现使用在继续执行之前,子句可以强制编译其他单元),但我希望这两个部分中的每一个都可以一次编译。

偏离它的唯一原因(我从未观察到,但从未搜索过)将是delphi编译器中的多个“编译”工作线程。

其他复杂因素:

  1. 循环/相互依赖,也是允许的(实现A使用B而B接口使用A)类型。通常可以正确地检测直接的A-B deps,但是更大的周期可以导致重新编译。
  2. 多个目录中的多个源副本和/或(几乎)相同的包含文件(indy因此而臭名昭着)。不同的includefiles可以启用稍微不同的编译器选项,在某些情况下可能会(?)触发重新编译。
  3. 内联,泛型。 (交叉接口< - >实现分离,可能在使用代码处理之前需要实现信息)
  4. .dpr中的文件路径有一些影响。例如。选择具体的  以多种形式存在的文件的副本。 (您在新路径中签出,但dpr中的绝对路径指向旧签出)。在进行部分构建时,这在命令行构建中特别明显。 (建筑单位,而非项目/图书馆项目)
  5. (不完全确定。我有时觉得Delphi可以在IDE中查找文件,即使它们不在搜索路径中。这也可能导致多个副本的选择行为)
  6. 最重要的两个是#1和#2,并且FPC中的效果比Delphi中的效果更强。 (Delphi中更好的循环逻辑?)。重新编译Lazarus时,过度的重新编译是很正常的。

    #3来自理论,#4有时会出现在批量文件编译的较大树中。由于内联是正式可选的,因此它不应成为问题,但如果它至少试图超出所需要的范围,则没有记录。