Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F2051: Unit %s was compiled with a different version of %s

We've been fixing bugs in the VCL in Delphi XE6. So far the folder contains:

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

And we add the folder to our Library search path:

enter image description here

Along the way, we learned that we have to confine our fixes to the implementation section only. Otherwise the hash signatures of symbols in the interface section change. This causes the linker to realize that the symbols inside the DCU are not the same version they expect.

Barry Kelly had a good explanation for this behavior:

The important concept is that of symbol version. When saving a DCU, Delphi calculates a hash based on the interface declaration of the symbol and associates it with the symbol. Other units that use the symbol also store the symbol version. In this way, link-time conflicts caused by stale symbols are avoided, unlike most C linkers.

The upshot of this is that you should be able to add Classes.pas to your project and modify its implementation section almost to your heart's content, and still be able to statically link with the rest of the RTL and VCL and third-party libraries, even those provided in object format only.

Things to be careful of:

  • Inlined routines; the body of inlined routines are part of the symbol version
  • Generics; the implementation side of generic types and methods are part of the respective symbol versions

So we took pains to confine the bugfixes to the implementation section (e.g. introducing new cracker classes, rather than overriding the method in the public-facing class).

And then

Then I went to make a fix in Vcl.Themes.pas. I start simple, copying the file and placing it in the fixes folder:

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

Even though I have not (yet) even modified Vcl.Themes.pas, the compiler chokes on it:

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

Why

The important question is:

Why is this happening?

What is going on that the compiler is unable to realize that the exact same file is the exact same file? Is it possible that the VCL source shipped with XE6 is incorrect, and doesn't match what ships in the DCUs? Does it have something to do with library search order? Does it have something to do with inlining, generics, iterators, platforms, debug dcus, 64-bit compiler, ifdefs, code completion, synergy, outside the box?

There are the other, implicit, questions that go along with trying to answer the why:

Why does it work for two other files, but not this one?
Why does it fail when I didn't even change the file?

What have you tried?

  • tried moving VCL Source Fixes higher and lower in the search path
  • tried turning on Use debug dcus
  • tried switching to 64-bit platform
  • tried deleting all dcu files in my project's folder (although not deleting the D:\Programs\Embarcadero\Studio\14.0\lib\win32\release\Vcl.Themes.dcu that ships with Delphi XE6)
  • closing XE6 and re-running it
  • going to Wendy's for lunch

Of course I want to fix it. But more than wanting to fix it I want to understand why it's failing. The compiler isn't employing magic, voodoo, or Q-like powers. It's a deterministic machine, and is operating according to a fixed set of (undocumented) rules.

Why is this happening?

See also

  • Delphi - Unit x was compiled with a different version of x, when fixing a VCL bug
  • Can I modify a constant in the RTL class System.Classes.TStream and rebuild it at runtime in Delphi XE6?
like image 357
Ian Boyd Avatar asked Aug 28 '14 17:08

Ian Boyd


Video Answer


1 Answers

You need the compiler options to match those used when the unit was compiled by Embarcadero. That's the reason why your implementation section only change fails when it seems like it ought to succeed.

Start a default project and use CTRL + O + O to generate these options. I get

{$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}

when I do this in XE6.

Put that at the top of your copy of the unit and you should be good to go. You can probably get away with a cut-down subset of these, depending on your host project options. In my code I find that:

{$R-,T-,H+,X+}

suffices.

like image 87
David Heffernan Avatar answered Sep 27 '22 18:09

David Heffernan