Monday, August 29, 2011

Creating Custom Compiler Errors in Delphi

Unlike my normal posts, this one is short, and it describes an interesting Delphi solution that I want to share with you.

Here is the issue that I was faced with, along with the solution. I work with a number of different clients on a wide range of technologies (though it seems as though most of my work these days is Internet-related). Furthermore, I use many different versions of Delphi. Though it is not truly relevant to the technique that I want to share today, I run each version of Delphi in a separate virtual machine. If you are curious about why I do this, please feel free to read Developing in a Virtual World and Creating a More Manageable Development Environment

Getting to the point, here is the issue I faced. I have a project that I originally wrote using Delphi 2007, and in which I used Internet Direct (Indy) components that employ SSL (secure socket layer). I have since migrated that project to a more recent version of Delphi, and in the process deployed newer versions of the ssleay32.dll and libeay32.dll DLLs. These newer DLLs are incompatible with the version of Indy I have installed in Delphi 2007.

This might not sound like there is a problem, but there is. Specifically, now that I have moved to a later version of the SSL libraries, I should never compile and deploy that application using Delphi 2007. Remember, as a consultant I use many different versions of Delphi, and for the particular client for whom I built this application, we are using no less than three different versions of Delphi. Since I don't work on these projects everyday, it would be easy for me to check out this application from version control and try to update it using the wrong version of Delphi.

What I needed was some mechanism to prevent me from attempting to compile and deploy this particular application in Delphi 2007 (or earlier). What if, I thought, I could instruct the compiler to generate a fatal error upon attempting to compile the project in Delphi 2007, but not from a later version. Oh, sure, I could kludge a solution by including some reference to a symbol that was introduced in Delphi 2009, but what I really wanted was to be able to generate a meaningful compiler error, such as "This project must be compiled in Delphi 2009 or later" instead of a relatively meaningless
[DCC Error] Unit1.pas(28): E2003 Undeclared identifier: 'TBalloonHint'

Fortunately, there is an elegant solution, but I was unaware of it at the time. So, in my quest to find the correct solution, I turned to the Gods of Software, which is to say that I posted by inquiry on StackOverflow. My original post was answered by several people (Delphi folks that you'll likely know), and I had my answer.

So, here is the compiler directive that I added to my project, which I adapted from the answers provided on StackOverflow:

{$IF CompilerVersion <= 19.0} // Delphi 2007 = 19.0
  {$MESSAGE Error 'This project must be compiled in Delphi 2009 or later'}
{$IFEND}
And do you know what? This past week, when I was onsite with the client for whom I built the application, I encountered the following compiler error.

Thank goodness my application is now smarter than me.