fppu.pas 43 KB

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