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

R.J. Dunnill
  • 2,049
  • 3
  • 10
  • 21
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • See [Delphi - Unit x was compiled with a different version of x, when fixing a VCL bug](http://stackoverflow.com/q/24412299/576719) and [Can I modify a constant in the RTL class System.Classes.TStream and rebuild it at runtime in Delphi XE6?](http://stackoverflow.com/q/24145214/576719). See @DavidHeffernan answers. Voodoo it is. – LU RD Aug 28 '14 at 17:57
  • 1
    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. http://blog.marcocantu.com/blog/2014_august_buffer_overflow_bitmap.html marco's meant to be the dev relations guy so god help us when he won't listen to us – David Heffernan Aug 28 '14 at 18:19
  • 1
    Often times compiler settings make a difference. Perhaps it is the RTTI settings. Warren seemed to think that might be a lead. – David Heffernan Aug 28 '14 at 19:53
  • @DavidHeffernan That turned out to be there case. i'll wait a few days and append the answer to the question. – Ian Boyd Aug 28 '14 at 20:01
  • @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. – David Heffernan Aug 28 '14 at 20:06
  • I'm really keen to get on top of this too because without a solution I'm not keen on upgrading. – David Heffernan Aug 28 '14 at 20:07
  • 1
    @DavidHeffernan, some code generation in XE6 is flawed, see [Regression, Invalid code gen when referencing consts defined in classes or records](http://qc.embarcadero.com/wc/qcmain.aspx?d=124346). Resolved but no update or patch available. XE6 will not be used for production by us. – LU RD Aug 28 '14 at 20:38
  • @LURD XE7 is imminent. No doubt with a bunch of fixes, and a bunch of new bugs. Emba QA/QC is pathetic. – David Heffernan Aug 28 '14 at 20:44
  • @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 :) – Ian Boyd Aug 28 '14 at 20:44
  • Let me re-open then. Ok done. Over to you. – David Heffernan Aug 28 '14 at 20:49
  • @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! – Ian Boyd Aug 28 '14 at 20:51
  • Ok, I've added the text from my other answer. Now do feel free to edit it as you please! – David Heffernan Aug 28 '14 at 20:58
  • @IanBoyd XE2 perhaps? We've been using it for a couple years now and never faced any show-stopping bugs. – Jerry Dodge Aug 28 '14 at 23:43
  • @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! – David Heffernan Aug 29 '14 at 05:38
  • Possible duplicate of: http://stackoverflow.com/questions/429275/why-are-my-units-compiled-with-a-different-version-of-my-own-files/33221783#33221783 – Gabriel Oct 19 '15 at 18:56
  • This is how I solved it: http://stackoverflow.com/questions/429275/why-are-my-units-compiled-with-a-different-version-of-my-own-files/33221783#33221783 – Gabriel Oct 19 '15 at 18:57

1 Answers1

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490