问题
For static code analysis tools, it is necessary to know all effective source paths for a given Delphi project, which are defined on project level and in the global IDE configuration.
Is there a Delphi library which can collect this kind of project information?
As far as I know, the registry settings for the Delphi IDE can be in different places, to support multiple configurations. But for a given combination of the IDE registry location and a project file, it should be possible to collect the source paths.
Edit: Another solution is to use the --depends switch. This will cause dcc32.exe to write a ".d" file with all dcu file names of the project (and all dependencies), including the path names. However, the file list includes units which are compiled already, so it is not a correct solution for the original problem.
回答1:
You can use OpenTools API to get the active project's search path (merged from active configuration and option set) and the IDE's global library path. Here is a unit from my quick test design package:
unit Unit1;
interface
uses
Windows, SysUtils, Classes,
ToolsAPI;
type
TTestWizard = class(TNotifierObject, IOTAWizard, IOTAMenuWizard)
private
{ IOTAWizard }
function GetIDString: string;
function GetName: string;
function GetState: TWizardState;
procedure Execute;
{ IOTAMenuWizard }
function GetMenuText: string;
private
function AddLibraryPaths(Strings: TStrings): Integer;
function AddProjectSearchPaths(Strings: TStrings): Integer;
end;
procedure Register;
implementation
uses
Dialogs,
DCCStrs, TypInfo;
var
WizardIndex: Integer = -1;
procedure GetEnvironmentVariables(Strings: TStrings);
var
P: PChar;
begin
P := nil;
Strings.BeginUpdate;
try
Strings.Clear;
P := GetEnvironmentStrings;
repeat
Strings.Add(P);
P := StrEnd(P);
Inc(P);
until P^ = #0;
finally
if Assigned(P) then
FreeEnvironmentStrings(P);
Strings.EndUpdate;
end;
end;
function EvaluateEnvironmentVariables(const S: string): string;
var
Strings: TStringList;
I: Integer;
begin
Result := S;
Strings := TStringList.Create;
try
GetEnvironmentVariables(Strings);
for I := 0 to Strings.Count - 1 do
Result := StringReplace(Result, Format('$(%s)', [Strings.Names[I]]), Strings.ValueFromIndex[I],
[rfReplaceAll, rfIgnoreCase]);
finally
Strings.Free;
end;
end;
procedure Register;
begin
WizardIndex := (BorlandIDEServices as IOTAWizardServices).AddWizard(TTestWizard.Create);
end;
{ TTestWizard private: IOTAWizard }
function TTestWizard.GetIDString: string;
begin
Result := 'TOndrej.TestWizard';
end;
function TTestWizard.GetName: string;
begin
Result := 'TestWizard';
end;
function TTestWizard.GetState: TWizardState;
begin
Result := [wsEnabled];
end;
procedure TTestWizard.Execute;
var
Paths: TStrings;
begin
Paths := TStringList.Create;
try
AddProjectSearchPaths(Paths);
AddLibraryPaths(Paths);
ShowMessage(EvaluateEnvironmentVariables(Paths.Text));
finally
Paths.Free;
end;
end;
{ TTestWizard private: IOTAMenuWizard }
function TTestWizard.GetMenuText: string;
begin
Result := GetIDString;
end;
function TTestWizard.AddLibraryPaths(Strings: TStrings): Integer;
var
Paths: TStringList;
EnvironmentOptions: IOTAEnvironmentOptions;
begin
Paths := TStringList.Create;
try
Paths.Delimiter := ';';
Paths.StrictDelimiter := True;
EnvironmentOptions := (BorlandIDEServices as IOTAServices).GetEnvironmentOptions;
Paths.DelimitedText := EnvironmentOptions.Values['LibraryPath'];
Strings.AddStrings(Paths);
Result := Paths.Count;
finally
Paths.Free;
end;
end;
function TTestWizard.AddProjectSearchPaths(Strings: TStrings): Integer;
var
ActiveProject: IOTAProject;
Configurations: IOTAProjectOptionsConfigurations;
Configuration: IOTABuildConfiguration;
Paths: TStringList;
begin
Result := -1;
ActiveProject := GetActiveProject;
if not Assigned(ActiveProject) then
Exit;
Configurations := ActiveProject.ProjectOptions as IOTAProjectOptionsConfigurations;
Configuration := Configurations.ActiveConfiguration;
if not Assigned(Configuration) then
Exit;
Paths := TStringList.Create;
try
Configuration.GetValues(sUnitSearchPath, Paths, True);
Strings.AddStrings(Paths);
Result := Paths.Count;
finally
Paths.Free;
end;
end;
initialization
finalization
if WizardIndex <> -1 then
(BorlandIDEServices as IOTAWizardServices).RemoveWizard(WizardIndex);
end.
回答2:
Just found another solution:
if I launch the RAD Studio command prompt and run
msbuild /t:Rebuild
in the project directory, msbuild will show the full command line to invoke dcc32, including all path settings. Redirecting the build log to a file (or replacing dcc32.exe with a self made version which only captures the parameters) and parsing the output seems to be a lot easier than to parse dproj files.
Another advantage is that it can be used in automated builds / continuous integration.
来源:https://stackoverflow.com/questions/970994/is-there-a-delphi-library-which-returns-all-effective-source-paths-for-a-project