link.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  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. swapvectors;
  405. if useshell then
  406. shell(command+' '+para)
  407. else
  408. exec(command,para);
  409. swapvectors;
  410. if (doserror<>0) then
  411. begin
  412. Message(exec_e_cant_call_linker);
  413. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  414. DoExec:=false;
  415. end
  416. else
  417. if (dosexitcode<>0) then
  418. begin
  419. Message(exec_e_error_while_linking);
  420. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  421. DoExec:=false;
  422. end;
  423. end;
  424. { Update asmres when externmode is set }
  425. if cs_link_extern in aktglobalswitches then
  426. begin
  427. if showinfo then
  428. begin
  429. if DLLsource then
  430. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  431. else
  432. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  433. end
  434. else
  435. AsmRes.AddLinkCommand(Command,Para,'');
  436. end;
  437. end;
  438. Function TExternalLinker.MakeStaticLibrary:boolean;
  439. var
  440. smartpath,
  441. cmdstr,
  442. binstr : string;
  443. success : boolean;
  444. begin
  445. MakeStaticLibrary:=false;
  446. { remove the library, to be sure that it is rewritten }
  447. RemoveFile(current_module.staticlibfilename^);
  448. { Call AR }
  449. smartpath:=current_module.outputpath^+FixPath(FixFileName(current_module.modulename^)+target_info.smartext,false);
  450. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  451. Replace(cmdstr,'$LIB',current_module.staticlibfilename^);
  452. Replace(cmdstr,'$FILES',ScriptFixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  453. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  454. { Clean up }
  455. if not(cs_asm_leave in aktglobalswitches) then
  456. if not(cs_link_extern in aktglobalswitches) then
  457. begin
  458. while not SmartLinkOFiles.Empty do
  459. RemoveFile(SmartLinkOFiles.GetFirst);
  460. RemoveDir(smartpath);
  461. end
  462. else
  463. begin
  464. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  465. AsmRes.Add('rmdir '+smartpath);
  466. end;
  467. MakeStaticLibrary:=success;
  468. end;
  469. {*****************************************************************************
  470. TINTERNALLINKER
  471. *****************************************************************************}
  472. Constructor TInternalLinker.Create;
  473. begin
  474. inherited Create;
  475. exemap:=nil;
  476. exeoutput:=nil;
  477. end;
  478. Destructor TInternalLinker.Destroy;
  479. begin
  480. exeoutput.free;
  481. exeoutput:=nil;
  482. inherited destroy;
  483. end;
  484. procedure TInternalLinker.readobj(const fn:string);
  485. var
  486. objdata : TAsmObjectData;
  487. objinput : tobjectinput;
  488. begin
  489. Comment(V_Info,'Reading object '+fn);
  490. objinput:=exeoutput.newobjectinput;
  491. objdata:=objinput.newobjectdata(fn);
  492. if objinput.readobjectfile(fn,objdata) then
  493. exeoutput.addobjdata(objdata);
  494. { release input object }
  495. objinput.free;
  496. end;
  497. function TInternalLinker.MakeExecutable:boolean;
  498. var
  499. s : string;
  500. begin
  501. MakeExecutable:=false;
  502. { no support yet for libraries }
  503. if (not StaticLibFiles.Empty) or
  504. (not SharedLibFiles.Empty) then
  505. internalerror(123456789);
  506. if (cs_link_map in aktglobalswitches) then
  507. exemap:=texemap.create(current_module.mapfilename^);
  508. { read objects }
  509. readobj(FindObjectFile('prt0',''));
  510. while not ObjectFiles.Empty do
  511. begin
  512. s:=ObjectFiles.GetFirst;
  513. if s<>'' then
  514. readobj(s);
  515. end;
  516. { generate executable }
  517. exeoutput.GenerateExecutable(current_module.exefilename^);
  518. { close map }
  519. if assigned(exemap) then
  520. begin
  521. exemap.free;
  522. exemap:=nil;
  523. end;
  524. MakeExecutable:=true;
  525. end;
  526. {*****************************************************************************
  527. Init/Done
  528. *****************************************************************************}
  529. procedure InitLinker;
  530. var
  531. lk : TlinkerClass;
  532. begin
  533. if (cs_link_internal in aktglobalswitches) and
  534. assigned(target_info.link) then
  535. begin
  536. lk:=TLinkerClass(target_info.link);
  537. linker:=lk.Create;
  538. end
  539. else if assigned(target_info.linkextern) then
  540. begin
  541. lk:=TlinkerClass(target_info.linkextern);
  542. linker:=lk.Create;
  543. end
  544. else
  545. begin
  546. WriteLn('Hello!');
  547. linker:=Tlinker.Create;
  548. end;
  549. end;
  550. procedure DoneLinker;
  551. begin
  552. if assigned(linker) then
  553. Linker.Free;
  554. end;
  555. {*****************************************************************************
  556. Initialize
  557. *****************************************************************************}
  558. const
  559. ar_gnu_ar_info : tarinfo =
  560. (
  561. id : ar_gnu_ar;
  562. arcmd : 'ar rs $LIB $FILES'
  563. );
  564. initialization
  565. RegisterAr(ar_gnu_ar_info);
  566. end.
  567. {
  568. $Log$
  569. Revision 1.32 2002-11-09 15:37:21 carl
  570. - removed no longer used defines
  571. Revision 1.31 2002/09/07 15:25:02 peter
  572. * old logs removed and tabs fixed
  573. Revision 1.30 2002/08/12 15:08:39 carl
  574. + stab register indexes for powerpc (moved from gdb to cpubase)
  575. + tprocessor enumeration moved to cpuinfo
  576. + linker in target_info is now a class
  577. * many many updates for m68k (will soon start to compile)
  578. - removed some ifdef or correct them for correct cpu
  579. Revision 1.29 2002/07/01 18:46:22 peter
  580. * internal linker
  581. * reorganized aasm layer
  582. Revision 1.28 2002/05/18 13:34:08 peter
  583. * readded missing revisions
  584. Revision 1.27 2002/05/16 19:46:37 carl
  585. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  586. + try to fix temp allocation (still in ifdef)
  587. + generic constructor calls
  588. + start of tassembler / tmodulebase class cleanup
  589. Revision 1.25 2002/01/19 11:57:05 peter
  590. * fixed path appending for lib
  591. }