link.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Peter Vreman
  4. This unit handles the linker and binder calls for programs and
  5. libraries
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit link;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. cclasses,
  24. systems,
  25. fmodule;
  26. Type
  27. TLinkerInfo=record
  28. ExeCmd,
  29. DllCmd : array[1..3] of string[100];
  30. ResName : string[12];
  31. ScriptName : string[12];
  32. ExtraOptions : string;
  33. DynamicLinker : string[100];
  34. end;
  35. TLinker = class(TAbstractLinker)
  36. public
  37. ObjectFiles,
  38. SharedLibFiles,
  39. StaticLibFiles : TStringList;
  40. Constructor Create;virtual;
  41. Destructor Destroy;override;
  42. procedure AddModuleFiles(hp:tmodule);
  43. Procedure AddObject(const S,unitpath : String;isunit:boolean);
  44. Procedure AddStaticLibrary(const S : String);
  45. Procedure AddSharedLibrary(S : String);
  46. Procedure AddStaticCLibrary(const S : String);
  47. Procedure AddSharedCLibrary(S : String);
  48. Function MakeExecutable:boolean;virtual;
  49. Function MakeSharedLibrary:boolean;virtual;
  50. Function MakeStaticLibrary:boolean;virtual;
  51. end;
  52. TExternalLinker = class(TLinker)
  53. public
  54. Info : TLinkerInfo;
  55. Constructor Create;override;
  56. Destructor Destroy;override;
  57. Function FindUtil(const s:string):String;
  58. Function DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  59. procedure SetDefaultInfo;virtual;
  60. Function MakeStaticLibrary:boolean;override;
  61. end;
  62. TInternalLinker = class(TLinker)
  63. private
  64. procedure readobj(const fn:string);
  65. public
  66. Constructor Create;override;
  67. Destructor Destroy;override;
  68. Function MakeExecutable:boolean;override;
  69. end;
  70. var
  71. Linker : TLinker;
  72. function FindObjectFile(s : string;const unitpath:string;isunit:boolean) : string;
  73. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  74. procedure InitLinker;
  75. procedure DoneLinker;
  76. Implementation
  77. uses
  78. {$ifdef Delphi}
  79. dmisc,
  80. {$else Delphi}
  81. dos,
  82. {$endif Delphi}
  83. cutils,globtype,
  84. script,globals,verbose,ppu,
  85. aasmbase,aasmtai,aasmcpu,
  86. ogbase,ogmap;
  87. type
  88. TLinkerClass = class of Tlinker;
  89. {*****************************************************************************
  90. Helpers
  91. *****************************************************************************}
  92. { searches an object file }
  93. function FindObjectFile(s:string;const unitpath:string;isunit:boolean) : string;
  94. var
  95. found : boolean;
  96. foundfile : string;
  97. begin
  98. findobjectfile:='';
  99. if s='' then
  100. exit;
  101. { when it does not belong to the unit then check if
  102. the specified file exists without searching any paths }
  103. if not isunit then
  104. begin
  105. if FileExists(FixFileName(s)) then
  106. begin
  107. foundfile:=ScriptFixFileName(s);
  108. found:=true;
  109. end;
  110. end;
  111. if pos('.',s)=0 then
  112. s:=s+target_info.objext;
  113. { find object file
  114. 1. specified unit path (if specified)
  115. 2. cwd
  116. 3. unit search path
  117. 4. local object path
  118. 5. global object path
  119. 6. exepath }
  120. found:=false;
  121. if unitpath<>'' then
  122. found:=FindFile(s,unitpath,foundfile);
  123. if (not found) then
  124. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  125. if (not found) then
  126. found:=UnitSearchPath.FindFile(s,foundfile);
  127. if (not found) then
  128. found:=current_module.localobjectsearchpath.FindFile(s,foundfile);
  129. if (not found) then
  130. found:=objectsearchpath.FindFile(s,foundfile);
  131. if (not found) then
  132. found:=FindFile(s,exepath,foundfile);
  133. if not(cs_link_extern in aktglobalswitches) and (not found) then
  134. Message1(exec_w_objfile_not_found,s);
  135. findobjectfile:=ScriptFixFileName(foundfile);
  136. end;
  137. { searches an library file }
  138. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  139. var
  140. found : boolean;
  141. paths : string;
  142. begin
  143. findlibraryfile:=false;
  144. foundfile:=s;
  145. if s='' then
  146. exit;
  147. { split path from filename }
  148. paths:=SplitPath(s);
  149. s:=SplitFileName(s);
  150. { add prefix 'lib' }
  151. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  152. s:=prefix+s;
  153. { add extension }
  154. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  155. s:=s+ext;
  156. { readd the split path }
  157. s:=paths+s;
  158. if FileExists(s) then
  159. begin
  160. foundfile:=ScriptFixFileName(s);
  161. FindLibraryFile:=true;
  162. exit;
  163. end;
  164. { find libary
  165. 1. cwd
  166. 2. local libary dir
  167. 3. global libary dir
  168. 4. exe path of the compiler }
  169. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  170. if (not found) and (current_module.outputpath^<>'') then
  171. found:=FindFile(s,current_module.outputpath^,foundfile);
  172. if (not found) then
  173. found:=current_module.locallibrarysearchpath.FindFile(s,foundfile);
  174. if (not found) then
  175. found:=librarysearchpath.FindFile(s,foundfile);
  176. if (not found) then
  177. found:=FindFile(s,exepath,foundfile);
  178. foundfile:=ScriptFixFileName(foundfile);
  179. findlibraryfile:=found;
  180. end;
  181. {*****************************************************************************
  182. TLINKER
  183. *****************************************************************************}
  184. Constructor TLinker.Create;
  185. begin
  186. Inherited Create;
  187. ObjectFiles:=TStringList.Create_no_double;
  188. SharedLibFiles:=TStringList.Create_no_double;
  189. StaticLibFiles:=TStringList.Create_no_double;
  190. end;
  191. Destructor TLinker.Destroy;
  192. begin
  193. ObjectFiles.Free;
  194. SharedLibFiles.Free;
  195. StaticLibFiles.Free;
  196. end;
  197. procedure TLinker.AddModuleFiles(hp:tmodule);
  198. var
  199. mask : longint;
  200. begin
  201. with hp do
  202. begin
  203. { link unit files }
  204. if (flags and uf_no_link)=0 then
  205. begin
  206. { create mask which unit files need linking }
  207. mask:=link_allways;
  208. { static linking ? }
  209. if (cs_link_static in aktglobalswitches) then
  210. begin
  211. if (flags and uf_static_linked)=0 then
  212. begin
  213. { if smart not avail then try static linking }
  214. if (flags and uf_smart_linked)<>0 then
  215. begin
  216. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  217. mask:=mask or link_smart;
  218. end
  219. else
  220. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  221. end
  222. else
  223. mask:=mask or link_static;
  224. end;
  225. { smart linking ? }
  226. if (cs_link_smart in aktglobalswitches) then
  227. begin
  228. if (flags and uf_smart_linked)=0 then
  229. begin
  230. { if smart not avail then try static linking }
  231. if (flags and uf_static_linked)<>0 then
  232. begin
  233. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  234. mask:=mask or link_static;
  235. end
  236. else
  237. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  238. end
  239. else
  240. mask:=mask or link_smart;
  241. end;
  242. { shared linking }
  243. if (cs_link_shared in aktglobalswitches) then
  244. begin
  245. if (flags and uf_shared_linked)=0 then
  246. begin
  247. { if shared not avail then try static linking }
  248. if (flags and uf_static_linked)<>0 then
  249. begin
  250. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  251. mask:=mask or link_static;
  252. end
  253. else
  254. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  255. end
  256. else
  257. mask:=mask or link_shared;
  258. end;
  259. { unit files }
  260. while not linkunitofiles.empty do
  261. begin
  262. AddObject(linkunitofiles.getusemask(mask),path^,true);
  263. end;
  264. while not linkunitstaticlibs.empty do
  265. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  266. while not linkunitsharedlibs.empty do
  267. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  268. end;
  269. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  270. mask:=link_allways;
  271. while not linkotherofiles.empty do
  272. AddObject(linkotherofiles.Getusemask(mask),path^,false);
  273. while not linkotherstaticlibs.empty do
  274. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  275. while not linkothersharedlibs.empty do
  276. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  277. end;
  278. end;
  279. Procedure TLinker.AddObject(const S,unitpath : String;isunit:boolean);
  280. begin
  281. ObjectFiles.Concat(FindObjectFile(s,unitpath,isunit));
  282. end;
  283. Procedure TLinker.AddSharedLibrary(S:String);
  284. begin
  285. if s='' then
  286. exit;
  287. { remove prefix 'lib' }
  288. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  289. Delete(s,1,length(target_info.sharedlibprefix));
  290. { remove extension if any }
  291. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  292. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  293. { ready to be added }
  294. SharedLibFiles.Concat(S);
  295. end;
  296. Procedure TLinker.AddStaticLibrary(const S:String);
  297. var
  298. ns : string;
  299. found : boolean;
  300. begin
  301. if s='' then
  302. exit;
  303. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  304. if not(cs_link_extern in aktglobalswitches) and (not found) then
  305. Message1(exec_w_libfile_not_found,s);
  306. StaticLibFiles.Concat(ns);
  307. end;
  308. Procedure TLinker.AddSharedCLibrary(S:String);
  309. begin
  310. if s='' then
  311. exit;
  312. { remove prefix 'lib' }
  313. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  314. Delete(s,1,length(target_info.sharedclibprefix));
  315. { remove extension if any }
  316. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  317. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  318. { ready to be added }
  319. SharedLibFiles.Concat(S);
  320. end;
  321. Procedure TLinker.AddStaticCLibrary(const S:String);
  322. var
  323. ns : string;
  324. found : boolean;
  325. begin
  326. if s='' then
  327. exit;
  328. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  329. if not(cs_link_extern in aktglobalswitches) and (not found) then
  330. Message1(exec_w_libfile_not_found,s);
  331. StaticLibFiles.Concat(ns);
  332. end;
  333. function TLinker.MakeExecutable:boolean;
  334. begin
  335. MakeExecutable:=false;
  336. Message(exec_e_exe_not_supported);
  337. end;
  338. Function TLinker.MakeSharedLibrary:boolean;
  339. begin
  340. MakeSharedLibrary:=false;
  341. Message(exec_e_dll_not_supported);
  342. end;
  343. Function TLinker.MakeStaticLibrary:boolean;
  344. begin
  345. MakeStaticLibrary:=false;
  346. Message(exec_e_dll_not_supported);
  347. end;
  348. {*****************************************************************************
  349. TEXTERNALLINKER
  350. *****************************************************************************}
  351. Constructor TExternalLinker.Create;
  352. begin
  353. inherited Create;
  354. { set generic defaults }
  355. FillChar(Info,sizeof(Info),0);
  356. Info.ResName:='link.res';
  357. Info.ScriptName:='script.res';
  358. { set the linker specific defaults }
  359. SetDefaultInfo;
  360. { Allow Parameter overrides for linker info }
  361. with Info do
  362. begin
  363. if ParaLinkOptions<>'' then
  364. ExtraOptions:=ParaLinkOptions;
  365. if ParaDynamicLinker<>'' then
  366. DynamicLinker:=ParaDynamicLinker;
  367. end;
  368. end;
  369. Destructor TExternalLinker.Destroy;
  370. begin
  371. inherited destroy;
  372. end;
  373. Procedure TExternalLinker.SetDefaultInfo;
  374. begin
  375. end;
  376. Function TExternalLinker.FindUtil(const s:string):string;
  377. var
  378. Found : boolean;
  379. FoundBin : string;
  380. UtilExe : string;
  381. begin
  382. if cs_link_on_target in aktglobalswitches then
  383. begin
  384. { If linking on target, don't add any path PM }
  385. FindUtil:=AddExtension(s,target_info.exeext);
  386. exit;
  387. end;
  388. UtilExe:=AddExtension(s,source_info.exeext);
  389. FoundBin:='';
  390. Found:=false;
  391. if utilsdirectory<>'' then
  392. Found:=FindFile(utilexe,utilsdirectory,Foundbin);
  393. if (not Found) then
  394. Found:=FindExe(utilexe,Foundbin);
  395. if (not Found) and not(cs_link_extern in aktglobalswitches) then
  396. begin
  397. Message1(exec_e_util_not_found,utilexe);
  398. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  399. end;
  400. if (FoundBin<>'') then
  401. Message1(exec_t_using_util,FoundBin);
  402. FindUtil:=FoundBin;
  403. end;
  404. Function TExternalLinker.DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  405. begin
  406. DoExec:=true;
  407. if not(cs_link_extern in aktglobalswitches) then
  408. begin
  409. if useshell then
  410. shell(maybequoted(command)+' '+para)
  411. else
  412. begin
  413. swapvectors;
  414. exec(command,para);
  415. swapvectors;
  416. end;
  417. if (doserror<>0) then
  418. begin
  419. Message(exec_e_cant_call_linker);
  420. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  421. DoExec:=false;
  422. end
  423. else
  424. if (dosexitcode<>0) then
  425. begin
  426. Message(exec_e_error_while_linking);
  427. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  428. DoExec:=false;
  429. end;
  430. end;
  431. { Update asmres when externmode is set }
  432. if cs_link_extern in aktglobalswitches then
  433. begin
  434. if showinfo then
  435. begin
  436. if DLLsource then
  437. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  438. else
  439. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  440. end
  441. else
  442. AsmRes.AddLinkCommand(Command,Para,'');
  443. end;
  444. end;
  445. Function TExternalLinker.MakeStaticLibrary:boolean;
  446. var
  447. smartpath,
  448. cmdstr,
  449. binstr : string;
  450. success : boolean;
  451. begin
  452. MakeStaticLibrary:=false;
  453. { remove the library, to be sure that it is rewritten }
  454. RemoveFile(current_module.staticlibfilename^);
  455. { Call AR }
  456. smartpath:=current_module.outputpath^+FixPath(FixFileName(current_module.modulename^)+target_info.smartext,false);
  457. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  458. Replace(cmdstr,'$LIB',current_module.staticlibfilename^);
  459. Replace(cmdstr,'$FILES',FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  460. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  461. { Clean up }
  462. if not(cs_asm_leave in aktglobalswitches) then
  463. if not(cs_link_extern in aktglobalswitches) then
  464. begin
  465. while not SmartLinkOFiles.Empty do
  466. RemoveFile(SmartLinkOFiles.GetFirst);
  467. RemoveDir(smartpath);
  468. end
  469. else
  470. begin
  471. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  472. AsmRes.Add('rmdir '+smartpath);
  473. end;
  474. MakeStaticLibrary:=success;
  475. end;
  476. {*****************************************************************************
  477. TINTERNALLINKER
  478. *****************************************************************************}
  479. Constructor TInternalLinker.Create;
  480. begin
  481. inherited Create;
  482. exemap:=nil;
  483. exeoutput:=nil;
  484. end;
  485. Destructor TInternalLinker.Destroy;
  486. begin
  487. exeoutput.free;
  488. exeoutput:=nil;
  489. inherited destroy;
  490. end;
  491. procedure TInternalLinker.readobj(const fn:string);
  492. var
  493. objdata : TAsmObjectData;
  494. objinput : tobjectinput;
  495. begin
  496. Comment(V_Info,'Reading object '+fn);
  497. objinput:=exeoutput.newobjectinput;
  498. objdata:=objinput.newobjectdata(fn);
  499. if objinput.readobjectfile(fn,objdata) then
  500. exeoutput.addobjdata(objdata);
  501. { release input object }
  502. objinput.free;
  503. end;
  504. function TInternalLinker.MakeExecutable:boolean;
  505. var
  506. s : string;
  507. begin
  508. MakeExecutable:=false;
  509. { no support yet for libraries }
  510. if (not StaticLibFiles.Empty) or
  511. (not SharedLibFiles.Empty) then
  512. internalerror(123456789);
  513. if (cs_link_map in aktglobalswitches) then
  514. exemap:=texemap.create(current_module.mapfilename^);
  515. { read objects }
  516. readobj(FindObjectFile('prt0','',false));
  517. while not ObjectFiles.Empty do
  518. begin
  519. s:=ObjectFiles.GetFirst;
  520. if s<>'' then
  521. readobj(s);
  522. end;
  523. { generate executable }
  524. exeoutput.GenerateExecutable(current_module.exefilename^);
  525. { close map }
  526. if assigned(exemap) then
  527. begin
  528. exemap.free;
  529. exemap:=nil;
  530. end;
  531. MakeExecutable:=true;
  532. end;
  533. {*****************************************************************************
  534. Init/Done
  535. *****************************************************************************}
  536. procedure InitLinker;
  537. var
  538. lk : TlinkerClass;
  539. begin
  540. if (cs_link_internal in aktglobalswitches) and
  541. assigned(target_info.link) then
  542. begin
  543. lk:=TLinkerClass(target_info.link);
  544. linker:=lk.Create;
  545. end
  546. else if assigned(target_info.linkextern) then
  547. begin
  548. lk:=TlinkerClass(target_info.linkextern);
  549. linker:=lk.Create;
  550. end
  551. else
  552. begin
  553. linker:=Tlinker.Create;
  554. end;
  555. end;
  556. procedure DoneLinker;
  557. begin
  558. if assigned(linker) then
  559. Linker.Free;
  560. end;
  561. {*****************************************************************************
  562. Initialize
  563. *****************************************************************************}
  564. const
  565. ar_gnu_ar_info : tarinfo =
  566. (
  567. id : ar_gnu_ar;
  568. arcmd : 'ar rs $LIB $FILES'
  569. );
  570. initialization
  571. RegisterAr(ar_gnu_ar_info);
  572. end.
  573. {
  574. $Log$
  575. Revision 1.36 2003-05-09 17:47:02 peter
  576. * self moved to hidden parameter
  577. * removed hdisposen,hnewn,selfn
  578. Revision 1.35 2003/04/26 09:16:07 peter
  579. * .o files belonging to the unit are first searched in the same dir
  580. as the .ppu
  581. Revision 1.34 2003/02/12 22:04:59 carl
  582. - removed my stupid hello debug code
  583. Revision 1.33 2002/11/15 01:58:48 peter
  584. * merged changes from 1.0.7 up to 04-11
  585. - -V option for generating bug report tracing
  586. - more tracing for option parsing
  587. - errors for cdecl and high()
  588. - win32 import stabs
  589. - win32 records<=8 are returned in eax:edx (turned off by default)
  590. - heaptrc update
  591. - more info for temp management in .s file with EXTDEBUG
  592. Revision 1.32 2002/11/09 15:37:21 carl
  593. - removed no longer used defines
  594. Revision 1.31 2002/09/07 15:25:02 peter
  595. * old logs removed and tabs fixed
  596. Revision 1.30 2002/08/12 15:08:39 carl
  597. + stab register indexes for powerpc (moved from gdb to cpubase)
  598. + tprocessor enumeration moved to cpuinfo
  599. + linker in target_info is now a class
  600. * many many updates for m68k (will soon start to compile)
  601. - removed some ifdef or correct them for correct cpu
  602. Revision 1.29 2002/07/01 18:46:22 peter
  603. * internal linker
  604. * reorganized aasm layer
  605. Revision 1.28 2002/05/18 13:34:08 peter
  606. * readded missing revisions
  607. Revision 1.27 2002/05/16 19:46:37 carl
  608. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  609. + try to fix temp allocation (still in ifdef)
  610. + generic constructor calls
  611. + start of tassembler / tmodulebase class cleanup
  612. Revision 1.25 2002/01/19 11:57:05 peter
  613. * fixed path appending for lib
  614. }