7

对于静态代码分析工具,有必要知道给定 Delphi 项目的所有有效源路径,这些路径是在项目级别和全局 IDE 配置中定义的。

是否有可以收集此类项目信息的 Delphi 库?

据我所知,Delphi IDE的注册表设置可以在不同的地方,以支持多种配置。但是对于 IDE 注册表位置和项目文件的给定组合,应该可以收集源路径。

编辑:另一个解决方案是使用 --depends 开关。这将导致 dcc32.exe 写入一个“.d”文件,其中包含项目的所有 dcu 文件名(以及所有依赖项),包括路径名。但是,文件列表包括已经编译的单元,因此它不是原始问题的正确解决方案。

4

2 回答 2

12

您可以使用 OpenTools API 获取活动项目的搜索路径(从活动配置和选项集合并)和 IDE 的全局库路径。这是我的快速测试设计包中的一个单元:

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.
于 2009-06-09T20:58:07.053 回答
11

刚刚找到另一个解决方案:

如果我启动 RAD Studio 命令提示符并运行

msbuild /t:Rebuild

在项目目录中,msbuild 将显示调用 dcc32 的完整命令行,包括所有路径设置。将构建日志重定向到文件(或将 dcc32.exe 替换为仅捕获参数的自制版本)并解析输出似乎比解析 dproj 文件容易得多。

另一个优点是它可以用于自动化构建/持续集成。

于 2009-06-11T06:15:15.550 回答