link.pas 19 KB

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