IDE: Separate units ExtToolsConsole (no LCL) and ExtToolsIDE (with LCL) from ExtTools.

git-svn-id: trunk@58643 -
This commit is contained in:
juha 2018-07-28 13:38:06 +00:00
parent 257f905284
commit 2b381547b5
11 changed files with 653 additions and 474 deletions

2
.gitattributes vendored
View File

@ -6775,6 +6775,8 @@ ide/exttooldialog.pas svneol=native#text/pascal
ide/exttooleditdlg.lfm svneol=native#text/pascal
ide/exttooleditdlg.pas svneol=native#text/pascal
ide/exttools.pas svneol=native#text/plain
ide/exttoolsconsole.pas svneol=native#text/pascal
ide/exttoolside.pas svneol=native#text/pascal
ide/filereferencelist.pas svneol=native#text/pascal
ide/findinfilesdlg.lfm svneol=native#text/plain
ide/findinfilesdlg.pas svneol=native#text/pascal

View File

@ -394,9 +394,9 @@ type
FMessageLineClass: TMessageLineClass;
procedure CreateLines; virtual;
procedure FetchAllPending; virtual; // (main thread)
procedure ToolExited; virtual; // (main thread) called by InputClosed
procedure QueueAsyncOnChanged; virtual; abstract; // (worker thread)
procedure RemoveAsyncOnChanged; virtual; abstract; // (main or worker thread)
procedure ToolExited; virtual; // (main thread) called by InputClosed
procedure QueueAsyncOnChanged; virtual; // (worker thread)
procedure RemoveAsyncOnChanged; virtual; // (main or worker thread)
public
constructor Create(AOwner: TComponent); override; // (main thread)
destructor Destroy; override; // (main thread)
@ -450,7 +450,7 @@ type
ethStopped
);
TIDEExternalTools = class;
TExternalToolsBase = class;
TExternalToolGroup = class;
@ -476,7 +476,7 @@ type
FParsers: TFPList; // list of TExtToolParser
FReferences: TStringList;
FTitle: string;
FTools: TIDEExternalTools;
FTools: TExternalToolsBase;
FViews: TFPList; // list of TExtToolView
FCurrentDirectoryIsTestDir: boolean;
function GetCmdLineParams: string;
@ -521,7 +521,7 @@ type
property Hint: string read FHint write FHint; // this hint is shown in About dialog
property Data: TObject read FData write FData; // free for user, e.g. the IDE uses TIDEExternalToolData
property FreeData: boolean read FFreeData write FFreeData default false; // true = auto free Data on destroy
property Tools: TIDEExternalTools read FTools;
property Tools: TExternalToolsBase read FTools;
property Group: TExternalToolGroup read FGroup write SetGroup;
property EstimatedLoad: int64 read FEstimatedLoad write FEstimatedLoad default 1; // used for deciding which tool to run next
@ -623,10 +623,10 @@ type
property ErrorMessage: string read FErrorMessage write FErrorMessage;
end;
{ TIDEExternalTools
Implemented by the IDE. }
{ TExternalToolsBase
Implemented by an application or the IDE. }
TIDEExternalTools = class(TComponent)
TExternalToolsBase = class(TComponent)
private
function GetItems(Index: integer): TAbstractExternalTool; inline;
protected
@ -660,7 +660,7 @@ type
end;
var
ExternalToolList: TIDEExternalTools = nil; // will be set by the IDE
ExternalToolList: TExternalToolsBase = nil; // will be set by the IDE
type
{ TIDEExternalToolOptions }
@ -1183,8 +1183,8 @@ end;
constructor TAbstractExternalTool.Create(AOwner: TComponent);
begin
if AOwner is TIDEExternalTools then
FTools:=TIDEExternalTools(AOwner);
if AOwner is TExternalToolsBase then
FTools:=TExternalToolsBase(AOwner);
inherited Create(AOwner);
if FWorkerMessagesClass=nil then
FWorkerMessagesClass:=TMessageLine;
@ -1582,33 +1582,33 @@ begin
Result:=0;
end;
{ TIDEExternalTools }
{ TExternalToolsBase }
// inline
function TIDEExternalTools.GetItems(Index: integer): TAbstractExternalTool;
function TExternalToolsBase.GetItems(Index: integer): TAbstractExternalTool;
begin
Result:=TAbstractExternalTool(fItems[Index]);
end;
// inline
function TIDEExternalTools.Count: integer;
function TExternalToolsBase.Count: integer;
begin
Result:=fItems.Count;
end;
function TIDEExternalTools.AddDummy(Title: string): TAbstractExternalTool;
function TExternalToolsBase.AddDummy(Title: string): TAbstractExternalTool;
begin
Result:=Add(Title);
Result.Terminate;
end;
constructor TIDEExternalTools.Create(aOwner: TComponent);
constructor TExternalToolsBase.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
fItems:=TFPList.Create;
end;
destructor TIDEExternalTools.Destroy;
destructor TExternalToolsBase.Destroy;
begin
inherited Destroy;
FreeAndNil(fItems);
@ -1616,7 +1616,7 @@ begin
ExternalToolList:=nil;
end;
procedure TIDEExternalTools.ConsistencyCheck;
procedure TExternalToolsBase.ConsistencyCheck;
var
i: Integer;
begin
@ -1624,7 +1624,7 @@ begin
Items[i].ConsistencyCheck;
end;
function TIDEExternalTools.GetMsgPattern(SubTool: string; MsgID: integer; out
function TExternalToolsBase.GetMsgPattern(SubTool: string; MsgID: integer; out
Urgency: TMessageLineUrgency): string;
var
Parser: TExtToolParserClass;
@ -1639,7 +1639,7 @@ begin
end;
end;
function TIDEExternalTools.GetMsgHint(SubTool: string; MsgID: integer): string;
function TExternalToolsBase.GetMsgHint(SubTool: string; MsgID: integer): string;
var
Parser: TExtToolParserClass;
i: Integer;
@ -2296,7 +2296,17 @@ end;
procedure TExtToolView.ToolExited;
begin
;
end;
procedure TExtToolView.QueueAsyncOnChanged;
begin
raise Exception.Create('TExtToolView.QueueAsyncOnChanged should be overridden when needed.');
end;
procedure TExtToolView.RemoveAsyncOnChanged;
begin
;
end;
procedure TExtToolView.CreateLines;

View File

@ -17,10 +17,8 @@ interface
uses
Classes, SysUtils, contnrs,
// LCL
LCLProc, Forms,
// LazUtils
LazConfigStorage, LazMethodList,
LazConfigStorage, LazMethodList, LazLoggerBase, UITypes,
// IdeIntf
NewItemIntf, ProjPackIntf, PackageDependencyIntf;

View File

@ -183,7 +183,7 @@ type
destructor Destroy; override;
procedure SetupTransferMacros;
procedure TranslateMacros;
procedure SetupExternalTools;
procedure SetupExternalTools(aToolsClass: TExternalToolsClass);
procedure SetupCompilerInterface;
procedure SetupInputHistories(aInputHist: TInputHistories);
procedure EnvOptsChanged;
@ -519,10 +519,10 @@ begin
tr('MakeFile',lisTMFunctionChompPathDelimiter);
end;
procedure TBuildManager.SetupExternalTools;
procedure TBuildManager.SetupExternalTools(aToolsClass: TExternalToolsClass);
begin
// setup the external tool queue
ExternalTools:=TExternalTools.Create(Self);
ExternalTools:=aToolsClass.Create(Self);
EnvOptsChanged;
RegisterFPCParser;
RegisterPas2jsParser;

View File

@ -57,6 +57,7 @@ type
TLMsgWndView = class(TLazExtToolView)
private
FAsyncQueued: boolean;
FControl: TMessagesCtrl;
FFilter: TLMsgViewFilter;
fPaintBottom: integer; // only valid if FPaintStamp=Control.FPaintStamp
@ -65,10 +66,13 @@ type
FPendingChanges: TETMultiSrcChanges;
procedure SetFilter(AValue: TLMsgViewFilter);
procedure OnMarksFixed(ListOfTMessageLine: TFPList); // (main thread) called after mlfFixed was added to these messages
procedure CallOnChangedInMainThread({%H-}Data: PtrInt); // (main thread)
protected
procedure SetToolState(AValue: TLMVToolState); override;
procedure FetchAllPending; override; // (main thread)
procedure ToolExited; override; // (main thread)
procedure QueueAsyncOnChanged; override; // (worker thread)
procedure RemoveAsyncOnChanged; override; // (worker thread)
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
@ -733,6 +737,30 @@ begin
ToolState:=lmvtsSuccess;
end;
procedure TLMsgWndView.CallOnChangedInMainThread(Data: PtrInt);
begin
FAsyncQueued:=false;
if csDestroying in ComponentState then exit;
if Assigned(OnChanged) then
OnChanged(Self);
end;
procedure TLMsgWndView.QueueAsyncOnChanged;
begin
if FAsyncQueued then exit;
FAsyncQueued:=true;
if Application<>nil then
Application.QueueAsyncCall(@CallOnChangedInMainThread,0);
end;
procedure TLMsgWndView.RemoveAsyncOnChanged;
begin
if not FAsyncQueued then exit;
FAsyncQueued:=false;
if Application<>nil then
Application.RemoveAsyncCalls(Self);
end;
constructor TLMsgWndView.Create(AOwner: TComponent);
begin
fMessageLineClass:=TLMsgViewLine;

View File

@ -36,18 +36,11 @@ interface
uses
// RTL + FCL
Classes, SysUtils, math, process, Pipes, Laz_AVL_Tree,
// LCL
{$IFDEF VerboseExtToolThread}
LCLProc,
{$ENDIF}
LCLIntf, Forms, Dialogs,
// CodeTools
FileProcs,
// LazUtils
FileUtil, LazFileUtils, LazUtilities, UTF8Process, LazUTF8, AvgLvlTree,
FileUtil, LazFileUtils, LazUtilities, LazLoggerBase, UTF8Process, LazUTF8,
UITypes, AvgLvlTree,
// IDEIntf
IDEExternToolIntf, BaseIDEIntf, MacroIntf, IDEMsgIntf, IDEDialogs,
PackageIntf, LazIDEIntf,
IDEExternToolIntf, BaseIDEIntf, MacroIntf, LazMsgDialogs,
// IDE
IDECmdLine, TransferMacros, LazarusIDEStrConsts;
@ -63,53 +56,13 @@ type
TLazExtToolView = class(TExtToolView)
private
FAsyncQueued: boolean;
FToolState: TLMVToolState;
protected
procedure SetToolState(AValue: TLMVToolState); virtual;
procedure CallOnChangedInMainThread({%H-}Data: PtrInt); // (main thread)
procedure QueueAsyncOnChanged; override; // (worker thread)
procedure RemoveAsyncOnChanged; override; // (worker thread)
public
property ToolState: TLMVToolState read FToolState write SetToolState;
end;
{ TLazExtToolConsoleView }
TLazExtToolConsoleView = class(TLazExtToolView)
protected
fWrittenLineCount: integer;
procedure ToolExited; override; // (main thread)
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure InputClosed; override; // (main thread)
procedure ProcessNewMessages({%H-}AThread: TThread); override; // (worker thread, Tool is in Critical section)
procedure OnNewOutput(Sender: TObject; {%H-}FirstNewMsgLine: integer); // (main thread)
end;
{ TLazExtToolConsole }
TLazExtToolConsole = class(TComponent)
private
FTerminating: boolean;
fViews: TFPList; // list of TLazExtToolConsoleView
function GetViews(Index: integer): TLazExtToolConsoleView;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Clear;
function CreateView(Tool: TAbstractExternalTool): TLazExtToolConsoleView;
function FindUnfinishedView: TLazExtToolConsoleView;
property Views[Index: integer]: TLazExtToolConsoleView read GetViews;
function Count: integer; inline;
property Terminating: boolean read FTerminating write FTerminating;
end;
var
ExtToolConsole: TLazExtToolConsole = nil; // set by lazbuild
type
TExternalTool = class;
{ TExternalToolThread }
@ -142,16 +95,15 @@ type
procedure SetThread(AValue: TExternalToolThread); // main or worker thread
procedure SynchronizedImproveMessages; // (main thread) called by AddOutputLines
procedure DoTerminate; // (main thread)
procedure SyncAutoFree({%H-}aData: PtrInt); // (main thread)
protected
procedure DoExecute; override; // (main thread)
procedure DoStart; // (main thread)
procedure CreateView; // (main thread)
procedure DoExecute; override; // (main thread)
procedure DoStart; // (main thread)
procedure CreateView; virtual; abstract; // (main thread)
function GetExecuteAfter(Index: integer): TAbstractExternalTool; override;
function GetExecuteBefore(Index: integer): TAbstractExternalTool; override;
procedure Notification(AComponent: TComponent; Operation: TOperation);
override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
function CanFree: boolean; override;
procedure QueueAsyncAutoFree; virtual; abstract;
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
@ -170,9 +122,11 @@ type
function GetLongestEstimatedLoad: int64;
end;
TExternalToolClass = class of TExternalTool;
{ TExternalTools }
TExternalTools = class(TIDEExternalTools)
TExternalTools = class(TExternalToolsBase)
private
FCritSec: TRTLCriticalSection;
fRunning: TFPList; // list of TExternalTool, needs Enter/LeaveCriticalSection
@ -181,11 +135,12 @@ type
function GetRunningTools(Index: integer): TExternalTool;
procedure AddRunningTool(Tool: TExternalTool); // (worker thread)
procedure RemoveRunningTool(Tool: TExternalTool); // (worker thread)
function OnRunExternalTool(ToolOptions: TIDEExternalToolOptions): boolean; // (main thread)
protected
FToolClass: TExternalToolClass;
function GetParsers(Index: integer): TExtToolParserClass; override;
procedure Notification(AComponent: TComponent; Operation: TOperation);
override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
function RunToolAndDetach(ToolOptions: TIDEExternalToolOptions): boolean;
function RunToolWithParsers(ToolOptions: TIDEExternalToolOptions): boolean;
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
@ -201,8 +156,6 @@ type
property RunningTools[Index: integer]: TExternalTool read GetRunningTools;
procedure EnterCriticalSection; override;
procedure LeaveCriticalSection; override;
function GetIDEObject(ToolData: TIDEExternalToolData): TObject; override;
procedure HandleMesages; override;
// parsers
function ParserCount: integer; override;
procedure RegisterParser(Parser: TExtToolParserClass); override;
@ -213,131 +166,13 @@ type
function GetMsgTool(Msg: TMessageLine): TAbstractExternalTool; override;
end;
TExternalToolsClass = class of TExternalTools;
var
ExternalTools: TExternalTools = nil;
implementation
{ TLazExtToolConsole }
// inline
function TLazExtToolConsole.Count: integer;
begin
Result:=fViews.Count;
end;
function TLazExtToolConsole.GetViews(Index: integer): TLazExtToolConsoleView;
begin
Result:=TLazExtToolConsoleView(fViews[Index]);
end;
constructor TLazExtToolConsole.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fViews:=TFPList.Create;
ExtToolConsole:=Self;
end;
destructor TLazExtToolConsole.Destroy;
begin
Clear;
FreeAndNil(fViews);
ExtToolConsole:=nil;
inherited Destroy;
end;
procedure TLazExtToolConsole.Clear;
var
i: Integer;
begin
while FindUnfinishedView<>nil do begin
if Application<>nil then
Application.ProcessMessages
else
CheckSynchronize;
Sleep(10);
end;
for i:=Count-1 downto 0 do begin
if i>=Count then continue;
Views[i].Free;
end;
if Count>0 then
raise Exception.Create('TLazExtToolConsole.Clear: some views failed to free');
end;
function TLazExtToolConsole.CreateView(Tool: TAbstractExternalTool
): TLazExtToolConsoleView;
begin
Result:=TLazExtToolConsoleView.Create(Self);
Result.Caption:=Tool.Title;
Tool.AddHandlerOnNewOutput(@Result.OnNewOutput);
fViews.Add(Result);
end;
function TLazExtToolConsole.FindUnfinishedView: TLazExtToolConsoleView;
var
i: Integer;
begin
for i:=0 to fViews.Count-1 do begin
Result:=Views[i];
if not Result.HasFinished then exit;
end;
Result:=nil;
end;
{ TLazExtToolConsoleView }
procedure TLazExtToolConsoleView.ToolExited;
begin
inherited ToolExited;
if Tool.Terminated then begin
ToolState:=lmvtsFailed;
debugln('Error: (lazarus) ',Caption,': terminated');
end else if (ExitStatus<>0) then begin
ToolState:=lmvtsFailed;
debugln('Error: (lazarus) ',Caption,': stopped with exit code '+IntToStr(ExitStatus));
end else if Tool.ErrorMessage<>'' then begin
ToolState:=lmvtsFailed;
debugln('Error: (lazarus) ',Caption,': ',Tool.ErrorMessage);
end else begin
ToolState:=lmvtsSuccess;
end;
end;
procedure TLazExtToolConsoleView.ProcessNewMessages(AThread: TThread);
begin
end;
procedure TLazExtToolConsoleView.OnNewOutput(Sender: TObject;
FirstNewMsgLine: integer);
begin
if (ExtToolConsole<>nil) and ExtToolConsole.Terminating then
exit;
while fWrittenLineCount<Tool.WorkerOutput.Count do begin
debugln(Tool.WorkerOutput[fWrittenLineCount]);
inc(fWrittenLineCount);
end;
end;
constructor TLazExtToolConsoleView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;
destructor TLazExtToolConsoleView.Destroy;
begin
if Owner is TLazExtToolConsole then
TLazExtToolConsole(Owner).fViews.Remove(Self);
inherited Destroy;
end;
procedure TLazExtToolConsoleView.InputClosed;
begin
inherited InputClosed;
Free;
end;
{ TLazExtToolView }
procedure TLazExtToolView.SetToolState(AValue: TLMVToolState);
@ -346,30 +181,6 @@ begin
FToolState:=AValue;
end;
procedure TLazExtToolView.CallOnChangedInMainThread(Data: PtrInt);
begin
FAsyncQueued:=false;
if csDestroying in ComponentState then exit;
if Assigned(OnChanged) then
OnChanged(Self);
end;
procedure TLazExtToolView.QueueAsyncOnChanged;
begin
if FAsyncQueued then exit;
FAsyncQueued:=true;
if Application<>nil then
Application.QueueAsyncCall(@CallOnChangedInMainThread,0);
end;
procedure TLazExtToolView.RemoveAsyncOnChanged;
begin
if not FAsyncQueued then exit;
FAsyncQueued:=false;
if Application<>nil then
Application.RemoveAsyncCalls(Self);
end;
{ TExternalTool }
procedure TExternalTool.ProcessRunning;
@ -595,12 +406,8 @@ begin
if CallAutoFree then begin
if MainThreadID=GetCurrentThreadId then
AutoFree
else if (Application<>nil) then
Application.QueueAsyncCall(@SyncAutoFree,0)
else
begin
debugln(['WARNING: (lazarus) TExternalTool.SetThread can not call AutoFree from other thread']);
end;
QueueAsyncAutoFree;
end;
end;
@ -816,25 +623,6 @@ begin
Thread.Start;
end;
procedure TExternalTool.CreateView;
var
View: TExtToolView;
begin
if ViewCount>0 then exit;
View:=nil;
if ExtToolConsole<>nil then begin
// in console mode (lazbuild) all output goes unparsed to console
ClearParsers;
View:=ExtToolConsole.CreateView(Self);
end else if (ViewCount=0) and (ParserCount>0) then begin
// this tool generates parsed output => auto create view
if IDEMessagesWindow<>nil then
View:=IDEMessagesWindow.CreateView(Title);
end;
if View<>nil then
AddView(View);
end;
function TExternalTool.ExecuteBeforeCount: integer;
begin
Result:=fExecuteBefore.Count;
@ -882,13 +670,7 @@ begin
Process.Terminate(AbortedExitCode);
end;
procedure TExternalTool.SyncAutoFree(aData: PtrInt);
begin
AutoFree;
end;
procedure TExternalTool.Notification(AComponent: TComponent;
Operation: TOperation);
procedure TExternalTool.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if Operation=opRemove then begin
@ -1034,7 +816,7 @@ end;
procedure TExternalTool.WaitForExit;
var
MyTools: TIDEExternalTools;
MyTools: TExternalToolsBase;
begin
MyTools:=Tools;
repeat
@ -1047,10 +829,10 @@ begin
end;
// call synchronized tasks, this might free this tool
if MainThreadID=ThreadID then
if Application<>nil then
Application.ProcessMessages
else
CheckSynchronize;
begin
Assert(Owner is TExternalToolsBase, 'TExternalTool.WaitForExit: Owner is not TExternalToolsBase.');
TExternalToolsBase(Owner).HandleMesages;
end;
// check if this tool still exists
if MyTools.IndexOf(Self)<0 then exit;
// still running => wait
@ -1067,7 +849,7 @@ function TExternalTool.ResolveMacros: boolean;
if Result then exit;
if ErrorMessage='' then
ErrorMessage:=Format(lisInvalidMacrosIn, [aValue]);
IDEMessageDialog(lisCCOErrorCaption, Format(lisInvalidMacrosInExternalTool,
LazMessageDialog(lisCCOErrorCaption, Format(lisInvalidMacrosInExternalTool,
[aValue, Title]),
mtError,[mbCancel]);
end;
@ -1108,179 +890,171 @@ end;
{ TExternalTools }
function TExternalTools.OnRunExternalTool(ToolOptions: TIDEExternalToolOptions
): boolean;
function TExternalTools.RunToolAndDetach(ToolOptions: TIDEExternalToolOptions): boolean;
// simply run and detach
var
i: Integer;
Proc: TProcessUTF8;
sl: TStringList;
s, Path: String;
begin
Result:=false;
Proc:=TProcessUTF8.Create(nil);
try
Proc.InheritHandles:=false;
// working directory
s:=ToolOptions.WorkingDirectory;
if ToolOptions.ResolveMacros then begin
if not GlobalMacroList.SubstituteStr(s) then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: macros of WorkerDirectory: "',ToolOptions.WorkingDirectory,'"']);
exit;
end;
end;
s:=ChompPathDelim(CleanAndExpandDirectory(s));
if not DirectoryExistsUTF8(s) then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: missing directory "',s,'"']);
exit;
end;
Proc.CurrentDirectory:=s;
// environment
if ToolOptions.EnvironmentOverrides.Count>0 then
AssignEnvironmentTo(Proc.Environment,ToolOptions.EnvironmentOverrides);
if ToolOptions.ResolveMacros then begin
for i:=0 to Proc.Environment.Count-1 do begin
s:=Proc.Environment[i];
if not GlobalMacroList.SubstituteStr(s) then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: environment override "',Proc.Environment,'"']);
exit;
end;
Proc.Environment[i]:=s;
end;
end;
// executable
s:=ToolOptions.Executable;
if ToolOptions.ResolveMacros then begin
if not GlobalMacroList.SubstituteStr(s) then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: macros of Executable: "',ToolOptions.Executable,'"']);
exit;
end;
end;
if not FilenameIsAbsolute(s) then begin
// search in PATH
if Proc.Environment.Count>0 then
Path:=Proc.Environment.Values['PATH']
else
Path:=GetEnvironmentVariableUTF8('PATH');
s:=SearchFileInPath(s,Proc.CurrentDirectory,
Path, PathSeparator,
[]);
{$IFDEF Windows}
if (s='') and (ExtractFileExt(s)='') then begin
s:=SearchFileInPath(s+'.exe',Proc.CurrentDirectory,
Path, PathSeparator,
[]);
end;
{$ENDIF}
if s='' then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: missing executable "',ToolOptions.Executable,'"']);
exit;
end;
end;
if not ( FilenameIsAbsolute(s) and FileExistsUTF8(s) ) then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: missing executable: "',s,'"']);
exit;
end;
if DirectoryExistsUTF8(s) then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: executable is a directory: "',s,'"']);
exit;
end;
if not FileIsExecutable(s) then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: executable lacks permission to run: "',s,'"']);
exit;
end;
Proc.Executable:=s;
// params
s:=ToolOptions.CmdLineParams;
if ToolOptions.ResolveMacros then begin
if not GlobalMacroList.SubstituteStr(s) then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolAndDetach] ',ToolOptions.Title,' failed: macros in cmd line params "',ToolOptions.CmdLineParams,'"']);
exit;
end;
end;
sl:=TStringList.Create;
try
SplitCmdLineParams(s,sl);
Proc.Parameters:=sl;
finally
sl.Free;
end;
// run and detach
if ToolOptions.ShowConsole then
Proc.Options:=Proc.Options+[poNewConsole]-[poNoConsole]
else
Proc.Options:=Proc.Options-[poNewConsole]+[poNoConsole];
if ToolOptions.HideWindow then
Proc.ShowWindow:=swoHide
else
Proc.ShowWindow:=swoShow;
try
Proc.Execute;
except
end;
finally
Proc.Free;
end;
end;
function TExternalTools.RunToolWithParsers(ToolOptions: TIDEExternalToolOptions): boolean;
// run with parsers and messages
var
Tool: TAbstractExternalTool;
i: Integer;
Proc: TProcessUTF8;
s: String;
sl: TStringList;
Path: String;
begin
{$IFDEF VerboseExtToolThread}
debugln(['TExternalTools.OnRunExternalTool ',ToolOptions.Title,' exe="',ToolOptions.Executable,'" params="',ToolOptions.CmdLineParams,'"']);
debugln(['TExternalTools.RunToolWithParsers run with scanners ...']);
{$ENDIF}
Result:=false;
if (ToolOptions.Parsers.Count=0) and (ExtToolConsole=nil) then begin
// simply run and detach
Proc:=TProcessUTF8.Create(nil);
try
Proc.InheritHandles:=false;
// working directory
s:=ToolOptions.WorkingDirectory;
if ToolOptions.ResolveMacros then begin
if not GlobalMacroList.SubstituteStr(s) then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: macros of WorkerDirectory: "',ToolOptions.WorkingDirectory,'"']);
exit;
end;
end;
s:=ChompPathDelim(CleanAndExpandDirectory(s));
if not DirectoryExistsUTF8(s) then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: missing directory "',s,'"']);
exit;
end;
Proc.CurrentDirectory:=s;
// environment
if ToolOptions.EnvironmentOverrides.Count>0 then
AssignEnvironmentTo(Proc.Environment,ToolOptions.EnvironmentOverrides);
if ToolOptions.ResolveMacros then begin
for i:=0 to Proc.Environment.Count-1 do begin
s:=Proc.Environment[i];
if not GlobalMacroList.SubstituteStr(s) then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: environment override "',Proc.Environment,'"']);
exit;
end;
Proc.Environment[i]:=s;
end;
end;
// executable
s:=ToolOptions.Executable;
if ToolOptions.ResolveMacros then begin
if not GlobalMacroList.SubstituteStr(s) then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: macros of Executable: "',ToolOptions.Executable,'"']);
exit;
end;
end;
if not FilenameIsAbsolute(s) then begin
// search in PATH
if Proc.Environment.Count>0 then
Path:=Proc.Environment.Values['PATH']
else
Path:=GetEnvironmentVariableUTF8('PATH');
s:=SearchFileInPath(s,Proc.CurrentDirectory,
Path, PathSeparator,
[]);
{$IFDEF Windows}
if (s='') and (ExtractFileExt(s)='') then begin
s:=SearchFileInPath(s+'.exe',Proc.CurrentDirectory,
Path, PathSeparator,
[]);
end;
{$ENDIF}
if s='' then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: missing executable "',ToolOptions.Executable,'"']);
exit;
end;
end;
if (not FilenameIsAbsolute(s))
or (not FileExistsUTF8(s)) then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: missing executable: "',s,'"']);
exit;
end;
if DirectoryExistsUTF8(s) then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: executable is a directory: "',s,'"']);
exit;
end;
if not FileIsExecutable(s) then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: executable lacks permission to run: "',s,'"']);
exit;
end;
Proc.Executable:=s;
// params
s:=ToolOptions.CmdLineParams;
if ToolOptions.ResolveMacros then begin
if not GlobalMacroList.SubstituteStr(s) then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] ',ToolOptions.Title,' failed: macros in cmd line params "',ToolOptions.CmdLineParams,'"']);
exit;
end;
end;
sl:=TStringList.Create;
try
SplitCmdLineParams(s,sl);
Proc.Parameters:=sl;
finally
sl.Free;
end;
// run and detach
{$IF FPC_FULLVERSION<20604}
Proc.InheritHandles:=false;
{$ENDIF}
if ToolOptions.ShowConsole then
Proc.Options:=Proc.Options+[poNewConsole]-[poNoConsole]
else
Proc.Options:=Proc.Options-[poNewConsole]+[poNoConsole];
if ToolOptions.HideWindow then
Proc.ShowWindow:=swoHide
else
Proc.ShowWindow:=swoShow;
try
Proc.Execute;
except
end;
finally
Proc.Free;
Tool:=Add(ToolOptions.Title);
Tool.Reference(Self,ClassName);
try
Tool.Hint:=ToolOptions.Hint;
Tool.Process.CurrentDirectory:=ToolOptions.WorkingDirectory;
Tool.Process.Executable:=ToolOptions.Executable;
Tool.CmdLineParams:=ToolOptions.CmdLineParams;
Tool.EnvironmentOverrides:=ToolOptions.EnvironmentOverrides;
Assert(Assigned(ToolOptions.Parsers), 'TExternalTools.RunToolWithParsers: Parsers=Nil.');
for i:=0 to ToolOptions.Parsers.Count-1 do
Tool.AddParsers(ToolOptions.Parsers[i]);
if ToolOptions.ShowConsole then
Tool.Process.Options:=Tool.Process.Options+[poNewConsole]-[poNoConsole]
else
Tool.Process.Options:=Tool.Process.Options-[poNewConsole]+[poNoConsole];
if ToolOptions.HideWindow then
Tool.Process.ShowWindow:=swoHide
else
Tool.Process.ShowWindow:=swoShow;
if ToolOptions.ResolveMacros and not Tool.ResolveMacros then begin
debugln(['Error: (lazarus) [TExternalTools.RunToolWithParsers] failed to resolve macros']);
exit;
end;
end else begin
// run with parsers and messages
{$IFDEF VerboseExtToolThread}
debugln(['TExternalTools.OnRunExternalTool run with scanners ...']);
debugln(['TExternalTools.RunToolWithParsers Execute ',Tool.Title,' WD="',Tool.Process.CurrentDirectory,'" Exe="',Tool.Process.Executable,'" Params="',Tool.CmdLineParams,'" ...']);
{$ENDIF}
Tool:=Add(ToolOptions.Title);
Tool.Reference(Self,ClassName);
try
Tool.Hint:=ToolOptions.Hint;
Tool.Process.CurrentDirectory:=ToolOptions.WorkingDirectory;
Tool.Process.Executable:=ToolOptions.Executable;
Tool.CmdLineParams:=ToolOptions.CmdLineParams;
Tool.EnvironmentOverrides:=ToolOptions.EnvironmentOverrides;
if ExtToolConsole=nil then
for i:=0 to ToolOptions.Parsers.Count-1 do
Tool.AddParsers(ToolOptions.Parsers[i]);
if ToolOptions.ShowConsole then
Tool.Process.Options:=Tool.Process.Options+[poNewConsole]-[poNoConsole]
else
Tool.Process.Options:=Tool.Process.Options-[poNewConsole]+[poNoConsole];
if ToolOptions.HideWindow then
Tool.Process.ShowWindow:=swoHide
else
Tool.Process.ShowWindow:=swoShow;
if ToolOptions.ResolveMacros then begin
if not Tool.ResolveMacros then begin
debugln(['Error: (lazarus) [TExternalTools.OnRunExternalTool] failed to resolve macros']);
exit;
end;
end;
{$IFDEF VerboseExtToolThread}
debugln(['TExternalTools.OnRunExternalTool Execute ',Tool.Title,' WD="',Tool.Process.CurrentDirectory,'" Exe="',Tool.Process.Executable,'" Params="',Tool.CmdLineParams,'" ...']);
{$ENDIF}
Tool.Execute;
{$IFDEF VerboseExtToolThread}
debugln(['TExternalTools.OnRunExternalTool WaitForExit ',Tool.Title,' ...']);
{$ENDIF}
Tool.WaitForExit;
{$IFDEF VerboseExtToolThread}
debugln(['TExternalTools.OnRunExternalTool Done ',Tool.Title]);
{$ENDIF}
Result:=(Tool.ErrorMessage='') and (not Tool.Terminated) and (Tool.ExitStatus=0);
finally
Tool.Release(Self);
end;
Tool.Execute;
{$IFDEF VerboseExtToolThread}
debugln(['TExternalTools.RunToolWithParsers WaitForExit ',Tool.Title,' ...']);
{$ENDIF}
Tool.WaitForExit;
{$IFDEF VerboseExtToolThread}
debugln(['TExternalTools.RunToolWithParsers Done ',Tool.Title]);
{$ENDIF}
Result:=(Tool.ErrorMessage='') and (not Tool.Terminated) and (Tool.ExitStatus=0);
finally
Tool.Release(Self);
end;
end;
@ -1320,8 +1094,7 @@ begin
Result:=TExtToolParserClass(fParsers[Index]);
end;
procedure TExternalTools.Notification(AComponent: TComponent;
Operation: TOperation);
procedure TExternalTools.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if Operation=opRemove then begin
@ -1348,7 +1121,6 @@ begin
ExternalToolList:=Self;
if ExternalTools=nil then
ExternalTools:=Self;
RunExternalTool:=@OnRunExternalTool;
end;
destructor TExternalTools.Destroy;
@ -1374,7 +1146,7 @@ end;
function TExternalTools.Add(Title: string): TAbstractExternalTool;
begin
Result:=TExternalTool.Create(Self);
Result:=FToolClass.Create(Self);
Result.Title:=Title;
fItems.Add(Result);
end;
@ -1427,18 +1199,15 @@ begin
end;
procedure TExternalTools.TerminateAll;
// terminate all current tools
var
i: Integer;
begin
// terminate all current tools
if ExtToolConsole<>nil then
ExtToolConsole.Terminating:=true;
for i:=Count-1 downto 0 do begin
if i>=Count then continue;
for i:=Count-1 downto 0 do
begin
Assert(i<Count, 'TExternalTools.TerminateAll: xxx'); // if i>=Count then continue; <- why was this?
Terminate(Items[i] as TExternalTool);
end;
if ExtToolConsole<>nil then
ExtToolConsole.Terminating:=false;
end;
procedure TExternalTools.Clear;
@ -1463,27 +1232,6 @@ begin
System.LeaveCriticalsection(FCritSec);
end;
function TExternalTools.GetIDEObject(ToolData: TIDEExternalToolData): TObject;
begin
Result:=nil;
if ToolData=nil then exit;
if ToolData.Kind=IDEToolCompileProject then begin
Result:=LazarusIDE.ActiveProject;
end else if ToolData.Kind=IDEToolCompilePackage then begin
Result:=PackageEditingInterface.FindPackageWithName(ToolData.ModuleName);
end else if ToolData.Kind=IDEToolCompileIDE then begin
Result:=LazarusIDE;
end;
end;
procedure TExternalTools.HandleMesages;
begin
if Application<>nil then
Application.ProcessMessages
else
CheckSynchronize;
end;
procedure TExternalTools.RegisterParser(Parser: TExtToolParserClass);
begin
if fParsers.IndexOf(Parser)>=0 then exit;
@ -1496,8 +1244,7 @@ begin
fParsers.Remove(Parser);
end;
function TExternalTools.FindParserForTool(const SubTool: string
): TExtToolParserClass;
function TExternalTools.FindParserForTool(const SubTool: string): TExtToolParserClass;
var
i: Integer;
begin
@ -1508,8 +1255,7 @@ begin
Result:=nil;
end;
function TExternalTools.FindParserWithName(const ParserName: string
): TExtToolParserClass;
function TExternalTools.FindParserWithName(const ParserName: string): TExtToolParserClass;
var
i: Integer;
begin

264
ide/exttoolsconsole.pas Normal file
View File

@ -0,0 +1,264 @@
unit ExtToolsConsole;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
// LazUtils
LazLogger,
// IDEIntf
IDEExternToolIntf,
// IDE
ExtTools;
type
{ TLazExtToolConsoleView }
TLazExtToolConsoleView = class(TLazExtToolView)
protected
fWrittenLineCount: integer;
procedure ToolExited; override; // (main thread)
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure InputClosed; override; // (main thread)
procedure ProcessNewMessages({%H-}AThread: TThread); override; // (worker thread, Tool is in Critical section)
procedure OnNewOutput(Sender: TObject; {%H-}FirstNewMsgLine: integer); // (main thread)
end;
{ TLazExtToolConsole }
TLazExtToolConsole = class(TComponent)
private
FTerminating: boolean;
fViews: TFPList; // list of TLazExtToolConsoleView
function GetViews(Index: integer): TLazExtToolConsoleView;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Clear;
function FindUnfinishedView: TLazExtToolConsoleView;
property Views[Index: integer]: TLazExtToolConsoleView read GetViews;
function Count: integer; inline;
end;
{ TExternalToolConsole }
// ToDo: Replace TLazExtToolConsole with this TExternalToolConsole somehow.
TExternalToolConsole = class(TExternalTool)
private
protected
procedure CreateView; override;
procedure QueueAsyncAutoFree; override;
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
end;
{ TExternalToolsConsole }
TExternalToolsConsole = class(TExternalTools)
private
function RunExtToolHandler(ToolOptions: TIDEExternalToolOptions): boolean;
protected
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
procedure TerminateAll; override;
function GetIDEObject(ToolData: TIDEExternalToolData): TObject; override;
procedure HandleMesages; override;
end;
var
ExtToolConsole: TLazExtToolConsole = nil; // set by lazbuild
implementation
{ TLazExtToolConsoleView }
constructor TLazExtToolConsoleView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;
destructor TLazExtToolConsoleView.Destroy;
begin
Assert(Owner is TLazExtToolConsole, 'TLazExtToolConsoleView.Destroy: Owner is not TLazExtToolConsole.');
TLazExtToolConsole(Owner).fViews.Remove(Self);
inherited Destroy;
end;
procedure TLazExtToolConsoleView.ToolExited;
begin
inherited ToolExited;
if Tool.Terminated then begin
ToolState:=lmvtsFailed;
debugln('Error: (lazarus) ',Caption,': terminated');
end else if (ExitStatus<>0) then begin
ToolState:=lmvtsFailed;
debugln('Error: (lazarus) ',Caption,': stopped with exit code '+IntToStr(ExitStatus));
end else if Tool.ErrorMessage<>'' then begin
ToolState:=lmvtsFailed;
debugln('Error: (lazarus) ',Caption,': ',Tool.ErrorMessage);
end else begin
ToolState:=lmvtsSuccess;
end;
end;
procedure TLazExtToolConsoleView.ProcessNewMessages(AThread: TThread);
begin
end;
procedure TLazExtToolConsoleView.OnNewOutput(Sender: TObject;
FirstNewMsgLine: integer);
begin
if (ExtToolConsole<>nil) and ExtToolConsole.FTerminating then
exit;
while fWrittenLineCount<Tool.WorkerOutput.Count do begin
debugln(Tool.WorkerOutput[fWrittenLineCount]);
inc(fWrittenLineCount);
end;
end;
procedure TLazExtToolConsoleView.InputClosed;
begin
inherited InputClosed;
Free;
end;
{ TLazExtToolConsole }
constructor TLazExtToolConsole.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fViews:=TFPList.Create;
ExtToolConsole:=Self;
end;
destructor TLazExtToolConsole.Destroy;
begin
Clear;
FreeAndNil(fViews);
ExtToolConsole:=nil;
inherited Destroy;
end;
// inline
function TLazExtToolConsole.Count: integer;
begin
Result:=fViews.Count;
end;
function TLazExtToolConsole.GetViews(Index: integer): TLazExtToolConsoleView;
begin
Result:=TLazExtToolConsoleView(fViews[Index]);
end;
procedure TLazExtToolConsole.Clear;
var
i: Integer;
begin
while FindUnfinishedView<>nil do begin
CheckSynchronize;
Sleep(10);
end;
for i:=Count-1 downto 0 do begin
if i>=Count then continue;
Views[i].Free;
end;
if Count>0 then
raise Exception.Create('TLazExtToolConsole.Clear: some views failed to free');
end;
function TLazExtToolConsole.FindUnfinishedView: TLazExtToolConsoleView;
var
i: Integer;
begin
for i:=0 to fViews.Count-1 do begin
Result:=Views[i];
if not Result.HasFinished then exit;
end;
Result:=nil;
end;
{ TExternalToolConsole }
constructor TExternalToolConsole.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
end;
destructor TExternalToolConsole.Destroy;
begin
inherited Destroy;
end;
procedure TExternalToolConsole.CreateView;
// in console mode all output goes unparsed to console
var
View: TLazExtToolConsoleView;
begin
if ViewCount>0 then exit;
ClearParsers;
//View := ExtToolConsole.CreateView(Self);
View := TLazExtToolConsoleView.Create(ExtToolConsole);
View.Caption:=Self.Title;
AddHandlerOnNewOutput(@View.OnNewOutput);
ExtToolConsole.fViews.Add(View); // ToDo: Eliminate ExtToolConsole.
AddView(View);
end;
procedure TExternalToolConsole.QueueAsyncAutoFree;
begin
debugln(['WARNING: TExternalTool.SetThread can not call AutoFree from other thread']);
end;
{ TExternalToolsConsole }
constructor TExternalToolsConsole.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FToolClass := TExternalToolConsole;
RunExternalTool := @RunExtToolHandler;
end;
destructor TExternalToolsConsole.Destroy;
begin
inherited Destroy;
end;
function TExternalToolsConsole.RunExtToolHandler(ToolOptions: TIDEExternalToolOptions): boolean;
begin
{$IFDEF VerboseExtToolThread}
debugln(['TExternalToolsConsole.RunExtToolHandler ',ToolOptions.Title,' exe="',ToolOptions.Executable,'" params="',ToolOptions.CmdLineParams,'"']);
{$ENDIF}
Assert(ToolOptions.Parsers.Count=0, 'TExternalToolsConsole.RunExtToolHandler: Parsers.Count>0.');
Result := RunToolWithParsers(ToolOptions);
end;
procedure TExternalToolsConsole.TerminateAll;
begin
// ToDo: If the assertion never triggers, remove this whole method and var FTerminating.
Assert(ExtToolConsole=Nil, 'TExternalToolsConsole.TerminateAll: ExtToolConsole is assigned.');
//ExtToolConsole.FTerminating:=true;
inherited TerminateAll;
//ExtToolConsole.FTerminating:=false;
end;
function TExternalToolsConsole.GetIDEObject(ToolData: TIDEExternalToolData): TObject;
begin
raise Exception.Create('TExternalToolsConsole.GetIDEObject: Should not happen!');
end;
procedure TExternalToolsConsole.HandleMesages;
begin
if IsMultiThread then
CheckSynchronize;
end;
end.

126
ide/exttoolside.pas Normal file
View File

@ -0,0 +1,126 @@
unit ExtToolsIDE;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
// LCL
Forms,
// LazUtils
LazLogger,
// IDEIntf
IDEExternToolIntf, IDEMsgIntf, PackageIntf, LazIDEIntf,
// IDE
ExtTools;
type
{ TExternalToolIDE }
TExternalToolIDE = class(TExternalTool)
private
procedure SyncAutoFree({%H-}aData: PtrInt); // (main thread)
protected
procedure CreateView; override;
procedure QueueAsyncAutoFree; override;
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
end;
{ TExternalToolsIDE }
TExternalToolsIDE = class(TExternalTools)
private
function RunExtToolHandler(ToolOptions: TIDEExternalToolOptions): boolean;
protected
public
constructor Create(aOwner: TComponent); override;
destructor Destroy; override;
function GetIDEObject(ToolData: TIDEExternalToolData): TObject; override;
procedure HandleMesages; override;
end;
implementation
{ TExternalToolIDE }
constructor TExternalToolIDE.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
end;
destructor TExternalToolIDE.Destroy;
begin
inherited Destroy;
end;
procedure TExternalToolIDE.CreateView;
// this tool generates parsed output => auto create view
var
View: TExtToolView;
begin
if ViewCount>0 then exit;
if (ViewCount=0) and (ParserCount>0) and (IDEMessagesWindow<>nil) then
begin
View := IDEMessagesWindow.CreateView(Title);
if View<>nil then
AddView(View);
end;
end;
procedure TExternalToolIDE.SyncAutoFree(aData: PtrInt);
begin
AutoFree;
end;
procedure TExternalToolIDE.QueueAsyncAutoFree;
begin
Application.QueueAsyncCall(@SyncAutoFree,0);
end;
{ TExternalToolsIDE }
constructor TExternalToolsIDE.Create(aOwner: TComponent);
begin
inherited Create(aOwner);
FToolClass := TExternalToolIDE;
RunExternalTool := @RunExtToolHandler;
end;
destructor TExternalToolsIDE.Destroy;
begin
inherited Destroy;
end;
function TExternalToolsIDE.GetIDEObject(ToolData: TIDEExternalToolData): TObject;
begin
Result:=nil;
if ToolData=nil then exit;
if ToolData.Kind=IDEToolCompileProject then begin
Result:=LazarusIDE.ActiveProject;
end else if ToolData.Kind=IDEToolCompilePackage then begin
Result:=PackageEditingInterface.FindPackageWithName(ToolData.ModuleName);
end else if ToolData.Kind=IDEToolCompileIDE then begin
Result:=LazarusIDE;
end;
end;
procedure TExternalToolsIDE.HandleMesages;
begin
Application.ProcessMessages;
end;
function TExternalToolsIDE.RunExtToolHandler(ToolOptions: TIDEExternalToolOptions): boolean;
begin
{$IFDEF VerboseExtToolThread}
debugln(['TExternalToolsIDE.RunExtToolHandler ',ToolOptions.Title,' exe="',ToolOptions.Executable,'" params="',ToolOptions.CmdLineParams,'"']);
{$ENDIF}
//if ToolOptions.Parsers.Count=0 then
Result := RunToolAndDetach(ToolOptions)
end;
end.

View File

@ -65,7 +65,7 @@
<PackageName Value="SynEdit"/>
</Item7>
</RequiredPackages>
<Units Count="242">
<Units Count="243">
<Unit0>
<Filename Value="lazarus.pp"/>
<IsPartOfProject Value="True"/>
@ -1417,6 +1417,11 @@
<IsPartOfProject Value="True"/>
<UnitName Value="etPas2jsMsgParser"/>
</Unit241>
<Unit242>
<Filename Value="exttoolside.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="ExtToolsIDE"/>
</Unit242>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -41,7 +41,7 @@ uses
BaseIDEIntf, MacroIntf, PackageIntf, LazMsgDialogs, ProjectIntf, IDEExternToolIntf,
CompOptsIntf, IDEOptionsIntf, PackageDependencyIntf,
// IDE
IDEProcs, InitialSetupProc, ExtTools, CompilerOptions,
InitialSetupProc, ExtToolsConsole, CompilerOptions,
ApplicationBundle, TransferMacros, EnvironmentOpts, IDETranslations,
LazarusIDEStrConsts, IDECmdLine, MiscOptions, Project, LazConf, PackageDefs,
PackageLinks, PackageSystem, InterPkgConflictFiles, BuildLazDialog,
@ -1155,7 +1155,7 @@ begin
SetupCodetools;
SetupFPCExeFilename;
SetupPackageSystem;
MainBuildBoss.SetupExternalTools;
MainBuildBoss.SetupExternalTools(TExternalToolsConsole);
ExtToolConsole:=TLazExtToolConsole.Create(nil);
MainBuildBoss.SetupCompilerInterface;

View File

@ -87,7 +87,7 @@ uses
// compile
CompilerOptions, CheckCompilerOpts, BuildProjectDlg,
ApplicationBundle,
ExtTools,
ExtTools, ExtToolsIDE,
// projects
ProjectResources, Project, ProjectDefs, NewProjectDlg,
PublishProjectDlg, ProjectInspector, PackageDefs, ProjectDescriptors,
@ -1525,7 +1525,7 @@ begin
{$IFDEF IDE_MEM_CHECK}CheckHeapWrtMemCnt('TMainIDE.Create CODETOOLS');{$ENDIF}
MainBuildBoss.SetupExternalTools;
MainBuildBoss.SetupExternalTools(TExternalToolsIDE);
MainBuildBoss.EnvOptsChanged;
// build and position the MainIDE form