fppu.pas 40 KB

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