fpcompil.pas 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214
  1. {
  2. This file is part of the Free Pascal Integrated Development Environment
  3. Copyright (c) 1998 by Berczi Gabor
  4. Compiler call routines for the IDE
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$i globdir.inc}
  12. unit FPCompil;
  13. interface
  14. { don't redir under linux, because all stdout (also from the ide!) will
  15. then be redired (PFV) }
  16. { this should work now correctly because
  17. RedirDisableAll and RedirEnableAll function are added in fpredir (PM) }
  18. { $define VERBOSETXT}
  19. {$mode objfpc}
  20. uses
  21. { We need to include the exceptions from SysUtils, but the types from
  22. Objects need to be used. Keep the order SysUtils,Objects }
  23. SysUtils,
  24. Objects,
  25. FInput,
  26. Drivers,Views,Dialogs,
  27. WUtils,WViews,WCEdit,
  28. FPSymbol,
  29. FPViews;
  30. type
  31. TCompileMode = (cBuild,cMake,cCompile,cRun);
  32. type
  33. PCompilerMessage = ^TCompilerMessage;
  34. TCompilerMessage = object(TMessageItem)
  35. function GetText(MaxLen: Sw_Integer): String; virtual;
  36. end;
  37. PCompilerMessageListBox = ^TCompilerMessageListBox;
  38. TCompilerMessageListBox = object(TMessageListBox)
  39. function GetPalette: PPalette; virtual;
  40. procedure SelectFirstError;
  41. end;
  42. PCompilerMessageWindow = ^TCompilerMessageWindow;
  43. TCompilerMessageWindow = object(TFPWindow)
  44. constructor Init;
  45. procedure HandleEvent(var Event: TEvent); virtual;
  46. function GetPalette: PPalette; virtual;
  47. procedure Close;virtual;
  48. destructor Done; virtual;
  49. procedure SizeLimits(var Min, Max: TPoint); virtual;
  50. procedure AddMessage(AClass: longint;const Msg, Module: string; Line, Column: longint);
  51. procedure ClearMessages;
  52. constructor Load(var S: TStream);
  53. procedure Store(var S: TStream);
  54. procedure SetState(AState: Word; Enable: Boolean); virtual;
  55. procedure UpdateCommands; virtual;
  56. private
  57. {CompileShowed : boolean;}
  58. {Mode : TCompileMode;}
  59. MsgLB : PCompilerMessageListBox;
  60. {CurrST,
  61. InfoST : PColorStaticText;}
  62. end;
  63. PCompilerStatusDialog = ^TCompilerStatusDialog;
  64. TCompilerStatusDialog = object(TCenterDialog)
  65. ST : PAdvancedStaticText;
  66. KeyST : PColorStaticText;
  67. constructor Init;
  68. destructor Done;virtual;
  69. procedure Update;
  70. end;
  71. TFPInputFile = class(tinputfile)
  72. constructor Create(AEditor: PFileEditor);
  73. protected
  74. function fileopen(const filename: string): boolean; override;
  75. function fileseek(pos: longint): boolean; override;
  76. function fileread(var databuf; maxsize: longint): longint; override;
  77. function fileeof: boolean; override;
  78. function fileclose: boolean; override;
  79. procedure filegettime; override;
  80. private
  81. Editor: PFileEditor;
  82. S: PStream;
  83. end;
  84. const
  85. CompilerMessageWindow : PCompilerMessageWindow = nil;
  86. CompilerStatusDialog : PCompilerStatusDialog = nil;
  87. CompileStamp : longint = 0;
  88. RestartingDebugger : boolean = false;
  89. procedure DoCompile(Mode: TCompileMode);
  90. function NeedRecompile(Mode :TCompileMode; verbose : boolean): boolean;
  91. procedure ParseUserScreen;
  92. procedure RegisterFPCompile;
  93. const
  94. CompilingHiddenFile : PSourceWindow = nil;
  95. implementation
  96. uses
  97. {$ifdef Unix}
  98. Unix, BaseUnix,
  99. {$endif}
  100. {$ifdef go32v2}
  101. dpmiexcp,
  102. {$endif}
  103. {$ifdef win32}
  104. signals,
  105. {$endif}
  106. { $ifdef HasSignal}
  107. fpcatch,
  108. { $endif HasSignal}
  109. Dos,
  110. {$ifdef fpc}
  111. Video,
  112. {$endif fpc}
  113. globals,
  114. StdDlg,App,tokens,
  115. FVConsts,
  116. CompHook, Compiler, systems, browcol,
  117. WEditor,
  118. FPString,FPRedir,FPDesk,
  119. FPUsrScr,FPHelp,
  120. {$ifndef NODEBUG}FPDebug,{$endif}
  121. FPConst,FPVars,FPUtils,
  122. FPCodCmp,FPIntf,FPSwitch;
  123. {$ifndef NOOBJREG}
  124. const
  125. RCompilerMessageListBox: TStreamRec = (
  126. ObjType: 1211;
  127. VmtLink: Ofs(TypeOf(TCompilerMessageListBox)^);
  128. Load: @TCompilerMessageListBox.Load;
  129. Store: @TCompilerMessageListBox.Store
  130. );
  131. RCompilerMessageWindow: TStreamRec = (
  132. ObjType: 1212;
  133. VmtLink: Ofs(TypeOf(TCompilerMessageWindow)^);
  134. Load: @TCompilerMessageWindow.Load;
  135. Store: @TCompilerMessageWindow.Store
  136. );
  137. {$endif}
  138. procedure ParseUserScreen;
  139. var
  140. y : longint;
  141. Text,Attr : String;
  142. DisplayCompilerWindow : boolean;
  143. cc: integer;
  144. procedure SearchBackTrace;
  145. var AText,ModuleName,st : String;
  146. row : longint;
  147. begin
  148. if pos(' 0x',Text)=1 then
  149. begin
  150. AText:=Text;
  151. Delete(Text,1,10);
  152. While pos(' ',Text)=1 do
  153. Delete(Text,1,1);
  154. if pos('of ',Text)>0 then
  155. begin
  156. ModuleName:=Copy(Text,pos('of ',Text)+3,255);
  157. While ModuleName[Length(ModuleName)]=' ' do
  158. Delete(ModuleName,Length(ModuleName),1);
  159. end
  160. else
  161. ModuleName:='';
  162. if pos('line ',Text)>0 then
  163. begin
  164. Text:=Copy(Text,Pos('line ',Text)+5,255);
  165. st:=Copy(Text,1,Pos(' ',Text)-1);
  166. Val(st,row,cc);
  167. end
  168. else
  169. row:=0;
  170. CompilerMessageWindow^.AddMessage(V_Fatal,AText
  171. ,ModuleName,row,1);
  172. DisplayCompilerWindow:=true;
  173. end;
  174. end;
  175. procedure InsertInMessages(Const TypeStr : String;_Type : longint;EnableDisplay : boolean);
  176. var p,p2,col,row : longint;
  177. St,ModuleName : string;
  178. begin
  179. p:=pos(TypeStr,Text);
  180. p2:=Pos('(',Text);
  181. if (p>0) and (p2>0) and (p2<p) then
  182. begin
  183. ModuleName:=Copy(Text,1,p2-1);
  184. st:=Copy(Text,p2+1,255);
  185. Val(Copy(st,1,pos(',',st)-1),row,cc);
  186. st:=Copy(st,Pos(',',st)+1,255);
  187. Val(Copy(st,1,pos(')',st)-1),col,cc);
  188. CompilerMessageWindow^.AddMessage(_type,Copy(Text,pos(':',Text)+1,255)
  189. ,ModuleName,row,col);
  190. If EnableDisplay then
  191. DisplayCompilerWindow:=true;
  192. end;
  193. end;
  194. begin
  195. if not assigned(UserScreen) then
  196. exit;
  197. DisplayCompilerWindow:=false;
  198. PushStatus('Parsing User Screen');
  199. CompilerMessageWindow^.Lock;
  200. for Y:=0 to UserScreen^.GetHeight do
  201. begin
  202. UserScreen^.GetLine(Y,Text,Attr);
  203. SearchBackTrace;
  204. InsertInMessages(' Fatal:',v_Fatal or v_lineinfo,true);
  205. InsertInMessages(' Error:',v_Error or v_lineinfo,true);
  206. InsertInMessages(' Warning:',v_Warning or v_lineinfo,false);
  207. InsertInMessages(' Note:',v_Note or v_lineinfo,false);
  208. InsertInMessages(' Info:',v_Info or v_lineinfo,false);
  209. InsertInMessages(' Hint:',v_Hint or v_lineinfo,false);
  210. end;
  211. if DisplayCompilerWindow then
  212. begin
  213. if not CompilerMessageWindow^.GetState(sfVisible) then
  214. CompilerMessageWindow^.Show;
  215. CompilerMessageWindow^.MakeFirst;
  216. CompilerMessageWindow^.MsgLB^.SelectFirstError;
  217. end;
  218. CompilerMessageWindow^.UnLock;
  219. PopStatus;
  220. end;
  221. {*****************************************************************************
  222. TCompilerMessage
  223. *****************************************************************************}
  224. function TCompilerMessage.GetText(MaxLen: Sw_Integer): String;
  225. var
  226. ClassS: string[20];
  227. S: string;
  228. begin
  229. case TClass and V_LevelMask of
  230. V_Fatal : ClassS:=msg_class_Fatal;
  231. V_Error : ClassS:=msg_class_Error;
  232. V_Normal : ClassS:=msg_class_Normal;
  233. V_Warning : ClassS:=msg_class_Warning;
  234. V_Note : ClassS:=msg_class_Note;
  235. V_Hint : ClassS:=msg_class_Hint;
  236. {$ifdef VERBOSETXT}
  237. V_Conditional : ClassS:=msg_class_conditional;
  238. V_Info : ClassS:=msg_class_info;
  239. V_Status : ClassS:=msg_class_status;
  240. V_Used : ClassS:=msg_class_used;
  241. V_Tried : ClassS:=msg_class_tried;
  242. V_Debug : ClassS:=msg_class_debug;
  243. else
  244. ClassS:='???';
  245. {$endif}
  246. else
  247. ClassS:='';
  248. end;
  249. if ClassS<>'' then
  250. ClassS:=RExpand(ClassS,0)+': ';
  251. if assigned(Module) and
  252. ((TClass and V_LineInfo)=V_LineInfo) then
  253. begin
  254. if Row>0 then
  255. begin
  256. if Col>0 then
  257. S:=NameAndExtOf(Module^)+'('+IntToStr(Row)+','+IntToStr(Col)+') '+ClassS
  258. else
  259. S:=NameAndExtOf(Module^)+'('+IntToStr(Row)+') '+ClassS;
  260. end
  261. else
  262. S:=NameAndExtOf(Module^)+'('+IntToStr(Row)+') '+ClassS
  263. end
  264. else
  265. S:=ClassS;
  266. if assigned(Text) then
  267. S:=S+Text^;
  268. if length(S)>MaxLen then
  269. S:=copy(S,1,MaxLen-2)+'..';
  270. GetText:=S;
  271. end;
  272. {*****************************************************************************
  273. TCompilerMessageListBox
  274. *****************************************************************************}
  275. function TCompilerMessageListBox.GetPalette: PPalette;
  276. const
  277. P: string[length(CBrowserListBox)] = CBrowserListBox;
  278. begin
  279. GetPalette:=@P;
  280. end;
  281. procedure TCompilerMessageListBox.SelectFirstError;
  282. function IsError(P : PCompilerMessage) : boolean;
  283. begin
  284. IsError:=(P^.TClass and (V_Fatal or V_Error))<>0;
  285. end;
  286. var
  287. P : PCompilerMessage;
  288. begin
  289. P:=List^.FirstThat(@IsError);
  290. If Assigned(P) then
  291. Begin
  292. FocusItem(List^.IndexOf(P));
  293. DrawView;
  294. End;
  295. end;
  296. {*****************************************************************************
  297. TCompilerMessageWindow
  298. *****************************************************************************}
  299. constructor TCompilerMessageWindow.Init;
  300. var R: TRect;
  301. HSB,VSB: PScrollBar;
  302. begin
  303. Desktop^.GetExtent(R);
  304. R.A.Y:=R.B.Y-7;
  305. inherited Init(R,dialog_compilermessages,{SearchFreeWindowNo}wnNoNumber);
  306. HelpCtx:=hcCompilerMessagesWindow;
  307. AutoNumber:=true;
  308. HSB:=StandardScrollBar(sbHorizontal+sbHandleKeyboard);
  309. HSB^.GrowMode:=gfGrowLoY+gfGrowHiX+gfGrowHiY;
  310. Insert(HSB);
  311. VSB:=StandardScrollBar(sbVertical+sbHandleKeyboard);
  312. VSB^.GrowMode:=gfGrowLoX+gfGrowHiX+gfGrowHiY;
  313. Insert(VSB);
  314. GetExtent(R);
  315. R.Grow(-1,-1);
  316. New(MsgLB, Init(R, HSB, VSB));
  317. MsgLB^.GrowMode:=gfGrowHiX+gfGrowHiY;
  318. Insert(MsgLB);
  319. CompilerMessageWindow:=@self;
  320. end;
  321. procedure TCompilerMessageWindow.AddMessage(AClass: longint;const Msg, Module: string; Line, Column: longint);
  322. begin
  323. if (AClass and V_LineInfo)<>V_LineInfo then
  324. Line:=0;
  325. MsgLB^.AddItem(New(PCompilerMessage,Init(AClass, Msg, MsgLB^.AddModuleName(Module), Line, Column)));
  326. if (@Self=CompilerMessageWindow) and ((AClass = V_fatal) or (AClass = V_Error)) then
  327. begin
  328. if not GetState(sfVisible) then
  329. Show;
  330. if Desktop^.First<>PView(CompilerMessageWindow) then
  331. MakeFirst;
  332. end;
  333. end;
  334. procedure TCompilerMessageWindow.ClearMessages;
  335. begin
  336. MsgLB^.Clear;
  337. ReDraw;
  338. end;
  339. {procedure TCompilerMessageWindow.Updateinfo;
  340. begin
  341. if CompileShowed then
  342. begin
  343. InfoST^.SetText(
  344. RExpand(' Main file : '#1#$7f+Copy(SmartPath(MainFile),1,39),40)+#2+
  345. 'Total lines : '#1#$7e+IntToStr(Status.CompiledLines)+#2#13+
  346. RExpand(' Target : '#1#$7f+KillTilde(TargetSwitches^.ItemName(TargetSwitches^.GetCurrSel)),40)+#2+
  347. 'Total errors : '#1#$7e+IntToStr(Status.ErrorCount)
  348. );
  349. if status.currentline>0 then
  350. CurrST^.SetText(' Status: '#1#$7e+status.currentsource+'('+IntToStr(status.currentline)+')'#2)
  351. else
  352. CurrST^.SetText(' Status: '#1#$7e+status.currentsource+#2);
  353. end;
  354. ReDraw;
  355. end;}
  356. procedure TCompilerMessageWindow.HandleEvent(var Event: TEvent);
  357. begin
  358. case Event.What of
  359. evBroadcast :
  360. case Event.Command of
  361. cmListFocusChanged :
  362. if Event.InfoPtr=MsgLB then
  363. Message(Application,evBroadcast,cmClearLineHighlights,@Self);
  364. end;
  365. end;
  366. inherited HandleEvent(Event);
  367. end;
  368. procedure TCompilerMessageWindow.SizeLimits(var Min, Max: TPoint);
  369. begin
  370. inherited SizeLimits(Min,Max);
  371. Min.X:=20;
  372. Min.Y:=4;
  373. end;
  374. procedure TCompilerMessageWindow.Close;
  375. begin
  376. Hide;
  377. end;
  378. function TCompilerMessageWindow.GetPalette: PPalette;
  379. const
  380. S : string[length(CBrowserWindow)] = CBrowserWindow;
  381. begin
  382. GetPalette:=@S;
  383. end;
  384. constructor TCompilerMessageWindow.Load(var S: TStream);
  385. begin
  386. inherited Load(S);
  387. GetSubViewPtr(S,MsgLB);
  388. end;
  389. procedure TCompilerMessageWindow.Store(var S: TStream);
  390. begin
  391. if MsgLB^.List=nil then
  392. MsgLB^.NewList(New(PCollection, Init(100,100)));
  393. inherited Store(S);
  394. PutSubViewPtr(S,MsgLB);
  395. end;
  396. procedure TCompilerMessageWindow.UpdateCommands;
  397. var Active: boolean;
  398. begin
  399. Active:=GetState(sfActive);
  400. SetCmdState(CompileCmds,Active);
  401. Message(Application,evBroadcast,cmCommandSetChanged,nil);
  402. end;
  403. procedure TCompilerMessageWindow.SetState(AState: Word; Enable: Boolean);
  404. var OldState: word;
  405. begin
  406. OldState:=State;
  407. inherited SetState(AState,Enable);
  408. if ((AState and sfActive)<>0) and (((OldState xor State) and sfActive)<>0) then
  409. UpdateCommands;
  410. end;
  411. destructor TCompilerMessageWindow.Done;
  412. begin
  413. CompilerMessageWindow:=nil;
  414. inherited Done;
  415. end;
  416. {****************************************************************************
  417. CompilerStatusDialog
  418. ****************************************************************************}
  419. constructor TCompilerStatusDialog.Init;
  420. var R: TRect;
  421. begin
  422. R.Assign(0,0,56,11);
  423. ClearFormatParams; AddFormatParamStr(KillTilde(SwitchesModeName[SwitchesMode]));
  424. inherited Init(R, FormatStrF(dialog_compilingwithmode, FormatParams));
  425. GetExtent(R); R.B.Y:=11;
  426. R.Grow(-3,-2);
  427. New(ST, Init(R, ''));
  428. Insert(ST);
  429. GetExtent(R); R.B.Y:=11;
  430. R.Grow(-1,-1); R.A.Y:=R.B.Y-1;
  431. New(KeyST, Init(R, '', Blue*16+White+longint($80+Blue*16+White)*256,true));
  432. Insert(KeyST);
  433. { Reset Status infos see bug 1585 }
  434. Fillchar(Status,SizeOf(Status),#0);
  435. end;
  436. destructor TCompilerStatusDialog.Done;
  437. begin
  438. if @Self=CompilerStatusDialog then
  439. CompilerStatusDialog:=nil;
  440. Inherited Done;
  441. end;
  442. procedure TCompilerStatusDialog.Update;
  443. var
  444. StatusS,KeyS: string;
  445. hstatus : TFPCHeapStatus;
  446. const
  447. MaxFileNameSize = 46;
  448. begin
  449. case CompilationPhase of
  450. cpCompiling :
  451. begin
  452. ClearFormatParams;
  453. if Status.Compiling_current then
  454. begin
  455. AddFormatParamStr(ShrinkPath(SmartPath(Status.Currentsourcepath+Status.CurrentSource),
  456. MaxFileNameSize - Length(msg_compilingfile)));
  457. StatusS:=FormatStrF(msg_compilingfile,FormatParams);
  458. end
  459. else
  460. begin
  461. if Status.CurrentSource='' then
  462. StatusS:=''
  463. else
  464. begin
  465. StatusS:=ShrinkPath(SmartPath(DirAndNameOf(Status.Currentsourcepath+Status.CurrentSource)),
  466. MaxFileNameSize-Length(msg_loadingunit));
  467. AddFormatParamStr(StatusS);
  468. StatusS:=FormatStrF(msg_loadingunit,FormatParams);
  469. end;
  470. end;
  471. KeyS:=msg_hint_pressesctocancel;
  472. end;
  473. cpLinking :
  474. begin
  475. ClearFormatParams;
  476. AddFormatParamStr(ShrinkPath(ExeFile,
  477. MaxFileNameSize-Length(msg_linkingfile)));
  478. StatusS:=FormatStrF(msg_linkingfile,FormatParams);
  479. KeyS:=msg_hint_pleasewait;
  480. end;
  481. cpDone :
  482. begin
  483. StatusS:=msg_compiledone;
  484. KeyS:=msg_hint_compilesuccessfulpressenter;
  485. end;
  486. cpFailed :
  487. begin
  488. StatusS:=msg_failedtocompile;
  489. KeyS:=msg_hint_compilefailed;
  490. end;
  491. cpAborted :
  492. begin
  493. StatusS:=msg_compilationaborted;
  494. KeyS:=msg_hint_compileaborted;
  495. end;
  496. end;
  497. ClearFormatParams;
  498. AddFormatParamStr(ShrinkPath(SmartPath(MainFile),
  499. MaxFileNameSize-Length('Main file: %s')));
  500. AddFormatParamStr(StatusS);
  501. AddFormatParamStr(KillTilde(TargetSwitches^.ItemName(TargetSwitches^.GetCurrSel)));
  502. AddFormatParamInt(Status.CurrentLine);
  503. AddFormatParamInt(Status.CompiledLines);
  504. hstatus:=GetFPCHeapStatus;
  505. AddFormatParamInt(hstatus.CurrHeapUsed div 1024);
  506. AddFormatParamInt(hstatus.CurrHeapSize div 1024);
  507. AddFormatParamInt(Status.ErrorCount);
  508. ST^.SetText(
  509. FormatStrF(
  510. 'Main file: %s'#13+
  511. '%s'+#13#13+
  512. 'Target: %s'#13+
  513. 'Line number: %6d '+'Total lines: %6d'+#13+
  514. 'Used memory: %6dK '+'Allocated memory: %6dK'#13+
  515. 'Total errors: %5d',
  516. FormatParams)
  517. );
  518. KeyST^.SetText(^C+KeyS);
  519. end;
  520. {****************************************************************************
  521. Compiler Hooks
  522. ****************************************************************************}
  523. function getrealtime : real;
  524. var
  525. {$IFDEF USE_SYSUTILS}
  526. h,m,s,s1000 : word;
  527. {$ELSE USE_SYSUTILS}
  528. h,m,s,s100 : word;
  529. {$ENDIF USE_SYSUTILS}
  530. begin
  531. {$IFDEF USE_SYSUTILS}
  532. DecodeTime(Time,h,m,s,s1000);
  533. getrealtime:=h*3600.0+m*60.0+s+s1000/1000.0;
  534. {$ELSE USE_SYSUTILS}
  535. gettime(h,m,s,s100);
  536. getrealtime:=h*3600.0+m*60.0+s+s100/100.0;
  537. {$ENDIF USE_SYSUTILS}
  538. end;
  539. const
  540. lasttime : real = 0;
  541. function CompilerStatus: boolean; {$ifndef FPC}far;{$endif}
  542. var
  543. event : tevent;
  544. begin
  545. GetKeyEvent(Event);
  546. if (Event.What=evKeyDown) and (Event.KeyCode=kbEsc) then
  547. begin
  548. CompilationPhase:=cpAborted;
  549. { update info messages }
  550. if assigned(CompilerStatusDialog) then
  551. begin
  552. {$ifdef redircompiler}
  553. RedirDisableAll;
  554. {$endif}
  555. CompilerStatusDialog^.Update;
  556. {$ifdef redircompiler}
  557. RedirEnableAll;
  558. {$endif}
  559. end;
  560. CompilerStatus:=true;
  561. exit;
  562. end;
  563. { only display line info every 100 lines, ofcourse all other messages
  564. will be displayed directly }
  565. if (getrealtime-lasttime>=CompilerStatusUpdateDelay) or (status.compiledlines=1) then
  566. begin
  567. lasttime:=getrealtime;
  568. { update info messages }
  569. {$ifdef redircompiler}
  570. RedirDisableAll;
  571. {$endif}
  572. if assigned(CompilerStatusDialog) then
  573. CompilerStatusDialog^.Update;
  574. {$ifdef redircompiler}
  575. RedirEnableAll;
  576. {$endif}
  577. { update memory usage }
  578. { HeapView^.Update; }
  579. end;
  580. CompilerStatus:=false;
  581. end;
  582. Function CompilerGetNamedFileTime(const filename : string) : Longint; {$ifndef FPC}far;{$endif}
  583. var t: longint;
  584. W: PSourceWindow;
  585. begin
  586. W:=EditorWindowFile(FExpand(filename));
  587. if Assigned(W) and (W^.Editor^.GetModified) then
  588. t:=Now
  589. else
  590. t:=def_getnamedfiletime(filename);
  591. CompilerGetNamedFileTime:=t;
  592. end;
  593. function CompilerOpenInputFile(const filename: string): tinputfile; {$ifndef FPC}far;{$endif}
  594. var f: tinputfile;
  595. W: PSourceWindow;
  596. begin
  597. if assigned(CompilingHiddenFile) and
  598. (NameandExtof(filename)=CompilingHiddenFile^.Editor^.Filename) then
  599. W:=CompilingHiddenFile
  600. else
  601. W:=EditorWindowFile(FExpand(filename));
  602. if Assigned(W) and (W^.Editor^.GetModified) then
  603. f:=TFPInputFile.Create(W^.Editor)
  604. else
  605. f:=def_openinputfile(filename);
  606. if assigned(W) then
  607. W^.Editor^.CompileStamp:=CompileStamp;
  608. CompilerOpenInputFile:=f;
  609. end;
  610. function CompilerComment(Level:Longint; const s:string):boolean; {$ifndef FPC}far;{$endif}
  611. begin
  612. CompilerComment:=false;
  613. if (status.verbosity and Level)<>0 then
  614. begin
  615. {$ifdef redircompiler}
  616. RedirDisableAll;
  617. {$endif}
  618. if not CompilerMessageWindow^.GetState(sfVisible) then
  619. CompilerMessageWindow^.Show;
  620. if Desktop^.First<>PView(CompilerMessageWindow) then
  621. CompilerMessageWindow^.MakeFirst;
  622. CompilerMessageWindow^.AddMessage(Level,S,status.currentsourcepath+status.currentsource,
  623. status.currentline,status.currentcolumn);
  624. { update info messages }
  625. if assigned(CompilerStatusDialog) then
  626. CompilerStatusDialog^.Update;
  627. {$ifdef redircompiler}
  628. RedirEnableAll;
  629. {$endif}
  630. { update memory usage }
  631. { HeapView^.Update; }
  632. end;
  633. end;
  634. {****************************************************************************
  635. DoCompile
  636. ****************************************************************************}
  637. { This function must return '' if
  638. "Options|Directories|Exe and PPU directory" is empty }
  639. function GetExePath: string;
  640. var Path: string;
  641. I: Sw_integer;
  642. begin
  643. Path:='';
  644. if DirectorySwitches<>nil then
  645. with DirectorySwitches^ do
  646. for I:=0 to ItemCount-1 do
  647. begin
  648. if ItemParam(I)='-FE' then
  649. begin
  650. Path:=GetStringItem(I);
  651. Break;
  652. end;
  653. end;
  654. if Path<>'' then
  655. GetExePath:=CompleteDir(FExpand(Path))
  656. else
  657. GetExePath:='';
  658. end;
  659. function GetMainFile(Mode: TCompileMode): string;
  660. var FileName: string;
  661. P : PSourceWindow;
  662. begin
  663. if assigned(CompilingHiddenFile) then
  664. P:=CompilingHiddenFile
  665. else
  666. P:=Message(Desktop,evBroadcast,cmSearchWindow,nil);
  667. if (PrimaryFileMain='') and (P=nil) then
  668. FileName:='' { nothing to compile }
  669. else
  670. begin
  671. if (PrimaryFileMain<>'') and (Mode<>cCompile) then
  672. FileName:=PrimaryFileMain
  673. else if assigned(P) then
  674. begin
  675. FileName:=P^.Editor^.FileName;
  676. if FileName='' then
  677. begin
  678. P^.Editor^.SaveAsk(true);
  679. FileName:=P^.Editor^.FileName;
  680. end;
  681. end
  682. else
  683. FileName:='';
  684. end;
  685. If (FileName<>'') then
  686. FileName:=FixFileName(FExpand(FileName));
  687. GetMainFile:=FileName;
  688. end;
  689. procedure ResetErrorMessages;
  690. procedure ResetErrorLine(P: PView); {$ifndef FPC}far;{$endif}
  691. begin
  692. if assigned(P) and
  693. (TypeOf(P^)=TypeOf(TSourceWindow)) then
  694. PSourceWindow(P)^.Editor^.SetErrorMessage('');
  695. end;
  696. begin
  697. Desktop^.ForEach(@ResetErrorLine);
  698. end;
  699. procedure DoCompile(Mode: TCompileMode);
  700. function IsExitEvent(E: TEvent): boolean;
  701. begin
  702. { following suggestion by Harsha Senanayake }
  703. IsExitEvent:=(E.What=evKeyDown);
  704. end;
  705. function GetTargetExeExt : string;
  706. begin
  707. GetTargetExeExt:=target_info.exeext;
  708. end;
  709. var
  710. s,FileName: string;
  711. ErrFile : Text;
  712. MustRestartDebugger : boolean;
  713. Error,LinkErrorCount : longint;
  714. E : TEvent;
  715. DummyView: PView;
  716. PPasFile : string[64];
  717. begin
  718. AskRecompileIfModifiedFlag:=true;
  719. { Get FileName }
  720. FileName:=GetMainFile(Mode);
  721. if FileName='' then
  722. begin
  723. ErrorBox(msg_nothingtocompile,nil);
  724. Exit;
  725. end else
  726. { THis is not longer necessary as unsaved files are loaded from a memorystream,
  727. and with the file as primaryfile set it is already incompatible with itself
  728. if FileName='*' then
  729. begin
  730. ErrorBox(msg_cantcompileunsavedfile,nil);
  731. Exit;
  732. end; }
  733. PushStatus('Beginning compilation...');
  734. { Show Compiler Messages Window }
  735. { if not CompilerMessageWindow^.GetState(sfVisible) then
  736. CompilerMessageWindow^.Show;
  737. CompilerMessageWindow^.MakeFirst;}
  738. CompilerMessageWindow^.ClearMessages;
  739. { Tell why we compile }
  740. NeedRecompile(Mode,true);
  741. MainFile:=FileName;
  742. SetStatus('Writing switches to file...');
  743. WriteSwitches(SwitchesPath);
  744. { leaving open browsers leads to crashes !! (PM) }
  745. SetStatus('Preparing symbol info...');
  746. CloseAllBrowsers;
  747. if ((DesktopFileFlags and dfSymbolInformation)<>0) then
  748. WriteSymbolsFile(BrowserName);
  749. { MainFile:=FixFileName(FExpand(FileName));}
  750. SetStatus('Preparing to compile...'+NameOf(MainFile));
  751. { Reset }
  752. CtrlBreakHit:=false;
  753. { Create Compiler Status Dialog }
  754. CompilationPhase:=cpCompiling;
  755. if not assigned(CompilingHiddenFile) then
  756. begin
  757. New(CompilerStatusDialog, Init);
  758. CompilerStatusDialog^.SetState(sfModal,true);
  759. { disable window closing }
  760. CompilerStatusDialog^.Flags:=CompilerStatusDialog^.Flags and not wfclose;
  761. Application^.Insert(CompilerStatusDialog);
  762. CompilerStatusDialog^.Update;
  763. end;
  764. { Restore dir that could be changed during debugging }
  765. {$I-}
  766. ChDir(StartUpDir);
  767. {$I+}
  768. EatIO;
  769. { hook compiler output }
  770. do_status:=@CompilerStatus;
  771. do_comment:=@CompilerComment;
  772. do_openinputfile:=@CompilerOpenInputFile;
  773. do_getnamedfiletime:=@CompilerGetNamedFileTime;
  774. do_initsymbolinfo:=@InitBrowserCol;
  775. do_donesymbolinfo:=@DoneBrowserCol;
  776. do_extractsymbolinfo:=@CreateBrowserCol;
  777. { Compile ! }
  778. {$ifdef redircompiler}
  779. ChangeRedirOut(FPOutFileName,false);
  780. ChangeRedirError(FPErrFileName,false);
  781. {$endif}
  782. { insert "" around name so that spaces are allowed }
  783. { only supported in compiler after 2000/01/14 PM }
  784. if pos(' ',FileName)>0 then
  785. FileName:='"'+FileName+'"';
  786. if mode=cBuild then
  787. FileName:='-B '+FileName;
  788. { tokens are created and distroed by compiler.compile !! PM }
  789. DoneTokens;
  790. PPasFile:='ppas'+source_info.scriptext;
  791. WUtils.DeleteFile(GetExePath+PpasFile);
  792. SetStatus('Compiling...');
  793. inc(CompileStamp);
  794. ResetErrorMessages;
  795. {$ifndef NODEBUG}
  796. MustRestartDebugger:=false;
  797. if assigned(Debugger) then
  798. if Debugger^.HasExe then
  799. begin
  800. Debugger^.Reset;
  801. MustRestartDebugger:=true;
  802. end;
  803. {$endif NODEBUG}
  804. try
  805. FpIntF.Compile(FileName,SwitchesPath);
  806. except
  807. on ECompilerAbort do
  808. CompilerMessageWindow^.AddMessage(V_error,'Error during compilation','',0,0);
  809. on E:Exception do
  810. CompilerMessageWindow^.AddMessage(V_error,E.Message+' during compilation','',0,0);
  811. end;
  812. SetStatus('Finished compiling...');
  813. { Retrieve created exefile }
  814. If GetEXEPath<>'' then
  815. EXEFile:=FixFileName(GetEXEPath+NameOf(MainFile)+GetTargetExeExt)
  816. else
  817. EXEFile:=DirOf(MainFile)+NameOf(MainFile)+GetTargetExeExt;
  818. DefaultReplacements(ExeFile);
  819. { tokens are created and distroyed by compiler.compile !! PM }
  820. InitTokens;
  821. if LinkAfter and
  822. ExistsFile(GetExePath+PpasFile) and
  823. (CompilationPhase<>cpAborted) and
  824. (status.errorCount=0) then
  825. begin
  826. CompilationPhase:=cpLinking;
  827. if assigned(CompilerStatusDialog) then
  828. CompilerStatusDialog^.Update;
  829. SetStatus('Assembling and/or linking...');
  830. {$ifndef redircompiler}
  831. { At least here we want to catch output
  832. of batch file PM }
  833. ChangeRedirOut(FPOutFileName,false);
  834. ChangeRedirError(FPErrFileName,false);
  835. {$endif}
  836. {$ifdef Unix}
  837. {$ifdef ver1_0}
  838. Shell(GetExePath+PpasFile);
  839. Error:=LinuxError;
  840. {$else}
  841. error:=0;
  842. If Shell(GetExePath+PpasFile)=-1 Then
  843. Error:=fpgeterrno;
  844. {$endif}
  845. {$else}
  846. DosExecute(GetEnv('COMSPEC'),'/C '+GetExePath+PpasFile);
  847. Error:=DosError;
  848. {$endif}
  849. SetStatus('Finished linking...');
  850. RestoreRedirOut;
  851. RestoreRedirError;
  852. if Error<>0 then
  853. Inc(status.errorCount);
  854. if Status.IsExe and not Status.IsLibrary and not ExistsFile(EXEFile) then
  855. begin
  856. Inc(status.errorCount);
  857. ClearFormatParams; AddFormatParamStr(ExeFile);
  858. CompilerMessageWindow^.AddMessage(V_error,FormatStrF(msg_couldnotcreatefile,FormatParams),'',0,0);
  859. {$I-}
  860. Assign(ErrFile,FPErrFileName);
  861. Reset(ErrFile);
  862. if EatIO<>0 then
  863. ErrorBox(FormatStrStr(msg_cantopenfile,FPErrFileName),nil)
  864. else
  865. begin
  866. LinkErrorCount:=0;
  867. While not eof(ErrFile) and (LinkErrorCount<25) do
  868. begin
  869. readln(ErrFile,s);
  870. CompilerMessageWindow^.AddMessage(V_error,s,'',0,0);
  871. inc(LinkErrorCount);
  872. end;
  873. if not eof(ErrFile) then
  874. begin
  875. ClearFormatParams; AddFormatParamStr(FPErrFileName);
  876. CompilerMessageWindow^.AddMessage(V_error,
  877. FormatStrF(msg_therearemoreerrorsinfile,FormatParams),'',0,0);
  878. end;
  879. Close(ErrFile);
  880. end;
  881. EatIO;
  882. {$I+}
  883. end
  884. else if error=0 then
  885. WUtils.DeleteFile(GetExePath+PpasFile);
  886. end;
  887. {$ifdef redircompiler}
  888. RestoreRedirOut;
  889. RestoreRedirError;
  890. {$endif}
  891. PopStatus;
  892. { Set end status }
  893. if not (CompilationPhase in [cpAborted,cpFailed]) then
  894. if (status.errorCount=0) then
  895. begin
  896. CompilationPhase:=cpDone;
  897. LastCompileTime := cardinal(Now);
  898. end
  899. else
  900. CompilationPhase:=cpFailed;
  901. { Show end status }
  902. { reenable window closing }
  903. if assigned(CompilerStatusDialog) then
  904. begin
  905. CompilerStatusDialog^.Flags:=CompilerStatusDialog^.Flags or wfclose;
  906. CompilerStatusDialog^.Update;
  907. CompilerStatusDialog^.ReDraw;
  908. CompilerStatusDialog^.SetState(sfModal,false);
  909. if ((CompilationPhase in [cpAborted,cpDone,cpFailed]) or (ShowStatusOnError))
  910. and ((Mode<>cRun) or (CompilationPhase<>cpDone)) then
  911. repeat
  912. CompilerStatusDialog^.GetEvent(E);
  913. if IsExitEvent(E)=false then
  914. CompilerStatusDialog^.HandleEvent(E);
  915. until IsExitEvent(E) or not assigned(CompilerStatusDialog);
  916. {if IsExitEvent(E) then
  917. Application^.PutEvent(E);}
  918. if assigned(CompilerStatusDialog) then
  919. begin
  920. Application^.Delete(CompilerStatusDialog);
  921. Dispose(CompilerStatusDialog, Done);
  922. end;
  923. end;
  924. CompilerStatusDialog:=nil;
  925. { end compilation returns true if the messagewindow should be removed }
  926. if CompilationPhase=cpDone then
  927. begin
  928. CompilerMessageWindow^.Hide;
  929. { This is the last compiled main file }
  930. PrevMainFile:=MainFile;
  931. MainHasDebugInfo:=DebugInfoSwitches^.GetCurrSelParam<>'-';
  932. end;
  933. { Update the app }
  934. Message(Application,evCommand,cmUpdate,nil);
  935. DummyView:=Desktop^.First;
  936. while (DummyView<>nil) and (DummyView^.GetState(sfVisible)=false) do
  937. begin
  938. DummyView:=DummyView^.NextView;
  939. end;
  940. with DummyView^ do
  941. if GetState(sfVisible) then
  942. begin
  943. SetState(sfSelected,false);
  944. SetState(sfSelected,true);
  945. end;
  946. if Assigned(CompilerMessageWindow) then
  947. with CompilerMessageWindow^ do
  948. begin
  949. if GetState(sfVisible) then
  950. begin
  951. SetState(sfSelected,false);
  952. SetState(sfSelected,true);
  953. end;
  954. if (status.errorCount>0) then
  955. MsgLB^.SelectFirstError;
  956. end;
  957. { ^^^ we need this trick to reactivate the desktop }
  958. EditorModified:=false;
  959. {$ifndef NODEBUG}
  960. if MustRestartDebugger then
  961. InitDebugger;
  962. {$endif NODEBUG}
  963. { In case we have something that the compiler touched }
  964. AskToReloadAllModifiedFiles;
  965. { Try to read Browser info in again if compilation failure !! }
  966. if Not Assigned(Modules) and (CompilationPhase<>cpDone) and
  967. ((DesktopFileFlags and dfSymbolInformation)<>0) then
  968. ReadSymbolsFile(BrowserName);
  969. if UseAllUnitsInCodeComplete and not assigned(CompilingHiddenFile) then
  970. AddAvailableUnitsToCodeComplete(false);
  971. end;
  972. function NeedRecompile(Mode :TCompileMode; verbose : boolean): boolean;
  973. var Need: boolean;
  974. I: sw_integer;
  975. SF: PSourceFile;
  976. SourceTime,PPUTime,ObjTime: longint;
  977. W: PSourceWindow;
  978. begin
  979. if Assigned(SourceFiles)=false then
  980. Need:={(EditorModified=true)}true
  981. else
  982. begin
  983. Need:=(PrevMainFile<>GetMainFile(Mode)) and (PrevMainFile<>'');
  984. if Need then
  985. begin
  986. if verbose then
  987. begin
  988. ClearFormatParams; AddFormatParamStr(GetMainFile(Mode));
  989. CompilerMessageWindow^.AddMessage(V_info,
  990. FormatStrF(msg_firstcompilationof,FormatParams),
  991. '',0,0);
  992. end;
  993. end
  994. else
  995. for I:=0 to SourceFiles^.Count-1 do
  996. begin
  997. SF:=SourceFiles^.At(I);
  998. SourceTime:=wutils.GetFileTime(SF^.GetSourceFileName);
  999. PPUTime:=wutils.GetFileTime(SF^.GetPPUFileName);
  1000. ObjTime:=wutils.GetFileTime(SF^.GetObjFileName);
  1001. { writeln('S: ',SF^.GetSourceFileName,' - ',SourceTime);
  1002. writeln('P: ',SF^.GetPPUFileName,' - ',PPUTime);
  1003. writeln('O: ',SF^.GetObjFileName,' - ',ObjTime);
  1004. writeln('------');}
  1005. { some units don't generate object files }
  1006. W:=EditorWindowFile(SF^.GetSourceFileName);
  1007. if (SourceTime<>-1) then
  1008. if ((SourceTime>PPUTime) or
  1009. ((SourceTime>ObjTime) and
  1010. (ObjTime<>-1))) or
  1011. (assigned(W) and (W^.Editor^.CompileStamp<0)) then
  1012. begin
  1013. Need:=true;
  1014. if verbose then
  1015. begin
  1016. ClearFormatParams; AddFormatParamStr(SF^.GetSourceFileName);
  1017. CompilerMessageWindow^.AddMessage(V_info,
  1018. FormatStrF(msg_recompilingbecauseof,FormatParams),
  1019. SF^.GetSourceFileName,1,1);
  1020. end;
  1021. Break;
  1022. end;
  1023. end;
  1024. { writeln('Need?', Need); system.readln;}
  1025. end;
  1026. NeedRecompile:=Need;
  1027. end;
  1028. constructor TFPInputFile.Create(AEditor: PFileEditor);
  1029. begin
  1030. if not Assigned(AEditor) then Fail;
  1031. if inherited Create(AEditor^.FileName)=nil then
  1032. Fail;
  1033. Editor:=AEditor;
  1034. end;
  1035. function TFPInputFile.fileopen(const filename: string): boolean;
  1036. var OK: boolean;
  1037. begin
  1038. S:=New(PMemoryStream, Init(0,0));
  1039. OK:=Assigned(S) and (S^.Status=stOK);
  1040. if OK then OK:=Editor^.SaveToStream(S);
  1041. if OK then
  1042. S^.Seek(0)
  1043. else
  1044. begin
  1045. if Assigned(S) then Dispose(S, Done);
  1046. S:=nil;
  1047. end;
  1048. fileopen:=OK;
  1049. end;
  1050. function TFPInputFile.fileseek(pos: longint): boolean;
  1051. var OK: boolean;
  1052. begin
  1053. OK:=assigned(S);
  1054. if OK then
  1055. begin
  1056. S^.Reset;
  1057. S^.Seek(pos);
  1058. OK:=(S^.Status=stOK);
  1059. end;
  1060. fileseek:=OK;
  1061. end;
  1062. function TFPInputFile.fileread(var databuf; maxsize: longint): longint;
  1063. var
  1064. size: longint;
  1065. begin
  1066. if not assigned(S) then size:=0 else
  1067. begin
  1068. size:=min(maxsize,(S^.GetSize-S^.GetPos));
  1069. S^.Read(databuf,size);
  1070. if S^.Status<>stOK then size:=0;
  1071. end;
  1072. fileread:=size;
  1073. end;
  1074. function TFPInputFile.fileeof: boolean;
  1075. var EOF: boolean;
  1076. begin
  1077. EOF:=not assigned(S);
  1078. if not EOF then
  1079. EOF:=(S^.Status<>stOK) or (S^.GetPos=S^.GetSize);
  1080. fileeof:=EOF;
  1081. end;
  1082. function TFPInputFile.fileclose: boolean;
  1083. var OK: boolean;
  1084. begin
  1085. OK:=assigned(S);
  1086. if OK then
  1087. begin
  1088. S^.Reset;
  1089. Dispose(S, Done);
  1090. S:=nil;
  1091. OK:=true;
  1092. end;
  1093. fileclose:=OK;
  1094. end;
  1095. procedure tfpinputfile.filegettime;
  1096. var
  1097. dt : datetime;
  1098. hsec,wday : word;
  1099. begin
  1100. { current time }
  1101. dos.getdate(dt.year,dt.month,dt.day,wday);
  1102. dos.gettime(dt.hour,dt.min,dt.sec,hsec);
  1103. packtime(dt,filetime);
  1104. end;
  1105. procedure RegisterFPCompile;
  1106. begin
  1107. {$ifndef NOOBJREG}
  1108. RegisterType(RCompilerMessageListBox);
  1109. RegisterType(RCompilerMessageWindow);
  1110. {$endif}
  1111. end;
  1112. end.