我们的团队多年来一直使用Delphi 6,然后在2006年转为Delphi。对于这两个版本,我们都有以下问题:编译器经常抱怨一个据称递归使用的单元。这个单位是一个40k的LOC单位,是一个项目的核心,有近100万LOC(包括第三方)。
错误消息不正确:项目的完整版本始终有效。不幸的是,错误消息并没有告诉我们所谓的循环引用的位置,只是该单元的名称。有时甚至会发生有效的错误消息列出2-4次,直到“找到”循环引用问题。显然编译器在这里运行一个圆圈。由于该项目的大小,很难手动找到问题。因此我制作了一个证明的工具,确实没有循环引用(该工具创建单元的有向依赖图并确定该图中的相干成分 - 除非我故意放一些,否则没有在)。
这不仅会影响F9编译,还会影响大多数时候都无法正常工作的代码完成/洞察力。有时它会在我第二次按下ctrl-space时起作用...
我们如何隔离甚至解决问题?请注意,将40k LOC单元拆分成较小的单元是非常困难的,因为它包含大约15个在接口部分相互依赖的大类(我知道它很糟糕,但无论如何都应该工作)。
更新的
我们不断进行重构,但这是重构的一个难点,因为一切都取决于一切,差不多。一直试图通过接口来解决它,但我们正在谈论一些具有100种方法和属性的类。它会慢一些。
升级到D2009可能是一个选择,但现在我们仍然坚持使用D2006(unicode的东西和价格标签是这里的两个塞子)。问题是无论如何它会有所帮助,因为问题出现在那里,至少是D6。
关于修剪使用条款,我们经常与Icarus一起做这件事。但到目前为止这没有任何帮助。我们现在在界面部分有90个自定义单位。但是,通过真正的循环引用,问题可能出在任何单位。还试图将所有单位添加到dpr。
该项目与其他项目共享大量代码,并且有一些IFDEF。但是,定义不是在项目选项中设置的,而是通过公共包含文件设置的。因此,所有模块都应该看到相同的定义。此外,问题在完全重建后不久就会重新出现,而不会切换到另一个项目。
答案 0 :(得分:4)
我可能会因此而被投票。在D2005中,我有一个10k loc单元(datamodule),它完全停止编译。不得不将一些数据集/代码分离到另一个数据模块。那10k的单位是,而且是一团糟。你真的应该考虑将一些代码重构到其他单位。我的模块自D2005开始/分离成长更严重,但它仍在D2007中编译。所以我的答案是a)重构和b)升级到D2009。
答案 1 :(得分:2)
很明显,这是由于后台编译器与真实内容之间的细微差别。您可以环顾四周(QualityCentral)在该主题上已知的内容。
此外,由于您没有明确说明这一点,因此您应该删除不必要的单位,并尽可能将使用语句移至实现。也许你的工具可以帮助解决这个问题。
并确保您应该检查单位别名和路径设置。
答案 2 :(得分:2)
您认为完整版本始终成功,但在增量版本因此错误而失败后不久。假设您在IDE中遇到过这种情况,您是否尝试使用命令行编译器dcc32进行增量构建?
如果您没有为它提供“-Q”开关(可能是命令行构建的大多数Makefile或脚本),它将输出大量信息,它按哪种顺序编译的文件。您可以尝试在IDE中出现错误后进行增量构建,或者您可以在IDE和Alt + Tab旁边打开命令行进行编译,完全跳过IDE中的编译。
我只是假设你有一种方法可以使用dcc32,无论如何使用dcc32 - 除了你无法想象的项目大小。
答案 3 :(得分:2)
我们经常遇到类似的问题,而且我们从来没有管理(或困扰得足够长)以找到确切的原因。在按Ctrl-F9时,Delphi选择编译单元的顺序似乎存在问题,这与单元的实际依赖顺序不兼容。
答案 4 :(得分:0)
您是否有其他项目使用相同代码库的一部分?如果您在不同的编译器设置或IFDEF下编译其中一个,它可能会更改某些DCU中的某些内容,这会导致循环依赖。完整版本会重建所有DCU,然后问题就会消失。
答案 5 :(得分:0)
从Peganza尝试Icarus(免费)。如果这不能告诉您问题所在,请尝试使用Pascal Analyzer。
答案 6 :(得分:0)
我们也有这个问题,也有相当大的代码库。
我们目前正在使用D2009,但是所有以前版本的Delphi都遇到了这个问题。
最常见的是在从源代码控制进行更新后立即发生,因此我怀疑Delphi构建过程中存在一些时间戳问题。
在我们的例子中,如果Ctrl-F9失败并报告循环引用,则第二个Ctrl-F9通常会起作用
答案 7 :(得分:0)
我被告知处理这个问题的方法是在项目中打开另一个任意文件,更改该文件,保存它,然后再次尝试运行增量编译。令人惊讶的是,这通常有效。
我们有一个4 MLOC项目不时出现,这个“解决方案”对我有用。
答案 8 :(得分:0)
我以前曾经打过这个,根据我的经验,错误是准合法的。这已经有一段时间了(错误与版本无关)但我对这种情况的记忆是它涉及一个循环,其中部分循环在实现中。
单元A在实现中使用B.单元B在界面中使用A.如果你先编译B,它会调用A,但由于B的调用是在实现中,所以它成功了。如果你首先编译A,它会调用B,B转过来并在界面中调用A,繁荣。只有两个交叉引用都在实现中时,这样的循环才是安全的。
解决方案是设计东西,以便在界面中使用最少的东西,并确保在这些单元中没有任何类似的循环。只要你将类型定义与带代码的单元分开,这很容易做到。
根据你正在做的事情来来往往的错误是这个问题的标志,因为它归结为你如何进入循环。当你进行完整构建时,订单是一致的,你要么得到它100%或0%,它不是随机的。