6
votes

Whenever you add a new unit to the project Delphi rebuilds the .dpr file and all the IFDEFs in the uses section are gone.

To work around this I typically use NotePad to create new .pas files, and add it to the .dpr manually. If I need a form I use File->New->Form and then revert the .dpr file to the previous version. Not very RAD if you ask me ;-)

How do you deal with that? Is there a way to add a unit in the IDE while keeping the IFDEFs?

7
Could you please explain why you only sometimes want a unit to be a member of your project? I don't understand the purpose.Rob Kennedy
In our project we use the FastMM that comes with Delphi for release builds, but the external FastMM4.pas for debug builds. So we have an IFDEF around "uses FastMM4;"Uli Gerhardt
@Ulrich: I use FastMM4 for both DEBUG and RELEASE builds - why not? It's part of the project SVN repository, and I get the same environment regardless of compiler version. What's not to like?mghie
I must admit I haven't put too much thought in that. Intuitively I didn't want stuff in the (release) project that I don't use.Uli Gerhardt
@Rob: It can be handy if the product ships in different versions (a cheap and an expensive one etc.), so you can leave out features.Giel

7 Answers

9
votes

Sometimes I create a unit specifically as a place for all the IFDEFs and other stuff the IDE would mess up if it were in the dpr. This unit typically goes to the top of the dpr's uses clause. This trick doesn't cater for all scenarios but it sometimes saves a lot of tedious work.

3
votes

I don't put any ifdefs into a dpr file. If I want to use different units/forms in a project, depending on some condition, I split the project in two.

3
votes

I spent quite a while trying to work that one out,

I ended up have a project file (.dpr) for each build type, with the Conditions in Project|Project Options|Directories/Conditionals and only the units i wanted added in to the project

this dose have the down side that if you have custom code in the .dpr, it will have to be manually copied to the other project files when it changes.

as noted by Rob Kennedy, this can handled by putting the custom code into its own unit, which is called by a single procedure. thus minimizing the .dpr code size/changes to be made

Also, another bonus you get is that if you add all your .dpr files to a project group, you can build all your different versions with one click / cmd line

2
votes

You can add it manually from within the IDE. (Use the "view source" option on the project).

Normally the dpr is "hidden". You are not expected to change anything in there. And if you do, you better make sure all your changes are manual else you are losing some information.

1
votes

For forms, datamodules, and other units which contain a single class by which functionaity will be replaced, the solution is rather simple. Just DON'T add the custom units directly to the product, but do save them some place in the search path (or modify the project search path to include thier location).

1) Create a NEW unit, which contains either the parent for all of the other classes, or the interfaces that they all will implement (I generally prefer the later as it allows easier customization) [for example purposes this is called uSpecialParent.pas]

2) Add a class variable which will referenced when you need to create the new functionality. for instance if you just were going to show modal a bunch of forms, so didn't care about any other methods then you could have a variable that looked like the following:

TYPE
  TMySpecialFormClass : class of TForm;

VAR
  TMySpecialForm : TMySpecialFormClass;

3) Create another unit which will contain all of the IFDEFS. It could look something like the following:

Unit uRegisterSpecialForms;

interface

uses
{$IFDF SPECIAL1}
  uSpecial1,
{$ENDIF}
{$IFDEF SPECIAL2}
  uSpecial2,
{$ENDIF}
  uSpecialParent;

implementation

// no code needed.

initialization

{$IFDEF SPECIAL1}
  TMySpecialForm := uSpecial1.TSpecialForm1;
{$ENDIF}
{$IFDEF SPECIAL2}
  TMySpecialForm := uSpecial2.TSPecialForm2;
{$ENDIF}

end.

4) To reference this in your code you only need the uSpecialParent added to the unit which will be requesting a special form and then create it dynamically for example to show this modal you could invoke the following:

var
  frm : TForm;
begin
  frm := TMySpecialForm.Create(nil);
  try
    frm.showmodal;
  finally
    frm.free;
  end;
end;
1
votes

And here's the lo-tech approach for completeness' sake:

After the IDE has messed up your uses clause again:

  1. close the project
  2. go to your version control tool of choice and diff the DPR against the latest checked-in version using a merge-enabled diff tool like WinMerge
  3. revert the IDE changes
  4. save the DPR
  5. get on with it
0
votes

(Delphi 7)

I've just tried the same. Take a look at the first code version and at my comments below:

program Project1;

{$IFDEF TESTIFDEF}
uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};

{$ELSE}
uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};
{$ENDIF TESTIFDEF}

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.

At that point, I've just inserted the 2nd Form and noticed that the corresponding unit (Unit2.pas) was inserted inside the first part of the IFDEF i.e. inside the "TESTIFDEF" labeled part - hence not overriding the second block (after the {$ELSE}).

Thus your solution should be:

  1. define a IFDEF statement like "{$IFDEF DELPHIBASISCONFIGURATION}" in place of my "{$IFDEF TESTIFDEF}" where all the forms will be added.
  2. define as many alternative LABELS for the different configurations you want to work with.
  3. each time you've added a form to the project, copy the inserted line of the first block into the corresponding blocks below - depending on your needs...
  4. activate the required configuration using the define statement or the option dialog
  5. NEVER DEFINE "DELPHIBASISCONFIGURATION" ;)

Hence, it should look like this:

program Project1;

{$DEFINE MYCONFIG1} // THIS ONE IS NOW ACTIVE


{$IFDEF DELPHIBASISCONFIGURATION}
uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2},
  Unit3 in 'Unit3.pas' {Form3};

{$ELSE}
     // THIS IS A "COMMON TO ALL CONFIG" PART
     uses
       Forms,

       // FIRST CONFIGURATION
       {$IFDEF MYCONFIG1}
       Unit1 in 'Unit1.pas' {Form1},
       Unit3 in 'Unit3.pas' {Form3}
       {$ENDIF MYCONFIG1}

       // SECOND CONFIGURATION    
       {$IFDEF MYCONFIG2}
       Unit1 in 'Unit1.pas' {Form1},
       Unit2 in 'Unit2.pas' {Form2}
       {$ENDIF MYCONFIG2}

     // THIS IS THE "COMMON TO ALL CONFIG" END :)
     ;

{$ENDIF TESTIFDEF}

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  //Application.CreateForm(TForm3, Form3);
  //Application.CreateForm(TForm2, Form2);
  Application.Run;
end.

As you can see, I've discarded the calls to Application.CreateForm(...) for Form2 and Form3.

IMHO, it's usually better to dynamically create the supplemental forms at the moment you really need them i.e. not all the forms at program start...