Object Pascal: Compiler Directives


Tuesday, June 26, 2018

Photo by Mathyas Kurmann on Unsplash

Compilation Directives could help you to make your code multi-platform or even cross-compiled.


Compilation directives are powerful commands that developers could use to customize how the compiler works.

These directives pass parameters to the compiler, stating the arguments of the compilation, how must be compiled, and which will be compiled.

There are basically 3 types of compilation directives.

  • Switch directive
  • Parameter directive
  • Conditional compilation directive

The first two types change the compile parameters, while the last one changes what the compiler will perform on.

In this article we will deal with the last one: Conditionals.


They are powerful commands.

With just a few conditional commands, your Object Pascal code can be compilable across multiple platforms.

However, as we add more and more directives, the code will become more complex.

Let's take a look in the example below:

  Writeln('Debug is on.'); // This code executes.
  Writeln('Debug is off.'); // This code does not execute.
  Writeln('Debug is off.'); // This code executes.

In this example, only the first and third Writeln function calls will be executed.

All directives and also the second function call won't be part of the final executable, I mean, the ASSEMBLY code.


However, it looks like that the code is "dirty" and also we have a temporal coupling, because the constants need to be defined in a specific order.

Directives and definitions of constants that will be used in only a single unit may even be manageable, but what if you will work with tens or even hundreds of units that will use these directives and definitions, do you still think this approach is the best choice for the architecture of your project, with the purpose of building it as cross-compiled or multi-platform?

I don't think so.

Encapsulating Directives

Imagine a project that needs to be cross-compiled in Delphi and Free Pascal. We would like to use the same classes, the same code, but could exists some differences between these compilers.

The code needs to evolve independent of the compiler. I mean, if some changes could be done to improve the code when it is compiled on Free Pascal, for example, it should be done without thinking in some difference that might exist in Delphi.

To do so properly, we could not work in a code with many compilation directives, because some changes could broke the Delphi version or vice-versa.

Instead of seeing directives, it might be better seeing just classes.

I would called this, encapsulated directives.


Imagine an unit witch contains a class to represents a MD5 algorithm.

Free Pascal already has a md5 unit which has functions to do the job and of course we have to make classes to encapsulate those functions.

In Delphi, the unit that do the same job is named hash.

We do not want to "reinvent the wheel" then, let's use what is already done on both platforms.

So, how would you do this implementation neither using conditional directives in implementation code nor *.inc files?

First of all, let's create our MD5 unit:

unit MD5.Classes;


  {$ifdef FPC} MD5.FPC {$else} MD5.Delphi {$endif};

  TMD5Encoder = class(TEncoder);



As you can see, there is almost nothing on this unit. The real code will stay in others units, i.e, MD5.FPC and MD5.Delphi, one for each platform.

Let's create the FPC version:

unit MD5.FPC;



  TEncoder = class
    function Encode(const Value: string): string;


function TEncoder.Encode(const Value: string): string;
  Result := MD5Print(MD5String(Value));

Those functions with prefix "MD5" comes from md5 unit.

Then, let's create the Delphi version:

unit MD5.Delphi;



  TEncoder = class
    function Encode(const Value: string): string;


function TEncoder.Encode(const Value: string): string;
  Result :=THashMD5.GetHashString(Value);


Both units have the TEncoder class definition (yes, same name in both). Then, we created a TMD5Encoder class that inherits from the correct class, which is platform dependent, and voila! We have clean units, without any conditional directives inside methods.

Finally, we have two distinct classes in different units that can evolve its implementation independently, without any fear of breaking the code between platforms.


Compilation directives is a good tool for customize the code. However, it should be used with parsimony.

In object-oriented code, try to use more specialized objects than compilation directives.

For each conditional directive that you want to add to the code, I suggest implementing a new class that encapsulates the directive or a set of them.

Your code will be cleaner and sustainable.

See you.

Marcos Douglas B. Santos


This blog post has not received any comments yet.

Add a new comment:
  You will receive a confirmation mail with a link to validate your comment, so please use a valid email address.
Change Image
Fill in the characters from the image above:

All fields are required.

Previous  |  Next  |  Index