【问题标题】:Is there a Delphi library which returns all effective source paths for a project?是否有一个 Delphi 库可以返回项目的所有有效源路径?
【发布时间】:2010-11-01 13:01:17
【问题描述】:

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

有没有可以收集这类项目信息的Delphi库?

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

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

【问题讨论】:

  • 您想了解任何特定的 Delphi 版本吗?
  • Delphi 2009 - 因为它的构建配置要复杂得多,甚至可以继承,并且可以包含像'$(DCC_UnitSearchPath)' 这样的宏 - 这似乎比预期的要难......跨度>

标签: delphi path code-analysis delphi-2009


【解决方案1】:

您可以使用 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.

【讨论】:

  • 这看起来很有前途,非常感谢!我将仔细研究OTA。很容易获得项目源文件的列表(所有已明确添加到 DPR 的文件)?我也会看看 GExpert / cnWizard 的来源。
  • 是的,使用 OTA,您可以枚举项目的模块。看看 IOTAProject 界面。具体来说,IOTAProject40 方法 GetModuleCount、GetModule。
【解决方案2】:

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

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

msbuild /t:Rebuild

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-15
    • 1970-01-01
    • 2011-07-31
    • 2021-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多