fppu.pas 44 KB

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