Wednesday 27 March 2013

Migration to XE3: Almost there

Two months back, when I was replacing all of data layer components in Delphi 6, in preparation for the move to Delphi XE3, I never imagined that part would actually be the most time consuming. I am writing today having fully completed the software migration over to XE3. (There are still some utilities and bespoke projects to be done but these are small projects that take little time and wouldn't affect the launch of a new version of our standard package).

We have still to entirely functionally test the software for any run-time issues and unexpected behaviour changes, but our entire software codebase is now ported to XE3 and running well. The bottom line is this: it was much easier than I thought it would be.

As I mentioned in my previous post on the migration to ADO, the longest part of this process has been writing out the old components and replacing them with the dbGo ones. Obviously there is a good case here for better data abstraction, but time was limited and we had to get the job done so we did it the manual and long way. Maybe that's something we can work on over the coming years but for now, the job is done and the results are good.

Most of the run-time issues we've seen are actually database-related, so nothing to do with XE3, but more to do with subtle differences in the way ADO and ODBC work, as well as syntactical differences in the components.

As for the XE3 compilation, the bulk of what we encountered was to do with the Unicode breaking changes from Delphi 2009. This was largely covered in several white papers by Marco Cantu, Cary Jensen, Bob Swart, etc when Delphi 2009 was released. My colleague and I read the papers and agreed on the recommended approach that we move to full Unicode support, rather than replace String with AnsiString, PChar with PAnsiChar, etc.

Although our software is almost exclusively UK based (because of its nature), and the fact that the data we have to submit to HMRC (the UK government tax agency) is only allowed to contain ASCII characters, we found that it was easier for us to move forward with the native Delphi types than to try and maintain the older Ansi types.

The only exception to this, where I really had to put my brain into gear, was for some API headers that I had written in Delphi for some older hardware DLLs. The hardware communication stopped working with Unicode types, so I switched those back to Ansi types and everything worked as it did before. Also, we have some units that implement some well known encryption routines (SHA-1, Base64, MD5), and these all needed attention to prevent them from using Unicode.

Here is a summary of the things we came across most often:
  • Implicit string conversion warnings.
    90% of the time this was simply because different variable types were being used. In almost all cases for me personally, it was the use of the ShortString type that raised this warning, and so I made the decision to just do away with ShortString all together and always use String.
  • WideChar reduced to byte char in set expressions. Consider using 'CharInSet' function in 'SysUtils' unit.
    Another compiler warning well reported in the Unicode conversion white papers, this is simply as case of changing the syntax of testing for a Char in a set of Chars.
  • Syntax error using local settings constants.
    Having made much use of constants such as ShortDateFormat, ShortDayNames, etc, these now have to be prefix with the FormatSettings global variable.
  • [dcc32 Hint] Inline function 'TFont.GetStyle' has not been expanded because unit 'System.UITypes' is not specified in USES list.
    The name of the class and method often changes, but this compiler hint is always resolved by following the instruction: add UITypes to the unit's Uses clause.
  • Version Info and Release v Debug.
    This one really caught us out and I wasn't aware of it until we switched to XE3. Firstly, projects now have separate Release and Debug build configurations, which means any project options you have need to be set individually.

    Not a problem for the most part, but the Delphi 6 project file's (.dpr) VersionInfo doesn't migrate across correctly into XE3. The Language Locale reverted back to English (United States), where we had previously had it set to English (United Kingdom). Also, the information only came across for the Release configuration, so needed to be redone in the Debug configuration. We use the information in here for checking which modules can be loaded at run-time so it was important that it was set correctly in both configurations.

    Personally, I don't like having to switch to Debug mode into order to be able to set breakpoints and step through code, and then have to remember to set it back to Release mode for the final build. I guess you have the option to set both configurations to use the same Compiler settings, but this would add unncessary debug information to the compiled release executable, so I can see the point of having 2 options. I suppose it is just a case of having to get used to a new routine.
There were some nice new features that we were able to make use of and throw out some more third-party components and units, which I wasn't expecting. The native TZipFile type meant we could support Zip files without relying on a third-party unit or tool. And the RegularExpressions unit meant I could also get rid of an old unit written for Delphi 6 that enabled it to handle regular expressions.

I was also able to get rid of the manual manifest files I had created to allow Windows theme support, as this has been a project option for a long time in Delphi, but obviously not way back in D6.

I'd like to talk about the IDE and performance changes but I will save these for another post. But for now, I'm delighted with how well the migration has gone and the results we have. If you're thinking about doing it, but had the same reservations I me, then I can now say from experience that it isn't as bad as you think and it's worth the effort.

5 comments:

Tony said...

I'm glad your migration is going well! There's a couple things I'd like to point out that you may or may not be aware of. Hopefully you find this information useful.

First: The latest version of the open-source Abbrevia supports expansion of almost all .zipx files, with Deflate64, LZMA, PPMd, and WavPack decompression -- something that the built-in TZipFile doesn't do. Depending on what you application needs to interact with, it's worth keeping in mind. You also need to be mindful of the zlib version that Delphi ships with, and if it has any known security vulnerabilities.

Second: You can still set breakpoints in your own code in Release builds if you set "Debug Information", "Local Symbols", and "Symbol Reference Info" options on the "Compiling" page of your Project Options. Those only modify how the dcu files are built, but do not affect the resulting exe, so they're safe to turn on for Release builds. What I've normally used the "Debug" configuration for is using Debug DCUs for stepping through the RTL/VCL.

Unknown said...

Hey Anthony, thanks for taking the time to post.

1. I only need to create zip files, not read them or unzip them so support for other compression techniques is not needed, but I appreciate the suggestion. I was using the TMS Cab files component before but I'm happier using the TZipFile class now because users generally understand zip files more, and Windows handles them natively these days.

2. That's interesting about the Debug DCUs, I'll bear that in mind. I think I have a little to learn about this area so I appreciate your comments.

Bruce McGee said...

"Personally, I don't like having to switch to Debug mode into order to be able to set breakpoints and step through code, and then have to remember to set it back to Release mode for the final build"

This is a strong reason to automate your release builds. Even if it's as simple as a two line batch file:

call "%ProgramFiles(x86)%\Embarcadero\RAD Studio\10.0\bin\rsvars.bat"
msbuild MyProject.dproj /v:m /target:Rebuild /p:Config=Release

Unknown said...

Lovely, thanks Bruce.

David Heffernan said...

I concur regarding debug symbols. I do exactly that and it has the benefit that I can create full map files for my release builds. Which then lead to better madExcept stack traces.

I would say that having different builds for debug and release mode is important though. I do use different options. For example I have assertions, range checking, overflow checking in debug. And optimisation is off in debug.

You can manage all this very well with option sets. These are so much more powerful than the laughable features in Visual Studio. For once RAD Studio comes out on top here.

You need to have automated build scripts though. Don't even think about relying on remembering how to do the build. Code it up. Use msbuild with the .dproj file.