代码之家  ›  专栏  ›  技术社区  ›  Werner Lehmann

不正确的循环引用错误

  •  8
  • Werner Lehmann  · 技术社区  · 16 年前

    我们的团队已经使用Delphi6很多年了,然后在2006年前切换到Delphi。两个版本都有以下问题: 编译器经常抱怨一个被认为是递归使用的单元。 . 该单元是一个4万loc单元,是一个项目的核心,约有100万loc(包括第三方)。

    错误消息不正确: 项目的全面建设总是有效的 . 不幸的是,错误消息并没有告诉我们循环引用的位置,只是那个单元的名称。有时甚至会出现有效的错误消息被列出2-4次,直到找到循环引用问题。很明显,编译器在这里运行。由于该项目的规模,很难手动找到问题。所以我做了一个工具 证明 实际上没有循环引用(工具创建了一个单元的有向依赖关系图,并确定了该图中的一致性组件——除了我故意添加一些元素之外,没有其他元素)。

    这不仅会影响F9编译,而且还会影响大多数时间都不起作用的代码完成/洞察。有时,当我再次按下ctrl空格时,它会工作…

    有什么想法我们可以孤立甚至解决这个问题?请注意,将40k loc单元拆分为较小的单元将非常困难,因为它包含大约15个大型类,这些类在接口部分相互依赖(我知道这很糟糕,但无论如何都应该可以工作)。

    更新
    我们一直在进行重构,但这是一个很难重构的单元,因为几乎所有的东西都依赖于所有的东西。一直试图通过接口来解决这个问题,但我们正在讨论一些具有100个方法和属性的类。而且速度会慢一些。

    升级到D2009可能是一个不错的选择,但现在我们只能使用D2006(Unicode的东西和价格标签是这里的两个障碍)。不管怎样,问题是它是否会有帮助,因为问题至少在d6之后就存在了。

    关于修饰uses子句,我们经常使用icarus。但到目前为止没有帮助。我们现在在接口部分有90个自定义单元。然而,如果有一个真正的循环引用,问题可能出现在任何单元中。也试图向朝鲜民主主义人民共和国增派所有部队。

    该项目与其他项目共享许多代码,并且有一些ifdef。但是,定义不是在项目选项中设置的,而是通过一个公共包含文件设置的。因此,所有模块都应该看到相同的定义。此外,在完全重建后不久,问题又会再次出现,而不会切换到另一个项目。

    9 回复  |  直到 14 年前
        1
  •  4
  •   Tom    16 年前

    我可能会被否决。在d2005中,我有一个10k loc单元(datamodule),它完全停止了编译。必须将一些数据集/代码分离到另一个数据模块。那10K单位是一个烂摊子。你真的应该考虑把一些代码重构成其他单元。我的模块自d2005/分离之后变得更加糟糕,但它仍然在d2007中编译。所以我的答案是a)重构和b)升级到d2009。

        2
  •  2
  •   Henk Holterman    16 年前

    很明显,这是由于后台编译器和实际编译器之间的细微差别造成的。你可以四处看看(QualityCentral)关于这个主题的知识。

    另外,由于您没有显式地声明这一点,您应该删除不必要的单元,并在可能的情况下将uses语句下移到实现。也许你的工具能帮上忙。

    为了确保你应该检查单位别名和路径设置。

        3
  •  2
  •   mghie    16 年前

    您编写了一个完整的构建总是成功的,但是在增量构建失败并出现此错误后不久。假设您在ide中遇到过这种情况,您是否尝试过使用命令行编译器dcc32进行增量构建?

    如果不使用“-q”开关(这可能是大多数用于命令行构建的makefile或脚本所执行的操作),它将输出大量信息,即按什么顺序编译哪些文件。您可以在IDE中出现错误后尝试进行增量生成,也可以在IDE旁边保持命令行打开,并使用Alt+选项卡进行编译,完全跳过IDE中的编译。

    我只是假设你有一种使用Dcc32来构建的方法,不管是哪种方式,你的项目的大小我都无法想象。

        4
  •  2
  •   LeGEC    16 年前

    我们经常会遇到类似的问题,而且我们从来没有设法(或困扰足够长的时间)找到确切的原因。delphi在点击ctrl-f9时选择编译单元的顺序似乎有问题,这与单元的实际依赖顺序不兼容。

    • 在点击ctrl-f9之前,你试过删除“mybigfatunit.dcu”吗?
    • 您是否尝试过在DPR/DPK文件中重新排序单位声明,以便单位以正确的编译顺序出现?(即:如果B单元依赖于A单元,则A单元应首先出现在DPR/DPK中)
        5
  •  0
  •   Mason Wheeler    16 年前

    有没有其他项目使用同一代码库的一部分?如果在不同的编译器设置或ifdef下编译其中一个,可能会更改某些dcu中的某些内容,从而导致循环依赖。完整的构建会重建所有DCU,然后问题就消失了。

        6
  •  0
  •   frogb    16 年前

    尝试 Icarus (免费)从佩甘扎。如果这不能告诉你问题是什么,试试他们的pascal分析仪。

        7
  •  0
  •   Alistair Ward    16 年前

    我们也有这个问题,还有一个相当大的代码基。

    我们目前正在使用D2009,但在所有以前的Delphi版本中都有这个问题。

    最常见的情况是在执行源代码管理的更新之后立即执行,因此我怀疑delphi构建过程中存在时间戳问题。

    在我们的例子中,如果ctrl-f9失败并报告循环引用,则第二个ctrl-f9通常会工作

        8
  •  0
  •   Jonathan Morgan    14 年前

    有人告诉我处理这个问题的方法是在项目中打开另一个任意文件,更改该文件,保存它,然后再次尝试运行增量编译。令人惊讶的是,这通常是可行的。

    我们有一个4mloc的项目,这是不时出现的,这个“解决方案”为我工作。

        9
  •  0
  •   Loren Pechtel    14 年前

    我以前也曾与此抗争过,根据我的经验,这个错误几乎是合法的。已经有很长一段时间了(这个错误与版本无关),但我对这种情况的记忆是,它涉及一个循环,循环的一部分在实现中。

    单元A在实现中使用B。单元B在接口中使用A。如果先编译b,它会调用a,但由于b的调用在实现中,所以它会成功。如果你先编译一个,它会调用b,b在接口中返回并调用a,boom。只有当两个交叉引用都在实现中时,这样的循环才是安全的。

    解决方案是设计一些东西,以便在接口中使用最少的东西,并确保这些单元中没有类似于循环的东西。只要你用代码把类型定义和单元分开,这是很容易做到的。

    错误的发生和发展取决于你在做什么,这是这个问题的一个标志,因为它涉及到你如何进入循环。当你做一个完整的构建,顺序是一致的,你要么得到100%或0%,这不是随机的。