tags:

views:

436

answers:

8

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?

+2  A: 

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.

Gamecat
+6  A: 

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.

Ulrich Gerhardt
+1. I don't remember to have ever used conditional inclusion of units. Why would one want to do that?
mghie
@mghie: Portability across compiler and RTL versions. Portability across compilers (Delphi vs. C++ Builder.) Avoiding inclusion of units depending on the build configuration (e.g., you might not want stack dump support in a release build since there are no debugging symbols.) And a hundred other scenarios.
Mihai Limbășan
first of all this would not result in the conditionally included units becoming part of the project (and thus accessible from via the Project Manager)
Oliver Giesen
@moocha: If a unit does not use initialization or finalization there is no need to remove it from the project - the linker will take care of that. Everything else can be done in the unit files. I have never needed anything but a proper include file.
mghie
@moocha: Re-reading my first comment - of course I wanted to write "I don't remember to have ever used conditional inclusion of units in the DPR. Why would one want to do that?"
mghie
@Oliver: That's true but hasn't been an issue in my use cases.
Ulrich Gerhardt
@Oliver: I'm not sure about that. Looks like the project manager gets its information from the .dproj file. A file that's in the .dproj but not the .dpr still appears in the project manager.
Giel
@mghie: Another good reason is testing - once I had to run application with three different memory managers and I did this via additional unit which included (ifdef-managed) D7MM, FastMM or nothing (leaving default - D2005 if I recall - memory manager active).
gabr
@gabr: Agreed, but as you write this was done within another unit, so the DPR was free of IFDEFs, wasn't it? See my comment above, I think conditional unit inclusion is fine, but I had no reason yet to do this in the DPR file.
mghie
@mghie: Memory managers *must* be the very first unit seen by the linker and that's only possible via the .dpr file. That's the use case I was referring to (I'm using FastMM too, except in some apps where I hit bugs in it, and had to maintain IFDEFs in .dpr files since to test various versions.)
Mihai Limbășan
Yes, I did this with additional unit but only BECAUSE Delphi was confused if I put IFDEFs in the dpr.
gabr
+3  A: 

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

Christopher Chase
Most DPR code can be kept to a minimum by moving it to a different unit and then having a single line calling to it. That way, the DPR code is less likely to ever need to change.
Rob Kennedy
thankyou for that, i updated my answer and i am off to update my code ;)
Christopher Chase
+2  A: 

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.

dummzeuch
A: 

(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...

That's a very clever idea. Unfortunately it doesn't work with D2007, which apparently understands the defines and modifies the 'real' section :-(
Giel
+1  A: 

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;
skamradt
+1  A: 

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
Oliver Giesen
A: 

Great, Great, Great, Great, Great, Great Thanks a lot

Delphi Lover