link.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  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
  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. TLinkerClass = class of TLinker;
  76. var
  77. CLinker : array[tld] of TLinkerClass;
  78. Linker : TLinker;
  79. function FindObjectFile(s : string;const unitpath:string) : string;
  80. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  81. procedure RegisterLinker(t:tld;c:TLinkerClass);
  82. procedure InitLinker;
  83. procedure DoneLinker;
  84. Implementation
  85. uses
  86. {$ifdef Delphi}
  87. dmisc,
  88. {$else Delphi}
  89. dos,
  90. {$endif Delphi}
  91. cutils,globtype,
  92. script,globals,verbose,ppu,
  93. aasmbase,aasmtai,aasmcpu,
  94. ogbase,ogmap;
  95. {*****************************************************************************
  96. Helpers
  97. *****************************************************************************}
  98. { searches an object file }
  99. function FindObjectFile(s:string;const unitpath:string) : string;
  100. var
  101. found : boolean;
  102. foundfile : string;
  103. s1 : string;
  104. begin
  105. findobjectfile:='';
  106. if s='' then
  107. exit;
  108. if pos('.',s)=0 then
  109. s:=s+target_info.objext;
  110. s1:=FixFileName(s);
  111. if FileExists(s1) then
  112. begin
  113. Findobjectfile:=ScriptFixFileName(s);
  114. exit;
  115. end;
  116. { find object file
  117. 1. specified unit path (if specified)
  118. 2. cwd
  119. 3. unit search path
  120. 4. local object path
  121. 5. global object path
  122. 6. exepath }
  123. found:=false;
  124. if unitpath<>'' then
  125. found:=FindFile(s,unitpath,foundfile);
  126. if (not found) then
  127. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  128. if (not found) then
  129. found:=UnitSearchPath.FindFile(s,foundfile);
  130. if (not found) then
  131. found:=current_module.localobjectsearchpath.FindFile(s,foundfile);
  132. if (not found) then
  133. found:=objectsearchpath.FindFile(s,foundfile);
  134. if (not found) then
  135. found:=FindFile(s,exepath,foundfile);
  136. if not(cs_link_extern in aktglobalswitches) and (not found) then
  137. Message1(exec_w_objfile_not_found,s);
  138. findobjectfile:=ScriptFixFileName(foundfile);
  139. end;
  140. { searches an library file }
  141. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  142. var
  143. found : boolean;
  144. paths : string;
  145. begin
  146. findlibraryfile:=false;
  147. foundfile:=s;
  148. if s='' then
  149. exit;
  150. { split path from filename }
  151. paths:=SplitPath(s);
  152. s:=SplitFileName(s);
  153. { add prefix 'lib' }
  154. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  155. s:=prefix+s;
  156. { add extension }
  157. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  158. s:=s+ext;
  159. { readd the split path }
  160. s:=paths+s;
  161. if FileExists(s) then
  162. begin
  163. foundfile:=ScriptFixFileName(s);
  164. FindLibraryFile:=true;
  165. exit;
  166. end;
  167. { find libary
  168. 1. cwd
  169. 2. local libary dir
  170. 3. global libary dir
  171. 4. exe path of the compiler }
  172. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  173. if (not found) then
  174. found:=current_module.locallibrarysearchpath.FindFile(s,foundfile);
  175. if (not found) then
  176. found:=librarysearchpath.FindFile(s,foundfile);
  177. if (not found) then
  178. found:=FindFile(s,exepath,foundfile);
  179. foundfile:=ScriptFixFileName(foundfile);
  180. findlibraryfile:=found;
  181. end;
  182. {*****************************************************************************
  183. TLINKER
  184. *****************************************************************************}
  185. Constructor TLinker.Create;
  186. begin
  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. AddObject(linkunitofiles.getusemask(mask),path^);
  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^);
  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);
  278. begin
  279. ObjectFiles.Concat(FindObjectFile(s,unitpath));
  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. swapvectors;
  408. {$ifdef ALWAYSSHELL}
  409. shell(command+' '+para);
  410. {$else}
  411. if useshell then
  412. shell(command+' '+para)
  413. else
  414. exec(command,para);
  415. {$endif}
  416. swapvectors;
  417. if (doserror<>0) then
  418. begin
  419. Message(exec_e_cant_call_linker);
  420. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  421. DoExec:=false;
  422. end
  423. else
  424. if (dosexitcode<>0) then
  425. begin
  426. Message(exec_e_error_while_linking);
  427. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  428. DoExec:=false;
  429. end;
  430. end;
  431. { Update asmres when externmode is set }
  432. if cs_link_extern in aktglobalswitches then
  433. begin
  434. if showinfo then
  435. begin
  436. if DLLsource then
  437. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  438. else
  439. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  440. end
  441. else
  442. AsmRes.AddLinkCommand(Command,Para,'');
  443. end;
  444. end;
  445. Function TExternalLinker.MakeStaticLibrary:boolean;
  446. var
  447. smartpath,
  448. cmdstr,
  449. binstr : string;
  450. success : boolean;
  451. begin
  452. MakeStaticLibrary:=false;
  453. { remove the library, to be sure that it is rewritten }
  454. RemoveFile(current_module.staticlibfilename^);
  455. { Call AR }
  456. smartpath:=current_module.outputpath^+FixPath(FixFileName(current_module.modulename^)+target_info.smartext,false);
  457. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  458. Replace(cmdstr,'$LIB',current_module.staticlibfilename^);
  459. Replace(cmdstr,'$FILES',ScriptFixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  460. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  461. { Clean up }
  462. if not(cs_asm_leave in aktglobalswitches) then
  463. if not(cs_link_extern in aktglobalswitches) then
  464. begin
  465. while not SmartLinkOFiles.Empty do
  466. RemoveFile(SmartLinkOFiles.GetFirst);
  467. RemoveDir(smartpath);
  468. end
  469. else
  470. begin
  471. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  472. AsmRes.Add('rmdir '+smartpath);
  473. end;
  474. MakeStaticLibrary:=success;
  475. end;
  476. {*****************************************************************************
  477. TINTERNALLINKER
  478. *****************************************************************************}
  479. Constructor TInternalLinker.Create;
  480. begin
  481. inherited Create;
  482. exemap:=nil;
  483. exeoutput:=nil;
  484. end;
  485. Destructor TInternalLinker.Destroy;
  486. begin
  487. exeoutput.free;
  488. exeoutput:=nil;
  489. inherited destroy;
  490. end;
  491. procedure TInternalLinker.readobj(const fn:string);
  492. var
  493. objdata : TAsmObjectData;
  494. objinput : tobjectinput;
  495. begin
  496. Comment(V_Info,'Reading object '+fn);
  497. objinput:=exeoutput.newobjectinput;
  498. objdata:=objinput.newobjectdata(fn);
  499. if objinput.readobjectfile(fn,objdata) then
  500. exeoutput.addobjdata(objdata);
  501. { release input object }
  502. objinput.free;
  503. end;
  504. function TInternalLinker.MakeExecutable:boolean;
  505. var
  506. s : string;
  507. begin
  508. MakeExecutable:=false;
  509. { no support yet for libraries }
  510. if (not StaticLibFiles.Empty) or
  511. (not SharedLibFiles.Empty) then
  512. internalerror(123456789);
  513. if (cs_link_map in aktglobalswitches) then
  514. exemap:=texemap.create(current_module.mapfilename^);
  515. { read objects }
  516. readobj(FindObjectFile('prt0',''));
  517. while not ObjectFiles.Empty do
  518. begin
  519. s:=ObjectFiles.GetFirst;
  520. if s<>'' then
  521. readobj(s);
  522. end;
  523. { generate executable }
  524. exeoutput.GenerateExecutable(current_module.exefilename^);
  525. { close map }
  526. if assigned(exemap) then
  527. begin
  528. exemap.free;
  529. exemap:=nil;
  530. end;
  531. MakeExecutable:=true;
  532. end;
  533. {*****************************************************************************
  534. Init/Done
  535. *****************************************************************************}
  536. procedure RegisterLinker(t:tld;c:TLinkerClass);
  537. begin
  538. CLinker[t]:=c;
  539. end;
  540. procedure InitLinker;
  541. begin
  542. if (cs_link_internal in aktglobalswitches) and
  543. assigned(CLinker[target_info.link]) then
  544. linker:=CLinker[target_info.link].Create
  545. else if assigned(CLinker[target_info.linkextern]) then
  546. linker:=CLinker[target_info.linkextern].Create
  547. else
  548. linker:=Tlinker.Create;
  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.29 2002-07-01 18:46:22 peter
  570. * internal linker
  571. * reorganized aasm layer
  572. Revision 1.28 2002/05/18 13:34:08 peter
  573. * readded missing revisions
  574. Revision 1.27 2002/05/16 19:46:37 carl
  575. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  576. + try to fix temp allocation (still in ifdef)
  577. + generic constructor calls
  578. + start of tassembler / tmodulebase class cleanup
  579. Revision 1.25 2002/01/19 11:57:05 peter
  580. * fixed path appending for lib
  581. }