fppu.pas 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200
  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 (current_module.outputpath^<>'') then
  275. fnd:=PPUSearchPath(current_module.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(current_module.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(current_module.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. do_compile:=true;
  517. recompile_reason:=rr_sourcenewer;
  518. temp:=temp+' *'
  519. end;
  520. end;
  521. end;
  522. hp:=tinputfile.create(hs);
  523. { the indexing is wrong here PM }
  524. sourcefiles.register_file(hp);
  525. end;
  526. if is_main then
  527. begin
  528. stringdispose(mainsource);
  529. mainsource:=stringdup(hs);
  530. end;
  531. Message1(unit_u_ppu_source,hs+temp);
  532. is_main:=false;
  533. end;
  534. { check if we want to rebuild every unit, only if the sources are
  535. available }
  536. if do_build and sources_avail then
  537. begin
  538. do_compile:=true;
  539. recompile_reason:=rr_build;
  540. end;
  541. end;
  542. procedure tppumodule.readloadunit;
  543. var
  544. hs : string;
  545. intfchecksum,
  546. checksum : cardinal;
  547. in_interface : boolean;
  548. begin
  549. while not ppufile.endofentry do
  550. begin
  551. hs:=ppufile.getstring;
  552. checksum:=cardinal(ppufile.getlongint);
  553. intfchecksum:=cardinal(ppufile.getlongint);
  554. in_interface:=(ppufile.getbyte<>0);
  555. used_units.concat(tused_unit.create_to_load(hs,checksum,intfchecksum,in_interface));
  556. end;
  557. end;
  558. procedure tppumodule.readlinkcontainer(var p:tlinkcontainer);
  559. var
  560. s : string;
  561. m : longint;
  562. begin
  563. while not ppufile.endofentry do
  564. begin
  565. s:=ppufile.getstring;
  566. m:=ppufile.getlongint;
  567. p.add(s,m);
  568. end;
  569. end;
  570. procedure tppumodule.load_interface;
  571. var
  572. b : byte;
  573. newmodulename : string;
  574. begin
  575. { read interface part }
  576. repeat
  577. b:=ppufile.readentry;
  578. case b of
  579. ibmodulename :
  580. begin
  581. newmodulename:=ppufile.getstring;
  582. if upper(newmodulename)<>modulename^ then
  583. Message2(unit_f_unit_name_error,realmodulename^,newmodulename);
  584. stringdispose(modulename);
  585. stringdispose(realmodulename);
  586. modulename:=stringdup(upper(newmodulename));
  587. realmodulename:=stringdup(newmodulename);
  588. end;
  589. ibsourcefiles :
  590. readsourcefiles;
  591. ibusedmacros :
  592. readusedmacros;
  593. ibloadunit :
  594. readloadunit;
  595. iblinkunitofiles :
  596. readlinkcontainer(LinkUnitOFiles);
  597. iblinkunitstaticlibs :
  598. readlinkcontainer(LinkUnitStaticLibs);
  599. iblinkunitsharedlibs :
  600. readlinkcontainer(LinkUnitSharedLibs);
  601. iblinkotherofiles :
  602. readlinkcontainer(LinkotherOFiles);
  603. iblinkotherstaticlibs :
  604. readlinkcontainer(LinkotherStaticLibs);
  605. iblinkothersharedlibs :
  606. readlinkcontainer(LinkotherSharedLibs);
  607. ibendinterface :
  608. break;
  609. else
  610. Message1(unit_f_ppu_invalid_entry,tostr(b));
  611. end;
  612. until false;
  613. end;
  614. procedure tppumodule.load_symtable_refs;
  615. var
  616. b : byte;
  617. unitindex : word;
  618. begin
  619. { load local symtable first }
  620. if ((flags and uf_local_browser)<>0) then
  621. begin
  622. localsymtable:=tstaticsymtable.create(modulename^);
  623. tstaticsymtable(localsymtable).load(ppufile);
  624. end;
  625. { load browser }
  626. if (current_module.flags and uf_has_browser)<>0 then
  627. begin
  628. tstoredsymtable(globalsymtable).load_browser(ppufile);
  629. unitindex:=1;
  630. while assigned(map^[unitindex]) do
  631. begin
  632. { each unit wrote one browser entry }
  633. tstoredsymtable(globalsymtable).load_browser(ppufile);
  634. inc(unitindex);
  635. end;
  636. b:=ppufile.readentry;
  637. if b<>ibendbrowser then
  638. Message1(unit_f_ppu_invalid_entry,tostr(b));
  639. end;
  640. if ((current_module.flags and uf_local_browser)<>0) then
  641. tstaticsymtable(current_module.localsymtable).load_browser(ppufile);
  642. end;
  643. procedure tppumodule.writeppu;
  644. var
  645. pu : tused_unit;
  646. begin
  647. Message1(unit_u_ppu_write,realmodulename^);
  648. { create unit flags }
  649. {$ifdef GDB}
  650. if cs_gdb_dbx in aktglobalswitches then
  651. flags:=flags or uf_has_dbx;
  652. {$endif GDB}
  653. if cs_browser in aktmoduleswitches then
  654. flags:=flags or uf_has_browser;
  655. if cs_local_browser in aktmoduleswitches then
  656. flags:=flags or uf_local_browser;
  657. {$ifdef Test_Double_checksum_write}
  658. Assign(CRCFile,s+'.IMP');
  659. Rewrite(CRCFile);
  660. {$endif def Test_Double_checksum_write}
  661. { create new ppufile }
  662. ppufile:=tcompilerppufile.create(ppufilename^);
  663. if not ppufile.createfile then
  664. Message(unit_f_ppu_cannot_write);
  665. { first the unitname }
  666. ppufile.putstring(realmodulename^);
  667. ppufile.writeentry(ibmodulename);
  668. writesourcefiles;
  669. writeusedmacros;
  670. writeusedunit;
  671. { write the objectfiles and libraries that come for this unit,
  672. preserve the containers becuase they are still needed to load
  673. the link.res. All doesn't depend on the crc! It doesn't matter
  674. if a unit is in a .o or .a file }
  675. ppufile.do_crc:=false;
  676. writelinkcontainer(linkunitofiles,iblinkunitofiles,true);
  677. writelinkcontainer(linkunitstaticlibs,iblinkunitstaticlibs,true);
  678. writelinkcontainer(linkunitsharedlibs,iblinkunitsharedlibs,true);
  679. writelinkcontainer(linkotherofiles,iblinkotherofiles,false);
  680. writelinkcontainer(linkotherstaticlibs,iblinkotherstaticlibs,true);
  681. writelinkcontainer(linkothersharedlibs,iblinkothersharedlibs,true);
  682. ppufile.do_crc:=true;
  683. ppufile.writeentry(ibendinterface);
  684. { write the symtable entries }
  685. tstoredsymtable(globalsymtable).write(ppufile);
  686. { everything after this doesn't affect the crc }
  687. ppufile.do_crc:=false;
  688. ppufile.writeentry(ibendimplementation);
  689. { write static symtable
  690. needed for local debugging of unit functions }
  691. if ((flags and uf_local_browser)<>0) and
  692. assigned(localsymtable) then
  693. tstoredsymtable(localsymtable).write(ppufile);
  694. { write all browser section }
  695. if (flags and uf_has_browser)<>0 then
  696. begin
  697. tstoredsymtable(globalsymtable).write_browser(ppufile);
  698. pu:=tused_unit(used_units.first);
  699. while assigned(pu) do
  700. begin
  701. tstoredsymtable(pu.u.globalsymtable).write_browser(ppufile);
  702. pu:=tused_unit(pu.next);
  703. end;
  704. ppufile.writeentry(ibendbrowser);
  705. end;
  706. if ((flags and uf_local_browser)<>0) and
  707. assigned(localsymtable) then
  708. tstaticsymtable(localsymtable).write_browser(ppufile);
  709. { the last entry ibend is written automaticly }
  710. { flush to be sure }
  711. ppufile.flush;
  712. { create and write header }
  713. ppufile.header.size:=ppufile.size;
  714. ppufile.header.checksum:=ppufile.crc;
  715. ppufile.header.interface_checksum:=ppufile.interface_crc;
  716. ppufile.header.compiler:=wordversion;
  717. ppufile.header.cpu:=word(target_cpu);
  718. ppufile.header.target:=word(target_info.target);
  719. ppufile.header.flags:=flags;
  720. ppufile.writeheader;
  721. { save crc in current module also }
  722. crc:=ppufile.crc;
  723. interface_crc:=ppufile.interface_crc;
  724. {$ifdef Test_Double_checksum_write}
  725. close(CRCFile);
  726. {$endif Test_Double_checksum_write}
  727. ppufile.closefile;
  728. ppufile.free;
  729. ppufile:=nil;
  730. end;
  731. procedure tppumodule.getppucrc;
  732. begin
  733. {$ifdef Test_Double_checksum_write}
  734. Assign(CRCFile,s+'.INT')
  735. Rewrite(CRCFile);
  736. {$endif def Test_Double_checksum_write}
  737. { create new ppufile }
  738. ppufile:=tcompilerppufile.create(ppufilename^);
  739. ppufile.crc_only:=true;
  740. if not ppufile.createfile then
  741. Message(unit_f_ppu_cannot_write);
  742. { first the unitname }
  743. ppufile.putstring(realmodulename^);
  744. ppufile.writeentry(ibmodulename);
  745. { the interface units affect the crc }
  746. writeusedunit;
  747. ppufile.writeentry(ibendinterface);
  748. { write the symtable entries }
  749. tstoredsymtable(globalsymtable).write(ppufile);
  750. { save crc }
  751. crc:=ppufile.crc;
  752. interface_crc:=ppufile.interface_crc;
  753. {$ifdef Test_Double_checksum}
  754. crc_array:=ppufile.crc_test;
  755. ppufile.crc_test:=nil;
  756. crc_size:=ppufile.crc_index2;
  757. crc_array2:=ppufile.crc_test2;
  758. ppufile.crc_test2:=nil;
  759. crc_size2:=ppufile.crc_index2;
  760. {$endif Test_Double_checksum}
  761. {$ifdef Test_Double_checksum_write}
  762. close(CRCFile);
  763. {$endif Test_Double_checksum_write}
  764. ppufile.closefile;
  765. ppufile.free;
  766. ppufile:=nil;
  767. end;
  768. procedure tppumodule.load_usedunits;
  769. var
  770. pu : tused_unit;
  771. loaded_unit : tmodule;
  772. load_refs : boolean;
  773. nextmapentry : longint;
  774. b : byte;
  775. begin
  776. load_refs:=true;
  777. { init the map }
  778. new(map);
  779. fillchar(map^,sizeof(tunitmap),#0);
  780. {$ifdef NEWMAP}
  781. map^[0]:=current_module;
  782. {$endif NEWMAP}
  783. nextmapentry:=1;
  784. { load the used units from interface }
  785. in_implementation:=false;
  786. pu:=tused_unit(used_units.first);
  787. while assigned(pu) do
  788. begin
  789. if (not pu.loaded) and (pu.in_interface) then
  790. begin
  791. loaded_unit:=loadunit(pu.realname^,'');
  792. if compiled then
  793. exit;
  794. { register unit in used units }
  795. pu.u:=loaded_unit;
  796. pu.loaded:=true;
  797. { doubles are not important for that list PM }
  798. pu.u.dependent_units.concat(tdependent_unit.create(self));
  799. { need to recompile the current unit ? }
  800. if loaded_unit.crc<>pu.checksum then
  801. begin
  802. Message2(unit_u_recompile_crc_change,realmodulename^,pu.realname^);
  803. recompile_reason:=rr_crcchanged;
  804. do_compile:=true;
  805. dispose(map);
  806. map:=nil;
  807. exit;
  808. end;
  809. { setup the map entry for deref }
  810. {$ifndef NEWMAP}
  811. map^[nextmapentry]:=loaded_unit.globalsymtable;
  812. {$else NEWMAP}
  813. map^[nextmapentry]:=loaded_unit;
  814. {$endif NEWMAP}
  815. inc(nextmapentry);
  816. if nextmapentry>maxunits then
  817. Message(unit_f_too_much_units);
  818. end;
  819. pu:=tused_unit(pu.next);
  820. end;
  821. { ok, now load the interface of this unit }
  822. current_module:=self;
  823. SetCompileModule(current_module);
  824. globalsymtable:=tglobalsymtable.create(modulename^);
  825. tstoredsymtable(globalsymtable).load(ppufile);
  826. { now only read the implementation uses }
  827. in_implementation:=true;
  828. pu:=tused_unit(used_units.first);
  829. while assigned(pu) do
  830. begin
  831. if (not pu.loaded) and (not pu.in_interface) then
  832. begin
  833. loaded_unit:=loadunit(pu.realname^,'');
  834. if compiled then
  835. exit;
  836. { register unit in used units }
  837. pu.u:=loaded_unit;
  838. pu.loaded:=true;
  839. { need to recompile the current unit ? }
  840. if (loaded_unit.interface_crc<>pu.interface_checksum) {and
  841. not(current_module.in_second_compile) } then
  842. begin
  843. Message2(unit_u_recompile_crc_change,realmodulename^,pu.realname^+' {impl}');
  844. recompile_reason:=rr_crcchanged;
  845. do_compile:=true;
  846. dispose(map);
  847. map:=nil;
  848. exit;
  849. end;
  850. { setup the map entry for deref }
  851. {$ifndef NEWMAP}
  852. map^[nextmapentry]:=loaded_unit.globalsymtable;
  853. {$else NEWMAP}
  854. map^[nextmapentry]:=loaded_unit;
  855. {$endif NEWMAP}
  856. inc(nextmapentry);
  857. if nextmapentry>maxunits then
  858. Message(unit_f_too_much_units);
  859. end;
  860. pu:=tused_unit(pu.next);
  861. end;
  862. { read the implementation part }
  863. b:=ppufile.readentry;
  864. if b<>ibendimplementation then
  865. Message1(unit_f_ppu_invalid_entry,tostr(b));
  866. { load browser info if stored }
  867. if ((flags and uf_has_browser)<>0) and load_refs then
  868. begin
  869. current_module:=self;
  870. load_symtable_refs;
  871. end;
  872. { remove the map, it's not needed anymore }
  873. dispose(map);
  874. map:=nil;
  875. end;
  876. procedure tppumodule.loadppu;
  877. var
  878. name : string;
  879. begin
  880. { load interface section }
  881. if not do_compile then
  882. load_interface;
  883. { only load units when we don't recompile }
  884. if not do_compile then
  885. load_usedunits;
  886. { recompile if set }
  887. if do_compile then
  888. begin
  889. { we don't need the ppufile anymore }
  890. if assigned(ppufile) then
  891. begin
  892. ppufile.free;
  893. ppufile:=nil;
  894. end;
  895. { recompile the unit or give a fatal error if sources not available }
  896. if not(sources_avail) and
  897. not(sources_checked) then
  898. if (not search_unit(modulename^,'',true))
  899. and (length(modulename^)>8) then
  900. search_unit(copy(modulename^,1,8),'',true);
  901. if not(sources_avail) then
  902. begin
  903. if recompile_reason=rr_noppu then
  904. Message1(unit_f_cant_find_ppu,modulename^)
  905. else
  906. Message1(unit_f_cant_compile_unit,modulename^);
  907. end
  908. else
  909. begin
  910. if in_compile then
  911. begin
  912. in_second_compile:=true;
  913. Message1(parser_d_compiling_second_time,modulename^);
  914. end;
  915. current_scanner.tempcloseinputfile;
  916. name:=mainsource^;
  917. if assigned(scanner) then
  918. tscannerfile(scanner).invalid:=true;
  919. { compile this module }
  920. current_module:=self;
  921. compile(name);
  922. in_second_compile:=false;
  923. if (not current_scanner.invalid) then
  924. current_scanner.tempopeninputfile;
  925. end;
  926. end;
  927. if assigned(ppufile) then
  928. begin
  929. ppufile.closefile;
  930. ppufile.free;
  931. ppufile:=nil;
  932. end;
  933. end;
  934. {*****************************************************************************
  935. LoadUnit
  936. *****************************************************************************}
  937. function loadunit(const s : stringid;const fn:string) : tmodule;
  938. const
  939. ImplIntf : array[boolean] of string[15]=('interface','implementation');
  940. var
  941. st : tglobalsymtable;
  942. second_time : boolean;
  943. old_current_module,hp2 : tmodule;
  944. hp : tppumodule;
  945. scanner : tscannerfile;
  946. dummy : tmodule;
  947. ups : stringid;
  948. begin
  949. old_current_module:=current_module;
  950. { Info }
  951. Message3(unit_u_load_unit,current_module.modulename^,ImplIntf[current_module.in_implementation],s);
  952. ups:=upper(s);
  953. { unit not found }
  954. st:=nil;
  955. dummy:=nil;
  956. { search all loaded units }
  957. hp:=tppumodule(loaded_units.first);
  958. while assigned(hp) do
  959. begin
  960. if hp.modulename^=ups then
  961. begin
  962. { forced to reload ? }
  963. if hp.do_reload then
  964. begin
  965. hp.do_reload:=false;
  966. break;
  967. end;
  968. { only check for units. The main program is also
  969. as a unit in the loaded_units list. We simply need
  970. to ignore this entry (PFV) }
  971. if hp.is_unit then
  972. begin
  973. { the unit is already registered }
  974. { and this means that the unit }
  975. { is already compiled }
  976. { else there is a cyclic unit use }
  977. if assigned(hp.globalsymtable) then
  978. st:=tglobalsymtable(hp.globalsymtable)
  979. else
  980. begin
  981. { both units in interface ? }
  982. if (not current_module.in_implementation) and
  983. (not hp.in_implementation) then
  984. begin
  985. { check for a cycle }
  986. hp2:=current_module.loaded_from;
  987. while assigned(hp2) and (hp2<>hp) do
  988. begin
  989. if hp2.in_implementation then
  990. hp2:=nil
  991. else
  992. hp2:=hp2.loaded_from;
  993. end;
  994. if assigned(hp2) then
  995. Message2(unit_f_circular_unit_reference,current_module.modulename^,hp.modulename^);
  996. end;
  997. end;
  998. break;
  999. end;
  1000. end
  1001. else if copy(hp.modulename^,1,8)=ups then
  1002. dummy:=hp;
  1003. { the next unit }
  1004. hp:=tppumodule(hp.next);
  1005. end;
  1006. if assigned(dummy) and not assigned(hp) then
  1007. Message2(unit_w_unit_name_error,s,dummy.modulename^);
  1008. { the unit is not in the loaded units, we must load it first }
  1009. if (not assigned(st)) then
  1010. begin
  1011. if assigned(hp) then
  1012. begin
  1013. { remove the old unit, but save the scanner }
  1014. loaded_units.remove(hp);
  1015. scanner:=tscannerfile(hp.scanner);
  1016. hp.reset;
  1017. hp.scanner:=scanner;
  1018. { try to reopen ppu }
  1019. hp.search_unit(s,fn,false);
  1020. { try to load the unit a second time first }
  1021. current_module:=hp;
  1022. current_module.in_second_load:=true;
  1023. Message1(unit_u_second_load_unit,current_module.modulename^);
  1024. second_time:=true;
  1025. end
  1026. else
  1027. { generates a new unit info record }
  1028. begin
  1029. current_module:=tppumodule.create(s,fn,true);
  1030. scanner:=nil;
  1031. second_time:=false;
  1032. end;
  1033. { close old_current_ppu on system that are
  1034. short on file handles like DOS PM }
  1035. {$ifdef SHORT_ON_FILE_HANDLES}
  1036. if old_current_module.is_unit and
  1037. assigned(tppumodule(old_current_module).ppufile) then
  1038. tppumodule(old_current_module).ppufile.tempclose;
  1039. {$endif SHORT_ON_FILE_HANDLES}
  1040. { now we can register the unit }
  1041. current_module.loaded_from:=old_current_module;
  1042. loaded_units.insert(current_module);
  1043. { now realy load the ppu }
  1044. tppumodule(current_module).loadppu;
  1045. { set compiled flag }
  1046. current_module.compiled:=true;
  1047. { load return pointer }
  1048. hp:=tppumodule(current_module);
  1049. { for a second_time recompile reload all dependent units,
  1050. for a first time compile register the unit _once_ }
  1051. if second_time then
  1052. begin
  1053. { now reload all dependent units }
  1054. hp2:=tmodule(loaded_units.first);
  1055. while assigned(hp2) do
  1056. begin
  1057. if hp2.do_reload then
  1058. dummy:=loadunit(hp2.modulename^,'');
  1059. hp2:=tmodule(hp2.next);
  1060. end;
  1061. end
  1062. else
  1063. usedunits.concat(tused_unit.create(current_module,true));
  1064. end;
  1065. { set the old module }
  1066. {$ifdef SHORT_ON_FILE_HANDLES}
  1067. if old_current_module.is_unit and
  1068. assigned(tppumodule(old_current_module).ppufile) then
  1069. tppumodule(old_current_module).ppufile.tempopen;
  1070. {$endif SHORT_ON_FILE_HANDLES}
  1071. { we are back }
  1072. current_module:=old_current_module;
  1073. SetCompileModule(current_module);
  1074. loadunit:=hp;
  1075. end;
  1076. end.
  1077. {
  1078. $Log$
  1079. Revision 1.8 2001-06-04 11:49:08 peter
  1080. * store used units in original type in ppu
  1081. Revision 1.7 2001/05/19 23:05:19 peter
  1082. * support uses <unit> in <file> construction
  1083. Revision 1.6 2001/05/19 21:08:59 peter
  1084. * skip program when checking loaded_units for a unit
  1085. Revision 1.5 2001/05/19 13:22:47 peter
  1086. * fixed crash with invalid ppu version detected
  1087. Revision 1.4 2001/05/09 14:11:10 jonas
  1088. * range check error fixes from Peter
  1089. Revision 1.3 2001/05/08 21:06:30 florian
  1090. * some more support for widechars commited especially
  1091. regarding type casting and constants
  1092. Revision 1.2 2001/05/07 11:53:21 jonas
  1093. * fix from Peter for short_on_file_handles code
  1094. Revision 1.1 2001/05/06 14:49:17 peter
  1095. * ppu object to class rewrite
  1096. * move ppu read and write stuff to fppu
  1097. }