C++/Lazarus Integration

SimSoup no longer uses Lazarus. However, I'm leaving these notes here for anyone interested in using C++ with Lazarus.

SimSoup has was originally developed using the Borland products C++ Builder and Kylix (C++). At various times, there was uncertainty over the future of these products.

In order to ensure that a development platform would continue to be available for SimSoup, I migrated the project to use the Lazarus open source product for the user interface, and C++ for the main simulation code.

Lazarus is an open source IDE and set of class libraries for Free Pascal that provides functionality very similar to Borland's Delphi GUI Builder product on Windows. It also provides similar features to the Linux based Kylix (Delphi) product. Lazarus therefore provides a potential migration path for projects curently based on Delphi or Kylix (Delphi).

I plan to document the migration approach in due course. In the meantime, here is a very brief outline. Source code is also available on the download page.

Calling Mechanism

The C++ code has to be able to call Free Pascal code, and vice versa. This is achieved in the C++ code by declaring functions as:-

extern "C"

This applies both in the case of functions that are implemented in C++ (ie those that are called from Free Pascal) and functions that are implemented in Free Pascal (ie those that are called from C++). The Free Pascal code has to have an 'exports' section mentioning each of the Free Pascal functions / procedures that are called from C++.

Low Tech Communication

Both the C++ code and the Free Pascal code are object oriented. However, the mechanisms for calling methods of objects are not compatible. To deal with this, all of the calls between C++ and Free Pascal take place through a 'Low Tech Communication' layer in which information is passed using the C calling convention. Wrapper functions are used to isolate the main part of the object oriented application from this.

VCL Emulation

In order to enable C++ Builder-like code to compile with minimum changes, there are a set of VCL Emulation classes in the C++ code. Essentially these provide the declarations for VCL components, thereby enabling the C++ Builder-like code to compile. The C++ code that defines the behaviour of each C++ function simply calls the relevant Free Pascal function / procedure.

As an example, the C++ declaration of TCheckbox looks like this:-

class šTCheckBox: public TControl
{
    public:
        bool Get_Checked();
        void Set_Checked(bool Checked);
};

The "public TControl" part means that it inherits many of its properties from TControl (which has a separate declaration)

Note that I have "Get_Checked()" and "Set_Checked()" functions rather than a "Checked" property as in C++ Builder. This entails modifications to the syntax of the C++ Builder code. I'm not sure whether it would have been possible to avoid this. Possibly I could have done something with C++ operator overloading. In any case I don't see it as a substantial problem. The syntactical changes required are very straightforward. It would have been far more difficult to make the changes required to use a different widget set.

My VCL Emulation classes only declare and implement a fairly small number of classes and methods corresponding to those parts of the user interface component library that I actually use. The basic technique is of course extendable, so that if I want to use a Component or method that I have not used before, I just have to add it to the VCL Emulation code.

Pointer Passing

In order for the C++ code to be able to control the Lazarus GUI, it has to have a pointer to each widget. This is achieved by having the C++ code call a function to get a pointer to the widget. Eg, one such Free Pascal function is:-
function Laz_SimControl_Get_Action_Repeat_CheckBox_Ptr(Laz_Form_Ptr:
TMainForm):TCheckBox; cdecl;

//  Return a pointer to the Simulation Control Action Repeat CheckBox

begin
    Result := Laz_Form_Ptr.Action_Repeat_CheckBox;
end;
Once the C++ code has the pointer, it can then treat it as a pointer to a C++ object and call VCL Emulation functions for that object. For example, if the C++ code stores the result of the above function in CheckBox_Ptr, it can then say:-
CheckBox_Ptr->Set_Checked(true);
to make the CheckBox checked.