link.pas 19 KB

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