fppu.pas 39 KB

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