对于静态代码分析工具,有必要了解给定Delphi项目的所有有效源路径,这些路径在项目级别和全局IDE配置中定义.
是否有可以收集此类项目信息的Delphi库?
据我所知,Delphi IDE的注册表设置可以在不同的地方,以支持多种配置.但是对于IDE注册表位置和项目文件的给定组合,应该可以收集源路径.
编辑:另一种解决方案是使用--depends开关.这将导致dcc32.exe写入一个".d"文件,其中包含项目的所有dcu文件名(以及所有依赖项),包括路径名.但是,文件列表包含已编译的单元,因此它不是原始问题的正确解决方案.
您可以使用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.
刚发现另一个解决方案
如果我启动RAD Studio命令提示符并运行
msbuild /t:Rebuild
在项目目录中,msbuild将显示调用dcc32的完整命令行,包括所有路径设置.将构建日志重定向到一个文件(或用仅自动捕获参数的自制版本替换dcc32.exe)并解析输出似乎比解析dproj文件容易得多.
另一个优点是它可以用于自动构建/持续集成.