Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2020-05

Where to define conditionals for FPC

19 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Bo Berglund

I know that you can define "custom options" in Lazarus Project/Options/CompilerOptions/CustomOptions/Defines

These can then be used in constructs like this example:

{$IFDEF USE_LAZSERIAL}
//Code pertaining to LazSerial
{$ELSE}
//Code pertaining to AsyncPro
{$ENDIF}

But if I do not want to use Lazarus, how do I set the conditionals I want to use?

Something like:
{$DEFINE USE_LAZSERIAL}

written directly in a source file could perhaps be used?

But where do I put this so it will apply to the whole application? And so that Delphi will also read it if I use the source in Delphi...

Bo Berglund Developer in Sweden

Reply by email

Gabor Boros
to Bo Berglund

2020. 05. 08. 14:07 keltezéssel, Bo Berglund via lazarus írta:

Show quoted text 13 lines
I know that you can define "custom options" in Lazarus Project/Options/CompilerOptions/CustomOptions/Defines These can then be used in constructs like this example: {$IFDEF USE_LAZSERIAL} //Code pertaining to LazSerial {$ELSE} //Code pertaining to AsyncPro {$ENDIF} But if I do not want to use Lazarus, how do I set the conditionals I want to use?

Compile with "fpc ... -dUSE_LAZSERIAL".

Gabor

Reply by email

Bo Berglund
to Gabor Boros
Gabor Boros wrote 18 lines
2020. 05. 08. 14:07 keltezéssel, Bo Berglund via lazarus írta: > I know that you can define "custom options" in Lazarus > Project/Options/CompilerOptions/CustomOptions/Defines > > These can then be used in constructs like this example: > > {$IFDEF USE_LAZSERIAL} > //Code pertaining to LazSerial > {$ELSE} > //Code pertaining to AsyncPro > {$ENDIF} > > But if I do not want to use Lazarus, how do I set the conditionals I > want to use? Compile with "fpc ... -dUSE_LAZSERIAL".

I am trying to find a way to mmake the code build both in Delphi 2007 and Lazarus and since I have used conditionals to adapt the code to different components and environments I need to handle these in a consistent manner.
I know that I can use the Delphi and Lazarus GUI to set these conditional variables, but in the end I need the Delphi code (I have still not reached FPC/Lazarus for the complete project) to be accepted by the Lazarus Delphi Conversion function and then everything I think is read from the project sources.
In this case since Delphi 2007 stores the settings in the dproj file and since the Converter does not read that file I am trying to find a way to set the conditionals directly in the code...

Maybe in an include file, but where should that be included?

The dpr file only contains this after the uses file list:

begin
  {$i conditionals.inc}  //<== Can it be here? Will it be global then?
  if not Application.DelayInitialize or Application.Installing then
    Application.Initialize;
  Application.CreateForm(TRemoteServer, RemoteServer);
  Application.Run;
end.
Bo Berglund Developer in Sweden

Reply by email

Sven Barth
to Bo Berglund

Bo Berglund via lazarus schrieb am Fr., 8.
Mai 2020, 16:54:

Show quoted text 36 lines
On Fri, 8 May 2020 16:34:49 +0200, Gabor Boros via lazarus wrote: >2020. 05. 08. 14:07 keltezéssel, Bo Berglund via lazarus írta: >> I know that you can define "custom options" in Lazarus >> Project/Options/CompilerOptions/CustomOptions/Defines >> >> These can then be used in constructs like this example: >> >> {$IFDEF USE_LAZSERIAL} >> //Code pertaining to LazSerial >> {$ELSE} >> //Code pertaining to AsyncPro >> {$ENDIF} >> >> But if I do not want to use Lazarus, how do I set the conditionals I >> want to use? > > >Compile with "fpc ... -dUSE_LAZSERIAL". > I am trying to find a way to mmake the code build both in Delphi 2007 and Lazarus and since I have used conditionals to adapt the code to different components and environments I need to handle these in a consistent manner. I know that I can use the Delphi and Lazarus GUI to set these conditional variables, but in the end I need the Delphi code (I have still not reached FPC/Lazarus for the complete project) to be accepted by the Lazarus Delphi Conversion function and then everything I think is read from the project sources. In this case since Delphi 2007 stores the settings in the dproj file and since the Converter does not read that file I am trying to find a way to set the conditionals directly in the code... Maybe in an include file, but where should that be included?

Such an include file would need to be included in all units where a define might be needed.

Alternatively if you always use LazSerial for FPC/Lazarus you could simply check with "$ifdef FPC" instead.

Regards,
Sven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20200508/b16565d3/attachment.html>

Reply by email

Bo Berglund
to Sven Barth
Sven Barth wrote 5 lines
Such an include file would need to be included in all units where a define might be needed. Alternatively if you always use LazSerial for FPC/Lazarus you could simply check with "$ifdef FPC" instead.

Well LazSerial was just an example...

I am going over the code to remove functionality that has been outdated over the years and uses components that are hard to port.

I have created a bunch of conditionals which I can use to select or block certain functions in the code. I have also at the same time added the conditionals for FPC to switch between for example LazSerial and the corresponding serial component in Windows (there are actually two that can be selected between using another conditional in Windows).

All of this works OK in Delphi 2007 when I use the GUI to set the conditional variables.

But what is worrying me is that the Lazarus Delphi Converter will not find these conditionals and then convert stuff that are to be Delphi only...
As far as I have understood the converter does not read the dproj file where Delphi stores these settings.
But I might be overly anxious? Maybe Lazarus Delphi Converter can read the dproj file and find the settings?

I made a test conversion a number of weeks ago and it failed because of a lot of dependencies on components with no FCP counterpart etc... Then I had to backtrack a lot to get the project in working order again and decided to try to make the code FPC aware via the conditionals and still keep the way it works now.

Maybe I can just enclose the ifdef's in an outer layer ifdef DELPHI? Does the converter skip such sections during the conversion? Like:

{$IFDEF DELPHI}
  {$IFDEF USE_SUPERPRO}
    Sentinel,
  {$ENDIF}
{$ENDIF}

Then Sentinel will only ever be used if built by Delphi and only if SUPERPRO is set, right?

Bo Berglund Developer in Sweden

Reply by email

Sven Barth
to Bo Berglund

Bo Berglund via lazarus schrieb am Fr., 8.
Mai 2020, 18:03:

Show quoted text 13 lines
Maybe I can just enclose the ifdef's in an outer layer ifdef DELPHI? Does the converter skip such sections during the conversion? Like: {$IFDEF DELPHI} {$IFDEF USE_SUPERPRO} Sentinel, {$ENDIF} {$ENDIF} Then Sentinel will only ever be used if built by Delphi and only if SUPERPRO is set, right?

I don't know how the converter works, so I can't tell whether any of this will help.

However Delphi does not define a DELPHI define, so you'll have to use a negated check for FPC instead. In your example:

{$IFNDEF FPC}
  {$IFDEF USE_SUPERPRO}
    Sentinel,
  {$ENDIF}
{$ENDIF}

Regards,
Sven

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20200508/789c359a/attachment.html>

Reply by email

Bo Berglund
to Sven Barth
Sven Barth wrote 9 lines
However Delphi does not define a DELPHI define, so you'll have to use a negated check for FPC instead. In your example: {$IFNDEF FPC} {$IFDEF USE_SUPERPRO} Sentinel, {$ENDIF} {$ENDIF}

Thanks, I will use that instead!

Bo Berglund Developer in Sweden

Reply by email

Marc Weustink
to Bo Berglund: On Fri, 8 May 2020 17:19:30 +0200, Sven Barth via lazarus Well LazSerial was just an…
Bo Berglund wrote 29 lines
On Fri, 8 May 2020 17:19:30 +0200, Sven Barth via lazarus wrote: >Such an include file would need to be included in all units where a define >might be needed. > >Alternatively if you always use LazSerial for FPC/Lazarus you could simply >check with "$ifdef FPC" instead. Well LazSerial was just an example... I am going over the code to remove functionality that has been outdated over the years and uses components that are hard to port. I have created a bunch of conditionals which I can use to select or block certain functions in the code. I have also at the same time added the conditionals for FPC to switch between for example LazSerial and the corresponding serial component in Windows (there are actually two that can be selected between using another conditional in Windows). All of this works OK in Delphi 2007 when I use the GUI to set the conditional variables. But what is worrying me is that the Lazarus Delphi Converter will not find these conditionals and then convert stuff that are to be Delphi only...

The last weeks, since I'm working from home, I've been converting a lot of our Delphi 6 projects. I only use the convertor to get a Lazarus project from a dpr. All other changes I revert. The convertor breaks more than it fixes. Like in your case we still release our software build by Delphi. Once I have the lpi, I never use the convertor again. So it cannot touch defines and such.

Marc

Reply by email

Bo Berglund
to Marc Weustink
Marc Weustink wrote 6 lines
The last weeks, since I'm working from home, I've been converting a lot of our Delphi 6 projects. I only use the convertor to get a Lazarus project from a dpr. All other changes I revert. The convertor breaks more than it fixes. Like in your case we still release our software build by Delphi. Once I have the lpi, I never use the convertor again. So it cannot touch defines and such.

Interesting!
I have a few questions:

1) Lazarus project file conversion
You state that you just use the converter to get a project in Lazarus from the Delphi dpr file.
Exactly how do you do this?

2) Lazarus project file (lpi)
When you convert to Lazarus are you also getting an lpi file? And does the lpi file contain references into the Delphi install directories?
The lpi file from my first (failed) conversion contains stuff like this:

<SearchPaths>
<IncludeFiles Value="C:\Programs\CodeGear\RAD
Studio\5.0\source\Win32\vcl\;..\..\..\CMP\SentinelAGI;..\..\..\CMP\Log3R;..\..\..\CMP\SystemResource;..\..\..\CMP\Version;..\..\Common;..\..\..\CMP\AsyncPro\source;..\..\..\CMP\DLPortIO\source;..\..\..\CMP\Indy10\Protocols;$(ProjOutDir)"/> <OtherUnitFiles Value="C:\Programs\CodeGear\RAD
Studio\5.0\source\Win32\vcl\;..\..\..\CMP\SentinelAGI;..\..\..\CMP\Log3R;..\..\..\CMP\SystemResource;..\..\..\CMP\Version;..\..\Common;..\..\..\CMP\AsyncPro\source;..\..\..\CMP\DLPortIO\source;..\..\..\CMP\Indy10\Protocols;C:\Programs\CodeGear\RAD Studio\5.0\source\Win32\rtl\win\"/>
<UnitOutputDirectory Value="..\bin"/>
</SearchPaths>

and:
<Other>
<CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/>
</Other>

The lpr file looks pretty much like the dpr original except for the added:
{$MODE Delphi}

3) Compiling same code with Delphi and FPC?
Do you convert your projects (manually) to make it possible to use both Delphi and Lazarus as the IDE for further work on the same sources?
If so do you have any hints as to what to look out for?

What I am doing now is that inside Delphi 2007 I am editing all of the project files and adding this on top:

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

I also replace the uses reference to Windows with this (which is what the converter dir in the failed run):

uses

  {$IFDEF FPC}
    LCLIntf,
    LCLType,
    LMessages,
  {$ELSE}
    Windows,
  {$ENDIF}

Then I am also using conditionals to exclude functions relying on Delphi-only units and replacing these with "neutral" units. For example I am enabling Registry usage only if on Windows and instead use conf files on Linux. The built in Lazarus Registry unit handling of Registry calls on Linux is too complex for me...

And I am also purging no longer wanted old functions...

Grateful for any suggestions and advice!

Bo Berglund Developer in Sweden

Reply by email

Juha Manninen
to Bo Berglund: On Fri, 8 May 2020 17:19:30 +0200, Sven Barth via lazarus Well LazSerial was just an…
PM Bo Berglund wrote
All of this works OK in Delphi 2007 when I use the GUI to set the conditional variables.

You must have separate projects for Delphi and Lazarus in any case. Maintaining those variables in the Delphi project should not be a problem.

Show quoted text 7 lines
But what is worrying me is that the Lazarus Delphi Converter will not find these conditionals and then convert stuff that are to be Delphi only... As far as I have understood the converter does not read the dproj file where Delphi stores these settings. But I might be overly anxious? Maybe Lazarus Delphi Converter can read the dproj file and find the settings?

No, a .dproj file is not supported currently.
The converter reads .dpr project file and also .dof and .cfg files if available. At least earlier Delphi versions stored settings in those.

Show quoted text 5 lines
I made a test conversion a number of weeks ago and it failed because of a lot of dependencies on components with no FCP counterpart etc... Then I had to backtrack a lot to get the project in working order again and decided to try to make the code FPC aware via the conditionals and still keep the way it works now.

Some projects are almost impossible to convert because they have components which are not ported to Lazarus.
The automatic conversion cannot help you there.

AM Bo Berglund wrote
2) Lazarus project file (lpi) When you convert to Lazarus are you also getting an lpi file?

Yes. When a project is converted for Lazarus you obviously get an .lpi project file.

Show quoted text 13 lines
And does the lpi file contain references into the Delphi install directories? The lpi file from my first (failed) conversion contains stuff like this: <SearchPaths> <IncludeFiles Value="C:\Programs\CodeGear\RAD Studio\5.0\source\Win32\vcl\;..\..\..\CMP\SentinelAGI;..\..\..\CMP\Log3R;..\..\..\CMP\SystemResource;..\..\..\CMP\Version;..\..\Common;..\..\..\CMP\AsyncPro\source;..\..\..\CMP\DLPortIO\source;..\..\..\CMP\Indy10\Protocols;$(ProjOutDir)"/> <OtherUnitFiles Value="C:\Programs\CodeGear\RAD Studio\5.0\source\Win32\vcl\;..\..\..\CMP\SentinelAGI;..\..\..\CMP\Log3R;..\..\..\CMP\SystemResource;..\..\..\CMP\Version;..\..\Common;..\..\..\CMP\AsyncPro\source;..\..\..\CMP\DLPortIO\source;..\..\..\CMP\Indy10\Protocols;C:\Programs\CodeGear\RAD Studio\5.0\source\Win32\rtl\win\"/> <UnitOutputDirectory Value="..\bin"/> </SearchPaths>

It means those directories are in your Delphi project settings. Why are they there? Usually Delphi stores them in a global search path when components are installed.
If they are also in the global search path, they can be removed from the project and the converter will not add them.

Show quoted text 5 lines
3) Compiling same code with Delphi and FPC? Do you convert your projects (manually) to make it possible to use both Delphi and Lazarus as the IDE for further work on the same sources? If so do you have any hints as to what to look out for?

Experience has proven that maintaining a project for both Delphi and Lazarus is difficult. At some point you will decide to dump the Delphi support.
Maybe you should rethink your porting strategy and do a one-direction conversion from the beginning. You would save time in the long run. During a transition period you must maintain 2 versions, one for Delphi and one for Lazarus, but you don't need to struggle with an IFDEF mess.
Replacing code and the whole porting process becomes easier.

Juha

Reply by email

Marco van de Voort
to Bo Berglund: On Sun, 10 May 2020 14:37:12 +0200, Marc Weustink via lazarus Interesting! I have a few…

Op 2020-05-11 om 09:33 schreef Bo Berglund via lazarus:

Show quoted text 5 lines
and: <Other> <CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/> </Other>

Versions defines are not portable anyway. Long time ago, I wrote something for Jedi about it, which I later upgraded with some general Delphi-FPC advise. Though outdated, it might still be a good read:

http://www.stack.nl/~marcov/porting.pdf

Reply by email

Bo Berglund
to Marco van de Voort
Marco van de Voort wrote 13 lines
Op 2020-05-11 om 09:33 schreef Bo Berglund via lazarus: > and: > <Other> > <CustomOptions Value="-dBorland -dVer150 -dDelphi7 > -dCompiler6_Up -dPUREPASCAL"/> > </Other> Versions defines are not portable anyway. Long time ago, I wrote something for Jedi about it, which I later upgraded with some general Delphi-FPC advise. Though outdated, it might still be a good read: http://www.stack.nl/~marcov/porting.pdf

Thanks for the document link!
I think this is exactly what I need to put my defines into rather than inside the IDE menu somewhere. Makes it safer that they are actuially used by having them inside a single file (that gets included everywhere).

Was discussed earlier but this reinforces the method, I think.

Is the Lazarus code window taking account of these included defines?

And do I put the include in the beginning of every unit source file before or after the interface keyword?

Bo Berglund Developer in Sweden

Reply by email

Marc Weustink
to Bo Berglund: On Sun, 10 May 2020 14:37:12 +0200, Marc Weustink via lazarus Interesting! I have a few…
Bo Berglund wrote 17 lines
On Sun, 10 May 2020 14:37:12 +0200, Marc Weustink via lazarus wrote: > The last weeks, since I'm working from home, I've been converting a lot > of our Delphi 6 projects. I only use the convertor to get a Lazarus > project from a dpr. All other changes I revert. The convertor breaks > more than it fixes. Like in your case we still release our software > build by Delphi. Once I have the lpi, I never use the convertor again. > So it cannot touch defines and such. Interesting! I have a few questions: 1) Lazarus project file conversion You state that you just use the converter to get a project in Lazarus from the Delphi dpr file. Exactly how do you do this?

Tools - Delphi conversion - Convert delphi project. Disable scan files in parent directory

Show quoted text 15 lines
2) Lazarus project file (lpi) When you convert to Lazarus are you also getting an lpi file? And does the lpi file contain references into the Delphi install directories? The lpi file from my first (failed) conversion contains stuff like this: <SearchPaths> <IncludeFiles Value="C:\Programs\CodeGear\RAD Studio\5.0\source\Win32\vcl\;..\..\..\CMP\SentinelAGI;..\..\..\CMP\Log3R;..\..\..\CMP\SystemResource;..\..\..\CMP\Version;..\..\Common;..\..\..\CMP\AsyncPro\source;..\..\..\CMP\DLPortIO\source;..\..\..\CMP\Indy10\Protocols;$(ProjOutDir)"/> <OtherUnitFiles Value="C:\Programs\CodeGear\RAD Studio\5.0\source\Win32\vcl\;..\..\..\CMP\SentinelAGI;..\..\..\CMP\Log3R;..\..\..\CMP\SystemResource;..\..\..\CMP\Version;..\..\Common;..\..\..\CMP\AsyncPro\source;..\..\..\CMP\DLPortIO\source;..\..\..\CMP\Indy10\Protocols;C:\Programs\CodeGear\RAD Studio\5.0\source\Win32\rtl\win\"/> <UnitOutputDirectory Value="..\bin"/> </SearchPaths>

Yep, didn't get those, but others. Just removed them.

Show quoted text 5 lines
and: <Other> <CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/> </Other>

I keep them, it might be used by some 3rd party packages, and some of our earlier code. It doesn't hurt to keep them

The lpr file looks pretty much like the dpr original except for the added: {$MODE Delphi}

That one I remove as well. I define delphi mode in the compiler settings of the project. This way the units can be used inh delphi too (without adding extra ifdefs)

Show quoted text 5 lines
3) Compiling same code with Delphi and FPC? Do you convert your projects (manually) to make it possible to use both Delphi and Lazarus as the IDE for further work on the same sources? If so do you have any hints as to what to look out for?

Yes, it is a manual conversion. But in our case not that hard. Most of the converted projects are windows (network) services. The difference between a delphi service and a fpc daemon is covered in a BaseServer class / unit. So for services derived from it there is no different code.
Also we do have our own network/serial/async thread notification libraries. So once those got converted, most of the projects would build. Since we were using D6, a lot of newer win api functions were missing. Therefore we already had Win32Api unit for all missing functions/types. In case of FPC this unit is extended for missing functions in FPC (and later functions/types existing in FPC but missing in Delphi) This is also why I don't let the convertor touch the existing code, most incompatibilities are handled in this unit (openfile/fileopen for instance).

Show quoted text 6 lines
What I am doing now is that inside Delphi 2007 I am editing all of the project files and adding this on top: {$IFDEF FPC} {$MODE Delphi} {$ENDIF}

Not needed if you enable delphi mode in the compiler options

Show quoted text 11 lines
I also replace the uses reference to Windows with this (which is what the converter dir in the failed run): uses {$IFDEF FPC} LCLIntf, LCLType, LMessages, {$ELSE} Windows, {$ENDIF}

This is what I need to do as well. It is a nice reevaluation if I still need all those units.

Show quoted text 5 lines
Then I am also using conditionals to exclude functions relying on Delphi-only units and replacing these with "neutral" units. For example I am enabling Registry usage only if on Windows and instead use conf files on Linux. The built in Lazarus Registry unit handling of Registry calls on Linux is too complex for me...

Most of our services are configured by cmdline (and it gets parsed through our own helper class)

And I am also purging no longer wanted old functions... Grateful for any suggestions and advice!

Marc

Reply by email

Bo Berglund
to Marc Weustink: Tools - Delphi conversion - Convert delphi project. Disable scan files in parent directory
Marc Weustink wrote 117 lines
On 11-5-2020 09:33, Bo Berglund via lazarus wrote: > On Sun, 10 May 2020 14:37:12 +0200, Marc Weustink via lazarus > wrote: > >> The last weeks, since I'm working from home, I've been converting a lot >> of our Delphi 6 projects. I only use the convertor to get a Lazarus >> project from a dpr. All other changes I revert. The convertor breaks >> more than it fixes. Like in your case we still release our software >> build by Delphi. Once I have the lpi, I never use the convertor again. >> So it cannot touch defines and such. > > Interesting! > I have a few questions: > > 1) Lazarus project file conversion > You state that you just use the converter to get a project in Lazarus > from the Delphi dpr file. > Exactly how do you do this? Tools - Delphi conversion - Convert delphi project. Disable scan files in parent directory > 2) Lazarus project file (lpi) > When you convert to Lazarus are you also getting an lpi file? > And does the lpi file contain references into the Delphi install > directories? > The lpi file from my first (failed) conversion contains stuff like > this: > > <SearchPaths> > <IncludeFiles Value="C:\Programs\CodeGear\RAD > Studio\5.0\source\Win32\vcl\;..\..\..\CMP\SentinelAGI;..\..\..\CMP\Log3R;..\..\..\CMP\SystemResource;..\..\..\CMP\Version;..\..\Common;..\..\..\CMP\AsyncPro\source;..\..\..\CMP\DLPortIO\source;..\..\..\CMP\Indy10\Protocols;$(ProjOutDir)"/> > <OtherUnitFiles Value="C:\Programs\CodeGear\RAD > Studio\5.0\source\Win32\vcl\;..\..\..\CMP\SentinelAGI;..\..\..\CMP\Log3R;..\..\..\CMP\SystemResource;..\..\..\CMP\Version;..\..\Common;..\..\..\CMP\AsyncPro\source;..\..\..\CMP\DLPortIO\source;..\..\..\CMP\Indy10\Protocols;C:\Programs\CodeGear\RAD > Studio\5.0\source\Win32\rtl\win\"/> > <UnitOutputDirectory Value="..\bin"/> > </SearchPaths> Yep, didn't get those, but others. Just removed them. > and: > <Other> > <CustomOptions Value="-dBorland -dVer150 -dDelphi7 > -dCompiler6_Up -dPUREPASCAL"/> > </Other> I keep them, it might be used by some 3rd party packages, and some of our earlier code. It doesn't hurt to keep them > The lpr file looks pretty much like the dpr original except for the > added: > {$MODE Delphi} That one I remove as well. I define delphi mode in the compiler settings of the project. This way the units can be used inh delphi too (without adding extra ifdefs) > 3) Compiling same code with Delphi and FPC? > Do you convert your projects (manually) to make it possible to use > both Delphi and Lazarus as the IDE for further work on the same > sources? > If so do you have any hints as to what to look out for? Yes, it is a manual conversion. But in our case not that hard. Most of the converted projects are windows (network) services. The difference between a delphi service and a fpc daemon is covered in a BaseServer class / unit. So for services derived from it there is no different code. Also we do have our own network/serial/async thread notification libraries. So once those got converted, most of the projects would build. Since we were using D6, a lot of newer win api functions were missing. Therefore we already had Win32Api unit for all missing functions/types. In case of FPC this unit is extended for missing functions in FPC (and later functions/types existing in FPC but missing in Delphi) This is also why I don't let the convertor touch the existing code, most incompatibilities are handled in this unit (openfile/fileopen for instance). > What I am doing now is that inside Delphi 2007 I am editing all of the > project files and adding this on top: > > {$IFDEF FPC} > {$MODE Delphi} > {$ENDIF} Not needed if you enable delphi mode in the compiler options > I also replace the uses reference to Windows with this (which is what > the converter dir in the failed run): > > uses > {$IFDEF FPC} > LCLIntf, > LCLType, > LMessages, > {$ELSE} > Windows, > {$ENDIF} This is what I need to do as well. It is a nice reevaluation if I still need all those units. > Then I am also using conditionals to exclude functions relying on > Delphi-only units and replacing these with "neutral" units. > For example I am enabling Registry usage only if on Windows and > instead use conf files on Linux. The built in Lazarus Registry unit > handling of Registry calls on Linux is too complex for me... Most of our services are configured by cmdline (and it gets parsed through our own helper class) > And I am also purging no longer wanted old functions... > > Grateful for any suggestions and advice! Marc

Thank you so much for your comments/advice!
Much appreciated! :)

Bo Berglund Developer in Sweden

Reply by email

Bo Berglund
to Marc Weustink: Tools - Delphi conversion - Convert delphi project. Disable scan files in parent directory

On Tue, 12 May 2020 13:49:08 +0200, Marc Weustink via lazarus wrote:

While going through your post I got into this section:

Show quoted text 11 lines
> 3) Compiling same code with Delphi and FPC? > Do you convert your projects (manually) to make it possible to use > both Delphi and Lazarus as the IDE for further work on the same > sources? > If so do you have any hints as to what to look out for? Yes, it is a manual conversion. But in our case not that hard. Most of the converted projects are windows (network) services. The difference between a delphi service and a fpc daemon is covered in a BaseServer class / unit. So for services derived from it there is no different code.

Since I am dealing with a Windows Service too I wonder how you do it to get a daemon application in Lazarus?

I have installed the package lazdaemon 0.9.9 on advice elsewhere. It is said to be implementing services, but I don't know if it is involved in the Delphi conversion...

Coide snippets:

My service application is created in the dpr file:

  if not Application.DelayInitialize or Application.Installing then
    Application.Initialize;
  Application.CreateForm(TSSRemoteServer, SSRemoteServer);
  Application.Run;

And in the main source file:

type
  TSSRemoteServer = class(TService) // <== Using TService
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure ServiceShutdown(Sender: TService);
    procedure ServiceDestroy(Sender: TObject);
    procedure ServiceCreate(Sender: TObject);
  private
    {$IFNDEF FPC} //Delphi
      sckServer: TServerSocket;
    {$ELSE}  //FPC
      sckServer: TLTcp; //lNet socket
    {$ENDIF}
.... normal field and method declarations follow ...
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  SSRemoteServer.Controller(CtrlCode);
end;

....

var
  SSRemoteServer: TSSRemoteServer;
Bo Berglund Developer in Sweden

Reply by email

Marc Weustink
to Bo Berglund
Bo Berglund wrote 26 lines
On Tue, 12 May 2020 13:49:08 +0200, Marc Weustink via lazarus wrote: While going through your post I got into this section: >> 3) Compiling same code with Delphi and FPC? >> Do you convert your projects (manually) to make it possible to use >> both Delphi and Lazarus as the IDE for further work on the same >> sources? >> If so do you have any hints as to what to look out for? > >Yes, it is a manual conversion. But in our case not that hard. Most of >the converted projects are windows (network) services. >The difference between a delphi service and a fpc daemon is covered in a >BaseServer class / unit. So for services derived from it there is no >different code. Since I am dealing with a Windows Service too I wonder how you do it to get a daemon application in Lazarus? I have installed the package lazdaemon 0.9.9 on advice elsewhere. It is said to be implementing services, but I don't know if it is involved in the Delphi conversion...

I'll see if I can extract some example snippet. I cannot remember that I used a package.

I didn't use the form based service

Marc

Reply by email

Bo Berglund
to Marc Weustink
Marc Weustink wrote 32 lines
On May 14, 2020 10:21:22 AM GMT+02:00, Bo Berglund via lazarus wrote: >On Tue, 12 May 2020 13:49:08 +0200, Marc Weustink via lazarus > wrote: > >While going through your post I got into this section: > >>> 3) Compiling same code with Delphi and FPC? >>> Do you convert your projects (manually) to make it possible to use >>> both Delphi and Lazarus as the IDE for further work on the same >>> sources? >>> If so do you have any hints as to what to look out for? >> >>Yes, it is a manual conversion. But in our case not that hard. Most of > >>the converted projects are windows (network) services. >>The difference between a delphi service and a fpc daemon is covered in >a >>BaseServer class / unit. So for services derived from it there is no >>different code. > >Since I am dealing with a Windows Service too I wonder how you do it >to get a daemon application in Lazarus? > >I have installed the package lazdaemon 0.9.9 on advice elsewhere. >It is said to be implementing services, but I don't know if it is >involved in the Delphi conversion... > I'll see if I can extract some example snippet. I cannot remember that I used a package. I didn't use the form based service

Well this application also does not use any forms, but inherently the TService application creates a data module, which supplies some of the form functionality, I guess.

I tried in Lazarus by creating a new daemon application and look what it brings into the project...

But I did not figure out how it works by looking at the code framework so I guess I have to read up a lot about the way daemons work in FPC...
In any case there is a sort of form here as well, looks a lot like a data module.

Bo Berglund Developer in Sweden

Reply by email

Marc Weustink
to Bo Berglund
Bo Berglund wrote 48 lines
On Fri, 15 May 2020 21:26:43 +0200, Marc Weustink via lazarus wrote: > > > On May 14, 2020 10:21:22 AM GMT+02:00, Bo Berglund via lazarus wrote: >> On Tue, 12 May 2020 13:49:08 +0200, Marc Weustink via lazarus >> wrote: >> >> While going through your post I got into this section: >> >>>> 3) Compiling same code with Delphi and FPC? >>>> Do you convert your projects (manually) to make it possible to use >>>> both Delphi and Lazarus as the IDE for further work on the same >>>> sources? >>>> If so do you have any hints as to what to look out for? >>> >>> Yes, it is a manual conversion. But in our case not that hard. Most of >> >>> the converted projects are windows (network) services. >>> The difference between a delphi service and a fpc daemon is covered in >> a >>> BaseServer class / unit. So for services derived from it there is no >>> different code. >> >> Since I am dealing with a Windows Service too I wonder how you do it >> to get a daemon application in Lazarus? >> >> I have installed the package lazdaemon 0.9.9 on advice elsewhere. >> It is said to be implementing services, but I don't know if it is >> involved in the Delphi conversion... >> > I'll see if I can extract some example snippet. I cannot remember that I used a package. > > I didn't use the form based service Well this application also does not use any forms, but inherently the TService application creates a data module, which supplies some of the form functionality, I guess. I tried in Lazarus by creating a new daemon application and look what it brings into the project... But I did not figure out how it works by looking at the code framework so I guess I have to read up a lot about the way daemons work in FPC... In any case there is a sort of form here as well, looks a lot like a data module.

Never used that. I've attached and stripped down and anonymized version of our base server definition. At places where you should place your own code or where it is trivial, I wrote .....
I also didn't include the unit description defining the service derived from TMyBaseServer

Marc
-------------- next part --------------
================================================================================ unit MyDaemon;

interface
uses
  daemonapp, Classes, SysUtils, MyBaseServer;
type
  TMyDaemon = class(TDaemon)
  private
  protected
    function Install: Boolean; override;
    function Execute: Boolean; override;
  public
  end;
  TMyDebugDaemonController = class(TDaemonController)
  public
    function ReportStatus : Boolean; override;
  end;
  TMyDaemonThread = class(TDaemonThread)
  public
    property Terminated;
  end;
  TMyDaemonMapper = Class(TCustomDaemonMapper)
  public
    constructor Create(AOwner : TComponent); override;
  end;
  { TMyDaemonApplication }
  TMyDaemonApplication = class(TDaemonApplication)
  private
    FDebug: Boolean;
    procedure LogEvent(const ALogText: String);
  protected
    function DoConfig(AParams: TMyCommandParams): Boolean; virtual; abstract;
    function DoUpdate: Boolean; virtual; abstract;
    function DoDebug: Boolean; virtual;
    function ProcessRun: Boolean; virtual; abstract;
    procedure CreateDaemonController(var AController : TDaemonController); override;
    procedure CreateDaemonInstance(Var ADaemon : TCustomDaemon; DaemonDef : TDaemonDef); override;
    procedure DoRun; override;
    property Debug: Boolean read FDebug write FDebug;
  public
  end;
  TMyBaseServiceApplication = class(TMyDaemonApplication);
implementation

{ TMyDebugDaemonController }

function TMyDebugDaemonController.ReportStatus: Boolean;
begin
  Result := True;
end;

{ TMyDaemonMapper }

constructor TMyDaemonMapper.Create(AOwner: TComponent);
var
  D: TDaemonDef;
begin
  inherited Create(AOwner);
  D := DaemonDefs.Add as TDaemonDef;
  D.DisplayName := MyServer.DisplayName;
  D.Name := MyServer.Name;
  D.DaemonClassName := TMyDaemon.ClassName;
  D.WinBindings.ServiceType := stWin32;
end;

{ TMyDaemon }

function TMyDaemon.Install: Boolean;
begin
  MyServer.BeforeInstall;
  Result := inherited Install;
  MyServer.AfterInstall;
end;
function TMyDaemon.Execute: Boolean;
begin
  Result := True;
  MyServer.Execute;
end;

{ TMyDaemonApplication }

function TMyDaemonApplication.DoDebug: Boolean;
var
  T: TThread;
  M: TCustomDaemonMapper;
  D: TCustomDaemon;
begin
  Result := True;
  CreateServiceMapper(M);
  D := CreateDaemon(M.DaemonDefs[0]);
  D.Status := csStartPending;
  try
    T := TDaemonThread.Create(D);
    T.Resume;
    T.WaitFor;
    FreeAndNil(T);
  except
    on E : Exception do
      D.Logmessage(Format(SErrDaemonStartFailed,[D.Definition.Name,E.Message]));
  end;
end;
procedure TMyDaemonApplication.CreateDaemonController(var AController: TDaemonController);
begin
  if FDebug
  then AController := TMyDebugDaemonController.Create(Self)
  else inherited CreateDaemonController(AController);
end;
procedure TMyDaemonApplication.CreateDaemonInstance(var ADaemon: TCustomDaemon; DaemonDef: TDaemonDef);
begin
  inherited CreateDaemonInstance(ADaemon, DaemonDef);
  MyServer.Daemon := ADaemon;
end;
procedure TMyDaemonApplication.DoRun;
begin
  if ProcessRun then Exit;
  inherited;
end;
procedure TMyDaemonApplication.LogEvent(const ALogText: String);
begin
  WriteLn(AlogText);
end;
procedure InitApplication;
begin
  RegisterDaemonClass(TMyDaemon);
  RegisterDaemonMapper(TMyDaemonMapper);
end;
initialization
  InitApplication;
finalization
end.

================================================================================

unit MyBaseServer;
interface
{$ifndef FPC}
{$define WINDOWS}
{$define CPUI386}
{$endif}
.....

uses

  {$ifdef fpc}
  daemonapp,
  {$else}
  SvcMgr, WinSvc,
  {$endif}

.....

type
  {$ifdef fpc}
  { TMyService }
  TMyService = class(TComponent)
  private
    FDaemon: TCustomDaemon;
    FDisplayName: String;
    FServiceStartName: String;
    FErrCode: DWord;
    FWin32ErrorCode: DWord;
  protected
    function Terminated: Boolean;
    function ServiceThread: TThread;
  public
    procedure AfterInstall; virtual; abstract;
    procedure BeforeInstall; virtual; abstract;
    procedure Execute; virtual; abstract;
    procedure ReportStatus;
    property Daemon: TCustomDaemon read FDaemon write FDaemon;
    property DisplayName: String read FDisplayName write FDisplayName;
    property ServiceStartName: String read FServiceStartName write FServiceStartName;
    property ErrCode: DWord read FErrCode write FErrCode;
    property Win32ErrCode: DWord read FWin32ErrorCode write FWin32ErrorCode;
  end;
  {$else fpc}
  // delphi part
  TMyService = class(TService)
  private
    procedure ServiceBeforeInstall(Sender: TService);
    procedure ServiceAfterInstall(Sender: TService);
    procedure ServiceExecute(Sender: TService);
  protected
    procedure Execute; virtual; abstract;
    procedure AfterInstall; virtual; abstract;
    procedure BeforeInstall; virtual; abstract;
  public
    constructor Create(AOwner: TComponent); override;
    function GetServiceController: TServiceController; override;
  end;
  {$endif}

TMyBaseSrv = class(TMyService)

  private

.....

var
  MyServer: TMyBaseSrv;
implementation
{$ifdef fpc}
uses
  MyDaemon;
{$endif}
type
  {$ifndef fpc}
  TMyBaseServiceApplication = class(TServiceApplication)
  private
    FDebug: Boolean;
  protected
    function DoConfig(AParams: TMyCommandParams): Boolean; virtual; abstract;
    function DoUpdate: Boolean; virtual; abstract;
    function DoDebug: Boolean; virtual;
    function ProcessRun: Boolean; virtual; abstract;
    property Debug: Boolean read FDebug write FDebug;
  public
    procedure Run; override;
  end;
  {$endif}
  TMyServiceApplication = class(TMyBaseServiceApplication)
  private
  protected
    function DoConfig(AParams: TMyCommandParams): Boolean; override;
    function DoUpdate: Boolean; override;
    function ProcessRun: Boolean; override;
  public
  end;

.....

{ TMyServiceApplication }
{$ifndef MSWINDOWS}
function _GetApplicationName: String;
begin
  Result := 'myapp';
end;
{$endif}
function TMyServiceApplication.DoConfig(AParams: TMyCommandParams): Boolean;
begin
  Result := True;
  ......
end;
function TMyServiceApplication.DoUpdate: Boolean;
begin
  Result := MyServer.ServiceUpdate;
end;
function TMyServiceApplication.ProcessRun: Boolean;
var
  Params: TMyCommandParams;
begin
  Result := True;
  Params := TMyCommandParams.Create;
  try
    if Params.GetFlag('update')  cfUnset
    then begin
      if DoUpdate then Exit;
    end
    else if Params.GetFlag('config')  cfUnset
    then begin
      if DoConfig(Params) then Exit;
    end;
    Debug := Params.GetFlag('debug')  cfUnset
  finally
    Params.Free;
  end;
  if Debug
  then begin
    DoDebug;
    Exit;
  end;
  Result := False;
end;

.....

procedure TMyBaseSrv.Execute;
{$ifndef MSWINDOWS}
const
  ERROR_PROCESS_ABORTED = 1;
{$endif}
var
.....
  {$ifdef fpc}
  TMyDaemonThread(Daemon.DaemonThread).CheckControlMessage(False);
  {$else}
  ServiceThread.ProcessRequests(False);
  {$endif}
.....
{$ifdef fpc}

{ TMyService }

procedure TMyService.ReportStatus;
begin
  Daemon.ReportStatus;
end;
function TMyService.ServiceThread: TThread;
begin
  Result := TMyDaemonThread(Daemon.DaemonThread);
end;
function TMyService.Terminated: Boolean;
begin
  Result := TMyDaemonThread(Daemon.DaemonThread).Terminated;
end;
{$else}
// delphi
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  MyServer.Controller(CtrlCode);
end;
constructor TMyService.Create(AOwner: TComponent);
begin
  CreateNew(AOwner, 0);
  OnExecute := ServiceExecute;
  inherited BeforeInstall := ServiceBeforeInstall;
  inherited AfterInstall := ServiceAfterInstall;
end;
function TMyService.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;
procedure TMyService.ServiceAfterInstall(Sender: TService);
begin
  AfterInstall;
end;
procedure TMyService.ServiceBeforeInstall(Sender: TService);
begin
  BeforeInstall;
end;
procedure TMyService.ServiceExecute(Sender: TService);
begin
  Execute;
end;

{ TMyBaseServiceApplication }

function TMyBaseServiceApplication.DoDebug: Boolean;
begin
  Result := False;
end;
procedure TMyBaseServiceApplication.Run;
begin
  if ProcessRun then Exit;
  inherited;
end;
{$endif}
procedure InitApplication;
begin
  {$ifdef fpc}
  RegisterDaemonApplicationClass(TMyServiceApplication);
  {$else}
  Application.Free;
  Application := TMyServiceApplication.Create(nil);
  {$endif}
end;
initialization
  InitApplication;
finalization
end.

================================================================================

program MyApp;
{$ifdef fpc}
{$R 'MyApp_version.rc'}
{$else}
{$R 'MyApp_version.res' 'MyApp_version.rc'}
{$endif}

uses

  {$ifdef fpc}
  interfaces,
  daemonapp,
  {$else}
  svcmgr,
  {$endif}
  MyBaseServer,
  MyServer,

.....

begin
  Application.Initialize;
  Application.CreateForm(TMySrv, MyServer);
  Application.Run;
end.

================================================================================

Reply by email