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 GO32V2}
  23. {$define SHORT_ON_FILE_HANDLES}
  24. {$endif GO32V2}
  25. interface
  26. uses
  27. cutils,cclasses,
  28. globtype,globals,finput,fmodule,
  29. symbase,symppu,ppu;
  30. type
  31. tppumodule = class(tmodule)
  32. ppufile : tcompilerppufile; { the PPU file }
  33. {$ifdef Test_Double_checksum}
  34. crc_array : pointer;
  35. crc_size : longint;
  36. crc_array2 : pointer;
  37. crc_size2 : longint;
  38. {$endif def Test_Double_checksum}
  39. constructor create(const s:string;const fn:string;_is_unit:boolean);
  40. destructor destroy;override;
  41. procedure reset;override;
  42. function openppu:boolean;
  43. function search_unit(const n : string;const fn:string;onlysource:boolean):boolean;
  44. procedure getppucrc;
  45. procedure writeppu;
  46. procedure loadppu;
  47. private
  48. procedure load_interface;
  49. procedure load_symtable_refs;
  50. procedure load_usedunits;
  51. procedure writeusedmacro(p:TNamedIndexItem);
  52. procedure writeusedmacros;
  53. procedure writesourcefiles;
  54. procedure writeusedunit;
  55. procedure writelinkcontainer(var p:tlinkcontainer;id:byte;strippath:boolean);
  56. procedure readusedmacros;
  57. procedure readsourcefiles;
  58. procedure readloadunit;
  59. procedure readlinkcontainer(var p:tlinkcontainer);
  60. end;
  61. function loadunit(const s : stringid;const fn:string) : tmodule;
  62. implementation
  63. uses
  64. {$ifdef delphi}
  65. dmisc,
  66. {$else}
  67. dos,
  68. {$endif}
  69. verbose,systems,version,
  70. symtable,
  71. scanner,
  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 ttargetcpu(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 ttarget(ppufile.header.target)<>target_info.target 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);
  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. current_scanner.macros.foreach({$ifdef FPCPROCVAR}@{$endif}writeusedmacro);
  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.readusedmacros;
  406. var
  407. hs : string;
  408. mac : tmacro;
  409. was_defined_at_startup,
  410. was_used : boolean;
  411. begin
  412. while not ppufile.endofentry do
  413. begin
  414. hs:=ppufile.getstring;
  415. was_defined_at_startup:=boolean(ppufile.getbyte);
  416. was_used:=boolean(ppufile.getbyte);
  417. mac:=tmacro(current_scanner.macros.search(hs));
  418. if assigned(mac) then
  419. begin
  420. {$ifndef EXTDEBUG}
  421. { if we don't have the sources why tell }
  422. if sources_avail then
  423. {$endif ndef EXTDEBUG}
  424. if (not was_defined_at_startup) and
  425. was_used and
  426. mac.defined_at_startup then
  427. Message2(unit_h_cond_not_set_in_last_compile,hs,mainsource^);
  428. end
  429. else { not assigned }
  430. if was_defined_at_startup and
  431. was_used then
  432. Message2(unit_h_cond_not_set_in_last_compile,hs,mainsource^);
  433. end;
  434. end;
  435. procedure tppumodule.readsourcefiles;
  436. var
  437. temp,hs : string;
  438. temp_dir : string;
  439. main_dir : string;
  440. incfile_found,
  441. main_found,
  442. is_main : boolean;
  443. ppufiletime,
  444. source_time : longint;
  445. hp : tinputfile;
  446. begin
  447. ppufiletime:=getnamedfiletime(ppufilename^);
  448. sources_avail:=true;
  449. is_main:=true;
  450. main_dir:='';
  451. while not ppufile.endofentry do
  452. begin
  453. hs:=ppufile.getstring;
  454. temp_dir:='';
  455. if (flags and uf_in_library)<>0 then
  456. begin
  457. sources_avail:=false;
  458. temp:=' library';
  459. end
  460. else if pos('Macro ',hs)=1 then
  461. begin
  462. { we don't want to find this file }
  463. { but there is a problem with file indexing !! }
  464. temp:='';
  465. end
  466. else
  467. begin
  468. { check the date of the source files }
  469. Source_Time:=GetNamedFileTime(path^+hs);
  470. incfile_found:=false;
  471. main_found:=false;
  472. if Source_Time<>-1 then
  473. hs:=path^+hs
  474. else
  475. if not(is_main) then
  476. begin
  477. Source_Time:=GetNamedFileTime(main_dir+hs);
  478. if Source_Time<>-1 then
  479. hs:=main_dir+hs;
  480. end;
  481. if (Source_Time=-1) then
  482. begin
  483. if is_main then
  484. main_found:=unitsearchpath.FindFile(hs,temp_dir)
  485. else
  486. incfile_found:=includesearchpath.FindFile(hs,temp_dir);
  487. if incfile_found or main_found then
  488. begin
  489. Source_Time:=GetNamedFileTime(temp_dir);
  490. if Source_Time<>-1 then
  491. hs:=temp_dir;
  492. end;
  493. end;
  494. if Source_Time=-1 then
  495. begin
  496. sources_avail:=false;
  497. temp:=' not found';
  498. end
  499. else
  500. begin
  501. if main_found then
  502. main_dir:=temp_dir;
  503. { time newer? But only allow if the file is not searched
  504. in the include path (PFV), else you've problems with
  505. units which use the same includefile names }
  506. if incfile_found then
  507. temp:=' found'
  508. else
  509. begin
  510. temp:=' time '+filetimestring(source_time);
  511. if (source_time>ppufiletime) then
  512. begin
  513. if {is_main or} ((flags and uf_release)=0) then
  514. begin
  515. do_compile:=true;
  516. recompile_reason:=rr_sourcenewer;
  517. end
  518. else
  519. Message2(unit_h_source_modified,hs,ppufilename^);
  520. temp:=temp+' *';
  521. end;
  522. end;
  523. end;
  524. hp:=tinputfile.create(hs);
  525. { the indexing is wrong here PM }
  526. sourcefiles.register_file(hp);
  527. end;
  528. if is_main then
  529. begin
  530. stringdispose(mainsource);
  531. mainsource:=stringdup(hs);
  532. end;
  533. Message1(unit_u_ppu_source,hs+temp);
  534. is_main:=false;
  535. end;
  536. { check if we want to rebuild every unit, only if the sources are
  537. available }
  538. if do_build and sources_avail and
  539. ((flags and uf_release)=0) then
  540. begin
  541. do_compile:=true;
  542. recompile_reason:=rr_build;
  543. end;
  544. end;
  545. procedure tppumodule.readloadunit;
  546. var
  547. hs : string;
  548. intfchecksum,
  549. checksum : cardinal;
  550. in_interface : boolean;
  551. begin
  552. while not ppufile.endofentry do
  553. begin
  554. hs:=ppufile.getstring;
  555. checksum:=cardinal(ppufile.getlongint);
  556. intfchecksum:=cardinal(ppufile.getlongint);
  557. in_interface:=(ppufile.getbyte<>0);
  558. used_units.concat(tused_unit.create_to_load(hs,checksum,intfchecksum,in_interface));
  559. end;
  560. end;
  561. procedure tppumodule.readlinkcontainer(var p:tlinkcontainer);
  562. var
  563. s : string;
  564. m : longint;
  565. begin
  566. while not ppufile.endofentry do
  567. begin
  568. s:=ppufile.getstring;
  569. m:=ppufile.getlongint;
  570. p.add(s,m);
  571. end;
  572. end;
  573. procedure tppumodule.load_interface;
  574. var
  575. b : byte;
  576. newmodulename : string;
  577. begin
  578. { read interface part }
  579. repeat
  580. b:=ppufile.readentry;
  581. case b of
  582. ibmodulename :
  583. begin
  584. newmodulename:=ppufile.getstring;
  585. if (cs_check_unit_name in aktglobalswitches) and
  586. (upper(newmodulename)<>modulename^) then
  587. Message2(unit_f_unit_name_error,realmodulename^,newmodulename);
  588. stringdispose(modulename);
  589. stringdispose(realmodulename);
  590. modulename:=stringdup(upper(newmodulename));
  591. realmodulename:=stringdup(newmodulename);
  592. end;
  593. ibsourcefiles :
  594. readsourcefiles;
  595. ibusedmacros :
  596. readusedmacros;
  597. ibloadunit :
  598. readloadunit;
  599. iblinkunitofiles :
  600. readlinkcontainer(LinkUnitOFiles);
  601. iblinkunitstaticlibs :
  602. readlinkcontainer(LinkUnitStaticLibs);
  603. iblinkunitsharedlibs :
  604. readlinkcontainer(LinkUnitSharedLibs);
  605. iblinkotherofiles :
  606. readlinkcontainer(LinkotherOFiles);
  607. iblinkotherstaticlibs :
  608. readlinkcontainer(LinkotherStaticLibs);
  609. iblinkothersharedlibs :
  610. readlinkcontainer(LinkotherSharedLibs);
  611. ibendinterface :
  612. break;
  613. else
  614. Message1(unit_f_ppu_invalid_entry,tostr(b));
  615. end;
  616. until false;
  617. end;
  618. procedure tppumodule.load_symtable_refs;
  619. var
  620. b : byte;
  621. unitindex : word;
  622. begin
  623. { load local symtable first }
  624. if ((flags and uf_local_browser)<>0) then
  625. begin
  626. localsymtable:=tstaticsymtable.create(modulename^);
  627. tstaticsymtable(localsymtable).load(ppufile);
  628. end;
  629. { load browser }
  630. if (flags and uf_has_browser)<>0 then
  631. begin
  632. tstoredsymtable(globalsymtable).load_references(ppufile,true);
  633. unitindex:=1;
  634. while assigned(map^[unitindex]) do
  635. begin
  636. { each unit wrote one browser entry }
  637. tstoredsymtable(globalsymtable).load_references(ppufile,false);
  638. inc(unitindex);
  639. end;
  640. b:=ppufile.readentry;
  641. if b<>ibendbrowser then
  642. Message1(unit_f_ppu_invalid_entry,tostr(b));
  643. end;
  644. if ((flags and uf_local_browser)<>0) then
  645. tstaticsymtable(localsymtable).load_references(ppufile,true);
  646. end;
  647. procedure tppumodule.writeppu;
  648. var
  649. pu : tused_unit;
  650. begin
  651. Message1(unit_u_ppu_write,realmodulename^);
  652. { create unit flags }
  653. {$ifdef GDB}
  654. if cs_gdb_dbx in aktglobalswitches then
  655. flags:=flags or uf_has_dbx;
  656. {$endif GDB}
  657. if cs_browser in aktmoduleswitches then
  658. flags:=flags or uf_has_browser;
  659. if cs_local_browser in aktmoduleswitches then
  660. flags:=flags or uf_local_browser;
  661. if do_release then
  662. flags:=flags or uf_release;
  663. {$ifdef Test_Double_checksum_write}
  664. Assign(CRCFile,s+'.IMP');
  665. Rewrite(CRCFile);
  666. {$endif def Test_Double_checksum_write}
  667. { create new ppufile }
  668. ppufile:=tcompilerppufile.create(ppufilename^);
  669. if not ppufile.createfile then
  670. Message(unit_f_ppu_cannot_write);
  671. { first the unitname }
  672. ppufile.putstring(realmodulename^);
  673. ppufile.writeentry(ibmodulename);
  674. writesourcefiles;
  675. writeusedmacros;
  676. writeusedunit;
  677. { write the objectfiles and libraries that come for this unit,
  678. preserve the containers becuase they are still needed to load
  679. the link.res. All doesn't depend on the crc! It doesn't matter
  680. if a unit is in a .o or .a file }
  681. ppufile.do_crc:=false;
  682. writelinkcontainer(linkunitofiles,iblinkunitofiles,true);
  683. writelinkcontainer(linkunitstaticlibs,iblinkunitstaticlibs,true);
  684. writelinkcontainer(linkunitsharedlibs,iblinkunitsharedlibs,true);
  685. writelinkcontainer(linkotherofiles,iblinkotherofiles,false);
  686. writelinkcontainer(linkotherstaticlibs,iblinkotherstaticlibs,true);
  687. writelinkcontainer(linkothersharedlibs,iblinkothersharedlibs,true);
  688. ppufile.do_crc:=true;
  689. ppufile.writeentry(ibendinterface);
  690. { write the symtable entries }
  691. tstoredsymtable(globalsymtable).write(ppufile);
  692. { everything after this doesn't affect the crc }
  693. ppufile.do_crc:=false;
  694. ppufile.writeentry(ibendimplementation);
  695. { write static symtable
  696. needed for local debugging of unit functions }
  697. if ((flags and uf_local_browser)<>0) and
  698. assigned(localsymtable) then
  699. tstoredsymtable(localsymtable).write(ppufile);
  700. { write all browser section }
  701. if (flags and uf_has_browser)<>0 then
  702. begin
  703. tstoredsymtable(globalsymtable).write_references(ppufile,true);
  704. pu:=tused_unit(used_units.first);
  705. while assigned(pu) do
  706. begin
  707. tstoredsymtable(pu.u.globalsymtable).write_references(ppufile,false);
  708. pu:=tused_unit(pu.next);
  709. end;
  710. ppufile.writeentry(ibendbrowser);
  711. end;
  712. if ((flags and uf_local_browser)<>0) and
  713. assigned(localsymtable) then
  714. tstaticsymtable(localsymtable).write_references(ppufile,true);
  715. { the last entry ibend is written automaticly }
  716. { flush to be sure }
  717. ppufile.flush;
  718. { create and write header }
  719. ppufile.header.size:=ppufile.size;
  720. ppufile.header.checksum:=ppufile.crc;
  721. ppufile.header.interface_checksum:=ppufile.interface_crc;
  722. ppufile.header.compiler:=wordversion;
  723. ppufile.header.cpu:=word(target_cpu);
  724. ppufile.header.target:=word(target_info.target);
  725. ppufile.header.flags:=flags;
  726. ppufile.writeheader;
  727. { save crc in current module also }
  728. crc:=ppufile.crc;
  729. interface_crc:=ppufile.interface_crc;
  730. {$ifdef Test_Double_checksum_write}
  731. close(CRCFile);
  732. {$endif Test_Double_checksum_write}
  733. ppufile.closefile;
  734. ppufile.free;
  735. ppufile:=nil;
  736. end;
  737. procedure tppumodule.getppucrc;
  738. begin
  739. {$ifdef Test_Double_checksum_write}
  740. Assign(CRCFile,s+'.INT')
  741. Rewrite(CRCFile);
  742. {$endif def Test_Double_checksum_write}
  743. { create new ppufile }
  744. ppufile:=tcompilerppufile.create(ppufilename^);
  745. ppufile.crc_only:=true;
  746. if not ppufile.createfile then
  747. Message(unit_f_ppu_cannot_write);
  748. { first the unitname }
  749. ppufile.putstring(realmodulename^);
  750. ppufile.writeentry(ibmodulename);
  751. { the interface units affect the crc }
  752. writeusedunit;
  753. ppufile.writeentry(ibendinterface);
  754. { write the symtable entries }
  755. tstoredsymtable(globalsymtable).write(ppufile);
  756. { save crc }
  757. crc:=ppufile.crc;
  758. interface_crc:=ppufile.interface_crc;
  759. {$ifdef Test_Double_checksum}
  760. crc_array:=ppufile.crc_test;
  761. ppufile.crc_test:=nil;
  762. crc_size:=ppufile.crc_index2;
  763. crc_array2:=ppufile.crc_test2;
  764. ppufile.crc_test2:=nil;
  765. crc_size2:=ppufile.crc_index2;
  766. {$endif Test_Double_checksum}
  767. {$ifdef Test_Double_checksum_write}
  768. close(CRCFile);
  769. {$endif Test_Double_checksum_write}
  770. ppufile.closefile;
  771. ppufile.free;
  772. ppufile:=nil;
  773. end;
  774. procedure tppumodule.load_usedunits;
  775. var
  776. pu : tused_unit;
  777. loaded_unit : tmodule;
  778. load_refs : boolean;
  779. nextmapentry : longint;
  780. b : byte;
  781. begin
  782. load_refs:=true;
  783. { init the map }
  784. new(map);
  785. fillchar(map^,sizeof(tunitmap),#0);
  786. {$ifdef NEWMAP}
  787. map^[0]:=current_module;
  788. {$endif NEWMAP}
  789. nextmapentry:=1;
  790. { load the used units from interface }
  791. in_implementation:=false;
  792. pu:=tused_unit(used_units.first);
  793. while assigned(pu) do
  794. begin
  795. if (not pu.loaded) and (pu.in_interface) then
  796. begin
  797. loaded_unit:=loadunit(pu.realname^,'');
  798. if compiled then
  799. exit;
  800. { register unit in used units }
  801. pu.u:=loaded_unit;
  802. pu.loaded:=true;
  803. { doubles are not important for that list PM }
  804. pu.u.dependent_units.concat(tdependent_unit.create(self));
  805. { need to recompile the current unit ? }
  806. if loaded_unit.crc<>pu.checksum then
  807. begin
  808. Message2(unit_u_recompile_crc_change,realmodulename^,pu.realname^);
  809. recompile_reason:=rr_crcchanged;
  810. do_compile:=true;
  811. dispose(map);
  812. map:=nil;
  813. exit;
  814. end;
  815. { setup the map entry for deref }
  816. {$ifndef NEWMAP}
  817. map^[nextmapentry]:=loaded_unit.globalsymtable;
  818. {$else NEWMAP}
  819. map^[nextmapentry]:=loaded_unit;
  820. {$endif NEWMAP}
  821. inc(nextmapentry);
  822. if nextmapentry>maxunits then
  823. Message(unit_f_too_much_units);
  824. end;
  825. pu:=tused_unit(pu.next);
  826. end;
  827. { ok, now load the interface of this unit }
  828. current_module:=self;
  829. SetCompileModule(current_module);
  830. globalsymtable:=tglobalsymtable.create(modulename^);
  831. tstoredsymtable(globalsymtable).load(ppufile);
  832. { now only read the implementation uses }
  833. in_implementation:=true;
  834. pu:=tused_unit(used_units.first);
  835. while assigned(pu) do
  836. begin
  837. if (not pu.loaded) and (not pu.in_interface) then
  838. begin
  839. loaded_unit:=loadunit(pu.realname^,'');
  840. if compiled then
  841. exit;
  842. { register unit in used units }
  843. pu.u:=loaded_unit;
  844. pu.loaded:=true;
  845. { need to recompile the current unit ? }
  846. if (loaded_unit.interface_crc<>pu.interface_checksum) {and
  847. not(current_module.in_second_compile) } then
  848. begin
  849. Message2(unit_u_recompile_crc_change,realmodulename^,pu.realname^+' {impl}');
  850. recompile_reason:=rr_crcchanged;
  851. do_compile:=true;
  852. dispose(map);
  853. map:=nil;
  854. exit;
  855. end;
  856. { setup the map entry for deref }
  857. {$ifndef NEWMAP}
  858. map^[nextmapentry]:=loaded_unit.globalsymtable;
  859. {$else NEWMAP}
  860. map^[nextmapentry]:=loaded_unit;
  861. {$endif NEWMAP}
  862. inc(nextmapentry);
  863. if nextmapentry>maxunits then
  864. Message(unit_f_too_much_units);
  865. end;
  866. pu:=tused_unit(pu.next);
  867. end;
  868. { read the implementation part }
  869. b:=ppufile.readentry;
  870. if b<>ibendimplementation then
  871. Message1(unit_f_ppu_invalid_entry,tostr(b));
  872. { load browser info if stored }
  873. if ((flags and uf_has_browser)<>0) and load_refs then
  874. begin
  875. current_module:=self;
  876. load_symtable_refs;
  877. end;
  878. { remove the map, it's not needed anymore }
  879. dispose(map);
  880. map:=nil;
  881. end;
  882. procedure tppumodule.loadppu;
  883. var
  884. name : string;
  885. begin
  886. { load interface section }
  887. if not do_compile then
  888. load_interface;
  889. { only load units when we don't recompile }
  890. if not do_compile then
  891. load_usedunits;
  892. { recompile if set }
  893. if do_compile then
  894. begin
  895. { we don't need the ppufile anymore }
  896. if assigned(ppufile) then
  897. begin
  898. ppufile.free;
  899. ppufile:=nil;
  900. end;
  901. { recompile the unit or give a fatal error if sources not available }
  902. if not(sources_avail) and
  903. not(sources_checked) then
  904. if (not search_unit(modulename^,'',true))
  905. and (length(modulename^)>8) then
  906. search_unit(copy(modulename^,1,8),'',true);
  907. if not(sources_avail) then
  908. begin
  909. if recompile_reason=rr_noppu then
  910. Message1(unit_f_cant_find_ppu,modulename^)
  911. else
  912. Message1(unit_f_cant_compile_unit,modulename^);
  913. end
  914. else
  915. begin
  916. if in_compile then
  917. begin
  918. in_second_compile:=true;
  919. Message1(parser_d_compiling_second_time,modulename^);
  920. end;
  921. current_scanner.tempcloseinputfile;
  922. name:=mainsource^;
  923. if assigned(scanner) then
  924. tscannerfile(scanner).invalid:=true;
  925. { compile this module }
  926. current_module:=self;
  927. compile(name);
  928. in_second_compile:=false;
  929. if (not current_scanner.invalid) then
  930. current_scanner.tempopeninputfile;
  931. end;
  932. end;
  933. if assigned(ppufile) then
  934. begin
  935. ppufile.closefile;
  936. ppufile.free;
  937. ppufile:=nil;
  938. end;
  939. end;
  940. {*****************************************************************************
  941. LoadUnit
  942. *****************************************************************************}
  943. function loadunit(const s : stringid;const fn:string) : tmodule;
  944. const
  945. ImplIntf : array[boolean] of string[15]=('interface','implementation');
  946. var
  947. st : tglobalsymtable;
  948. second_time : boolean;
  949. old_current_module,hp2 : tmodule;
  950. hp : tppumodule;
  951. scanner : tscannerfile;
  952. dummy : tmodule;
  953. ups : stringid;
  954. begin
  955. old_current_module:=current_module;
  956. { Info }
  957. Message3(unit_u_load_unit,current_module.modulename^,ImplIntf[current_module.in_implementation],s);
  958. ups:=upper(s);
  959. { unit not found }
  960. st:=nil;
  961. dummy:=nil;
  962. { search all loaded units }
  963. hp:=tppumodule(loaded_units.first);
  964. while assigned(hp) do
  965. begin
  966. if hp.modulename^=ups then
  967. begin
  968. { forced to reload ? }
  969. if hp.do_reload then
  970. begin
  971. hp.do_reload:=false;
  972. break;
  973. end;
  974. { only check for units. The main program is also
  975. as a unit in the loaded_units list. We simply need
  976. to ignore this entry (PFV) }
  977. if hp.is_unit then
  978. begin
  979. { the unit is already registered }
  980. { and this means that the unit }
  981. { is already compiled }
  982. { else there is a cyclic unit use }
  983. if assigned(hp.globalsymtable) then
  984. st:=tglobalsymtable(hp.globalsymtable)
  985. else
  986. begin
  987. { both units in interface ? }
  988. if (not current_module.in_implementation) and
  989. (not hp.in_implementation) then
  990. begin
  991. { check for a cycle }
  992. hp2:=current_module.loaded_from;
  993. while assigned(hp2) and (hp2<>hp) do
  994. begin
  995. if hp2.in_implementation then
  996. hp2:=nil
  997. else
  998. hp2:=hp2.loaded_from;
  999. end;
  1000. if assigned(hp2) then
  1001. Message2(unit_f_circular_unit_reference,current_module.modulename^,hp.modulename^);
  1002. end;
  1003. end;
  1004. break;
  1005. end;
  1006. end
  1007. else if copy(hp.modulename^,1,8)=ups then
  1008. dummy:=hp;
  1009. { the next unit }
  1010. hp:=tppumodule(hp.next);
  1011. end;
  1012. if assigned(dummy) and not assigned(hp) then
  1013. Message2(unit_w_unit_name_error,s,dummy.modulename^);
  1014. { the unit is not in the loaded units, we must load it first }
  1015. if (not assigned(st)) then
  1016. begin
  1017. if assigned(hp) then
  1018. begin
  1019. { remove the old unit, but save the scanner }
  1020. loaded_units.remove(hp);
  1021. scanner:=tscannerfile(hp.scanner);
  1022. hp.reset;
  1023. hp.scanner:=scanner;
  1024. { try to reopen ppu }
  1025. hp.search_unit(s,fn,false);
  1026. { try to load the unit a second time first }
  1027. current_module:=hp;
  1028. current_module.in_second_load:=true;
  1029. Message1(unit_u_second_load_unit,current_module.modulename^);
  1030. second_time:=true;
  1031. end
  1032. else
  1033. { generates a new unit info record }
  1034. begin
  1035. current_module:=tppumodule.create(s,fn,true);
  1036. scanner:=nil;
  1037. second_time:=false;
  1038. end;
  1039. { close old_current_ppu on system that are
  1040. short on file handles like DOS PM }
  1041. {$ifdef SHORT_ON_FILE_HANDLES}
  1042. if old_current_module.is_unit and
  1043. assigned(tppumodule(old_current_module).ppufile) then
  1044. tppumodule(old_current_module).ppufile.tempclose;
  1045. {$endif SHORT_ON_FILE_HANDLES}
  1046. { now we can register the unit }
  1047. current_module.loaded_from:=old_current_module;
  1048. loaded_units.insert(current_module);
  1049. { now realy load the ppu }
  1050. tppumodule(current_module).loadppu;
  1051. { set compiled flag }
  1052. current_module.compiled:=true;
  1053. { load return pointer }
  1054. hp:=tppumodule(current_module);
  1055. { for a second_time recompile reload all dependent units,
  1056. for a first time compile register the unit _once_ }
  1057. if second_time then
  1058. begin
  1059. { now reload all dependent units }
  1060. hp2:=tmodule(loaded_units.first);
  1061. while assigned(hp2) do
  1062. begin
  1063. if hp2.do_reload then
  1064. dummy:=loadunit(hp2.modulename^,'');
  1065. hp2:=tmodule(hp2.next);
  1066. end;
  1067. end
  1068. else
  1069. usedunits.concat(tused_unit.create(current_module,true));
  1070. end;
  1071. { set the old module }
  1072. {$ifdef SHORT_ON_FILE_HANDLES}
  1073. if old_current_module.is_unit and
  1074. assigned(tppumodule(old_current_module).ppufile) then
  1075. tppumodule(old_current_module).ppufile.tempopen;
  1076. {$endif SHORT_ON_FILE_HANDLES}
  1077. { we are back }
  1078. current_module:=old_current_module;
  1079. SetCompileModule(current_module);
  1080. loadunit:=hp;
  1081. end;
  1082. end.
  1083. {
  1084. $Log$
  1085. Revision 1.12 2002-03-28 20:46:44 carl
  1086. - remove go32v1 support
  1087. Revision 1.11 2002/01/19 14:20:13 peter
  1088. * check for -Un when loading ppu with wrong name
  1089. Revision 1.10 2001/08/19 09:39:27 peter
  1090. * local browser support fixed
  1091. Revision 1.9 2001/06/18 20:36:23 peter
  1092. * -Ur switch (merged)
  1093. * masm fixes (merged)
  1094. * quoted filenames for go32v2 and win32
  1095. Revision 1.8 2001/06/04 11:49:08 peter
  1096. * store used units in original type in ppu
  1097. Revision 1.7 2001/05/19 23:05:19 peter
  1098. * support uses <unit> in <file> construction
  1099. Revision 1.6 2001/05/19 21:08:59 peter
  1100. * skip program when checking loaded_units for a unit
  1101. Revision 1.5 2001/05/19 13:22:47 peter
  1102. * fixed crash with invalid ppu version detected
  1103. Revision 1.4 2001/05/09 14:11:10 jonas
  1104. * range check error fixes from Peter
  1105. Revision 1.3 2001/05/08 21:06:30 florian
  1106. * some more support for widechars commited especially
  1107. regarding type casting and constants
  1108. Revision 1.2 2001/05/07 11:53:21 jonas
  1109. * fix from Peter for short_on_file_handles code
  1110. Revision 1.1 2001/05/06 14:49:17 peter
  1111. * ppu object to class rewrite
  1112. * move ppu read and write stuff to fppu
  1113. }