fppu.pas 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216
  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;const fn:string;_is_unit:boolean);
  43. destructor destroy;override;
  44. procedure reset;override;
  45. function openppu:boolean;
  46. function search_unit(const n : string;const fn: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;const fn:string) : 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;const fn: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^,fn,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. Message1(unit_u_ppu_invalid_version,tostr(ppufile.GetPPUVersion));
  143. ppufile.free;
  144. ppufile:=nil;
  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,hexstr(ppufile.header.checksum,8));
  171. Message1(unit_u_ppu_crc,hexstr(ppufile.header.interface_checksum,8)+' (intfc)');
  172. do_compile:=false;
  173. openppu:=true;
  174. end;
  175. function tppumodule.search_unit(const n : string;const fn: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. hs : string;
  261. begin
  262. filename:=FixFileName(n);
  263. { try to find unit
  264. 1. look for ppu in cwd
  265. 2. look for ppu in outputpath if set, this is tp7 compatible (PFV)
  266. 3. look for the specified source file (from the uses line)
  267. 4. look for source in cwd
  268. 5. local unit pathlist
  269. 6. global unit pathlist }
  270. fnd:=false;
  271. if not onlysource then
  272. begin
  273. fnd:=PPUSearchPath('.');
  274. if (not fnd) and (outputpath^<>'') then
  275. fnd:=PPUSearchPath(outputpath^);
  276. end;
  277. if (not fnd) and (fn<>'') then
  278. begin
  279. { the full filename is specified so we can't use here the
  280. searchpath (PFV) }
  281. Message1(unit_t_unitsearch,AddExtension(fn,target_info.sourceext));
  282. fnd:=FindFile(AddExtension(fn,target_info.sourceext),'',hs);
  283. if not fnd then
  284. begin
  285. Message1(unit_t_unitsearch,AddExtension(fn,target_info.pasext));
  286. fnd:=FindFile(AddExtension(fn,target_info.pasext),'',hs);
  287. end;
  288. if fnd then
  289. begin
  290. sources_avail:=true;
  291. do_compile:=true;
  292. recompile_reason:=rr_noppu;
  293. stringdispose(mainsource);
  294. mainsource:=StringDup(hs);
  295. SetFileName(hs,false);
  296. end;
  297. end;
  298. if (not fnd) then
  299. fnd:=SourceSearchPath('.');
  300. if (not fnd) then
  301. fnd:=SearchPathList(LocalUnitSearchPath);
  302. if (not fnd) then
  303. fnd:=SearchPathList(UnitSearchPath);
  304. { try to find a file with the first 8 chars of the modulename, like
  305. dos }
  306. if (not fnd) and (length(filename)>8) then
  307. begin
  308. filename:=copy(filename,1,8);
  309. fnd:=SearchPath('.');
  310. if (not fnd) then
  311. fnd:=SearchPathList(LocalUnitSearchPath);
  312. if not fnd then
  313. fnd:=SearchPathList(UnitSearchPath);
  314. end;
  315. search_unit:=fnd;
  316. end;
  317. {**********************************
  318. PPU Reading/Writing Helpers
  319. ***********************************}
  320. procedure tppumodule.writeusedmacro(p:TNamedIndexItem);
  321. begin
  322. if tmacro(p).is_used or tmacro(p).defined_at_startup then
  323. begin
  324. ppufile.putstring(p.name);
  325. ppufile.putbyte(byte(tmacro(p).defined_at_startup));
  326. ppufile.putbyte(byte(tmacro(p).is_used));
  327. end;
  328. end;
  329. procedure tppumodule.writeusedmacros;
  330. begin
  331. ppufile.do_crc:=false;
  332. current_scanner.macros.foreach({$ifdef FPCPROCVAR}@{$endif}writeusedmacro);
  333. ppufile.writeentry(ibusedmacros);
  334. ppufile.do_crc:=true;
  335. end;
  336. procedure tppumodule.writesourcefiles;
  337. var
  338. hp : tinputfile;
  339. i,j : longint;
  340. begin
  341. { second write the used source files }
  342. ppufile.do_crc:=false;
  343. hp:=sourcefiles.files;
  344. { write source files directly in good order }
  345. j:=0;
  346. while assigned(hp) do
  347. begin
  348. inc(j);
  349. hp:=hp.ref_next;
  350. end;
  351. while j>0 do
  352. begin
  353. hp:=sourcefiles.files;
  354. for i:=1 to j-1 do
  355. hp:=hp.ref_next;
  356. ppufile.putstring(hp.name^);
  357. dec(j);
  358. end;
  359. ppufile.writeentry(ibsourcefiles);
  360. ppufile.do_crc:=true;
  361. end;
  362. procedure tppumodule.writeusedunit;
  363. var
  364. hp : tused_unit;
  365. begin
  366. { renumber the units for derefence writing }
  367. numberunits;
  368. { write a reference for each used unit }
  369. hp:=tused_unit(used_units.first);
  370. while assigned(hp) do
  371. begin
  372. { implementation units should not change
  373. the CRC PM }
  374. ppufile.do_crc:=hp.in_interface;
  375. ppufile.putstring(hp.realname^);
  376. { the checksum should not affect the crc of this unit ! (PFV) }
  377. ppufile.do_crc:=false;
  378. ppufile.putlongint(longint(hp.checksum));
  379. ppufile.putlongint(longint(hp.interface_checksum));
  380. ppufile.putbyte(byte(hp.in_interface));
  381. ppufile.do_crc:=true;
  382. hp:=tused_unit(hp.next);
  383. end;
  384. ppufile.do_interface_crc:=true;
  385. ppufile.writeentry(ibloadunit);
  386. end;
  387. procedure tppumodule.writelinkcontainer(var p:tlinkcontainer;id:byte;strippath:boolean);
  388. var
  389. hcontainer : tlinkcontainer;
  390. s : string;
  391. mask : cardinal;
  392. begin
  393. hcontainer:=TLinkContainer.Create;
  394. while not p.empty do
  395. begin
  396. s:=p.get(mask);
  397. if strippath then
  398. ppufile.putstring(SplitFileName(s))
  399. else
  400. ppufile.putstring(s);
  401. ppufile.putlongint(mask);
  402. hcontainer.add(s,mask);
  403. end;
  404. ppufile.writeentry(id);
  405. p.Free;
  406. p:=hcontainer;
  407. end;
  408. procedure tppumodule.readusedmacros;
  409. var
  410. hs : string;
  411. mac : tmacro;
  412. was_defined_at_startup,
  413. was_used : boolean;
  414. begin
  415. while not ppufile.endofentry do
  416. begin
  417. hs:=ppufile.getstring;
  418. was_defined_at_startup:=boolean(ppufile.getbyte);
  419. was_used:=boolean(ppufile.getbyte);
  420. mac:=tmacro(current_scanner.macros.search(hs));
  421. if assigned(mac) then
  422. begin
  423. {$ifndef EXTDEBUG}
  424. { if we don't have the sources why tell }
  425. if sources_avail then
  426. {$endif ndef EXTDEBUG}
  427. if (not was_defined_at_startup) and
  428. was_used and
  429. mac.defined_at_startup then
  430. Message2(unit_h_cond_not_set_in_last_compile,hs,mainsource^);
  431. end
  432. else { not assigned }
  433. if was_defined_at_startup and
  434. was_used then
  435. Message2(unit_h_cond_not_set_in_last_compile,hs,mainsource^);
  436. end;
  437. end;
  438. procedure tppumodule.readsourcefiles;
  439. var
  440. temp,hs : string;
  441. temp_dir : string;
  442. main_dir : string;
  443. incfile_found,
  444. main_found,
  445. is_main : boolean;
  446. ppufiletime,
  447. source_time : longint;
  448. hp : tinputfile;
  449. begin
  450. ppufiletime:=getnamedfiletime(ppufilename^);
  451. sources_avail:=true;
  452. is_main:=true;
  453. main_dir:='';
  454. while not ppufile.endofentry do
  455. begin
  456. hs:=ppufile.getstring;
  457. temp_dir:='';
  458. if (flags and uf_in_library)<>0 then
  459. begin
  460. sources_avail:=false;
  461. temp:=' library';
  462. end
  463. else if pos('Macro ',hs)=1 then
  464. begin
  465. { we don't want to find this file }
  466. { but there is a problem with file indexing !! }
  467. temp:='';
  468. end
  469. else
  470. begin
  471. { check the date of the source files }
  472. Source_Time:=GetNamedFileTime(path^+hs);
  473. incfile_found:=false;
  474. main_found:=false;
  475. if Source_Time<>-1 then
  476. hs:=path^+hs
  477. else
  478. if not(is_main) then
  479. begin
  480. Source_Time:=GetNamedFileTime(main_dir+hs);
  481. if Source_Time<>-1 then
  482. hs:=main_dir+hs;
  483. end;
  484. if (Source_Time=-1) then
  485. begin
  486. if is_main then
  487. main_found:=unitsearchpath.FindFile(hs,temp_dir)
  488. else
  489. incfile_found:=includesearchpath.FindFile(hs,temp_dir);
  490. if incfile_found or main_found then
  491. begin
  492. Source_Time:=GetNamedFileTime(temp_dir);
  493. if Source_Time<>-1 then
  494. hs:=temp_dir;
  495. end;
  496. end;
  497. if Source_Time=-1 then
  498. begin
  499. sources_avail:=false;
  500. temp:=' not found';
  501. end
  502. else
  503. begin
  504. if main_found then
  505. main_dir:=temp_dir;
  506. { time newer? But only allow if the file is not searched
  507. in the include path (PFV), else you've problems with
  508. units which use the same includefile names }
  509. if incfile_found then
  510. temp:=' found'
  511. else
  512. begin
  513. temp:=' time '+filetimestring(source_time);
  514. if (source_time>ppufiletime) then
  515. begin
  516. if {is_main or} ((flags and uf_release)=0) then
  517. begin
  518. do_compile:=true;
  519. recompile_reason:=rr_sourcenewer;
  520. end
  521. else
  522. Message2(unit_h_source_modified,hs,ppufilename^);
  523. temp:=temp+' *';
  524. end;
  525. end;
  526. end;
  527. hp:=tinputfile.create(hs);
  528. { the indexing is wrong here PM }
  529. sourcefiles.register_file(hp);
  530. end;
  531. if is_main then
  532. begin
  533. stringdispose(mainsource);
  534. mainsource:=stringdup(hs);
  535. end;
  536. Message1(unit_u_ppu_source,hs+temp);
  537. is_main:=false;
  538. end;
  539. { check if we want to rebuild every unit, only if the sources are
  540. available }
  541. if do_build and sources_avail and
  542. ((flags and uf_release)=0) then
  543. begin
  544. do_compile:=true;
  545. recompile_reason:=rr_build;
  546. end;
  547. end;
  548. procedure tppumodule.readloadunit;
  549. var
  550. hs : string;
  551. intfchecksum,
  552. checksum : cardinal;
  553. in_interface : boolean;
  554. begin
  555. while not ppufile.endofentry do
  556. begin
  557. hs:=ppufile.getstring;
  558. checksum:=cardinal(ppufile.getlongint);
  559. intfchecksum:=cardinal(ppufile.getlongint);
  560. in_interface:=(ppufile.getbyte<>0);
  561. used_units.concat(tused_unit.create_to_load(hs,checksum,intfchecksum,in_interface));
  562. end;
  563. end;
  564. procedure tppumodule.readlinkcontainer(var p:tlinkcontainer);
  565. var
  566. s : string;
  567. m : longint;
  568. begin
  569. while not ppufile.endofentry do
  570. begin
  571. s:=ppufile.getstring;
  572. m:=ppufile.getlongint;
  573. p.add(s,m);
  574. end;
  575. end;
  576. procedure tppumodule.load_interface;
  577. var
  578. b : byte;
  579. newmodulename : string;
  580. begin
  581. { read interface part }
  582. repeat
  583. b:=ppufile.readentry;
  584. case b of
  585. ibmodulename :
  586. begin
  587. newmodulename:=ppufile.getstring;
  588. if upper(newmodulename)<>modulename^ then
  589. Message2(unit_f_unit_name_error,realmodulename^,newmodulename);
  590. stringdispose(modulename);
  591. stringdispose(realmodulename);
  592. modulename:=stringdup(upper(newmodulename));
  593. realmodulename:=stringdup(newmodulename);
  594. end;
  595. ibsourcefiles :
  596. readsourcefiles;
  597. ibusedmacros :
  598. readusedmacros;
  599. ibloadunit :
  600. readloadunit;
  601. iblinkunitofiles :
  602. readlinkcontainer(LinkUnitOFiles);
  603. iblinkunitstaticlibs :
  604. readlinkcontainer(LinkUnitStaticLibs);
  605. iblinkunitsharedlibs :
  606. readlinkcontainer(LinkUnitSharedLibs);
  607. iblinkotherofiles :
  608. readlinkcontainer(LinkotherOFiles);
  609. iblinkotherstaticlibs :
  610. readlinkcontainer(LinkotherStaticLibs);
  611. iblinkothersharedlibs :
  612. readlinkcontainer(LinkotherSharedLibs);
  613. ibendinterface :
  614. break;
  615. else
  616. Message1(unit_f_ppu_invalid_entry,tostr(b));
  617. end;
  618. until false;
  619. end;
  620. procedure tppumodule.load_symtable_refs;
  621. var
  622. b : byte;
  623. unitindex : word;
  624. begin
  625. { load local symtable first }
  626. if ((flags and uf_local_browser)<>0) then
  627. begin
  628. localsymtable:=tstaticsymtable.create(modulename^);
  629. tstaticsymtable(localsymtable).load(ppufile);
  630. end;
  631. { load browser }
  632. if (flags and uf_has_browser)<>0 then
  633. begin
  634. tstoredsymtable(globalsymtable).load_references(ppufile,true);
  635. unitindex:=1;
  636. while assigned(map^[unitindex]) do
  637. begin
  638. { each unit wrote one browser entry }
  639. tstoredsymtable(globalsymtable).load_references(ppufile,false);
  640. inc(unitindex);
  641. end;
  642. b:=ppufile.readentry;
  643. if b<>ibendbrowser then
  644. Message1(unit_f_ppu_invalid_entry,tostr(b));
  645. end;
  646. if ((flags and uf_local_browser)<>0) then
  647. tstaticsymtable(localsymtable).load_references(ppufile,true);
  648. end;
  649. procedure tppumodule.writeppu;
  650. var
  651. pu : tused_unit;
  652. begin
  653. Message1(unit_u_ppu_write,realmodulename^);
  654. { create unit flags }
  655. {$ifdef GDB}
  656. if cs_gdb_dbx in aktglobalswitches then
  657. flags:=flags or uf_has_dbx;
  658. {$endif GDB}
  659. if cs_browser in aktmoduleswitches then
  660. flags:=flags or uf_has_browser;
  661. if cs_local_browser in aktmoduleswitches then
  662. flags:=flags or uf_local_browser;
  663. if do_release then
  664. flags:=flags or uf_release;
  665. {$ifdef Test_Double_checksum_write}
  666. Assign(CRCFile,s+'.IMP');
  667. Rewrite(CRCFile);
  668. {$endif def Test_Double_checksum_write}
  669. { create new ppufile }
  670. ppufile:=tcompilerppufile.create(ppufilename^);
  671. if not ppufile.createfile then
  672. Message(unit_f_ppu_cannot_write);
  673. { first the unitname }
  674. ppufile.putstring(realmodulename^);
  675. ppufile.writeentry(ibmodulename);
  676. writesourcefiles;
  677. writeusedmacros;
  678. writeusedunit;
  679. { write the objectfiles and libraries that come for this unit,
  680. preserve the containers becuase they are still needed to load
  681. the link.res. All doesn't depend on the crc! It doesn't matter
  682. if a unit is in a .o or .a file }
  683. ppufile.do_crc:=false;
  684. writelinkcontainer(linkunitofiles,iblinkunitofiles,true);
  685. writelinkcontainer(linkunitstaticlibs,iblinkunitstaticlibs,true);
  686. writelinkcontainer(linkunitsharedlibs,iblinkunitsharedlibs,true);
  687. writelinkcontainer(linkotherofiles,iblinkotherofiles,false);
  688. writelinkcontainer(linkotherstaticlibs,iblinkotherstaticlibs,true);
  689. writelinkcontainer(linkothersharedlibs,iblinkothersharedlibs,true);
  690. ppufile.do_crc:=true;
  691. ppufile.writeentry(ibendinterface);
  692. { write the symtable entries }
  693. tstoredsymtable(globalsymtable).write(ppufile);
  694. { everything after this doesn't affect the crc }
  695. ppufile.do_crc:=false;
  696. ppufile.writeentry(ibendimplementation);
  697. { write static symtable
  698. needed for local debugging of unit functions }
  699. if ((flags and uf_local_browser)<>0) and
  700. assigned(localsymtable) then
  701. tstoredsymtable(localsymtable).write(ppufile);
  702. { write all browser section }
  703. if (flags and uf_has_browser)<>0 then
  704. begin
  705. tstoredsymtable(globalsymtable).write_references(ppufile,true);
  706. pu:=tused_unit(used_units.first);
  707. while assigned(pu) do
  708. begin
  709. tstoredsymtable(pu.u.globalsymtable).write_references(ppufile,false);
  710. pu:=tused_unit(pu.next);
  711. end;
  712. ppufile.writeentry(ibendbrowser);
  713. end;
  714. if ((flags and uf_local_browser)<>0) and
  715. assigned(localsymtable) then
  716. tstaticsymtable(localsymtable).write_references(ppufile,true);
  717. { the last entry ibend is written automaticly }
  718. { flush to be sure }
  719. ppufile.flush;
  720. { create and write header }
  721. ppufile.header.size:=ppufile.size;
  722. ppufile.header.checksum:=ppufile.crc;
  723. ppufile.header.interface_checksum:=ppufile.interface_crc;
  724. ppufile.header.compiler:=wordversion;
  725. ppufile.header.cpu:=word(target_cpu);
  726. ppufile.header.target:=word(target_info.target);
  727. ppufile.header.flags:=flags;
  728. ppufile.writeheader;
  729. { save crc in current module also }
  730. crc:=ppufile.crc;
  731. interface_crc:=ppufile.interface_crc;
  732. {$ifdef Test_Double_checksum_write}
  733. close(CRCFile);
  734. {$endif Test_Double_checksum_write}
  735. ppufile.closefile;
  736. ppufile.free;
  737. ppufile:=nil;
  738. end;
  739. procedure tppumodule.getppucrc;
  740. begin
  741. {$ifdef Test_Double_checksum_write}
  742. Assign(CRCFile,s+'.INT')
  743. Rewrite(CRCFile);
  744. {$endif def Test_Double_checksum_write}
  745. { create new ppufile }
  746. ppufile:=tcompilerppufile.create(ppufilename^);
  747. ppufile.crc_only:=true;
  748. if not ppufile.createfile then
  749. Message(unit_f_ppu_cannot_write);
  750. { first the unitname }
  751. ppufile.putstring(realmodulename^);
  752. ppufile.writeentry(ibmodulename);
  753. { the interface units affect the crc }
  754. writeusedunit;
  755. ppufile.writeentry(ibendinterface);
  756. { write the symtable entries }
  757. tstoredsymtable(globalsymtable).write(ppufile);
  758. { save crc }
  759. crc:=ppufile.crc;
  760. interface_crc:=ppufile.interface_crc;
  761. {$ifdef Test_Double_checksum}
  762. crc_array:=ppufile.crc_test;
  763. ppufile.crc_test:=nil;
  764. crc_size:=ppufile.crc_index2;
  765. crc_array2:=ppufile.crc_test2;
  766. ppufile.crc_test2:=nil;
  767. crc_size2:=ppufile.crc_index2;
  768. {$endif Test_Double_checksum}
  769. {$ifdef Test_Double_checksum_write}
  770. close(CRCFile);
  771. {$endif Test_Double_checksum_write}
  772. ppufile.closefile;
  773. ppufile.free;
  774. ppufile:=nil;
  775. end;
  776. procedure tppumodule.load_usedunits;
  777. var
  778. pu : tused_unit;
  779. loaded_unit : tmodule;
  780. load_refs : boolean;
  781. nextmapentry : longint;
  782. b : byte;
  783. begin
  784. load_refs:=true;
  785. { init the map }
  786. new(map);
  787. fillchar(map^,sizeof(tunitmap),#0);
  788. {$ifdef NEWMAP}
  789. map^[0]:=current_module;
  790. {$endif NEWMAP}
  791. nextmapentry:=1;
  792. { load the used units from interface }
  793. in_implementation:=false;
  794. pu:=tused_unit(used_units.first);
  795. while assigned(pu) do
  796. begin
  797. if (not pu.loaded) and (pu.in_interface) then
  798. begin
  799. loaded_unit:=loadunit(pu.realname^,'');
  800. if compiled then
  801. exit;
  802. { register unit in used units }
  803. pu.u:=loaded_unit;
  804. pu.loaded:=true;
  805. { doubles are not important for that list PM }
  806. pu.u.dependent_units.concat(tdependent_unit.create(self));
  807. { need to recompile the current unit ? }
  808. if loaded_unit.crc<>pu.checksum then
  809. begin
  810. Message2(unit_u_recompile_crc_change,realmodulename^,pu.realname^);
  811. recompile_reason:=rr_crcchanged;
  812. do_compile:=true;
  813. dispose(map);
  814. map:=nil;
  815. exit;
  816. end;
  817. { setup the map entry for deref }
  818. {$ifndef NEWMAP}
  819. map^[nextmapentry]:=loaded_unit.globalsymtable;
  820. {$else NEWMAP}
  821. map^[nextmapentry]:=loaded_unit;
  822. {$endif NEWMAP}
  823. inc(nextmapentry);
  824. if nextmapentry>maxunits then
  825. Message(unit_f_too_much_units);
  826. end;
  827. pu:=tused_unit(pu.next);
  828. end;
  829. { ok, now load the interface of this unit }
  830. current_module:=self;
  831. SetCompileModule(current_module);
  832. globalsymtable:=tglobalsymtable.create(modulename^);
  833. tstoredsymtable(globalsymtable).load(ppufile);
  834. { now only read the implementation uses }
  835. in_implementation:=true;
  836. pu:=tused_unit(used_units.first);
  837. while assigned(pu) do
  838. begin
  839. if (not pu.loaded) and (not pu.in_interface) then
  840. begin
  841. loaded_unit:=loadunit(pu.realname^,'');
  842. if compiled then
  843. exit;
  844. { register unit in used units }
  845. pu.u:=loaded_unit;
  846. pu.loaded:=true;
  847. { need to recompile the current unit ? }
  848. if (loaded_unit.interface_crc<>pu.interface_checksum) {and
  849. not(current_module.in_second_compile) } then
  850. begin
  851. Message2(unit_u_recompile_crc_change,realmodulename^,pu.realname^+' {impl}');
  852. recompile_reason:=rr_crcchanged;
  853. do_compile:=true;
  854. dispose(map);
  855. map:=nil;
  856. exit;
  857. end;
  858. { setup the map entry for deref }
  859. {$ifndef NEWMAP}
  860. map^[nextmapentry]:=loaded_unit.globalsymtable;
  861. {$else NEWMAP}
  862. map^[nextmapentry]:=loaded_unit;
  863. {$endif NEWMAP}
  864. inc(nextmapentry);
  865. if nextmapentry>maxunits then
  866. Message(unit_f_too_much_units);
  867. end;
  868. pu:=tused_unit(pu.next);
  869. end;
  870. { read the implementation part }
  871. b:=ppufile.readentry;
  872. if b<>ibendimplementation then
  873. Message1(unit_f_ppu_invalid_entry,tostr(b));
  874. { load browser info if stored }
  875. if ((flags and uf_has_browser)<>0) and load_refs then
  876. begin
  877. current_module:=self;
  878. load_symtable_refs;
  879. end;
  880. { remove the map, it's not needed anymore }
  881. dispose(map);
  882. map:=nil;
  883. end;
  884. procedure tppumodule.loadppu;
  885. var
  886. name : string;
  887. begin
  888. { load interface section }
  889. if not do_compile then
  890. load_interface;
  891. { only load units when we don't recompile }
  892. if not do_compile then
  893. load_usedunits;
  894. { recompile if set }
  895. if do_compile then
  896. begin
  897. { we don't need the ppufile anymore }
  898. if assigned(ppufile) then
  899. begin
  900. ppufile.free;
  901. ppufile:=nil;
  902. end;
  903. { recompile the unit or give a fatal error if sources not available }
  904. if not(sources_avail) and
  905. not(sources_checked) then
  906. if (not search_unit(modulename^,'',true))
  907. and (length(modulename^)>8) then
  908. search_unit(copy(modulename^,1,8),'',true);
  909. if not(sources_avail) then
  910. begin
  911. if recompile_reason=rr_noppu then
  912. Message1(unit_f_cant_find_ppu,modulename^)
  913. else
  914. Message1(unit_f_cant_compile_unit,modulename^);
  915. end
  916. else
  917. begin
  918. if in_compile then
  919. begin
  920. in_second_compile:=true;
  921. Message1(parser_d_compiling_second_time,modulename^);
  922. end;
  923. current_scanner.tempcloseinputfile;
  924. name:=mainsource^;
  925. if assigned(scanner) then
  926. tscannerfile(scanner).invalid:=true;
  927. { compile this module }
  928. current_module:=self;
  929. compile(name);
  930. in_second_compile:=false;
  931. if (not current_scanner.invalid) then
  932. current_scanner.tempopeninputfile;
  933. end;
  934. end;
  935. if assigned(ppufile) then
  936. begin
  937. ppufile.closefile;
  938. ppufile.free;
  939. ppufile:=nil;
  940. end;
  941. end;
  942. {*****************************************************************************
  943. LoadUnit
  944. *****************************************************************************}
  945. function loadunit(const s : stringid;const fn:string) : tmodule;
  946. const
  947. ImplIntf : array[boolean] of string[15]=('interface','implementation');
  948. var
  949. st : tglobalsymtable;
  950. second_time : boolean;
  951. old_current_module,hp2 : tmodule;
  952. hp : tppumodule;
  953. scanner : tscannerfile;
  954. dummy : tmodule;
  955. ups : stringid;
  956. begin
  957. old_current_module:=current_module;
  958. { Info }
  959. Message3(unit_u_load_unit,current_module.modulename^,ImplIntf[current_module.in_implementation],s);
  960. ups:=upper(s);
  961. { unit not found }
  962. st:=nil;
  963. dummy:=nil;
  964. { search all loaded units }
  965. hp:=tppumodule(loaded_units.first);
  966. while assigned(hp) do
  967. begin
  968. if hp.modulename^=ups then
  969. begin
  970. { forced to reload ? }
  971. if hp.do_reload then
  972. begin
  973. hp.do_reload:=false;
  974. break;
  975. end;
  976. { only check for units. The main program is also
  977. as a unit in the loaded_units list. We simply need
  978. to ignore this entry (PFV) }
  979. if hp.is_unit then
  980. begin
  981. { the unit is already registered }
  982. { and this means that the unit }
  983. { is already compiled }
  984. { else there is a cyclic unit use }
  985. if assigned(hp.globalsymtable) then
  986. st:=tglobalsymtable(hp.globalsymtable)
  987. else
  988. begin
  989. { both units in interface ? }
  990. if (not current_module.in_implementation) and
  991. (not hp.in_implementation) then
  992. begin
  993. { check for a cycle }
  994. hp2:=current_module.loaded_from;
  995. while assigned(hp2) and (hp2<>hp) do
  996. begin
  997. if hp2.in_implementation then
  998. hp2:=nil
  999. else
  1000. hp2:=hp2.loaded_from;
  1001. end;
  1002. if assigned(hp2) then
  1003. Message2(unit_f_circular_unit_reference,current_module.modulename^,hp.modulename^);
  1004. end;
  1005. end;
  1006. break;
  1007. end;
  1008. end
  1009. else if copy(hp.modulename^,1,8)=ups then
  1010. dummy:=hp;
  1011. { the next unit }
  1012. hp:=tppumodule(hp.next);
  1013. end;
  1014. if assigned(dummy) and not assigned(hp) then
  1015. Message2(unit_w_unit_name_error,s,dummy.modulename^);
  1016. { the unit is not in the loaded units, we must load it first }
  1017. if (not assigned(st)) then
  1018. begin
  1019. if assigned(hp) then
  1020. begin
  1021. { remove the old unit, but save the scanner }
  1022. loaded_units.remove(hp);
  1023. scanner:=tscannerfile(hp.scanner);
  1024. hp.reset;
  1025. hp.scanner:=scanner;
  1026. { try to reopen ppu }
  1027. hp.search_unit(s,fn,false);
  1028. { try to load the unit a second time first }
  1029. current_module:=hp;
  1030. current_module.in_second_load:=true;
  1031. Message1(unit_u_second_load_unit,current_module.modulename^);
  1032. second_time:=true;
  1033. end
  1034. else
  1035. { generates a new unit info record }
  1036. begin
  1037. current_module:=tppumodule.create(s,fn,true);
  1038. scanner:=nil;
  1039. second_time:=false;
  1040. end;
  1041. { close old_current_ppu on system that are
  1042. short on file handles like DOS PM }
  1043. {$ifdef SHORT_ON_FILE_HANDLES}
  1044. if old_current_module.is_unit and
  1045. assigned(tppumodule(old_current_module).ppufile) then
  1046. tppumodule(old_current_module).ppufile.tempclose;
  1047. {$endif SHORT_ON_FILE_HANDLES}
  1048. { now we can register the unit }
  1049. current_module.loaded_from:=old_current_module;
  1050. loaded_units.insert(current_module);
  1051. { now realy load the ppu }
  1052. tppumodule(current_module).loadppu;
  1053. { set compiled flag }
  1054. current_module.compiled:=true;
  1055. { load return pointer }
  1056. hp:=tppumodule(current_module);
  1057. { for a second_time recompile reload all dependent units,
  1058. for a first time compile register the unit _once_ }
  1059. if second_time then
  1060. begin
  1061. { now reload all dependent units }
  1062. hp2:=tmodule(loaded_units.first);
  1063. while assigned(hp2) do
  1064. begin
  1065. if hp2.do_reload then
  1066. dummy:=loadunit(hp2.modulename^,'');
  1067. hp2:=tmodule(hp2.next);
  1068. end;
  1069. end
  1070. else
  1071. usedunits.concat(tused_unit.create(current_module,true));
  1072. end;
  1073. { set the old module }
  1074. {$ifdef SHORT_ON_FILE_HANDLES}
  1075. if old_current_module.is_unit and
  1076. assigned(tppumodule(old_current_module).ppufile) then
  1077. tppumodule(old_current_module).ppufile.tempopen;
  1078. {$endif SHORT_ON_FILE_HANDLES}
  1079. { we are back }
  1080. current_module:=old_current_module;
  1081. SetCompileModule(current_module);
  1082. loadunit:=hp;
  1083. end;
  1084. end.
  1085. {
  1086. $Log$
  1087. Revision 1.10 2001-08-19 09:39:27 peter
  1088. * local browser support fixed
  1089. Revision 1.9 2001/06/18 20:36:23 peter
  1090. * -Ur switch (merged)
  1091. * masm fixes (merged)
  1092. * quoted filenames for go32v2 and win32
  1093. Revision 1.8 2001/06/04 11:49:08 peter
  1094. * store used units in original type in ppu
  1095. Revision 1.7 2001/05/19 23:05:19 peter
  1096. * support uses <unit> in <file> construction
  1097. Revision 1.6 2001/05/19 21:08:59 peter
  1098. * skip program when checking loaded_units for a unit
  1099. Revision 1.5 2001/05/19 13:22:47 peter
  1100. * fixed crash with invalid ppu version detected
  1101. Revision 1.4 2001/05/09 14:11:10 jonas
  1102. * range check error fixes from Peter
  1103. Revision 1.3 2001/05/08 21:06:30 florian
  1104. * some more support for widechars commited especially
  1105. regarding type casting and constants
  1106. Revision 1.2 2001/05/07 11:53:21 jonas
  1107. * fix from Peter for short_on_file_handles code
  1108. Revision 1.1 2001/05/06 14:49:17 peter
  1109. * ppu object to class rewrite
  1110. * move ppu read and write stuff to fppu
  1111. }