0

I am new in Delphi and I am trying to make an application in which I will give as an input a .dpr file and the application will create a list with all the .pas files used by this .dpr... I still cannot find a function in Delphi or a way to read the uses of the .dpr in order to navigate through the file system to these pas files and read their uses, and so on... Does anyone has any idea on how to achieve this?

thpst
  • 45
  • 7
  • Delphi has no built in functionality to do that. Either write a parser or find a third party one. Why do you need to do this anyway? – David Heffernan Oct 09 '14 at 20:04
  • 1
    You can use a tool, [DUDS, Delphi Unit Dependency Scanner](http://www.easy-ip.net/delphi-unit-dependency-scanner.html). – LU RD Oct 09 '14 at 20:23
  • Also: from the exe, not the dpr you can get the unit list from one of the resources: RCData / PACKAGEINFO. Not the answer but perhaps an alternative. – Ritsaert Hornstra Oct 09 '14 at 20:49
  • Thank you very much guys! I'll take a better look in each solution... David, I want to create an application where I will give a .dpr and it will copy to another folder in file system all relative units to this .dpr. That way I can get easily a copy with all the necessary units for the project even if I have .pas files in the same folder used by other projects. – thpst Oct 09 '14 at 21:08
  • 2
    Your revision control system is what you need to use. Please tell me that you are using revision control. – David Heffernan Oct 09 '14 at 21:26
  • See my answer on this [question][1] [1]: http://stackoverflow.com/questions/4076425/can-i-determine-the-order-in-which-my-units-have-been-initialized/4077426#4077426 – Remko Oct 10 '14 at 08:29
  • Why are you keeping source files for multiple projects in the same folder in the first place? Keep your projects separate. – Rob Kennedy Oct 10 '14 at 13:31
  • David Heffeman: I wanted to make it automatically and not searching through version control system... Remko: Thanks! very helpful... Rob Kennedy: Finally, I followed that solution simple and fits my needs for now :) Thanks everyone for your answers! – thpst Oct 23 '14 at 19:26

3 Answers3

3

It's not exactly straightforward: You don't just need to read the .dpr file, but you also need to parse the .dproj and registry to get Search Paths. If you're trying to do this right, you also have to parse the .dpr and .pas files as code files so you can find the uses statements, handle {$I '...'} includes, {$IFDEF} blocks, interface vs implementation sections, and so on.

All that said, you might want to look to the open source CnPack and GExperts projects for inspiration. Both of them have solved this problem, and you may be able to leverage their work towards whatever problem you're trying to solve.

afrazier
  • 4,784
  • 2
  • 27
  • 30
0

I would like to update this question for possible answer for future reference.

Create a separate unit file (PhonyObject.pas)

unit PhonyObject;

interface

uses
  System.Classes, FMX.Forms, FMX.Dialogs;

type
  TPhonyObject = class(TObject)
  end;

  TPhonyClass = class of TPhonyObject;

procedure FindUnitName(anObject: TObject);

var
  PhonyName: string;
  PhonyClass: TPhonyClass;
  PhonyInstance: TObject;
  PhonyClassName: procedure(anObject: TObject) = FindUnitName;  //function: String = FindUnitName;

implementation

uses System.TypInfo;

procedure FindUnitName(anObject: TObject);
begin
  if anObject <> nil then  PhonyName := anObject.UnitName
  else if not (TObject.UnitName <> 'System') then
  begin
    if TypInfo.GetTypeData(anObject.ClassInfo) <> nil then  PhonyName := String(GetTypeData(anObject.ClassInfo)^.UnitName);
  end else  PhonyName := TObject.UnitName;
  //FreeAndNilProperties
end;

initialization
  PhonyClass := TPhonyObject;
  PhonyInstance := PhonyClass.Create;

  ShowMessage('Unit Name =' + PhonyInstance.UnitName);

  PhonyInstance.Free;


finalization
  PhonyClass := nil; //PhonyClass.Free;

end.

And in order to use this inside another (multiple) units, this is the code I have used so far, but I hope to update it later on. I have this showing up inside a hand made "console" with black background and white text in a TMemo. If anyone wants the code for the TMemo (its not commonly known), or how to show all these inside basically a debug window, all you just have to do let me know. This is the best I have gotten it so far, but I need a better understanding of the child/parent object/classes

unit AnotherUnit;

interface

uses
  System.Classes, PhonyObject;

type
  TPhonyObj = class(TPhonyObject)
  end;

//var

implementation

{$R *.fmx}

uses ...;

initialization

  PhonyClass := TPhonyObj;
  PhonyInstance := PhonyClass.Create;

  ShowMessage('UnitName= ' + PhonyInstance.UnitName + ' (AnotherUnit)'); // PhonyClass.UnitName  // PhonyClassName(PhonyInstance);

  PhonyInstance.Free;

finalization
  PhonyClass := nil;

end;

I used as unique of Unit Names and class names, as I could and I realize I don't actually use any objects till the end, none the less it should work with out any problems. Please comment if there are some better ideas, but I think this is a powerful feature for Delphi programming when you can predict when certain unit names are going to suddenly show up. And how to predict for them too.

Barry Dick
  • 161
  • 3
  • 16
  • Looking at it this way, the initialization happens. The necessary code is here to inform the application of which unit initialization happened first, that way additional code only needs to process conditional statements to make sure that previous units have executed beforehand. Like for example, if you needed to create a database in 1 unit, connect to it, that way the next unit can be sure its been done, and move on. Of course there are statements that can be made to check that the tables or database exists first. That way if it needs to be appended – Barry Dick Jun 22 '17 at 16:58
  • You can however also create objects inside the initialization. All you have to do is add additional libraries. A part of the entire process of the application can therefor be done. simply in the initialization. – Barry Dick Jun 22 '17 at 17:30
  • Barry, why would you want to do things that way? In my opinion, unit initialization is there to set up core data structures which can't be initialized otherwise. What you are presenting here is very similar to the Factory [Design Pattern](https://en.wikipedia.org/wiki/Software_design_pattern) in conjunction with lazy initialization. IMHO it's rather unwieldy to initialize complex application object structures purely in unit initialization - it's tied to Singletons, and how do you inform the user and offer a "retry" button? – Semanino Sep 21 '17 at 05:58
  • [debug console](http://www.abatepain.com/abate/debug-console.png) << To accomplish this simple task. I know the exact pascal files that are loaded and when they are completed, and when they themselves have initialization code as seen with the few loaded mods. Eventually this could be adaptable to a database design or atleast with an array to know which ones are not loaded or further to explore pre-loadable modals. – Barry Dick Sep 22 '17 at 08:56
0

If you let Delphi create a .map file (linker option), it will contain a list of all source and dcu files used in that project. GExperts does that, using a simple parser for a map file which is taken from my dzlib https://sourceforge.net/p/dzlib/code/HEAD/tree/dzlib/trunk/src/u_dzMapFileReader.pas

dummzeuch
  • 10,975
  • 4
  • 51
  • 158