link.pas 19 KB

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