JEDI Code Library - Cross Platform Strategy

This paper presents the JCL teams strategy for cross platform compliance of the JEDI Code Library. It is based up on the discussions within the JCL newsgroup and JCL developer mailing lists. This document is currently work in progress and subject to changes with or without notice.

Version history:
    0.1 Initial release

Background

The main objective is to make the JEDI Code Library VisualCLX (Kylix for Delphi/Delphi) and Delphi.NET compatible. For a detailed explanation of the currently used terminology, see the following article Overview of the VCL for .NET.

We have to cope with nearly all aspects of cross platform progamming, like different APIs, different operating system concepts etc. Since we want to be as crossplatform compatible as possible interface compatability is the most important issue for us. JEDI Code Library users should have to opportunity the use the JCL on whatever platform they like. Figure 1 shows the three basic layers we have to deal with:


Fig 1: The JEDI Code Library crossplatform layer structure

The JEDI Code Library currently targets the following platforms:

and is trying to support the following platforms as soon as possible:

As a mid or long term perspective we are hoping to get the JCL FreePascal compatible. This involves the possibilty to have the JCL running on DOS, OS/2, FreeBSD and AmigaOS.

Common platform independent layer

This layer consists of all files which are not platform dependent or need only very minor adjustations. Furthermore all units in this layer do not depend on a specific component set. Examples for common platform independent units are JclBase, JclDateTime, JclFileUtils and JclMath. The units have been ported to all platforms and are the crossplatform "core" of the Jedi Code Library. As a general rule a unit in this layer should have no platform specific ifdefs in its interface section.

Platform dependent layer

Furthermore we do not have to differentiate between VCL and VisualCLX units only (the so called component set dependent layer), but also between UNIX, Windows and .NET dependent units. The platform dependent units doesn't need to be interface compatible (if there is an equivalent in one of the other suported platforms at all!). An example for a platform dependent unit is JclCLI. Nonetheless if there are equivalents in all other supported platforms as well it might be considerable to write a more general class and include that unit into the common platform indepedant layer.

Component set dependent layer

When it comes to sharing code between VCL and VisualCLX-applications, some facts need to be stated:

  • A unit is called VCL-dependent, when it uses some VCL-unit(s), e.g. Graphics.
  • A unit is called VisualCLX-dependent, when it uses some VisualCLX-unit(s), e.g. QGraphics.
  • When a unit contains neither VCL- nor VisualCLX-specific code, there is no problem: It can be used by either type of application.

    While it is basically possible to create VCL-dependent and VisualCLX-dependent variants of the same unit by means of conditional compilation - and use them in VCL- and VisualCLX-applications respectively -, this method fails at design time: One and the same unit cannot be installed twice in the IDE, not even as part of different packages. We would have to rename one of the variants, effectively creating a new unit. Therefor we will use a preprocessor to resolve the conditional compilation symbols related to VCL/VisualCLX-specific code and create VCL/VisualCLX units from a common codebase.

    Component dependent units should be largely "interface compatible" - interface adjustments for specific component sets are unavoidable - nonetheless similar interfaces are desirable.

    Preprocessor

    The preprocessor jpp is a modified version of Barry Kelly's ppp tool. In contrast to ppp, which resolves all conditional compilation directives without exception, with jpp symbols not only can be defined but also undefined. Those symbols which are neither defined nor explicitely undefined are considered as of unknown status and it and its related source code remains untouched.

    The usage of jpp is not too hard. It is called via

    jpp [options] <input files>...
    Possible options are
      -i       Process includes
    -c Process conditional directives
    -C Strip comments
    -pxxx Add xxx to include path
    -dxxx Define xxx as a preprocessor conditional symbol
    -uxxx Assume preprocessor conditional symbol xxx as not defined
    -x[n:]yyy Strip first n characters from file name; precede filename by prefix yyy

    The example command line below generates a file JclQGraphics.pas in subdirectory CLX from file Graphics.cb located in the current directory. Symbols "VisualCLX" and "COMPILER6_UP" are specified as defined, "Bitmap32" and "VCL" as undefined.

      jpp -c -dVisualCLX -dCOMPILER6_UP -uBitmap32 -uVCL -xCLX\JclQ Graphics.cb

    Generating Jcl[Q]Graphics.pas and Jcl[Q]GraphUtils.pas

    First compile Preprocessor\jpp.exe from Preprocessor\jpp.dpr. Then change to the "Source" directory and type "make" at the command line. This will create the units
    VCL\JclGraphics.pas
    VCL\JclGraphUtils.pas
    CLX\JclQGraphics.pas
    CLX\JclQGraphUtils.pas

    from their prototypes _Graphics.pas and _GraphUtils.pas.

    Minimizing VCL dependencies

    To reduce VCL dependencies in JCL, the following changes have been made:

    JclFileUtils
    PathCompactPath is an overloaded function. The variant which takes a TCanvas as argument (and thus creates a dependency on VCL unit Graphics) has been removed.

    JclShell
    ShellLinkGetIcon has been removed. It could get part of some genuine VCL-dependent unit (e.g. JclGraphUtils), but for now it is left out.

    JclPEImage
     Replace "uses Consts," by

    uses
    {$IFDEF COMPILER6_UP}
    RtlConsts, // VisualCLX-package compatible (part of rtlxx.bpl)
    {$ELSE}
    Consts, // not VisualCLX-package compatible (part of vclxx.bpl)
    {$ENDIF COMPILER6_UP}

    Note that the first two changes have enormous impact, since many JCL units use JclFileUtils and JclSysInfo (which both use JclShell). This leaves JclGraphics and JclGraphUtils as sole units with genuine VCL/VisualCLX-dependencies. JclPrint is the only remaining pure VCL-dependent units.

    New directory structure

    With the new JCL release we introduce a more appropriate source file directory structure. The files are now grouped according their respective layers.

    Source/
    Common
    DotNet
    Unix
    VCL
    VisCLX
    Windows

    Status - Platforms

    This table gives a short overview of which units are already working under four different Delphi language compilers/platforms. There are four status levels possible:

    +
      the unit has been ported to that platform
    -   the unit has not been ported to that platform
     (+)
      the unit compiles, but not all of its functionality has been ported to that platform.
     platform
      the unit is platform dependent and will not be ported.

    Name Delphi (Windows) Kylix for Delphi Delphi.NET Free Pascal
    Jcl8087 + + - ?
    JclAppInst + - - ?
    JclCil + - - ?
    JclClr + - - ?
    JclCom + - - ?
    JclComplex + + - ?
    JclConsole + - - ?
    JclCounter + + - ?
    JclDateTime + (+) - ?
    JclDebug + - - ?
    JclDotNet + - - ?
    JclEDI + + - ?
    JclEDISEF + + - ?
    JclEDIXML + + - ?
    JclEDI_ANSIX12 + + - ?
    JclEDI_UNEDIFACT + + - ?
    JclFileUtils + (+) - ?
    JclExprEval + +
    - ?
    JclHookExcept + - - ?
    JclIniFiles + +
    - ?
    JclLanMan + - - ?
    JclLocales + - - ?
    JclLogic + + - ?
    JclMapi + - - ?
    JclMath + + - ?
    JclMetaData + - - ?
    JclMidi + - - ?
    JclMime + + - ?
    JclMiscel + - - ?
    JclMultimedia + - - ?
    JclNTFS + - - ?
    JclPEImage + - - ?
    JclPrint + - - ?
    JclStrHashMap + +
    - ?
    JclStatistics + + - ?
    JclShell + - - ?
    JclSecurity + - - ?
    JclSchedule + + - ?
    JclRTTI + - - ?
    JclResources + - - ?
    JclRegistry + - - ?
    JclStrings + + - ?
    Jclsvcctrl + - - ?
    Jclsynch + - - ?
    JclTask platform - - ?
    JclSysUtils + (+)
    - ?
    JclSysInfo + (+)
    - ?
    JclTD32 + - - ?
    JclUnicode + - - ?
    JclUnitConv + + - ?
    JclWin32 platform - - ?
    JclWinMidi platform - - ?

    Assembler

    For crossplatform compatability it is absolutely necessary to reduce the amount of inline assembler code used. Therefore as a general rule every line of assembler must have a pure pascal pendant. Please use assembler only if it really has a noticeable impact on the libraries performance.

    {$IFNDEF PUREPASCAL}
    // assembler code here
    {$ELSE}
    // Delphi equivalent here
    {$ENDIF}

    Packages