link.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  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. { Needed for LFN support in path to the executable }
  22. {$ifdef GO32V2}
  23. { define ALWAYSSHELL, obsolete as go32v2 Dos.Exec
  24. now handles LFN names and converts them to SFN PM }
  25. {$endif}
  26. interface
  27. uses
  28. cclasses,
  29. systems,
  30. fmodule;
  31. Type
  32. TLinkerInfo=record
  33. ExeCmd,
  34. DllCmd : array[1..3] of string[100];
  35. ResName : string[12];
  36. ScriptName : string[12];
  37. ExtraOptions : string;
  38. DynamicLinker : string[100];
  39. end;
  40. TLinker = class(TAbstractLinker)
  41. public
  42. ObjectFiles,
  43. SharedLibFiles,
  44. StaticLibFiles : TStringList;
  45. Constructor Create;virtual;
  46. Destructor Destroy;override;
  47. procedure AddModuleFiles(hp:tmodule);
  48. Procedure AddObject(const S,unitpath : String);
  49. Procedure AddStaticLibrary(const S : String);
  50. Procedure AddSharedLibrary(S : String);
  51. Procedure AddStaticCLibrary(const S : String);
  52. Procedure AddSharedCLibrary(S : String);
  53. Function MakeExecutable:boolean;virtual;
  54. Function MakeSharedLibrary:boolean;virtual;
  55. Function MakeStaticLibrary:boolean;virtual;
  56. end;
  57. TExternalLinker = class(TLinker)
  58. public
  59. Info : TLinkerInfo;
  60. Constructor Create;override;
  61. Destructor Destroy;override;
  62. Function FindUtil(const s:string):String;
  63. Function DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  64. procedure SetDefaultInfo;virtual;
  65. Function MakeStaticLibrary:boolean;override;
  66. end;
  67. TInternalLinker = class(TLinker)
  68. private
  69. procedure readobj(const fn:string);
  70. public
  71. Constructor Create;override;
  72. Destructor Destroy;override;
  73. Function MakeExecutable:boolean;override;
  74. end;
  75. var
  76. Linker : TLinker;
  77. function FindObjectFile(s : string;const unitpath:string) : string;
  78. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  79. procedure InitLinker;
  80. procedure DoneLinker;
  81. Implementation
  82. uses
  83. {$ifdef Delphi}
  84. dmisc,
  85. {$else Delphi}
  86. dos,
  87. {$endif Delphi}
  88. cutils,globtype,
  89. script,globals,verbose,ppu,
  90. aasmbase,aasmtai,aasmcpu,
  91. ogbase,ogmap;
  92. type
  93. TLinkerClass = class of Tlinker;
  94. {*****************************************************************************
  95. Helpers
  96. *****************************************************************************}
  97. { searches an object file }
  98. function FindObjectFile(s:string;const unitpath:string) : string;
  99. var
  100. found : boolean;
  101. foundfile : string;
  102. s1 : string;
  103. begin
  104. findobjectfile:='';
  105. if s='' then
  106. exit;
  107. if pos('.',s)=0 then
  108. s:=s+target_info.objext;
  109. s1:=FixFileName(s);
  110. if FileExists(s1) then
  111. begin
  112. Findobjectfile:=ScriptFixFileName(s);
  113. exit;
  114. end;
  115. { find object file
  116. 1. specified unit path (if specified)
  117. 2. cwd
  118. 3. unit search path
  119. 4. local object path
  120. 5. global object path
  121. 6. exepath }
  122. found:=false;
  123. if unitpath<>'' then
  124. found:=FindFile(s,unitpath,foundfile);
  125. if (not found) then
  126. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  127. if (not found) then
  128. found:=UnitSearchPath.FindFile(s,foundfile);
  129. if (not found) then
  130. found:=current_module.localobjectsearchpath.FindFile(s,foundfile);
  131. if (not found) then
  132. found:=objectsearchpath.FindFile(s,foundfile);
  133. if (not found) then
  134. found:=FindFile(s,exepath,foundfile);
  135. if not(cs_link_extern in aktglobalswitches) and (not found) then
  136. Message1(exec_w_objfile_not_found,s);
  137. findobjectfile:=ScriptFixFileName(foundfile);
  138. end;
  139. { searches an library file }
  140. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  141. var
  142. found : boolean;
  143. paths : string;
  144. begin
  145. findlibraryfile:=false;
  146. foundfile:=s;
  147. if s='' then
  148. exit;
  149. { split path from filename }
  150. paths:=SplitPath(s);
  151. s:=SplitFileName(s);
  152. { add prefix 'lib' }
  153. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  154. s:=prefix+s;
  155. { add extension }
  156. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  157. s:=s+ext;
  158. { readd the split path }
  159. s:=paths+s;
  160. if FileExists(s) then
  161. begin
  162. foundfile:=ScriptFixFileName(s);
  163. FindLibraryFile:=true;
  164. exit;
  165. end;
  166. { find libary
  167. 1. cwd
  168. 2. local libary dir
  169. 3. global libary dir
  170. 4. exe path of the compiler }
  171. found:=FindFile(s,'.'+source_info.DirSep,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^);
  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^);
  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);
  280. begin
  281. ObjectFiles.Concat(FindObjectFile(s,unitpath));
  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. swapvectors;
  410. {$ifdef ALWAYSSHELL}
  411. shell(command+' '+para);
  412. {$else}
  413. if useshell then
  414. shell(command+' '+para)
  415. else
  416. exec(command,para);
  417. {$endif}
  418. swapvectors;
  419. if (doserror<>0) then
  420. begin
  421. Message(exec_e_cant_call_linker);
  422. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  423. DoExec:=false;
  424. end
  425. else
  426. if (dosexitcode<>0) then
  427. begin
  428. Message(exec_e_error_while_linking);
  429. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  430. DoExec:=false;
  431. end;
  432. end;
  433. { Update asmres when externmode is set }
  434. if cs_link_extern in aktglobalswitches then
  435. begin
  436. if showinfo then
  437. begin
  438. if DLLsource then
  439. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  440. else
  441. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  442. end
  443. else
  444. AsmRes.AddLinkCommand(Command,Para,'');
  445. end;
  446. end;
  447. Function TExternalLinker.MakeStaticLibrary:boolean;
  448. var
  449. smartpath,
  450. cmdstr,
  451. binstr : string;
  452. success : boolean;
  453. begin
  454. MakeStaticLibrary:=false;
  455. { remove the library, to be sure that it is rewritten }
  456. RemoveFile(current_module.staticlibfilename^);
  457. { Call AR }
  458. smartpath:=current_module.outputpath^+FixPath(FixFileName(current_module.modulename^)+target_info.smartext,false);
  459. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  460. Replace(cmdstr,'$LIB',current_module.staticlibfilename^);
  461. Replace(cmdstr,'$FILES',ScriptFixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  462. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  463. { Clean up }
  464. if not(cs_asm_leave in aktglobalswitches) then
  465. if not(cs_link_extern in aktglobalswitches) then
  466. begin
  467. while not SmartLinkOFiles.Empty do
  468. RemoveFile(SmartLinkOFiles.GetFirst);
  469. RemoveDir(smartpath);
  470. end
  471. else
  472. begin
  473. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  474. AsmRes.Add('rmdir '+smartpath);
  475. end;
  476. MakeStaticLibrary:=success;
  477. end;
  478. {*****************************************************************************
  479. TINTERNALLINKER
  480. *****************************************************************************}
  481. Constructor TInternalLinker.Create;
  482. begin
  483. inherited Create;
  484. exemap:=nil;
  485. exeoutput:=nil;
  486. end;
  487. Destructor TInternalLinker.Destroy;
  488. begin
  489. exeoutput.free;
  490. exeoutput:=nil;
  491. inherited destroy;
  492. end;
  493. procedure TInternalLinker.readobj(const fn:string);
  494. var
  495. objdata : TAsmObjectData;
  496. objinput : tobjectinput;
  497. begin
  498. Comment(V_Info,'Reading object '+fn);
  499. objinput:=exeoutput.newobjectinput;
  500. objdata:=objinput.newobjectdata(fn);
  501. if objinput.readobjectfile(fn,objdata) then
  502. exeoutput.addobjdata(objdata);
  503. { release input object }
  504. objinput.free;
  505. end;
  506. function TInternalLinker.MakeExecutable:boolean;
  507. var
  508. s : string;
  509. begin
  510. MakeExecutable:=false;
  511. { no support yet for libraries }
  512. if (not StaticLibFiles.Empty) or
  513. (not SharedLibFiles.Empty) then
  514. internalerror(123456789);
  515. if (cs_link_map in aktglobalswitches) then
  516. exemap:=texemap.create(current_module.mapfilename^);
  517. { read objects }
  518. readobj(FindObjectFile('prt0',''));
  519. while not ObjectFiles.Empty do
  520. begin
  521. s:=ObjectFiles.GetFirst;
  522. if s<>'' then
  523. readobj(s);
  524. end;
  525. { generate executable }
  526. exeoutput.GenerateExecutable(current_module.exefilename^);
  527. { close map }
  528. if assigned(exemap) then
  529. begin
  530. exemap.free;
  531. exemap:=nil;
  532. end;
  533. MakeExecutable:=true;
  534. end;
  535. {*****************************************************************************
  536. Init/Done
  537. *****************************************************************************}
  538. procedure InitLinker;
  539. var
  540. lk : TlinkerClass;
  541. begin
  542. if (cs_link_internal in aktglobalswitches) and
  543. assigned(target_info.link) then
  544. begin
  545. lk:=TLinkerClass(target_info.link);
  546. linker:=lk.Create;
  547. end
  548. else if assigned(target_info.linkextern) then
  549. begin
  550. lk:=TlinkerClass(target_info.linkextern);
  551. linker:=lk.Create;
  552. end
  553. else
  554. begin
  555. WriteLn('Hello!');
  556. linker:=Tlinker.Create;
  557. end;
  558. end;
  559. procedure DoneLinker;
  560. begin
  561. if assigned(linker) then
  562. Linker.Free;
  563. end;
  564. {*****************************************************************************
  565. Initialize
  566. *****************************************************************************}
  567. const
  568. ar_gnu_ar_info : tarinfo =
  569. (
  570. id : ar_gnu_ar;
  571. arcmd : 'ar rs $LIB $FILES'
  572. );
  573. initialization
  574. RegisterAr(ar_gnu_ar_info);
  575. end.
  576. {
  577. $Log$
  578. Revision 1.31 2002-09-07 15:25:02 peter
  579. * old logs removed and tabs fixed
  580. Revision 1.30 2002/08/12 15:08:39 carl
  581. + stab register indexes for powerpc (moved from gdb to cpubase)
  582. + tprocessor enumeration moved to cpuinfo
  583. + linker in target_info is now a class
  584. * many many updates for m68k (will soon start to compile)
  585. - removed some ifdef or correct them for correct cpu
  586. Revision 1.29 2002/07/01 18:46:22 peter
  587. * internal linker
  588. * reorganized aasm layer
  589. Revision 1.28 2002/05/18 13:34:08 peter
  590. * readded missing revisions
  591. Revision 1.27 2002/05/16 19:46:37 carl
  592. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  593. + try to fix temp allocation (still in ifdef)
  594. + generic constructor calls
  595. + start of tassembler / tmodulebase class cleanup
  596. Revision 1.25 2002/01/19 11:57:05 peter
  597. * fixed path appending for lib
  598. }