F2051: 单元 %s 是用不同版本的 %s 编译的。

13

我们一直在修复Delphi XE6中VCL的漏洞。目前,该文件夹包含:

| VCL Source Fixes
|----- Vcl.ComCtrls.pas
|----- Winapi.CommCtrl.pas

我们将该文件夹添加到我们的搜索路径中:

enter image description here

在此过程中,我们学到了我们必须仅限于implementation部分修复问题。 否则,interface部分中符号的哈希签名会发生更改。 这会导致链接器意识到DCU内的符号不是他们所期望的相同版本。

Barry Kelly 对此行为进行了很好的解释:

重要的概念是符号版本。在保存DCU时,Delphi基于符号的接口声明计算哈希并将其与符号关联起来。使用符号的其他单元也存储符号版本。通过这种方式,可以避免因陈旧符号引起的链接时间冲突,这与大多数C语言链接器不同。

由此产生的结果是,您应该能够将Classes.pas添加到项目中并几乎尽情修改其implementation部分,并且仍然能够与RTL和VCL及提供的仅以对象格式提供的第三方库进行静态链接。

需要注意的事项:

  • 内联例程; 内联例程的主体是符号版本的一部分
  • 泛型; 通用类型和方法的实现方面是相应符号版本的一部分

因此,我们费心将错误修复限制在实现部分(例如,引入新的破解器类而不是覆盖公共类中的方法)。

然后

然后我去修改Vcl.Themes.pas中的错误。 我从简单的开始,复制该文件并将其放在修复文件夹中:

| VCL Source Fixes
|----- Vcl.ComCtrls.pas
|----- Winapi.CommCtrl.pas
|----- Vcl.Themes.pas

尽管我甚至还没有修改过Vcl.Themes.pas,编译器仍然无法编译它:

[dcc32 Fatal Error] Vcl.Themes.pas(2074): F2051 Unit Vcl.Forms was compiled with a different version of Vcl.Themes.TMouseTrackControlStyleHook

为什么会发生这种情况?

重要的问题是:

为什么会发生这种情况?

为什么编译器无法意识到完全相同的文件是完全相同的文件?VCL源代码是否与XE6附带的DCUs不匹配?这是否与库搜索顺序有关?是否与内联、泛型、迭代器、平台、调试DCUs、64位编译器、ifdefs、代码完成、协同作用、超越常规思维有关?

解答“为什么”的其他隐含问题包括:

为什么对于另外两个文件它能正常工作,但对于这一个却失败了?
为什么即使我并没有更改文件,它也会出错?

你尝试了什么?

  • 尝试在搜索路径中将VCL Source Fixes上移或下移
  • 尝试打开Use debug dcus
  • 尝试切换到64位平台
  • 尝试删除我的项目文件夹中的所有dcu文件(但没有删除随Delphi XE6一起发行的D:\Programs\Embarcadero\Studio\14.0\lib\win32\release\Vcl.Themes.dcu
  • 关闭XE6并重新运行它
  • 去Wendy's吃午餐

当然,我想要解决它。但更重要的是,我想了解为什么它失败了。编译器没有使用魔法、巫术或Q式力量。它是一个确定性机器,并根据一组固定的(未记录的)规则操作。

为什么会发生这种情况?

另请参阅


1
抱歉,Ian,但你运气不佳。你需要绕路了。我试图说服Marco这个有问题,但他不相信我。http://blog.marcocantu.com/blog/2014_august_buffer_overflow_bitmap.html Marco应该是开发关系的人,所以当他不听我们的时候,上帝保佑我们。 - David Heffernan
1
往往编译器设置会有所不同。也许是RTTI设置。沃伦似乎认为这可能是一个线索。 - David Heffernan
1
@DavidHeffernan,XE6中的一些代码生成存在缺陷,请参见回归,引用类或记录中定义的常量时生成无效代码。已解决,但没有可用的更新或补丁。我们不会在生产中使用XE6。 - LU RD
@DavidHeffernan,这是您在某个地方提到的自己的解决方案。使用Ctrl+O+O将“标准”编译器选项插入替换后的pas文件顶部。这就是为什么我要在这里回答它:这样就有了一个答案,而不是随机的跌跌撞撞。 :) - Ian Boyd
@Jerry 除非你使用x64编译器。但是它不能正确实现异常处理。我们产品的第一个x64版本是用XE2构建的,我不得不自己修复异常处理,这很棘手! - David Heffernan
显示剩余11条评论
1个回答

8
您需要使用与Embarcadero编译该单元时相匹配的编译器选项。这就是为什么您的实现部分只会在看起来应该成功时失败的原因。
启动默认项目并使用CTRL + O + O生成这些选项。我得到了:
{$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N-,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1}

当我在XE6中进行此操作时。 将其放置在单元的顶部,您就可以开始使用了。根据您的宿主项目选项,您可能可以使用缩减版的这些内容。在我的代码中,我发现:
{$R-,T-,H+,X+}

足够。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接