fppu.pas 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. This unit implements the first loading and searching of the modules
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit fppu;
  19. {$i defines.inc}
  20. { close ppufiles on system that are
  21. short on file handles like DOS system PM }
  22. {$ifdef GO32V1}
  23. {$define SHORT_ON_FILE_HANDLES}
  24. {$endif GO32V1}
  25. {$ifdef GO32V2}
  26. {$define SHORT_ON_FILE_HANDLES}
  27. {$endif GO32V2}
  28. interface
  29. uses
  30. cutils,cclasses,
  31. globtype,globals,finput,fmodule,
  32. symbase,symppu,ppu;
  33. type
  34. tppumodule = class(tmodule)
  35. ppufile : tcompilerppufile; { the PPU file }
  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(const s:string;_is_unit:boolean);
  43. destructor destroy;override;
  44. procedure reset;override;
  45. function openppu:boolean;
  46. function search_unit(const n : string;onlysource:boolean):boolean;
  47. procedure getppucrc;
  48. procedure writeppu;
  49. procedure loadppu;
  50. private
  51. procedure load_interface;
  52. procedure load_symtable_refs;
  53. procedure load_usedunits;
  54. procedure writeusedmacro(p:TNamedIndexItem);
  55. procedure writeusedmacros;
  56. procedure writesourcefiles;
  57. procedure writeusedunit;
  58. procedure writelinkcontainer(var p:tlinkcontainer;id:byte;strippath:boolean);
  59. procedure readusedmacros;
  60. procedure readsourcefiles;
  61. procedure readloadunit;
  62. procedure readlinkcontainer(var p:tlinkcontainer);
  63. end;
  64. function loadunit(const s : stringid) : tmodule;
  65. implementation
  66. uses
  67. {$ifdef delphi}
  68. dmisc,
  69. {$else}
  70. dos,
  71. {$endif}
  72. verbose,systems,version,
  73. symtable,
  74. scanner,
  75. parser;
  76. {****************************************************************************
  77. TPPUMODULE
  78. ****************************************************************************}
  79. constructor tppumodule.create(const s:string;_is_unit:boolean);
  80. begin
  81. inherited create(s,_is_unit);
  82. ppufile:=nil;
  83. { search the PPU file if it is an unit }
  84. if is_unit then
  85. begin
  86. { use the realmodulename so we can also find a case sensitive
  87. source filename }
  88. search_unit(realmodulename^,false);
  89. { it the sources_available is changed then we know that
  90. the sources aren't available }
  91. if not sources_avail then
  92. sources_checked:=true;
  93. end;
  94. end;
  95. destructor tppumodule.Destroy;
  96. begin
  97. if assigned(ppufile) then
  98. ppufile.free;
  99. ppufile:=nil;
  100. inherited Destroy;
  101. end;
  102. procedure tppumodule.reset;
  103. begin
  104. if assigned(ppufile) then
  105. begin
  106. ppufile.free;
  107. ppufile:=nil;
  108. end;
  109. inherited reset;
  110. end;
  111. function tppumodule.openppu:boolean;
  112. var
  113. ppufiletime : longint;
  114. begin
  115. openppu:=false;
  116. Message1(unit_t_ppu_loading,ppufilename^);
  117. { Get ppufile time (also check if the file exists) }
  118. ppufiletime:=getnamedfiletime(ppufilename^);
  119. if ppufiletime=-1 then
  120. exit;
  121. { Open the ppufile }
  122. Message1(unit_u_ppu_name,ppufilename^);
  123. ppufile:=tcompilerppufile.create(ppufilename^);
  124. if not ppufile.openfile then
  125. begin
  126. ppufile.free;
  127. ppufile:=nil;
  128. Message(unit_u_ppu_file_too_short);
  129. exit;
  130. end;
  131. { check for a valid PPU file }
  132. if not ppufile.CheckPPUId then
  133. begin
  134. ppufile.free;
  135. ppufile:=nil;
  136. Message(unit_u_ppu_invalid_header);
  137. exit;
  138. end;
  139. { check for allowed PPU versions }
  140. if not (ppufile.GetPPUVersion = CurrentPPUVersion) then
  141. begin
  142. ppufile.free;
  143. ppufile:=nil;
  144. Message1(unit_u_ppu_invalid_version,tostr(ppufile.GetPPUVersion));
  145. exit;
  146. end;
  147. { check the target processor }
  148. if ttargetcpu(ppufile.header.cpu)<>target_cpu then
  149. begin
  150. ppufile.free;
  151. ppufile:=nil;
  152. Message(unit_u_ppu_invalid_processor);
  153. exit;
  154. end;
  155. { check target }
  156. if ttarget(ppufile.header.target)<>target_info.target then
  157. begin
  158. ppufile.free;
  159. ppufile:=nil;
  160. Message(unit_u_ppu_invalid_target);
  161. exit;
  162. end;
  163. { Load values to be access easier }
  164. flags:=ppufile.header.flags;
  165. crc:=ppufile.header.checksum;
  166. interface_crc:=ppufile.header.interface_checksum;
  167. { Show Debug info }
  168. Message1(unit_u_ppu_time,filetimestring(ppufiletime));
  169. Message1(unit_u_ppu_flags,tostr(flags));
  170. Message1(unit_u_ppu_crc,tostr(ppufile.header.checksum));
  171. Message1(unit_u_ppu_crc,tostr(ppufile.header.interface_checksum)+' (intfc)');
  172. do_compile:=false;
  173. openppu:=true;
  174. end;
  175. function tppumodule.search_unit(const n : string;onlysource:boolean):boolean;
  176. var
  177. singlepathstring,
  178. filename : string;
  179. Function UnitExists(const ext:string;var foundfile:string):boolean;
  180. begin
  181. Message1(unit_t_unitsearch,Singlepathstring+filename+ext);
  182. UnitExists:=FindFile(FileName+ext,Singlepathstring,foundfile);
  183. end;
  184. Function PPUSearchPath(const s:string):boolean;
  185. var
  186. found : boolean;
  187. hs : string;
  188. begin
  189. Found:=false;
  190. singlepathstring:=FixPath(s,false);
  191. { Check for PPU file }
  192. Found:=UnitExists(target_info.unitext,hs);
  193. if Found then
  194. Begin
  195. SetFileName(hs,false);
  196. Found:=OpenPPU;
  197. End;
  198. PPUSearchPath:=Found;
  199. end;
  200. Function SourceSearchPath(const s:string):boolean;
  201. var
  202. found : boolean;
  203. hs : string;
  204. begin
  205. Found:=false;
  206. singlepathstring:=FixPath(s,false);
  207. { Check for Sources }
  208. ppufile:=nil;
  209. do_compile:=true;
  210. recompile_reason:=rr_noppu;
  211. {Check for .pp file}
  212. Found:=UnitExists(target_info.sourceext,hs);
  213. if not Found then
  214. begin
  215. { Check for .pas }
  216. Found:=UnitExists(target_info.pasext,hs);
  217. end;
  218. stringdispose(mainsource);
  219. if Found then
  220. begin
  221. sources_avail:=true;
  222. { Load Filenames when found }
  223. mainsource:=StringDup(hs);
  224. SetFileName(hs,false);
  225. end
  226. else
  227. sources_avail:=false;
  228. SourceSearchPath:=Found;
  229. end;
  230. Function SearchPath(const s:string):boolean;
  231. var
  232. found : boolean;
  233. begin
  234. { First check for a ppu, then for the source }
  235. found:=false;
  236. if not onlysource then
  237. found:=PPUSearchPath(s);
  238. if not found then
  239. found:=SourceSearchPath(s);
  240. SearchPath:=found;
  241. end;
  242. Function SearchPathList(list:TSearchPathList):boolean;
  243. var
  244. hp : TStringListItem;
  245. found : boolean;
  246. begin
  247. found:=false;
  248. hp:=TStringListItem(list.First);
  249. while assigned(hp) do
  250. begin
  251. found:=SearchPath(hp.Str);
  252. if found then
  253. break;
  254. hp:=TStringListItem(hp.next);
  255. end;
  256. SearchPathList:=found;
  257. end;
  258. var
  259. fnd : boolean;
  260. begin
  261. filename:=FixFileName(n);
  262. { try to find unit
  263. 1. look for ppu in cwd
  264. 2. look for ppu in outputpath if set, this is tp7 compatible (PFV)
  265. 3. look for source in cwd
  266. 4. local unit pathlist
  267. 5. global unit pathlist }
  268. fnd:=false;
  269. if not onlysource then
  270. begin
  271. fnd:=PPUSearchPath('.');
  272. if (not fnd) and (current_module.outputpath^<>'') then
  273. fnd:=PPUSearchPath(current_module.outputpath^);
  274. end;
  275. if (not fnd) then
  276. fnd:=SourceSearchPath('.');
  277. if (not fnd) then
  278. fnd:=SearchPathList(current_module.LocalUnitSearchPath);
  279. if (not fnd) then
  280. fnd:=SearchPathList(UnitSearchPath);
  281. { try to find a file with the first 8 chars of the modulename, like
  282. dos }
  283. if (not fnd) and (length(filename)>8) then
  284. begin
  285. filename:=copy(filename,1,8);
  286. fnd:=SearchPath('.');
  287. if (not fnd) then
  288. fnd:=SearchPathList(current_module.LocalUnitSearchPath);
  289. if not fnd then
  290. fnd:=SearchPathList(UnitSearchPath);
  291. end;
  292. search_unit:=fnd;
  293. end;
  294. {**********************************
  295. PPU Reading/Writing Helpers
  296. ***********************************}
  297. procedure tppumodule.writeusedmacro(p:TNamedIndexItem);
  298. begin
  299. if tmacro(p).is_used or tmacro(p).defined_at_startup then
  300. begin
  301. ppufile.putstring(p.name);
  302. ppufile.putbyte(byte(tmacro(p).defined_at_startup));
  303. ppufile.putbyte(byte(tmacro(p).is_used));
  304. end;
  305. end;
  306. procedure tppumodule.writeusedmacros;
  307. begin
  308. ppufile.do_crc:=false;
  309. current_scanner.macros.foreach({$ifdef FPCPROCVAR}@{$endif}writeusedmacro);
  310. ppufile.writeentry(ibusedmacros);
  311. ppufile.do_crc:=true;
  312. end;
  313. procedure tppumodule.writesourcefiles;
  314. var
  315. hp : tinputfile;
  316. i,j : longint;
  317. begin
  318. { second write the used source files }
  319. ppufile.do_crc:=false;
  320. hp:=sourcefiles.files;
  321. { write source files directly in good order }
  322. j:=0;
  323. while assigned(hp) do
  324. begin
  325. inc(j);
  326. hp:=hp.ref_next;
  327. end;
  328. while j>0 do
  329. begin
  330. hp:=sourcefiles.files;
  331. for i:=1 to j-1 do
  332. hp:=hp.ref_next;
  333. ppufile.putstring(hp.name^);
  334. dec(j);
  335. end;
  336. ppufile.writeentry(ibsourcefiles);
  337. ppufile.do_crc:=true;
  338. end;
  339. procedure tppumodule.writeusedunit;
  340. var
  341. hp : tused_unit;
  342. begin
  343. { renumber the units for derefence writing }
  344. numberunits;
  345. { write a reference for each used unit }
  346. hp:=tused_unit(used_units.first);
  347. while assigned(hp) do
  348. begin
  349. { implementation units should not change
  350. the CRC PM }
  351. ppufile.do_crc:=hp.in_interface;
  352. ppufile.putstring(hp.name^);
  353. { the checksum should not affect the crc of this unit ! (PFV) }
  354. ppufile.do_crc:=false;
  355. ppufile.putlongint(hp.checksum);
  356. ppufile.putlongint(hp.interface_checksum);
  357. ppufile.putbyte(byte(hp.in_interface));
  358. ppufile.do_crc:=true;
  359. hp:=tused_unit(hp.next);
  360. end;
  361. ppufile.do_interface_crc:=true;
  362. ppufile.writeentry(ibloadunit);
  363. end;
  364. procedure tppumodule.writelinkcontainer(var p:tlinkcontainer;id:byte;strippath:boolean);
  365. var
  366. hcontainer : tlinkcontainer;
  367. s : string;
  368. mask : cardinal;
  369. begin
  370. hcontainer:=TLinkContainer.Create;
  371. while not p.empty do
  372. begin
  373. s:=p.get(mask);
  374. if strippath then
  375. ppufile.putstring(SplitFileName(s))
  376. else
  377. ppufile.putstring(s);
  378. ppufile.putlongint(mask);
  379. hcontainer.add(s,mask);
  380. end;
  381. ppufile.writeentry(id);
  382. p.Free;
  383. p:=hcontainer;
  384. end;
  385. procedure tppumodule.readusedmacros;
  386. var
  387. hs : string;
  388. mac : tmacro;
  389. was_defined_at_startup,
  390. was_used : boolean;
  391. begin
  392. while not ppufile.endofentry do
  393. begin
  394. hs:=ppufile.getstring;
  395. was_defined_at_startup:=boolean(ppufile.getbyte);
  396. was_used:=boolean(ppufile.getbyte);
  397. mac:=tmacro(current_scanner.macros.search(hs));
  398. if assigned(mac) then
  399. begin
  400. {$ifndef EXTDEBUG}
  401. { if we don't have the sources why tell }
  402. if sources_avail then
  403. {$endif ndef EXTDEBUG}
  404. if (not was_defined_at_startup) and
  405. was_used and
  406. mac.defined_at_startup then
  407. Message2(unit_h_cond_not_set_in_last_compile,hs,mainsource^);
  408. end
  409. else { not assigned }
  410. if was_defined_at_startup and
  411. was_used then
  412. Message2(unit_h_cond_not_set_in_last_compile,hs,mainsource^);
  413. end;
  414. end;
  415. procedure tppumodule.readsourcefiles;
  416. var
  417. temp,hs : string;
  418. temp_dir : string;
  419. main_dir : string;
  420. incfile_found,
  421. main_found,
  422. is_main : boolean;
  423. ppufiletime,
  424. source_time : longint;
  425. hp : tinputfile;
  426. begin
  427. ppufiletime:=getnamedfiletime(ppufilename^);
  428. sources_avail:=true;
  429. is_main:=true;
  430. main_dir:='';
  431. while not ppufile.endofentry do
  432. begin
  433. hs:=ppufile.getstring;
  434. temp_dir:='';
  435. if (flags and uf_in_library)<>0 then
  436. begin
  437. sources_avail:=false;
  438. temp:=' library';
  439. end
  440. else if pos('Macro ',hs)=1 then
  441. begin
  442. { we don't want to find this file }
  443. { but there is a problem with file indexing !! }
  444. temp:='';
  445. end
  446. else
  447. begin
  448. { check the date of the source files }
  449. Source_Time:=GetNamedFileTime(path^+hs);
  450. incfile_found:=false;
  451. main_found:=false;
  452. if Source_Time<>-1 then
  453. hs:=path^+hs
  454. else
  455. if not(is_main) then
  456. begin
  457. Source_Time:=GetNamedFileTime(main_dir+hs);
  458. if Source_Time<>-1 then
  459. hs:=main_dir+hs;
  460. end;
  461. if (Source_Time=-1) then
  462. begin
  463. if is_main then
  464. main_found:=unitsearchpath.FindFile(hs,temp_dir)
  465. else
  466. incfile_found:=includesearchpath.FindFile(hs,temp_dir);
  467. if incfile_found or main_found then
  468. begin
  469. Source_Time:=GetNamedFileTime(temp_dir);
  470. if Source_Time<>-1 then
  471. hs:=temp_dir;
  472. end;
  473. end;
  474. if Source_Time=-1 then
  475. begin
  476. sources_avail:=false;
  477. temp:=' not found';
  478. end
  479. else
  480. begin
  481. if main_found then
  482. main_dir:=temp_dir;
  483. { time newer? But only allow if the file is not searched
  484. in the include path (PFV), else you've problems with
  485. units which use the same includefile names }
  486. if incfile_found then
  487. temp:=' found'
  488. else
  489. begin
  490. temp:=' time '+filetimestring(source_time);
  491. if (source_time>ppufiletime) then
  492. begin
  493. do_compile:=true;
  494. recompile_reason:=rr_sourcenewer;
  495. temp:=temp+' *'
  496. end;
  497. end;
  498. end;
  499. hp:=tinputfile.create(hs);
  500. { the indexing is wrong here PM }
  501. sourcefiles.register_file(hp);
  502. end;
  503. if is_main then
  504. begin
  505. stringdispose(mainsource);
  506. mainsource:=stringdup(hs);
  507. end;
  508. Message1(unit_u_ppu_source,hs+temp);
  509. is_main:=false;
  510. end;
  511. { check if we want to rebuild every unit, only if the sources are
  512. available }
  513. if do_build and sources_avail then
  514. begin
  515. do_compile:=true;
  516. recompile_reason:=rr_build;
  517. end;
  518. end;
  519. procedure tppumodule.readloadunit;
  520. var
  521. hs : string;
  522. intfchecksum,
  523. checksum : longint;
  524. in_interface : boolean;
  525. begin
  526. while not ppufile.endofentry do
  527. begin
  528. hs:=ppufile.getstring;
  529. checksum:=ppufile.getlongint;
  530. intfchecksum:=ppufile.getlongint;
  531. in_interface:=(ppufile.getbyte<>0);
  532. used_units.concat(tused_unit.create_to_load(hs,checksum,intfchecksum,in_interface));
  533. end;
  534. end;
  535. procedure tppumodule.readlinkcontainer(var p:tlinkcontainer);
  536. var
  537. s : string;
  538. m : longint;
  539. begin
  540. while not ppufile.endofentry do
  541. begin
  542. s:=ppufile.getstring;
  543. m:=ppufile.getlongint;
  544. p.add(s,m);
  545. end;
  546. end;
  547. procedure tppumodule.load_interface;
  548. var
  549. b : byte;
  550. newmodulename : string;
  551. begin
  552. { read interface part }
  553. repeat
  554. b:=ppufile.readentry;
  555. case b of
  556. ibmodulename :
  557. begin
  558. newmodulename:=ppufile.getstring;
  559. if upper(newmodulename)<>modulename^ then
  560. Message2(unit_f_unit_name_error,realmodulename^,newmodulename);
  561. stringdispose(modulename);
  562. stringdispose(realmodulename);
  563. modulename:=stringdup(upper(newmodulename));
  564. realmodulename:=stringdup(newmodulename);
  565. end;
  566. ibsourcefiles :
  567. readsourcefiles;
  568. ibusedmacros :
  569. readusedmacros;
  570. ibloadunit :
  571. readloadunit;
  572. iblinkunitofiles :
  573. readlinkcontainer(LinkUnitOFiles);
  574. iblinkunitstaticlibs :
  575. readlinkcontainer(LinkUnitStaticLibs);
  576. iblinkunitsharedlibs :
  577. readlinkcontainer(LinkUnitSharedLibs);
  578. iblinkotherofiles :
  579. readlinkcontainer(LinkotherOFiles);
  580. iblinkotherstaticlibs :
  581. readlinkcontainer(LinkotherStaticLibs);
  582. iblinkothersharedlibs :
  583. readlinkcontainer(LinkotherSharedLibs);
  584. ibendinterface :
  585. break;
  586. else
  587. Message1(unit_f_ppu_invalid_entry,tostr(b));
  588. end;
  589. until false;
  590. end;
  591. procedure tppumodule.load_symtable_refs;
  592. var
  593. b : byte;
  594. unitindex : word;
  595. begin
  596. { load local symtable first }
  597. if ((flags and uf_local_browser)<>0) then
  598. begin
  599. localsymtable:=tstaticsymtable.create(modulename^);
  600. tstaticsymtable(localsymtable).load(ppufile);
  601. end;
  602. { load browser }
  603. if (current_module.flags and uf_has_browser)<>0 then
  604. begin
  605. tstoredsymtable(globalsymtable).load_browser(ppufile);
  606. unitindex:=1;
  607. while assigned(map^[unitindex]) do
  608. begin
  609. { each unit wrote one browser entry }
  610. tstoredsymtable(globalsymtable).load_browser(ppufile);
  611. inc(unitindex);
  612. end;
  613. b:=ppufile.readentry;
  614. if b<>ibendbrowser then
  615. Message1(unit_f_ppu_invalid_entry,tostr(b));
  616. end;
  617. if ((current_module.flags and uf_local_browser)<>0) then
  618. tstaticsymtable(current_module.localsymtable).load_browser(ppufile);
  619. end;
  620. procedure tppumodule.writeppu;
  621. var
  622. pu : tused_unit;
  623. begin
  624. Message1(unit_u_ppu_write,realmodulename^);
  625. { create unit flags }
  626. {$ifdef GDB}
  627. if cs_gdb_dbx in aktglobalswitches then
  628. flags:=flags or uf_has_dbx;
  629. {$endif GDB}
  630. if cs_browser in aktmoduleswitches then
  631. flags:=flags or uf_has_browser;
  632. if cs_local_browser in aktmoduleswitches then
  633. flags:=flags or uf_local_browser;
  634. {$ifdef Test_Double_checksum_write}
  635. Assign(CRCFile,s+'.IMP');
  636. Rewrite(CRCFile);
  637. {$endif def Test_Double_checksum_write}
  638. { create new ppufile }
  639. ppufile:=tcompilerppufile.create(ppufilename^);
  640. if not ppufile.createfile then
  641. Message(unit_f_ppu_cannot_write);
  642. { first the unitname }
  643. ppufile.putstring(realmodulename^);
  644. ppufile.writeentry(ibmodulename);
  645. writesourcefiles;
  646. writeusedmacros;
  647. writeusedunit;
  648. { write the objectfiles and libraries that come for this unit,
  649. preserve the containers becuase they are still needed to load
  650. the link.res. All doesn't depend on the crc! It doesn't matter
  651. if a unit is in a .o or .a file }
  652. ppufile.do_crc:=false;
  653. writelinkcontainer(linkunitofiles,iblinkunitofiles,true);
  654. writelinkcontainer(linkunitstaticlibs,iblinkunitstaticlibs,true);
  655. writelinkcontainer(linkunitsharedlibs,iblinkunitsharedlibs,true);
  656. writelinkcontainer(linkotherofiles,iblinkotherofiles,false);
  657. writelinkcontainer(linkotherstaticlibs,iblinkotherstaticlibs,true);
  658. writelinkcontainer(linkothersharedlibs,iblinkothersharedlibs,true);
  659. ppufile.do_crc:=true;
  660. ppufile.writeentry(ibendinterface);
  661. { write the symtable entries }
  662. tstoredsymtable(globalsymtable).write(ppufile);
  663. { everything after this doesn't affect the crc }
  664. ppufile.do_crc:=false;
  665. ppufile.writeentry(ibendimplementation);
  666. { write static symtable
  667. needed for local debugging of unit functions }
  668. if ((flags and uf_local_browser)<>0) and
  669. assigned(localsymtable) then
  670. tstoredsymtable(localsymtable).write(ppufile);
  671. { write all browser section }
  672. if (flags and uf_has_browser)<>0 then
  673. begin
  674. tstoredsymtable(globalsymtable).write_browser(ppufile);
  675. pu:=tused_unit(used_units.first);
  676. while assigned(pu) do
  677. begin
  678. tstoredsymtable(pu.u.globalsymtable).write_browser(ppufile);
  679. pu:=tused_unit(pu.next);
  680. end;
  681. ppufile.writeentry(ibendbrowser);
  682. end;
  683. if ((flags and uf_local_browser)<>0) and
  684. assigned(localsymtable) then
  685. tstaticsymtable(localsymtable).write_browser(ppufile);
  686. { the last entry ibend is written automaticly }
  687. { flush to be sure }
  688. ppufile.flush;
  689. { create and write header }
  690. ppufile.header.size:=ppufile.size;
  691. ppufile.header.checksum:=ppufile.crc;
  692. ppufile.header.interface_checksum:=ppufile.interface_crc;
  693. ppufile.header.compiler:=wordversion;
  694. ppufile.header.cpu:=word(target_cpu);
  695. ppufile.header.target:=word(target_info.target);
  696. ppufile.header.flags:=flags;
  697. ppufile.writeheader;
  698. { save crc in current module also }
  699. crc:=ppufile.crc;
  700. interface_crc:=ppufile.interface_crc;
  701. {$ifdef Test_Double_checksum_write}
  702. close(CRCFile);
  703. {$endif Test_Double_checksum_write}
  704. ppufile.closefile;
  705. ppufile.free;
  706. ppufile:=nil;
  707. end;
  708. procedure tppumodule.getppucrc;
  709. begin
  710. {$ifdef Test_Double_checksum_write}
  711. Assign(CRCFile,s+'.INT')
  712. Rewrite(CRCFile);
  713. {$endif def Test_Double_checksum_write}
  714. { create new ppufile }
  715. ppufile:=tcompilerppufile.create(ppufilename^);
  716. ppufile.crc_only:=true;
  717. if not ppufile.createfile then
  718. Message(unit_f_ppu_cannot_write);
  719. { first the unitname }
  720. ppufile.putstring(realmodulename^);
  721. ppufile.writeentry(ibmodulename);
  722. { the interface units affect the crc }
  723. writeusedunit;
  724. ppufile.writeentry(ibendinterface);
  725. { write the symtable entries }
  726. tstoredsymtable(globalsymtable).write(ppufile);
  727. { save crc }
  728. crc:=ppufile.crc;
  729. interface_crc:=ppufile.interface_crc;
  730. {$ifdef Test_Double_checksum}
  731. crc_array:=ppufile.crc_test;
  732. ppufile.crc_test:=nil;
  733. crc_size:=ppufile.crc_index2;
  734. crc_array2:=ppufile.crc_test2;
  735. ppufile.crc_test2:=nil;
  736. crc_size2:=ppufile.crc_index2;
  737. {$endif Test_Double_checksum}
  738. {$ifdef Test_Double_checksum_write}
  739. close(CRCFile);
  740. {$endif Test_Double_checksum_write}
  741. ppufile.closefile;
  742. ppufile.free;
  743. ppufile:=nil;
  744. end;
  745. procedure tppumodule.load_usedunits;
  746. var
  747. pu : tused_unit;
  748. loaded_unit : tmodule;
  749. load_refs : boolean;
  750. nextmapentry : longint;
  751. b : byte;
  752. begin
  753. load_refs:=true;
  754. { init the map }
  755. new(map);
  756. fillchar(map^,sizeof(tunitmap),#0);
  757. {$ifdef NEWMAP}
  758. map^[0]:=current_module;
  759. {$endif NEWMAP}
  760. nextmapentry:=1;
  761. { load the used units from interface }
  762. in_implementation:=false;
  763. pu:=tused_unit(used_units.first);
  764. while assigned(pu) do
  765. begin
  766. if (not pu.loaded) and (pu.in_interface) then
  767. begin
  768. loaded_unit:=loadunit(pu.name^);
  769. if compiled then
  770. exit;
  771. { register unit in used units }
  772. pu.u:=loaded_unit;
  773. pu.loaded:=true;
  774. { doubles are not important for that list PM }
  775. pu.u.dependent_units.concat(tdependent_unit.create(self));
  776. { need to recompile the current unit ? }
  777. if loaded_unit.crc<>pu.checksum then
  778. begin
  779. Message2(unit_u_recompile_crc_change,modulename^,pu.name^);
  780. recompile_reason:=rr_crcchanged;
  781. do_compile:=true;
  782. dispose(map);
  783. map:=nil;
  784. exit;
  785. end;
  786. { setup the map entry for deref }
  787. {$ifndef NEWMAP}
  788. map^[nextmapentry]:=loaded_unit.globalsymtable;
  789. {$else NEWMAP}
  790. map^[nextmapentry]:=loaded_unit;
  791. {$endif NEWMAP}
  792. inc(nextmapentry);
  793. if nextmapentry>maxunits then
  794. Message(unit_f_too_much_units);
  795. end;
  796. pu:=tused_unit(pu.next);
  797. end;
  798. { ok, now load the interface of this unit }
  799. current_module:=self;
  800. SetCompileModule(current_module);
  801. globalsymtable:=tglobalsymtable.create(modulename^);
  802. tstoredsymtable(globalsymtable).load(ppufile);
  803. { now only read the implementation uses }
  804. in_implementation:=true;
  805. pu:=tused_unit(used_units.first);
  806. while assigned(pu) do
  807. begin
  808. if (not pu.loaded) and (not pu.in_interface) then
  809. begin
  810. loaded_unit:=loadunit(pu.name^);
  811. if compiled then
  812. exit;
  813. { register unit in used units }
  814. pu.u:=loaded_unit;
  815. pu.loaded:=true;
  816. { need to recompile the current unit ? }
  817. if (loaded_unit.interface_crc<>pu.interface_checksum) {and
  818. not(current_module.in_second_compile) } then
  819. begin
  820. Message2(unit_u_recompile_crc_change,modulename^,pu.name^+' {impl}');
  821. recompile_reason:=rr_crcchanged;
  822. do_compile:=true;
  823. dispose(map);
  824. map:=nil;
  825. exit;
  826. end;
  827. { setup the map entry for deref }
  828. {$ifndef NEWMAP}
  829. map^[nextmapentry]:=loaded_unit.globalsymtable;
  830. {$else NEWMAP}
  831. map^[nextmapentry]:=loaded_unit;
  832. {$endif NEWMAP}
  833. inc(nextmapentry);
  834. if nextmapentry>maxunits then
  835. Message(unit_f_too_much_units);
  836. end;
  837. pu:=tused_unit(pu.next);
  838. end;
  839. { read the implementation part }
  840. b:=ppufile.readentry;
  841. if b<>ibendimplementation then
  842. Message1(unit_f_ppu_invalid_entry,tostr(b));
  843. { load browser info if stored }
  844. if ((flags and uf_has_browser)<>0) and load_refs then
  845. begin
  846. current_module:=self;
  847. load_symtable_refs;
  848. end;
  849. { remove the map, it's not needed anymore }
  850. dispose(map);
  851. map:=nil;
  852. end;
  853. procedure tppumodule.loadppu;
  854. var
  855. name : string;
  856. begin
  857. { load interface section }
  858. if not do_compile then
  859. load_interface;
  860. { only load units when we don't recompile }
  861. if not do_compile then
  862. load_usedunits;
  863. { recompile if set }
  864. if do_compile then
  865. begin
  866. { we don't need the ppufile anymore }
  867. if assigned(ppufile) then
  868. begin
  869. ppufile.free;
  870. ppufile:=nil;
  871. end;
  872. { recompile the unit or give a fatal error if sources not available }
  873. if not(sources_avail) and
  874. not(sources_checked) then
  875. if (not search_unit(modulename^,true))
  876. and (length(modulename^)>8) then
  877. search_unit(copy(modulename^,1,8),true);
  878. if not(sources_avail) then
  879. begin
  880. if recompile_reason=rr_noppu then
  881. Message1(unit_f_cant_find_ppu,modulename^)
  882. else
  883. Message1(unit_f_cant_compile_unit,modulename^);
  884. end
  885. else
  886. begin
  887. if in_compile then
  888. begin
  889. in_second_compile:=true;
  890. Message1(parser_d_compiling_second_time,modulename^);
  891. end;
  892. current_scanner.tempcloseinputfile;
  893. name:=mainsource^;
  894. if assigned(scanner) then
  895. tscannerfile(scanner).invalid:=true;
  896. { compile this module }
  897. current_module:=self;
  898. compile(name);
  899. in_second_compile:=false;
  900. if (not current_scanner.invalid) then
  901. current_scanner.tempopeninputfile;
  902. end;
  903. end;
  904. if assigned(ppufile) then
  905. begin
  906. ppufile.closefile;
  907. ppufile.free;
  908. ppufile:=nil;
  909. end;
  910. end;
  911. {*****************************************************************************
  912. LoadUnit
  913. *****************************************************************************}
  914. function loadunit(const s : stringid) : tmodule;
  915. const
  916. ImplIntf : array[boolean] of string[15]=('interface','implementation');
  917. var
  918. st : tglobalsymtable;
  919. second_time : boolean;
  920. old_current_module,hp2 : tmodule;
  921. hp : tppumodule;
  922. scanner : tscannerfile;
  923. dummy : tmodule;
  924. ups : stringid;
  925. begin
  926. old_current_module:=current_module;
  927. { Info }
  928. Message3(unit_u_load_unit,current_module.modulename^,ImplIntf[current_module.in_implementation],s);
  929. ups:=upper(s);
  930. { unit not found }
  931. st:=nil;
  932. dummy:=nil;
  933. { search all loaded units }
  934. hp:=tppumodule(loaded_units.first);
  935. while assigned(hp) do
  936. begin
  937. if hp.modulename^=ups then
  938. begin
  939. { forced to reload ? }
  940. if hp.do_reload then
  941. begin
  942. hp.do_reload:=false;
  943. break;
  944. end;
  945. { the unit is already registered }
  946. { and this means that the unit }
  947. { is already compiled }
  948. { else there is a cyclic unit use }
  949. if assigned(hp.globalsymtable) then
  950. st:=tglobalsymtable(hp.globalsymtable)
  951. else
  952. begin
  953. { both units in interface ? }
  954. if (not current_module.in_implementation) and
  955. (not hp.in_implementation) then
  956. begin
  957. { check for a cycle }
  958. hp2:=current_module.loaded_from;
  959. while assigned(hp2) and (hp2<>hp) do
  960. begin
  961. if hp2.in_implementation then
  962. hp2:=nil
  963. else
  964. hp2:=hp2.loaded_from;
  965. end;
  966. if assigned(hp2) then
  967. Message2(unit_f_circular_unit_reference,current_module.modulename^,hp.modulename^);
  968. end;
  969. end;
  970. break;
  971. end
  972. else if copy(hp.modulename^,1,8)=ups then
  973. dummy:=hp;
  974. { the next unit }
  975. hp:=tppumodule(hp.next);
  976. end;
  977. if assigned(dummy) and not assigned(hp) then
  978. Message2(unit_w_unit_name_error,s,dummy.modulename^);
  979. { the unit is not in the loaded units, we must load it first }
  980. if (not assigned(st)) then
  981. begin
  982. if assigned(hp) then
  983. begin
  984. { remove the old unit, but save the scanner }
  985. loaded_units.remove(hp);
  986. scanner:=tscannerfile(hp.scanner);
  987. hp.reset;
  988. hp.scanner:=scanner;
  989. { try to reopen ppu }
  990. hp.search_unit(s,false);
  991. { try to load the unit a second time first }
  992. current_module:=hp;
  993. current_module.in_second_load:=true;
  994. Message1(unit_u_second_load_unit,current_module.modulename^);
  995. second_time:=true;
  996. end
  997. else
  998. { generates a new unit info record }
  999. begin
  1000. current_module:=tppumodule.create(s,true);
  1001. scanner:=nil;
  1002. second_time:=false;
  1003. end;
  1004. { close old_current_ppu on system that are
  1005. short on file handles like DOS PM }
  1006. {$ifdef SHORT_ON_FILE_HANDLES}
  1007. if old_current_module.is_unit and
  1008. assigned(tppumodule(old_current_module).ppufile) then
  1009. tppumodule(old_current_module.ppufile).tempclose;
  1010. {$endif SHORT_ON_FILE_HANDLES}
  1011. { now we can register the unit }
  1012. current_module.loaded_from:=old_current_module;
  1013. loaded_units.insert(current_module);
  1014. { now realy load the ppu }
  1015. tppumodule(current_module).loadppu;
  1016. { set compiled flag }
  1017. current_module.compiled:=true;
  1018. { load return pointer }
  1019. hp:=tppumodule(current_module);
  1020. { for a second_time recompile reload all dependent units,
  1021. for a first time compile register the unit _once_ }
  1022. if second_time then
  1023. begin
  1024. { now reload all dependent units }
  1025. hp2:=tmodule(loaded_units.first);
  1026. while assigned(hp2) do
  1027. begin
  1028. if hp2.do_reload then
  1029. dummy:=loadunit(hp2.modulename^);
  1030. hp2:=tmodule(hp2.next);
  1031. end;
  1032. end
  1033. else
  1034. usedunits.concat(tused_unit.create(current_module,true));
  1035. end;
  1036. { set the old module }
  1037. {$ifdef SHORT_ON_FILE_HANDLES}
  1038. if old_current_module.is_unit and
  1039. assigned(tppumodule(old_current_module).ppufile) then
  1040. tppumodule(old_current_module.ppufile).tempopen;
  1041. {$endif SHORT_ON_FILE_HANDLES}
  1042. { we are back }
  1043. current_module:=old_current_module;
  1044. SetCompileModule(current_module);
  1045. loadunit:=hp;
  1046. end;
  1047. end.
  1048. {
  1049. $Log$
  1050. Revision 1.1 2001-05-06 14:49:17 peter
  1051. * ppu object to class rewrite
  1052. * move ppu read and write stuff to fppu
  1053. }