fppu.pas 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the first loading and searching of the modules
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit fppu;
  18. {$i fpcdefs.inc}
  19. { close ppufiles on system that are
  20. short on file handles like DOS system PM }
  21. {$ifdef GO32V2}
  22. {$define SHORT_ON_FILE_HANDLES}
  23. {$endif GO32V2}
  24. {$ifdef WATCOM}
  25. {$define SHORT_ON_FILE_HANDLES}
  26. {$endif WATCOM}
  27. interface
  28. uses
  29. cutils,cclasses,
  30. globtype,globals,finput,fmodule,
  31. symbase,ppu,symtype;
  32. type
  33. tppumodule = class(tmodule)
  34. ppufile : tcompilerppufile; { the PPU file }
  35. sourcefn : pstring; { Source specified with "uses .. in '..'" }
  36. {$ifdef Test_Double_checksum}
  37. crc_array : pointer;
  38. crc_size : longint;
  39. crc_array2 : pointer;
  40. crc_size2 : longint;
  41. {$endif def Test_Double_checksum}
  42. constructor create(LoadedFrom:TModule;const s:string;const fn:string;_is_unit:boolean);
  43. destructor destroy;override;
  44. procedure reset;override;
  45. function openppu:boolean;
  46. procedure getppucrc;
  47. procedure writeppu;
  48. procedure loadppu;
  49. function needrecompile:boolean;
  50. private
  51. function search_unit(onlysource,shortname:boolean):boolean;
  52. procedure load_interface;
  53. procedure load_implementation;
  54. procedure load_symtable_refs;
  55. procedure load_usedunits;
  56. procedure writesourcefiles;
  57. procedure writeusedunit(intf:boolean);
  58. procedure writelinkcontainer(var p:tlinkcontainer;id:byte;strippath:boolean);
  59. procedure writederefmap;
  60. procedure writederefdata;
  61. procedure writeImportSymbols;
  62. procedure readsourcefiles;
  63. procedure readloadunit;
  64. procedure readlinkcontainer(var p:tlinkcontainer);
  65. procedure readderefmap;
  66. procedure readderefdata;
  67. procedure readImportSymbols;
  68. {$IFDEF MACRO_DIFF_HINT}
  69. procedure writeusedmacro(p:TNamedIndexItem;arg:pointer);
  70. procedure writeusedmacros;
  71. procedure readusedmacros;
  72. {$ENDIF}
  73. end;
  74. procedure reload_flagged_units;
  75. function registerunit(callermodule:tmodule;const s : stringid;const fn:string) : tppumodule;
  76. implementation
  77. uses
  78. verbose,systems,version,
  79. symtable, symsym,
  80. scanner,
  81. aasmbase,ogbase,
  82. parser;
  83. {****************************************************************************
  84. Helpers
  85. ****************************************************************************}
  86. procedure reload_flagged_units;
  87. var
  88. hp : tmodule;
  89. begin
  90. { now reload all dependent units }
  91. hp:=tmodule(loaded_units.first);
  92. while assigned(hp) do
  93. begin
  94. if hp.do_reload then
  95. tppumodule(hp).loadppu;
  96. hp:=tmodule(hp.next);
  97. end;
  98. end;
  99. {****************************************************************************
  100. TPPUMODULE
  101. ****************************************************************************}
  102. constructor tppumodule.create(LoadedFrom:TModule;const s:string;const fn:string;_is_unit:boolean);
  103. begin
  104. inherited create(LoadedFrom,s,_is_unit);
  105. ppufile:=nil;
  106. sourcefn:=stringdup(fn);
  107. end;
  108. destructor tppumodule.Destroy;
  109. begin
  110. if assigned(ppufile) then
  111. ppufile.free;
  112. ppufile:=nil;
  113. stringdispose(sourcefn);
  114. inherited Destroy;
  115. end;
  116. procedure tppumodule.reset;
  117. begin
  118. if assigned(ppufile) then
  119. begin
  120. ppufile.free;
  121. ppufile:=nil;
  122. end;
  123. inherited reset;
  124. end;
  125. function tppumodule.openppu:boolean;
  126. var
  127. ppufiletime : longint;
  128. begin
  129. openppu:=false;
  130. Message1(unit_t_ppu_loading,ppufilename^);
  131. { Get ppufile time (also check if the file exists) }
  132. ppufiletime:=getnamedfiletime(ppufilename^);
  133. if ppufiletime=-1 then
  134. exit;
  135. { Open the ppufile }
  136. Message1(unit_u_ppu_name,ppufilename^);
  137. ppufile:=tcompilerppufile.create(ppufilename^);
  138. if not ppufile.openfile then
  139. begin
  140. ppufile.free;
  141. ppufile:=nil;
  142. Message(unit_u_ppu_file_too_short);
  143. exit;
  144. end;
  145. { check for a valid PPU file }
  146. if not ppufile.CheckPPUId then
  147. begin
  148. ppufile.free;
  149. ppufile:=nil;
  150. Message(unit_u_ppu_invalid_header);
  151. exit;
  152. end;
  153. { check for allowed PPU versions }
  154. if not (ppufile.GetPPUVersion = CurrentPPUVersion) then
  155. begin
  156. Message1(unit_u_ppu_invalid_version,tostr(ppufile.GetPPUVersion));
  157. ppufile.free;
  158. ppufile:=nil;
  159. exit;
  160. end;
  161. { check the target processor }
  162. if tsystemcpu(ppufile.header.cpu)<>target_cpu then
  163. begin
  164. ppufile.free;
  165. ppufile:=nil;
  166. Message(unit_u_ppu_invalid_processor);
  167. exit;
  168. end;
  169. { check target }
  170. if tsystem(ppufile.header.target)<>target_info.system then
  171. begin
  172. ppufile.free;
  173. ppufile:=nil;
  174. Message(unit_u_ppu_invalid_target);
  175. exit;
  176. end;
  177. {$ifdef cpufpemu}
  178. { check if floating point emulation is on?}
  179. { fpu emulation isn't unit levelwise
  180. if ((ppufile.header.flags and uf_fpu_emulation)<>0) and
  181. (cs_fp_emulation in aktmoduleswitches) then
  182. begin
  183. ppufile.free;
  184. ppufile:=nil;
  185. Message(unit_u_ppu_invalid_fpumode);
  186. exit;
  187. end;
  188. }
  189. {$endif cpufpemu}
  190. { Load values to be access easier }
  191. flags:=ppufile.header.flags;
  192. crc:=ppufile.header.checksum;
  193. interface_crc:=ppufile.header.interface_checksum;
  194. { Show Debug info }
  195. Message1(unit_u_ppu_time,filetimestring(ppufiletime));
  196. Message1(unit_u_ppu_flags,tostr(flags));
  197. Message1(unit_u_ppu_crc,hexstr(ppufile.header.checksum,8));
  198. Message1(unit_u_ppu_crc,hexstr(ppufile.header.interface_checksum,8)+' (intfc)');
  199. do_compile:=false;
  200. openppu:=true;
  201. end;
  202. function tppumodule.search_unit(onlysource,shortname:boolean):boolean;
  203. var
  204. singlepathstring,
  205. filename : string;
  206. Function UnitExists(const ext:string;var foundfile:string):boolean;
  207. begin
  208. Message1(unit_t_unitsearch,Singlepathstring+filename+ext);
  209. UnitExists:=FindFile(FileName+ext,Singlepathstring,foundfile);
  210. end;
  211. Function PPUSearchPath(const s:string):boolean;
  212. var
  213. found : boolean;
  214. hs : string;
  215. begin
  216. Found:=false;
  217. singlepathstring:=FixPath(s,false);
  218. { Check for PPU file }
  219. Found:=UnitExists(target_info.unitext,hs);
  220. if Found then
  221. Begin
  222. SetFileName(hs,false);
  223. Found:=OpenPPU;
  224. End;
  225. PPUSearchPath:=Found;
  226. end;
  227. Function SourceSearchPath(const s:string):boolean;
  228. var
  229. found : boolean;
  230. hs : string;
  231. begin
  232. Found:=false;
  233. singlepathstring:=FixPath(s,false);
  234. { Check for Sources }
  235. ppufile:=nil;
  236. do_compile:=true;
  237. recompile_reason:=rr_noppu;
  238. {Check for .pp file}
  239. Found:=UnitExists(sourceext,hs);
  240. if not Found then
  241. begin
  242. { Check for .pas }
  243. Found:=UnitExists(pasext,hs);
  244. end;
  245. if not Found and (m_mac in aktmodeswitches) then
  246. begin
  247. { Check for .p, if mode is macpas}
  248. Found:=UnitExists(pext,hs);
  249. end;
  250. stringdispose(mainsource);
  251. if Found then
  252. begin
  253. sources_avail:=true;
  254. { Load Filenames when found }
  255. mainsource:=StringDup(hs);
  256. SetFileName(hs,false);
  257. end
  258. else
  259. sources_avail:=false;
  260. SourceSearchPath:=Found;
  261. end;
  262. Function SearchPath(const s:string):boolean;
  263. var
  264. found : boolean;
  265. begin
  266. { First check for a ppu, then for the source }
  267. found:=false;
  268. if not onlysource then
  269. found:=PPUSearchPath(s);
  270. if not found then
  271. found:=SourceSearchPath(s);
  272. SearchPath:=found;
  273. end;
  274. Function SearchPathList(list:TSearchPathList):boolean;
  275. var
  276. hp : TStringListItem;
  277. found : boolean;
  278. begin
  279. found:=false;
  280. hp:=TStringListItem(list.First);
  281. while assigned(hp) do
  282. begin
  283. found:=SearchPath(hp.Str);
  284. if found then
  285. break;
  286. hp:=TStringListItem(hp.next);
  287. end;
  288. SearchPathList:=found;
  289. end;
  290. var
  291. fnd : boolean;
  292. hs : string;
  293. begin
  294. if shortname then
  295. filename:=FixFileName(Copy(realmodulename^,1,8))
  296. else
  297. filename:=FixFileName(realmodulename^);
  298. { try to find unit
  299. 1. look for ppu in cwd
  300. 2. look for ppu in outputpath if set, this is tp7 compatible (PFV)
  301. 3. look for the specified source file (from the uses line)
  302. 4. look for source in cwd
  303. 5. look in same path as local unit
  304. 6. local unit pathlist
  305. 7. global unit pathlist }
  306. fnd:=false;
  307. if not onlysource then
  308. begin
  309. fnd:=PPUSearchPath('.');
  310. if (not fnd) and (outputpath^<>'') then
  311. fnd:=PPUSearchPath(outputpath^);
  312. end;
  313. if (not fnd) and (sourcefn^<>'') then
  314. begin
  315. { the full filename is specified so we can't use here the
  316. searchpath (PFV) }
  317. Message1(unit_t_unitsearch,AddExtension(sourcefn^,sourceext));
  318. fnd:=FindFile(AddExtension(sourcefn^,sourceext),'',hs);
  319. if not fnd then
  320. begin
  321. Message1(unit_t_unitsearch,AddExtension(sourcefn^,pasext));
  322. fnd:=FindFile(AddExtension(sourcefn^,pasext),'',hs);
  323. end;
  324. if not fnd and ((m_mac in aktmodeswitches) or (tf_p_ext_support in target_info.flags)) then
  325. begin
  326. Message1(unit_t_unitsearch,AddExtension(sourcefn^,pext));
  327. fnd:=FindFile(AddExtension(sourcefn^,pext),'',hs);
  328. end;
  329. if fnd then
  330. begin
  331. sources_avail:=true;
  332. do_compile:=true;
  333. recompile_reason:=rr_noppu;
  334. stringdispose(mainsource);
  335. mainsource:=StringDup(hs);
  336. SetFileName(hs,false);
  337. end;
  338. end;
  339. if not fnd then
  340. fnd:=SourceSearchPath('.');
  341. if (not fnd) and Assigned(Loaded_From) then
  342. begin
  343. fnd:=PPUSearchPath(Loaded_From.Path^);
  344. if not fnd then
  345. fnd:=SourceSearchPath(Loaded_From.Path^);
  346. if not fnd then
  347. fnd:=SearchPathList(Loaded_From.LocalUnitSearchPath);
  348. end;
  349. if not fnd then
  350. fnd:=SearchPathList(UnitSearchPath);
  351. { try to find a file with the first 8 chars of the modulename, like
  352. dos }
  353. if (not fnd) and (length(filename)>8) then
  354. begin
  355. filename:=copy(filename,1,8);
  356. fnd:=SearchPath('.');
  357. if (not fnd) then
  358. fnd:=SearchPathList(LocalUnitSearchPath);
  359. if not fnd then
  360. fnd:=SearchPathList(UnitSearchPath);
  361. end;
  362. search_unit:=fnd;
  363. end;
  364. {**********************************
  365. PPU Reading/Writing Helpers
  366. ***********************************}
  367. {$IFDEF MACRO_DIFF_HINT}
  368. var
  369. is_initial: Boolean;
  370. procedure tppumodule.writeusedmacro(p:TNamedIndexItem;arg:pointer);
  371. begin
  372. if tmacro(p).is_used or is_initial then
  373. begin
  374. ppufile.putstring(p.name);
  375. ppufile.putbyte(byte(is_initial));
  376. ppufile.putbyte(byte(tmacro(p).is_used));
  377. end;
  378. end;
  379. procedure tppumodule.writeusedmacros;
  380. begin
  381. ppufile.do_crc:=false;
  382. is_initial:= true;
  383. initialmacrosymtable.foreach(@writeusedmacro,nil);
  384. is_initial:= false;
  385. if assigned(globalmacrosymtable) then
  386. globalmacrosymtable.foreach(@writeusedmacro,nil);
  387. localmacrosymtable.foreach(@writeusedmacro,nil);
  388. ppufile.writeentry(ibusedmacros);
  389. ppufile.do_crc:=true;
  390. end;
  391. {$ENDIF}
  392. procedure tppumodule.writesourcefiles;
  393. var
  394. hp : tinputfile;
  395. i,j : longint;
  396. begin
  397. { second write the used source files }
  398. ppufile.do_crc:=false;
  399. hp:=sourcefiles.files;
  400. { write source files directly in good order }
  401. j:=0;
  402. while assigned(hp) do
  403. begin
  404. inc(j);
  405. hp:=hp.ref_next;
  406. end;
  407. while j>0 do
  408. begin
  409. hp:=sourcefiles.files;
  410. for i:=1 to j-1 do
  411. hp:=hp.ref_next;
  412. ppufile.putstring(hp.name^);
  413. ppufile.putlongint(hp.getfiletime);
  414. dec(j);
  415. end;
  416. ppufile.writeentry(ibsourcefiles);
  417. ppufile.do_crc:=true;
  418. end;
  419. procedure tppumodule.writeusedunit(intf:boolean);
  420. var
  421. hp : tused_unit;
  422. oldcrc : boolean;
  423. begin
  424. { write a reference for each used unit }
  425. hp:=tused_unit(used_units.first);
  426. while assigned(hp) do
  427. begin
  428. if hp.in_interface=intf then
  429. begin
  430. ppufile.putstring(hp.u.realmodulename^);
  431. { the checksum should not affect the crc of this unit ! (PFV) }
  432. oldcrc:=ppufile.do_crc;
  433. ppufile.do_crc:=false;
  434. ppufile.putlongint(longint(hp.checksum));
  435. ppufile.putlongint(longint(hp.interface_checksum));
  436. ppufile.do_crc:=oldcrc;
  437. end;
  438. hp:=tused_unit(hp.next);
  439. end;
  440. ppufile.do_interface_crc:=true;
  441. ppufile.writeentry(ibloadunit);
  442. end;
  443. procedure tppumodule.writelinkcontainer(var p:tlinkcontainer;id:byte;strippath:boolean);
  444. var
  445. hcontainer : tlinkcontainer;
  446. s : string;
  447. mask : cardinal;
  448. begin
  449. hcontainer:=TLinkContainer.Create;
  450. while not p.empty do
  451. begin
  452. s:=p.get(mask);
  453. if strippath then
  454. ppufile.putstring(SplitFileName(s))
  455. else
  456. ppufile.putstring(s);
  457. ppufile.putlongint(mask);
  458. hcontainer.add(s,mask);
  459. end;
  460. ppufile.writeentry(id);
  461. p.Free;
  462. p:=hcontainer;
  463. end;
  464. procedure tppumodule.writederefmap;
  465. var
  466. i : longint;
  467. oldcrc : boolean;
  468. begin
  469. { This does not influence crc }
  470. oldcrc:=ppufile.do_crc;
  471. ppufile.do_crc:=false;
  472. { The unit map used for resolving }
  473. ppufile.putlongint(derefmapcnt);
  474. for i:=0 to derefmapcnt-1 do
  475. begin
  476. if not assigned(derefmap[i].u) then
  477. internalerror(2005011512);
  478. ppufile.putstring(derefmap[i].u.modulename^)
  479. end;
  480. ppufile.writeentry(ibderefmap);
  481. ppufile.do_crc:=oldcrc;
  482. end;
  483. procedure tppumodule.writederefdata;
  484. var
  485. oldcrc : boolean;
  486. len,hlen : longint;
  487. buf : array[0..1023] of byte;
  488. begin
  489. if derefdataintflen>derefdata.size then
  490. internalerror(200310223);
  491. derefdata.seek(0);
  492. { Write interface data }
  493. len:=derefdataintflen;
  494. while (len>0) do
  495. begin
  496. if len>1024 then
  497. hlen:=1024
  498. else
  499. hlen:=len;
  500. derefdata.read(buf,hlen);
  501. ppufile.putdata(buf,hlen);
  502. dec(len,hlen);
  503. end;
  504. { Write implementation data, this does not influence crc }
  505. oldcrc:=ppufile.do_crc;
  506. ppufile.do_crc:=false;
  507. len:=derefdata.size-derefdataintflen;
  508. while (len>0) do
  509. begin
  510. if len>1024 then
  511. hlen:=1024
  512. else
  513. hlen:=len;
  514. derefdata.read(buf,hlen);
  515. ppufile.putdata(buf,hlen);
  516. dec(len,hlen);
  517. end;
  518. if derefdata.pos<>derefdata.size then
  519. internalerror(200310224);
  520. ppufile.do_crc:=oldcrc;
  521. ppufile.writeentry(ibderefdata);
  522. end;
  523. procedure tppumodule.writeImportSymbols;
  524. var
  525. i,j : longint;
  526. ImportLibrary : TImportLibrary;
  527. ImportSymbol : TImportSymbol;
  528. begin
  529. for i:=0 to ImportLibraryList.Count-1 do
  530. begin
  531. ImportLibrary:=TImportLibrary(ImportLibraryList[i]);
  532. ppufile.putstring(ImportLibrary.Name);
  533. ppufile.putlongint(ImportLibrary.ImportSymbolList.Count);
  534. for j:=0 to ImportLibrary.ImportSymbolList.Count-1 do
  535. begin
  536. ImportSymbol:=TImportSymbol(ImportLibrary.ImportSymbolList[j]);
  537. ppufile.putstring(ImportSymbol.Name);
  538. ppufile.putlongint(ImportSymbol.OrdNr);
  539. ppufile.putbyte(byte(ImportSymbol.IsVar));
  540. end;
  541. end;
  542. ppufile.writeentry(ibImportSymbols);
  543. end;
  544. {$IFDEF MACRO_DIFF_HINT}
  545. {
  546. Define MACRO_DIFF_HINT for the whole compiler (and ppudump)
  547. to turn this facility on. Also the hint messages defined
  548. below must be commented in in the msg/errore.msg file.
  549. There is some problems with this, thats why it is shut off:
  550. At the first compilation, consider a macro which is not initially
  551. defined, but it is used (e g the check that it is undefined is true).
  552. Since it do not exist, there is no macro object where the is_used
  553. flag can be set. Later on when the macro is defined, and the ppu
  554. is opened, the check cannot detect this.
  555. Also, in which macro object should this flag be set ? It cant be set
  556. for macros in the initialmacrosymboltable since this table is shared
  557. between different files.
  558. }
  559. procedure tppumodule.readusedmacros;
  560. var
  561. hs : string;
  562. mac : tmacro;
  563. was_initial,
  564. was_used : boolean;
  565. {Reads macros which was defined or used when the module was compiled.
  566. This is done when a ppu file is open, before it possibly is parsed.}
  567. begin
  568. while not ppufile.endofentry do
  569. begin
  570. hs:=ppufile.getstring;
  571. was_initial:=boolean(ppufile.getbyte);
  572. was_used:=boolean(ppufile.getbyte);
  573. mac:=tmacro(initialmacrosymtable.search(hs));
  574. if assigned(mac) then
  575. begin
  576. {$ifndef EXTDEBUG}
  577. { if we don't have the sources why tell }
  578. if sources_avail then
  579. {$endif ndef EXTDEBUG}
  580. if (not was_initial) and was_used then
  581. Message2(unit_h_cond_not_set_in_last_compile,hs,mainsource^);
  582. end
  583. else { not assigned }
  584. if was_initial and
  585. was_used then
  586. Message2(unit_h_cond_set_in_last_compile,hs,mainsource^);
  587. end;
  588. end;
  589. {$ENDIF}
  590. procedure tppumodule.readsourcefiles;
  591. var
  592. temp,hs : string;
  593. temp_dir : string;
  594. main_dir : string;
  595. found,
  596. is_main : boolean;
  597. orgfiletime,
  598. source_time : longint;
  599. hp : tinputfile;
  600. begin
  601. sources_avail:=true;
  602. is_main:=true;
  603. main_dir:='';
  604. while not ppufile.endofentry do
  605. begin
  606. hs:=ppufile.getstring;
  607. orgfiletime:=ppufile.getlongint;
  608. temp_dir:='';
  609. if (flags and uf_in_library)<>0 then
  610. begin
  611. sources_avail:=false;
  612. temp:=' library';
  613. end
  614. else if pos('Macro ',hs)=1 then
  615. begin
  616. { we don't want to find this file }
  617. { but there is a problem with file indexing !! }
  618. temp:='';
  619. end
  620. else
  621. begin
  622. { check the date of the source files:
  623. 1 path of ppu
  624. 2 path of main source
  625. 3 current dir
  626. 4 include/unit path }
  627. Source_Time:=GetNamedFileTime(path^+hs);
  628. found:=false;
  629. if Source_Time<>-1 then
  630. hs:=path^+hs
  631. else
  632. if not(is_main) then
  633. begin
  634. Source_Time:=GetNamedFileTime(main_dir+hs);
  635. if Source_Time<>-1 then
  636. hs:=main_dir+hs;
  637. end;
  638. if Source_Time=-1 then
  639. Source_Time:=GetNamedFileTime(hs);
  640. if (Source_Time=-1) then
  641. begin
  642. if is_main then
  643. found:=unitsearchpath.FindFile(hs,temp_dir)
  644. else
  645. found:=includesearchpath.FindFile(hs,temp_dir);
  646. if found then
  647. begin
  648. Source_Time:=GetNamedFileTime(temp_dir);
  649. if Source_Time<>-1 then
  650. hs:=temp_dir;
  651. end;
  652. end;
  653. if Source_Time<>-1 then
  654. begin
  655. if is_main then
  656. main_dir:=splitpath(hs);
  657. temp:=' time '+filetimestring(source_time);
  658. if (orgfiletime<>-1) and
  659. (source_time<>orgfiletime) then
  660. begin
  661. if ((flags and uf_release)=0) then
  662. begin
  663. do_compile:=true;
  664. recompile_reason:=rr_sourcenewer;
  665. end
  666. else
  667. Message2(unit_h_source_modified,hs,ppufilename^);
  668. temp:=temp+' *';
  669. end;
  670. end
  671. else
  672. begin
  673. sources_avail:=false;
  674. temp:=' not found';
  675. end;
  676. hp:=tinputfile.create(hs);
  677. { the indexing is wrong here PM }
  678. sourcefiles.register_file(hp);
  679. end;
  680. if is_main then
  681. begin
  682. stringdispose(mainsource);
  683. mainsource:=stringdup(hs);
  684. end;
  685. Message1(unit_u_ppu_source,hs+temp);
  686. is_main:=false;
  687. end;
  688. { check if we want to rebuild every unit, only if the sources are
  689. available }
  690. if do_build and sources_avail and
  691. ((flags and uf_release)=0) then
  692. begin
  693. do_compile:=true;
  694. recompile_reason:=rr_build;
  695. end;
  696. end;
  697. procedure tppumodule.readloadunit;
  698. var
  699. hs : string;
  700. pu : tused_unit;
  701. hp : tppumodule;
  702. intfchecksum,
  703. checksum : cardinal;
  704. begin
  705. while not ppufile.endofentry do
  706. begin
  707. hs:=ppufile.getstring;
  708. checksum:=cardinal(ppufile.getlongint);
  709. intfchecksum:=cardinal(ppufile.getlongint);
  710. { set the state of this unit before registering, this is
  711. needed for a correct circular dependency check }
  712. hp:=registerunit(self,hs,'');
  713. pu:=addusedunit(hp,false,nil);
  714. pu.checksum:=checksum;
  715. pu.interface_checksum:=intfchecksum;
  716. end;
  717. in_interface:=false;
  718. end;
  719. procedure tppumodule.readlinkcontainer(var p:tlinkcontainer);
  720. var
  721. s : string;
  722. m : longint;
  723. begin
  724. while not ppufile.endofentry do
  725. begin
  726. s:=ppufile.getstring;
  727. m:=ppufile.getlongint;
  728. p.add(s,m);
  729. end;
  730. end;
  731. procedure tppumodule.readderefmap;
  732. var
  733. i : longint;
  734. begin
  735. { Load unit map used for resolving }
  736. derefmapsize:=ppufile.getlongint;
  737. derefmapcnt:=derefmapsize;
  738. getmem(derefmap,derefmapsize*sizeof(tderefmaprec));
  739. fillchar(derefmap^,derefmapsize*sizeof(tderefmaprec),0);
  740. for i:=0 to derefmapsize-1 do
  741. derefmap[i].modulename:=stringdup(ppufile.getstring);
  742. end;
  743. procedure tppumodule.readderefdata;
  744. var
  745. len,hlen : longint;
  746. buf : array[0..1023] of byte;
  747. begin
  748. len:=ppufile.entrysize;
  749. while (len>0) do
  750. begin
  751. if len>1024 then
  752. hlen:=1024
  753. else
  754. hlen:=len;
  755. ppufile.getdata(buf,hlen);
  756. derefdata.write(buf,hlen);
  757. dec(len,hlen);
  758. end;
  759. end;
  760. procedure tppumodule.readImportSymbols;
  761. var
  762. j,
  763. extsymcnt : longint;
  764. ImportLibrary : TImportLibrary;
  765. extsymname : string;
  766. extsymordnr : longint;
  767. extsymisvar : boolean;
  768. begin
  769. while not ppufile.endofentry do
  770. begin
  771. ImportLibrary:=TImportLibrary.Create(ImportLibraryList,ppufile.getstring);
  772. extsymcnt:=ppufile.getlongint;
  773. for j:=0 to extsymcnt-1 do
  774. begin
  775. extsymname:=ppufile.getstring;
  776. extsymordnr:=ppufile.getlongint;
  777. extsymisvar:=(ppufile.getbyte<>0);
  778. TImportSymbol.Create(ImportLibrary.ImportSymbolList,extsymname,extsymordnr,extsymisvar);
  779. end;
  780. end;
  781. end;
  782. procedure tppumodule.load_interface;
  783. var
  784. b : byte;
  785. newmodulename : string;
  786. begin
  787. { read interface part }
  788. repeat
  789. b:=ppufile.readentry;
  790. case b of
  791. ibmodulename :
  792. begin
  793. newmodulename:=ppufile.getstring;
  794. if (cs_check_unit_name in aktglobalswitches) and
  795. (upper(newmodulename)<>modulename^) then
  796. Message2(unit_f_unit_name_error,realmodulename^,newmodulename);
  797. stringdispose(modulename);
  798. stringdispose(realmodulename);
  799. modulename:=stringdup(upper(newmodulename));
  800. realmodulename:=stringdup(newmodulename);
  801. end;
  802. ibsourcefiles :
  803. readsourcefiles;
  804. {$IFDEF MACRO_DIFF_HINT}
  805. ibusedmacros :
  806. readusedmacros;
  807. {$ENDIF}
  808. ibloadunit :
  809. readloadunit;
  810. iblinkunitofiles :
  811. readlinkcontainer(LinkUnitOFiles);
  812. iblinkunitstaticlibs :
  813. readlinkcontainer(LinkUnitStaticLibs);
  814. iblinkunitsharedlibs :
  815. readlinkcontainer(LinkUnitSharedLibs);
  816. iblinkotherofiles :
  817. readlinkcontainer(LinkotherOFiles);
  818. iblinkotherstaticlibs :
  819. readlinkcontainer(LinkotherStaticLibs);
  820. iblinkothersharedlibs :
  821. readlinkcontainer(LinkotherSharedLibs);
  822. ibImportSymbols :
  823. readImportSymbols;
  824. ibderefmap :
  825. readderefmap;
  826. ibderefdata :
  827. readderefdata;
  828. ibendinterface :
  829. break;
  830. else
  831. Message1(unit_f_ppu_invalid_entry,tostr(b));
  832. end;
  833. { we can already stop when we know that we must recompile }
  834. if do_compile then
  835. exit;
  836. until false;
  837. end;
  838. procedure tppumodule.load_implementation;
  839. var
  840. b : byte;
  841. begin
  842. { read implementation part }
  843. repeat
  844. b:=ppufile.readentry;
  845. case b of
  846. ibloadunit :
  847. readloadunit;
  848. ibasmsymbols :
  849. {$warning TODO Remove ibasmsymbols}
  850. ;
  851. ibendimplementation :
  852. break;
  853. else
  854. Message1(unit_f_ppu_invalid_entry,tostr(b));
  855. end;
  856. until false;
  857. end;
  858. procedure tppumodule.load_symtable_refs;
  859. var
  860. b : byte;
  861. i : longint;
  862. begin
  863. if (flags and uf_has_browser)<>0 then
  864. begin
  865. tstoredsymtable(globalsymtable).load_references(ppufile,true);
  866. for i:=0 to unitmapsize-1 do
  867. tstoredsymtable(globalsymtable).load_references(ppufile,false);
  868. b:=ppufile.readentry;
  869. if b<>ibendbrowser then
  870. Message1(unit_f_ppu_invalid_entry,tostr(b));
  871. end;
  872. if ((flags and uf_local_browser)<>0) then
  873. tstaticsymtable(localsymtable).load_references(ppufile,true);
  874. end;
  875. procedure tppumodule.writeppu;
  876. var
  877. pu : tused_unit;
  878. begin
  879. Message1(unit_u_ppu_write,realmodulename^);
  880. { create unit flags }
  881. if cs_browser in aktmoduleswitches then
  882. flags:=flags or uf_has_browser;
  883. if cs_local_browser in aktmoduleswitches then
  884. flags:=flags or uf_local_browser;
  885. if do_release then
  886. flags:=flags or uf_release;
  887. if assigned(localsymtable) then
  888. flags:=flags or uf_local_symtable;
  889. {$ifdef cpufpemu}
  890. if (cs_fp_emulation in aktmoduleswitches) then
  891. flags:=flags or uf_fpu_emulation;
  892. {$endif cpufpemu}
  893. {$ifdef Test_Double_checksum_write}
  894. Assign(CRCFile,s+'.IMP');
  895. Rewrite(CRCFile);
  896. {$endif def Test_Double_checksum_write}
  897. { create new ppufile }
  898. ppufile:=tcompilerppufile.create(ppufilename^);
  899. if not ppufile.createfile then
  900. Message(unit_f_ppu_cannot_write);
  901. { first the unitname }
  902. ppufile.putstring(realmodulename^);
  903. ppufile.writeentry(ibmodulename);
  904. writesourcefiles;
  905. {$IFDEF MACRO_DIFF_HINT}
  906. writeusedmacros;
  907. {$ENDIF}
  908. { write interface uses }
  909. writeusedunit(true);
  910. { write the objectfiles and libraries that come for this unit,
  911. preserve the containers becuase they are still needed to load
  912. the link.res. All doesn't depend on the crc! It doesn't matter
  913. if a unit is in a .o or .a file }
  914. ppufile.do_crc:=false;
  915. writelinkcontainer(linkunitofiles,iblinkunitofiles,true);
  916. writelinkcontainer(linkunitstaticlibs,iblinkunitstaticlibs,true);
  917. writelinkcontainer(linkunitsharedlibs,iblinkunitsharedlibs,true);
  918. writelinkcontainer(linkotherofiles,iblinkotherofiles,false);
  919. writelinkcontainer(linkotherstaticlibs,iblinkotherstaticlibs,true);
  920. writelinkcontainer(linkothersharedlibs,iblinkothersharedlibs,true);
  921. writeImportSymbols;
  922. ppufile.do_crc:=true;
  923. { generate implementation deref data, the interface deref data is
  924. already generated when calculating the interface crc }
  925. if (cs_compilesystem in aktmoduleswitches) then
  926. begin
  927. tstoredsymtable(globalsymtable).buildderef;
  928. derefdataintflen:=derefdata.size;
  929. end;
  930. tstoredsymtable(globalsymtable).buildderefimpl;
  931. if (flags and uf_local_symtable)<>0 then
  932. begin
  933. tstoredsymtable(localsymtable).buildderef;
  934. tstoredsymtable(localsymtable).buildderefimpl;
  935. end;
  936. writederefmap;
  937. writederefdata;
  938. ppufile.writeentry(ibendinterface);
  939. { write the symtable entries }
  940. tstoredsymtable(globalsymtable).ppuwrite(ppufile);
  941. if assigned(globalmacrosymtable) and (globalmacrosymtable.symindex.count > 0) then
  942. begin
  943. ppufile.putbyte(byte(true));
  944. ppufile.writeentry(ibexportedmacros);
  945. tstoredsymtable(globalmacrosymtable).ppuwrite(ppufile);
  946. end
  947. else
  948. begin
  949. ppufile.putbyte(byte(false));
  950. ppufile.writeentry(ibexportedmacros);
  951. end;
  952. { everything after this doesn't affect the crc }
  953. ppufile.do_crc:=false;
  954. { write implementation uses }
  955. writeusedunit(false);
  956. { end of implementation }
  957. ppufile.writeentry(ibendimplementation);
  958. { write static symtable
  959. needed for local debugging of unit functions }
  960. if (flags and uf_local_symtable)<>0 then
  961. tstoredsymtable(localsymtable).ppuwrite(ppufile);
  962. { write all browser section }
  963. if (flags and uf_has_browser)<>0 then
  964. begin
  965. tstoredsymtable(globalsymtable).write_references(ppufile,true);
  966. pu:=tused_unit(used_units.first);
  967. while assigned(pu) do
  968. begin
  969. tstoredsymtable(pu.u.globalsymtable).write_references(ppufile,false);
  970. pu:=tused_unit(pu.next);
  971. end;
  972. ppufile.writeentry(ibendbrowser);
  973. end;
  974. if ((flags and uf_local_browser)<>0) then
  975. begin
  976. if not assigned(localsymtable) then
  977. internalerror(200408271);
  978. tstaticsymtable(localsymtable).write_references(ppufile,true);
  979. end;
  980. { the last entry ibend is written automaticly }
  981. { flush to be sure }
  982. ppufile.flush;
  983. { create and write header }
  984. ppufile.header.size:=ppufile.size;
  985. ppufile.header.checksum:=ppufile.crc;
  986. ppufile.header.interface_checksum:=ppufile.interface_crc;
  987. ppufile.header.compiler:=wordversion;
  988. ppufile.header.cpu:=word(target_cpu);
  989. ppufile.header.target:=word(target_info.system);
  990. ppufile.header.flags:=flags;
  991. ppufile.writeheader;
  992. { save crc in current module also }
  993. crc:=ppufile.crc;
  994. interface_crc:=ppufile.interface_crc;
  995. {$ifdef Test_Double_checksum_write}
  996. close(CRCFile);
  997. {$endif Test_Double_checksum_write}
  998. ppufile.closefile;
  999. ppufile.free;
  1000. ppufile:=nil;
  1001. end;
  1002. procedure tppumodule.getppucrc;
  1003. begin
  1004. {$ifdef Test_Double_checksum_write}
  1005. Assign(CRCFile,s+'.INT')
  1006. Rewrite(CRCFile);
  1007. {$endif def Test_Double_checksum_write}
  1008. { create new ppufile }
  1009. ppufile:=tcompilerppufile.create(ppufilename^);
  1010. ppufile.crc_only:=true;
  1011. if not ppufile.createfile then
  1012. Message(unit_f_ppu_cannot_write);
  1013. { first the unitname }
  1014. ppufile.putstring(realmodulename^);
  1015. ppufile.writeentry(ibmodulename);
  1016. { the interface units affect the crc }
  1017. writeusedunit(true);
  1018. { deref data of interface that affect the crc }
  1019. derefdata.reset;
  1020. tstoredsymtable(globalsymtable).buildderef;
  1021. derefdataintflen:=derefdata.size;
  1022. writederefmap;
  1023. writederefdata;
  1024. ppufile.writeentry(ibendinterface);
  1025. { write the symtable entries }
  1026. tstoredsymtable(globalsymtable).ppuwrite(ppufile);
  1027. if assigned(globalmacrosymtable) and (globalmacrosymtable.symindex.count > 0) then
  1028. begin
  1029. ppufile.putbyte(byte(true));
  1030. ppufile.writeentry(ibexportedmacros);
  1031. tstoredsymtable(globalmacrosymtable).ppuwrite(ppufile);
  1032. end
  1033. else
  1034. begin
  1035. ppufile.putbyte(byte(false));
  1036. ppufile.writeentry(ibexportedmacros);
  1037. end;
  1038. { save crc }
  1039. crc:=ppufile.crc;
  1040. interface_crc:=ppufile.interface_crc;
  1041. { end of implementation, to generate a correct ppufile
  1042. for ppudump when using INTFPPU define }
  1043. ppufile.writeentry(ibendimplementation);
  1044. {$ifdef Test_Double_checksum}
  1045. crc_array:=ppufile.crc_test;
  1046. ppufile.crc_test:=nil;
  1047. crc_size:=ppufile.crc_index2;
  1048. crc_array2:=ppufile.crc_test2;
  1049. ppufile.crc_test2:=nil;
  1050. crc_size2:=ppufile.crc_index2;
  1051. {$endif Test_Double_checksum}
  1052. {$ifdef Test_Double_checksum_write}
  1053. close(CRCFile);
  1054. {$endif Test_Double_checksum_write}
  1055. { create and write header, this will only be used
  1056. for debugging purposes }
  1057. ppufile.header.size:=ppufile.size;
  1058. ppufile.header.checksum:=ppufile.crc;
  1059. ppufile.header.interface_checksum:=ppufile.interface_crc;
  1060. ppufile.header.compiler:=wordversion;
  1061. ppufile.header.cpu:=word(target_cpu);
  1062. ppufile.header.target:=word(target_info.system);
  1063. ppufile.header.flags:=flags;
  1064. ppufile.writeheader;
  1065. ppufile.closefile;
  1066. ppufile.free;
  1067. ppufile:=nil;
  1068. end;
  1069. procedure tppumodule.load_usedunits;
  1070. var
  1071. pu : tused_unit;
  1072. load_refs : boolean;
  1073. begin
  1074. if current_module<>self then
  1075. internalerror(200212284);
  1076. load_refs:=true;
  1077. { load the used units from interface }
  1078. in_interface:=true;
  1079. pu:=tused_unit(used_units.first);
  1080. while assigned(pu) do
  1081. begin
  1082. if pu.in_interface then
  1083. begin
  1084. tppumodule(pu.u).loadppu;
  1085. { if this unit is compiled we can stop }
  1086. if state=ms_compiled then
  1087. exit;
  1088. { add this unit to the dependencies }
  1089. pu.u.adddependency(self);
  1090. { need to recompile the current unit, check the interface
  1091. crc. And when not compiled with -Ur then check the complete
  1092. crc }
  1093. if (pu.u.interface_crc<>pu.interface_checksum) or
  1094. (
  1095. ((ppufile.header.flags and uf_release)=0) and
  1096. (pu.u.crc<>pu.checksum)
  1097. ) then
  1098. begin
  1099. Message2(unit_u_recompile_crc_change,realmodulename^,pu.u.realmodulename^);
  1100. recompile_reason:=rr_crcchanged;
  1101. do_compile:=true;
  1102. exit;
  1103. end;
  1104. end;
  1105. pu:=tused_unit(pu.next);
  1106. end;
  1107. { ok, now load the interface of this unit }
  1108. if current_module<>self then
  1109. internalerror(200208187);
  1110. globalsymtable:=tglobalsymtable.create(modulename^,moduleid);
  1111. tstoredsymtable(globalsymtable).ppuload(ppufile);
  1112. if ppufile.readentry<>ibexportedmacros then
  1113. Message(unit_f_ppu_read_error);
  1114. if boolean(ppufile.getbyte) then
  1115. begin
  1116. globalmacrosymtable:=tmacrosymtable.Create(true);
  1117. tstoredsymtable(globalmacrosymtable).ppuload(ppufile)
  1118. end;
  1119. interface_compiled:=true;
  1120. { read the implementation part, containing
  1121. the implementation uses and ObjData }
  1122. in_interface:=false;
  1123. load_implementation;
  1124. { now only read the implementation uses }
  1125. pu:=tused_unit(used_units.first);
  1126. while assigned(pu) do
  1127. begin
  1128. if (not pu.in_interface) then
  1129. begin
  1130. tppumodule(pu.u).loadppu;
  1131. { if this unit is compiled we can stop }
  1132. if state=ms_compiled then
  1133. exit;
  1134. { add this unit to the dependencies }
  1135. pu.u.adddependency(self);
  1136. { need to recompile the current unit ? }
  1137. if (pu.u.interface_crc<>pu.interface_checksum) then
  1138. begin
  1139. Message2(unit_u_recompile_crc_change,realmodulename^,pu.u.realmodulename^+' {impl}');
  1140. recompile_reason:=rr_crcchanged;
  1141. do_compile:=true;
  1142. exit;
  1143. end;
  1144. end;
  1145. pu:=tused_unit(pu.next);
  1146. end;
  1147. { load implementation symtable }
  1148. if (flags and uf_local_symtable)<>0 then
  1149. begin
  1150. localsymtable:=tstaticsymtable.create(modulename^,moduleid);
  1151. tstaticsymtable(localsymtable).ppuload(ppufile);
  1152. end;
  1153. { we can now derefence all pointers to the implementation parts }
  1154. tstoredsymtable(globalsymtable).derefimpl;
  1155. if assigned(localsymtable) then
  1156. tstoredsymtable(localsymtable).derefimpl;
  1157. { load browser info if stored }
  1158. if ((flags and uf_has_browser)<>0) and load_refs then
  1159. begin
  1160. if current_module<>self then
  1161. internalerror(200208188);
  1162. load_symtable_refs;
  1163. end;
  1164. end;
  1165. function tppumodule.needrecompile:boolean;
  1166. var
  1167. pu : tused_unit;
  1168. begin
  1169. result:=false;
  1170. pu:=tused_unit(used_units.first);
  1171. while assigned(pu) do
  1172. begin
  1173. { need to recompile the current unit, check the interface
  1174. crc. And when not compiled with -Ur then check the complete
  1175. crc }
  1176. if (pu.u.interface_crc<>pu.interface_checksum) or
  1177. (
  1178. (pu.in_interface) and
  1179. (pu.u.crc<>pu.checksum)
  1180. ) then
  1181. begin
  1182. result:=true;
  1183. exit;
  1184. end;
  1185. pu:=tused_unit(pu.next);
  1186. end;
  1187. end;
  1188. procedure tppumodule.loadppu;
  1189. const
  1190. ImplIntf : array[boolean] of string[15]=('implementation','interface');
  1191. var
  1192. do_load,
  1193. second_time : boolean;
  1194. old_current_module : tmodule;
  1195. begin
  1196. old_current_module:=current_module;
  1197. Message3(unit_u_load_unit,old_current_module.modulename^,
  1198. ImplIntf[old_current_module.in_interface],
  1199. modulename^);
  1200. { Update loaded_from to detect cycles }
  1201. loaded_from:=old_current_module;
  1202. { check if the globalsymtable is already available, but
  1203. we must reload when the do_reload flag is set }
  1204. if (not do_reload) and
  1205. assigned(globalsymtable) then
  1206. exit;
  1207. { reset }
  1208. do_load:=true;
  1209. second_time:=false;
  1210. current_module:=self;
  1211. SetCompileModule(current_module);
  1212. Fillchar(aktfilepos,0,sizeof(aktfilepos));
  1213. { A force reload }
  1214. if do_reload then
  1215. begin
  1216. Message(unit_u_forced_reload);
  1217. do_reload:=false;
  1218. { When the unit is already loaded or being loaded
  1219. we can maybe skip a complete reload/recompile }
  1220. if assigned(globalsymtable) and
  1221. (not needrecompile) then
  1222. begin
  1223. { When we don't have any data stored yet there
  1224. is nothing to resolve }
  1225. if interface_compiled then
  1226. begin
  1227. Message1(unit_u_reresolving_unit,modulename^);
  1228. tstoredsymtable(globalsymtable).deref;
  1229. tstoredsymtable(globalsymtable).derefimpl;
  1230. if assigned(localsymtable) then
  1231. begin
  1232. tstoredsymtable(localsymtable).deref;
  1233. tstoredsymtable(localsymtable).derefimpl;
  1234. end;
  1235. end
  1236. else
  1237. Message1(unit_u_skipping_reresolving_unit,modulename^);
  1238. do_load:=false;
  1239. end;
  1240. end;
  1241. if do_load then
  1242. begin
  1243. { we are loading a new module, save the state of the scanner
  1244. and reset scanner+module }
  1245. if assigned(current_scanner) then
  1246. current_scanner.tempcloseinputfile;
  1247. current_scanner:=nil;
  1248. { loading the unit for a second time? }
  1249. if state=ms_registered then
  1250. state:=ms_load
  1251. else
  1252. begin
  1253. { try to load the unit a second time first }
  1254. Message1(unit_u_second_load_unit,modulename^);
  1255. Message2(unit_u_previous_state,modulename^,ModuleStateStr[state]);
  1256. { Flag modules to reload }
  1257. flagdependent(old_current_module);
  1258. { Reset the module }
  1259. reset;
  1260. if state in [ms_compile,ms_second_compile] then
  1261. begin
  1262. Message1(unit_u_second_compile_unit,modulename^);
  1263. state:=ms_second_compile;
  1264. do_compile:=true;
  1265. end
  1266. else
  1267. state:=ms_second_load;
  1268. second_time:=true;
  1269. end;
  1270. { close old_current_ppu on system that are
  1271. short on file handles like DOS PM }
  1272. {$ifdef SHORT_ON_FILE_HANDLES}
  1273. if old_current_module.is_unit and
  1274. assigned(tppumodule(old_current_module).ppufile) then
  1275. tppumodule(old_current_module).ppufile.tempclose;
  1276. {$endif SHORT_ON_FILE_HANDLES}
  1277. { try to opening ppu, skip this when we already
  1278. know that we need to compile the unit }
  1279. if not do_compile then
  1280. begin
  1281. Message1(unit_u_loading_unit,modulename^);
  1282. search_unit(false,false);
  1283. if not do_compile then
  1284. begin
  1285. load_interface;
  1286. if not do_compile then
  1287. begin
  1288. load_usedunits;
  1289. if not do_compile then
  1290. Message1(unit_u_finished_loading_unit,modulename^);
  1291. end;
  1292. end;
  1293. { PPU is not needed anymore }
  1294. if assigned(ppufile) then
  1295. begin
  1296. ppufile.closefile;
  1297. ppufile.free;
  1298. ppufile:=nil;
  1299. end;
  1300. end;
  1301. { Do we need to recompile the unit }
  1302. if do_compile then
  1303. begin
  1304. { recompile the unit or give a fatal error if sources not available }
  1305. if not(sources_avail) then
  1306. begin
  1307. if (not search_unit(true,false)) and
  1308. (length(modulename^)>8) then
  1309. search_unit(true,true);
  1310. if not(sources_avail) then
  1311. begin
  1312. if recompile_reason=rr_noppu then
  1313. Message1(unit_f_cant_find_ppu,realmodulename^)
  1314. else
  1315. Message1(unit_f_cant_compile_unit,realmodulename^);
  1316. end;
  1317. end;
  1318. { Flag modules to reload }
  1319. flagdependent(old_current_module);
  1320. { Reset the module }
  1321. reset;
  1322. { compile this module }
  1323. if not(state in [ms_compile,ms_second_compile]) then
  1324. state:=ms_compile;
  1325. compile(mainsource^);
  1326. end
  1327. else
  1328. state:=ms_compiled;
  1329. if current_module<>self then
  1330. internalerror(200212282);
  1331. if in_interface then
  1332. internalerror(200212283);
  1333. { for a second_time recompile reload all dependent units,
  1334. for a first time compile register the unit _once_ }
  1335. if second_time then
  1336. reload_flagged_units
  1337. else
  1338. usedunits.concat(tused_unit.create(self,true,false,nil));
  1339. { reopen the old module }
  1340. {$ifdef SHORT_ON_FILE_HANDLES}
  1341. if old_current_module.is_unit and
  1342. assigned(tppumodule(old_current_module).ppufile) then
  1343. tppumodule(old_current_module).ppufile.tempopen;
  1344. {$endif SHORT_ON_FILE_HANDLES}
  1345. { reload old scanner }
  1346. current_scanner:=tscannerfile(old_current_module.scanner);
  1347. if assigned(current_scanner) then
  1348. begin
  1349. current_scanner.tempopeninputfile;
  1350. current_scanner.gettokenpos
  1351. end
  1352. else
  1353. fillchar(aktfilepos,sizeof(aktfilepos),0);
  1354. end;
  1355. { we are back, restore current_module }
  1356. current_module:=old_current_module;
  1357. SetCompileModule(current_module);
  1358. end;
  1359. {*****************************************************************************
  1360. RegisterUnit
  1361. *****************************************************************************}
  1362. function registerunit(callermodule:tmodule;const s : stringid;const fn:string) : tppumodule;
  1363. var
  1364. ups : stringid;
  1365. hp : tppumodule;
  1366. hp2 : tmodule;
  1367. begin
  1368. { Info }
  1369. ups:=upper(s);
  1370. { search all loaded units }
  1371. hp:=tppumodule(loaded_units.first);
  1372. while assigned(hp) do
  1373. begin
  1374. if hp.modulename^=ups then
  1375. begin
  1376. { only check for units. The main program is also
  1377. as a unit in the loaded_units list. We simply need
  1378. to ignore this entry (PFV) }
  1379. if hp.is_unit then
  1380. begin
  1381. { both units in interface ? }
  1382. if callermodule.in_interface and
  1383. hp.in_interface then
  1384. begin
  1385. { check for a cycle }
  1386. hp2:=callermodule.loaded_from;
  1387. while assigned(hp2) and (hp2<>hp) do
  1388. begin
  1389. if hp2.in_interface then
  1390. hp2:=hp2.loaded_from
  1391. else
  1392. hp2:=nil;
  1393. end;
  1394. if assigned(hp2) then
  1395. Message2(unit_f_circular_unit_reference,callermodule.realmodulename^,hp.realmodulename^);
  1396. end;
  1397. break;
  1398. end;
  1399. end;
  1400. { the next unit }
  1401. hp:=tppumodule(hp.next);
  1402. end;
  1403. { the unit is not in the loaded units,
  1404. we create an entry and register the unit }
  1405. if not assigned(hp) then
  1406. begin
  1407. Message1(unit_u_registering_new_unit,Upper(s));
  1408. hp:=tppumodule.create(callermodule,s,fn,true);
  1409. hp.loaded_from:=callermodule;
  1410. addloadedunit(hp);
  1411. end;
  1412. { return }
  1413. registerunit:=hp;
  1414. end;
  1415. end.