2

I have a VCL component that runs on Delphi 7 to 10.3. I am now porting it to FMX.

To avoid maintaining two codebases, I will use conditional defines in my source to separate any custom FMX and VCL code. When I compile the component for distribution a script will output either the VCL or FMX source files.

My problem is how to make the VCL DCUs and FMX DCUs co-exist on the same system (for users who have both the VCL and FMX versions of my component) as both folders will need to be on the Delphi path.

In other words, my VCL units are named: myunit1.pas, myunit2.pas, etc.

And the FMX versions: fmx.myunit1.pas, fmx.myunit2.pas, etc

(Ideally I would name the VCL ones vcl.myunit1.pas, vcl.myunit2.pas, etc. That way the VCL version of the component would only see the vcl.-.pas files and the FireMonkey only the fmx.-.pas files. Unfortunately I cannot do this because then it won't work on older Delphi versions).

Now when I compile a FireMonkey app it tries to use the non-fmx prefixed source files, in preference to the fmx._.pas ones. I need to "hide" the vcl source folder to get it to compile (re-ordering the Delphi paths does not help).

If there another way to make FireMonkey avoid using the vcl files?

(I fear I will need to write a script to give all the files a new name, e.g. FMXmyunit1.pas and update all of the references in all of the files).

Zax
  • 471
  • 1
  • 4
  • 14
  • 1
    Use `{$ifdef` to ensure conditional compilation. You can use this whereever you see fit and using whatever `{$define` values suit your application design. – Freddie Bell Sep 26 '19 at 08:33
  • 1
    You don't need separate source files to support VCL and FMX. A single source will suffice, you just need different packages with different output folders, and you can register your component in such a way that the IDE will filter out the VCL version in FMX projects and vice versa. – Remy Lebeau Sep 26 '19 at 08:38
  • Am I right in assuming that you don't want to give the FMX source code to users who only buy VCL and vice versa? And that's the reason you create different source files from the originally combined sources? Are you sure that this is worth the effort? – dummzeuch Sep 26 '19 at 15:33
  • 1
    Related: https://stackoverflow.com/questions/38556892/how-to-make-a-single-component-support-both-vcl-and-fmx – Jerry Dodge Sep 26 '19 at 16:41
  • Thanks for all the feedback. I don't mind users having both the VCL and FMX source, but I thought it might be easier to have source in separate folders. There is no true FMX define in Delphi (just an "IF DECLARED", which means it cannot be used in an INC file and cannot conditionally specify units in the interface uses clause). So I have a different "platform" inc files in each folder. Come to think of it, they could be named fmx.plat.inc and vcl.plat.inc and the compiler would choose the correct one.... – Zax Sep 26 '19 at 21:12
  • ...Though I also would need to wrap the {$I plat.inc} in a version checking define (for each version of Delphi that supports vcl. prefix, in each of my 140 units). – Zax Sep 26 '19 at 21:13
  • Am I missing something obvious here? Is there an easier way to cope with the lack of an FMX define? – Zax Sep 26 '19 at 21:19

2 Answers2

2

Because Delphi does not provide predefined compiler conditionals to distinguish between the Firemonkey and the VCL framework you can add the symbol $(FrameworkType) into the conditional defines list of the application project settings. This enables the differentiation of the framework within your library by using the conditional compiling symbols FMX and VCL.

Example of typical usage:

uses
  {$IFDEF FMX}
  FMX.Forms,
  {$ENDIF}
  {$IFDEF VCL}
  VCL.Forms,
  {$ENDIF}

This works in my own cross-platform library for pure VCL and FMX projects, where I let integrate the source files directly into the project. In this simple way, the DCU will be recompiled each time. In the case of mixed projects, the $(FrameworkType) contains the initial framework of the application.

When you deliver a package (bpl) things get more complex. You must provide two versions of your bpl for FMX and VCL. If you also provide the source code for debugging purposes, the only option is to completely differentiate the source code files for the FMX and VCL versions, as long as they have platform-dependent code.

  • 1
    So then, how does the Delphi IDE achieve the separation? The answer is Unit Scope Names. http://docwiki.embarcadero.com/RADStudio/Rio/en/Unit_Scope_Names – Freddie Bell Sep 27 '19 at 06:27
  • Thank you for your suggestion, SIL. That would require the user of my component to add $(FrameworkType) to their project settings too, wouldn't it? – Zax Sep 28 '19 at 02:40
  • @Zax: Yes, that is true. I don't understand why Embarcadero has not introduced such conditional compiler define symbol by default. The argument, that the libraries can be mixed is for me not valid because each project (dproj) is defined for only one (FMX or VCL). Often, this declaration get lost at project start. For this purpose I integrated a good comment in the first line of my library, where this symbol is required. – Schneider Infosystems Ltd Sep 29 '19 at 07:17
0

Well, I don't know if it's really a solution, but it works for me.

I wrote an application that copies all my VCL files to my FireMonkey folder and renames them with an FMX prefix, i.e myunit.pas becomes FMXmyunit.pas. It also updates all the references in the pas files and adds a {$DEFINE FMX} to the header. Now both my VCL and FMX versions coexist happily.

Also, I have set my merge tool (Beyond Compare) to ignore the FMX prefix, so I can merge either platform version directly to my local Git copy.

Zax
  • 471
  • 1
  • 4
  • 14