fppu.pas 50 KB

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