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

1

13

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

Muscovado answered 28/8, 2014 at 17:49 Comment(16)
See Delphi - Unit x was compiled with a different version of x, when fixing a VCL bug and Can I modify a constant in the RTL class System.Classes.TStream and rebuild it at runtime in Delphi XE6?. See @DavidHeffernan answers. Voodoo it is.Metamorphic
Sorry Ian but you are out of luck. You'll need a detour. I tried to persuade Marco that this was broken but he doesn't believe me. blog.marcocantu.com/blog/… marco's meant to be the dev relations guy so god help us when he won't listen to usUngainly
Often times compiler settings make a difference. Perhaps it is the RTTI settings. Warren seemed to think that might be a lead.Ungainly
@DavidHeffernan That turned out to be there case. i'll wait a few days and append the answer to the question.Muscovado
@Ian Can you expand? Do you have some RTTI settings that fix all these woes? It would be good to add an answer to Warren's question I think. It's a shame he answered RRUZ's non-answer which ignored the real problem. Or I'd be very happy to reopen this question and close the others if you have an answer. Let me know.Ungainly
I'm really keen to get on top of this too because without a solution I'm not keen on upgrading.Ungainly
@DavidHeffernan, some code generation in XE6 is flawed, see Regression, Invalid code gen when referencing consts defined in classes or records. Resolved but no update or patch available. XE6 will not be used for production by us.Metamorphic
@LURD XE7 is imminent. No doubt with a bunch of fixes, and a bunch of new bugs. Emba QA/QC is pathetic.Ungainly
@DavidHeffernan It was your own solution that you mentioned somewhere. Ctrl+O+O to insert the "standard" compiler options at the top of the replacement pas file. That's why i was going to answer it here: so it has an answer rather than random stumblings elsewhere :)Muscovado
Let me re-open then. Ok done. Over to you.Ungainly
@DavidHeffernan You know the hell i went through to get XE6. We're three weeks in and still in bug-fixing mode. What was the last "good" version of Delphi? Also: i cannot answer my own question for two days; back to you!Muscovado
Ok, I've added the text from my other answer. Now do feel free to edit it as you please!Ungainly
@IanBoyd XE2 perhaps? We've been using it for a couple years now and never faced any show-stopping bugs.Picture
@Jerry Unless you use the x64 compiler. Which doesn't implement exception handling correctly. The first x64 version of our product was built with XE2 and I had to fix the exception handling myself which was tricky!Ungainly
Possible duplicate of: #429775Juvenility
This is how I solved it: #429775Juvenility
U
8

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.

Ungainly answered 28/8, 2014 at 20:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.