link.pas 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. {
  2. Copyright (c) 1998-2002 by Peter Vreman
  3. This unit handles the linker and binder calls for programs and
  4. libraries
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit link;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cclasses,
  23. systems,
  24. fmodule,
  25. globtype,
  26. ogbase;
  27. Type
  28. TLinkerInfo=record
  29. ExeCmd,
  30. DllCmd : array[1..3] of string;
  31. ResName : string[100];
  32. ScriptName : string[100];
  33. ExtraOptions : string;
  34. DynamicLinker : string[100];
  35. end;
  36. TLinker = class(TAbstractLinker)
  37. public
  38. HasResources,
  39. HasExports : boolean;
  40. SysInitUnit : string[20];
  41. ObjectFiles,
  42. SharedLibFiles,
  43. StaticLibFiles : TStringList;
  44. Constructor Create;virtual;
  45. Destructor Destroy;override;
  46. procedure AddModuleFiles(hp:tmodule);
  47. Procedure AddObject(const S,unitpath : String;isunit:boolean);
  48. Procedure AddStaticLibrary(const S : String);
  49. Procedure AddSharedLibrary(S : String);
  50. Procedure AddStaticCLibrary(const S : String);
  51. Procedure AddSharedCLibrary(S : String);
  52. procedure AddImportSymbol(const libname,symname:string;OrdNr: longint;isvar:boolean);virtual;
  53. Procedure InitSysInitUnitName;virtual;
  54. Function MakeExecutable:boolean;virtual;
  55. Function MakeSharedLibrary:boolean;virtual;
  56. Function MakeStaticLibrary:boolean;virtual;
  57. procedure ExpandAndApplyOrder(var Src:TStringList);
  58. procedure LoadPredefinedLibraryOrder;virtual;
  59. function ReOrderEntries : boolean;
  60. end;
  61. TExternalLinker = class(TLinker)
  62. public
  63. Info : TLinkerInfo;
  64. Constructor Create;override;
  65. Destructor Destroy;override;
  66. Function FindUtil(const s:string):String;
  67. Function DoExec(const command:string; para:TCmdStr;showinfo,useshell:boolean):boolean;
  68. procedure SetDefaultInfo;virtual;
  69. Function MakeStaticLibrary:boolean;override;
  70. end;
  71. TInternalLinker = class(TLinker)
  72. private
  73. FCExeOutput : TExeOutputClass;
  74. FCObjInput : TObjInputClass;
  75. { Libraries }
  76. FStaticLibraryList : TFPHashObjectList;
  77. FImportLibraryList : TFPHashObjectList;
  78. procedure Load_ReadObject(const para:string);
  79. procedure Load_ReadStaticLibrary(const para:string);
  80. procedure ParseScript_Load;
  81. procedure ParseScript_Order;
  82. procedure ParseScript_CalcPos;
  83. procedure PrintLinkerScript;
  84. function RunLinkScript(const outputname:string):boolean;
  85. protected
  86. property CObjInput:TObjInputClass read FCObjInput write FCObjInput;
  87. property CExeOutput:TExeOutputClass read FCExeOutput write FCExeOutput;
  88. property StaticLibraryList:TFPHashObjectList read FStaticLibraryList;
  89. property ImportLibraryList:TFPHashObjectList read FImportLibraryList;
  90. procedure DefaultLinkScript;virtual;abstract;
  91. linkscript : TStringList;
  92. public
  93. IsSharedLibrary : boolean;
  94. Constructor Create;override;
  95. Destructor Destroy;override;
  96. Function MakeExecutable:boolean;override;
  97. Function MakeSharedLibrary:boolean;override;
  98. procedure AddImportSymbol(const libname,symname:string;OrdNr: longint;isvar:boolean);override;
  99. end;
  100. var
  101. Linker : TLinker;
  102. function FindObjectFile(s : string;const unitpath:string;isunit:boolean) : string;
  103. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  104. function FindDLL(const s:string;var founddll:string):boolean;
  105. procedure InitLinker;
  106. procedure DoneLinker;
  107. Implementation
  108. uses
  109. SysUtils,
  110. cutils,cfileutils,
  111. script,globals,verbose,comphook,ppu,
  112. aasmbase,aasmtai,aasmdata,aasmcpu,
  113. owbase,owar,ogmap;
  114. type
  115. TLinkerClass = class of Tlinker;
  116. {*****************************************************************************
  117. Helpers
  118. *****************************************************************************}
  119. { searches an object file }
  120. function FindObjectFile(s:string;const unitpath:string;isunit:boolean) : string;
  121. var
  122. found : boolean;
  123. foundfile : string;
  124. begin
  125. findobjectfile:='';
  126. if s='' then
  127. exit;
  128. {When linking on target, the units has not been assembled yet,
  129. so there is no object files to look for at
  130. the host. Look for the corresponding assembler file instead,
  131. because it will be assembled to object file on the target.}
  132. if isunit and (cs_link_on_target in current_settings.globalswitches) then
  133. s:=ChangeFileExt(s,target_info.asmext);
  134. { when it does not belong to the unit then check if
  135. the specified file exists without searching any paths }
  136. if not isunit then
  137. begin
  138. if FileExists(FixFileName(s),false) then
  139. begin
  140. foundfile:=ScriptFixFileName(s);
  141. found:=true;
  142. end;
  143. end;
  144. if pos('.',s)=0 then
  145. s:=s+target_info.objext;
  146. { find object file
  147. 1. output unit path
  148. 2. output exe path
  149. 3. specified unit path (if specified)
  150. 4. cwd
  151. 5. unit search path
  152. 6. local object path
  153. 7. global object path
  154. 8. exepath (not when linking on target)
  155. for all finds don't use the directory caching }
  156. found:=false;
  157. if isunit and (OutputUnitDir<>'') then
  158. found:=FindFile(s,OutPutUnitDir,false,foundfile)
  159. else
  160. if OutputExeDir<>'' then
  161. found:=FindFile(s,OutPutExeDir,false,foundfile);
  162. if (not found) and (unitpath<>'') then
  163. found:=FindFile(s,unitpath,false,foundfile);
  164. if (not found) then
  165. found:=FindFile(s, CurDirRelPath(source_info),false,foundfile);
  166. if (not found) then
  167. found:=UnitSearchPath.FindFile(s,false,foundfile);
  168. if (not found) then
  169. found:=current_module.localobjectsearchpath.FindFile(s,false,foundfile);
  170. if (not found) then
  171. found:=objectsearchpath.FindFile(s,false,foundfile);
  172. if not(cs_link_on_target in current_settings.globalswitches) and (not found) then
  173. found:=FindFile(s,exepath,false,foundfile);
  174. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  175. Message1(exec_w_objfile_not_found,s);
  176. {Restore file extension}
  177. if isunit and (cs_link_on_target in current_settings.globalswitches) then
  178. foundfile:= ChangeFileExt(foundfile,target_info.objext);
  179. findobjectfile:=ScriptFixFileName(foundfile);
  180. end;
  181. { searches a (windows) DLL file }
  182. function FindDLL(const s:string;var founddll:string):boolean;
  183. var
  184. sysdir : string;
  185. Found : boolean;
  186. begin
  187. Found:=false;
  188. { Look for DLL in:
  189. 1. Current dir
  190. 2. Library Path
  191. 3. windir,windir/system,windir/system32 }
  192. Found:=FindFile(s,'.'+source_info.DirSep,false,founddll);
  193. if (not found) then
  194. Found:=librarysearchpath.FindFile(s,false,founddll);
  195. if (not found) then
  196. begin
  197. sysdir:=FixPath(GetEnvironmentVariable('windir'),false);
  198. Found:=FindFile(s,sysdir+';'+sysdir+'system'+source_info.DirSep+';'+sysdir+'system32'+source_info.DirSep,false,founddll);
  199. end;
  200. if (not found) then
  201. begin
  202. message1(exec_w_libfile_not_found,s);
  203. FoundDll:=s;
  204. end;
  205. FindDll:=Found;
  206. end;
  207. { searches an library file }
  208. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  209. var
  210. found : boolean;
  211. paths : string;
  212. begin
  213. findlibraryfile:=false;
  214. foundfile:=s;
  215. if s='' then
  216. exit;
  217. { split path from filename }
  218. paths:=ExtractFilePath(s);
  219. s:=ExtractFileName(s);
  220. { add prefix 'lib' }
  221. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  222. s:=prefix+s;
  223. { add extension }
  224. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  225. s:=s+ext;
  226. { readd the split path }
  227. s:=paths+s;
  228. if FileExists(s,false) then
  229. begin
  230. foundfile:=ScriptFixFileName(s);
  231. FindLibraryFile:=true;
  232. exit;
  233. end;
  234. { find libary
  235. 1. cwd
  236. 2. local libary dir
  237. 3. global libary dir
  238. 4. exe path of the compiler (not when linking on target)
  239. for all searches don't use the directory cache }
  240. found:=FindFile(s, CurDirRelPath(source_info), false,foundfile);
  241. if (not found) and (current_module.outputpath^<>'') then
  242. found:=FindFile(s,current_module.outputpath^,false,foundfile);
  243. if (not found) then
  244. found:=current_module.locallibrarysearchpath.FindFile(s,false,foundfile);
  245. if (not found) then
  246. found:=librarysearchpath.FindFile(s,false,foundfile);
  247. if not(cs_link_on_target in current_settings.globalswitches) and (not found) then
  248. found:=FindFile(s,exepath,false,foundfile);
  249. foundfile:=ScriptFixFileName(foundfile);
  250. findlibraryfile:=found;
  251. end;
  252. {*****************************************************************************
  253. TLINKER
  254. *****************************************************************************}
  255. Constructor TLinker.Create;
  256. begin
  257. Inherited Create;
  258. ObjectFiles:=TStringList.Create_no_double;
  259. SharedLibFiles:=TStringList.Create_no_double;
  260. StaticLibFiles:=TStringList.Create_no_double;
  261. end;
  262. Destructor TLinker.Destroy;
  263. begin
  264. ObjectFiles.Free;
  265. SharedLibFiles.Free;
  266. StaticLibFiles.Free;
  267. end;
  268. procedure TLinker.AddModuleFiles(hp:tmodule);
  269. var
  270. mask : longint;
  271. i,j : longint;
  272. ImportLibrary : TImportLibrary;
  273. ImportSymbol : TImportSymbol;
  274. begin
  275. with hp do
  276. begin
  277. if (flags and uf_has_resourcefiles)<>0 then
  278. HasResources:=true;
  279. if (flags and uf_has_exports)<>0 then
  280. HasExports:=true;
  281. { link unit files }
  282. if (flags and uf_no_link)=0 then
  283. begin
  284. { create mask which unit files need linking }
  285. mask:=link_always;
  286. { static linking ? }
  287. if (cs_link_static in current_settings.globalswitches) then
  288. begin
  289. if (flags and uf_static_linked)=0 then
  290. begin
  291. { if smart not avail then try static linking }
  292. if (flags and uf_smart_linked)<>0 then
  293. begin
  294. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  295. mask:=mask or link_smart;
  296. end
  297. else
  298. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  299. end
  300. else
  301. mask:=mask or link_static;
  302. end;
  303. { smart linking ? }
  304. if (cs_link_smart in current_settings.globalswitches) then
  305. begin
  306. if (flags and uf_smart_linked)=0 then
  307. begin
  308. { if smart not avail then try static linking }
  309. if (flags and uf_static_linked)<>0 then
  310. begin
  311. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  312. mask:=mask or link_static;
  313. end
  314. else
  315. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  316. end
  317. else
  318. mask:=mask or link_smart;
  319. end;
  320. { shared linking }
  321. if (cs_link_shared in current_settings.globalswitches) then
  322. begin
  323. if (flags and uf_shared_linked)=0 then
  324. begin
  325. { if shared not avail then try static linking }
  326. if (flags and uf_static_linked)<>0 then
  327. begin
  328. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  329. mask:=mask or link_static;
  330. end
  331. else
  332. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  333. end
  334. else
  335. mask:=mask or link_shared;
  336. end;
  337. { unit files }
  338. while not linkunitofiles.empty do
  339. AddObject(linkunitofiles.getusemask(mask),path^,true);
  340. while not linkunitstaticlibs.empty do
  341. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  342. while not linkunitsharedlibs.empty do
  343. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  344. end;
  345. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  346. mask:=link_always;
  347. while not linkotherofiles.empty do
  348. AddObject(linkotherofiles.Getusemask(mask),path^,false);
  349. while not linkotherstaticlibs.empty do
  350. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  351. while not linkothersharedlibs.empty do
  352. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  353. { Known Library/DLL Imports }
  354. for i:=0 to ImportLibraryList.Count-1 do
  355. begin
  356. ImportLibrary:=TImportLibrary(ImportLibraryList[i]);
  357. for j:=0 to ImportLibrary.ImportSymbolList.Count-1 do
  358. begin
  359. ImportSymbol:=TImportSymbol(ImportLibrary.ImportSymbolList[j]);
  360. AddImportSymbol(ImportLibrary.Name,ImportSymbol.Name,ImportSymbol.OrdNr,ImportSymbol.IsVar);
  361. end;
  362. end;
  363. end;
  364. end;
  365. procedure TLinker.AddImportSymbol(const libname,symname:string;OrdNr: longint;isvar:boolean);
  366. begin
  367. end;
  368. Procedure TLinker.AddObject(const S,unitpath : String;isunit:boolean);
  369. begin
  370. ObjectFiles.Concat(FindObjectFile(s,unitpath,isunit));
  371. end;
  372. Procedure TLinker.AddSharedLibrary(S:String);
  373. begin
  374. if s='' then
  375. exit;
  376. { remove prefix 'lib' }
  377. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  378. Delete(s,1,length(target_info.sharedlibprefix));
  379. { remove extension if any }
  380. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  381. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  382. { ready to be added }
  383. SharedLibFiles.Concat(S);
  384. end;
  385. Procedure TLinker.AddStaticLibrary(const S:String);
  386. var
  387. ns : string;
  388. found : boolean;
  389. begin
  390. if s='' then
  391. exit;
  392. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  393. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  394. Message1(exec_w_libfile_not_found,s);
  395. StaticLibFiles.Concat(ns);
  396. end;
  397. Procedure TLinker.AddSharedCLibrary(S:String);
  398. begin
  399. if s='' then
  400. exit;
  401. { remove prefix 'lib' }
  402. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  403. Delete(s,1,length(target_info.sharedclibprefix));
  404. { remove extension if any }
  405. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  406. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  407. { ready to be added }
  408. SharedLibFiles.Concat(S);
  409. end;
  410. Procedure TLinker.AddStaticCLibrary(const S:String);
  411. var
  412. ns : string;
  413. found : boolean;
  414. begin
  415. if s='' then
  416. exit;
  417. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  418. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  419. Message1(exec_w_libfile_not_found,s);
  420. StaticLibFiles.Concat(ns);
  421. end;
  422. procedure AddImportSymbol(const libname,symname:string;OrdNr: longint;isvar:boolean);
  423. begin
  424. end;
  425. procedure TLinker.InitSysInitUnitName;
  426. begin
  427. end;
  428. function TLinker.MakeExecutable:boolean;
  429. begin
  430. MakeExecutable:=false;
  431. Message(exec_e_exe_not_supported);
  432. end;
  433. Function TLinker.MakeSharedLibrary:boolean;
  434. begin
  435. MakeSharedLibrary:=false;
  436. Message(exec_e_dll_not_supported);
  437. end;
  438. Function TLinker.MakeStaticLibrary:boolean;
  439. begin
  440. MakeStaticLibrary:=false;
  441. Message(exec_e_dll_not_supported);
  442. end;
  443. Procedure TLinker.ExpandAndApplyOrder(var Src:TStringList);
  444. var
  445. p : TLinkStrMap;
  446. i : longint;
  447. begin
  448. // call Virtual TLinker method to initialize
  449. LoadPredefinedLibraryOrder;
  450. // something to do?
  451. if (LinkLibraryAliases.count=0) and (LinkLibraryOrder.Count=0) Then
  452. exit;
  453. p:=TLinkStrMap.Create;
  454. // expand libaliases, clears src
  455. LinkLibraryAliases.expand(src,p);
  456. // writeln(src.count,' ',p.count,' ',linklibraryorder.count,' ',linklibraryaliases.count);
  457. // apply order
  458. p.UpdateWeights(LinkLibraryOrder);
  459. p.SortOnWeight;
  460. // put back in src
  461. for i:=0 to p.count-1 do
  462. src.insert(p[i].Key);
  463. p.free;
  464. end;
  465. procedure TLinker.LoadPredefinedLibraryOrder;
  466. begin
  467. end;
  468. function TLinker.ReOrderEntries : boolean;
  469. begin
  470. result:=(LinkLibraryOrder.count>0) or (LinkLibraryAliases.count>0);
  471. end;
  472. {*****************************************************************************
  473. TEXTERNALLINKER
  474. *****************************************************************************}
  475. Constructor TExternalLinker.Create;
  476. begin
  477. inherited Create;
  478. { set generic defaults }
  479. FillChar(Info,sizeof(Info),0);
  480. if cs_link_on_target in current_settings.globalswitches then
  481. begin
  482. Info.ResName:=outputexedir+ChangeFileExt(inputfilename,'_link.res');
  483. Info.ScriptName:=outputexedir+ChangeFileExt(inputfilename,'_script.res');
  484. end
  485. else
  486. begin
  487. Info.ResName:='link.res';
  488. Info.ScriptName:='script.res';
  489. end;
  490. { set the linker specific defaults }
  491. SetDefaultInfo;
  492. { Allow Parameter overrides for linker info }
  493. with Info do
  494. begin
  495. if ParaLinkOptions<>'' then
  496. ExtraOptions:=ParaLinkOptions;
  497. if ParaDynamicLinker<>'' then
  498. DynamicLinker:=ParaDynamicLinker;
  499. end;
  500. end;
  501. Destructor TExternalLinker.Destroy;
  502. begin
  503. inherited destroy;
  504. end;
  505. Procedure TExternalLinker.SetDefaultInfo;
  506. begin
  507. end;
  508. Function TExternalLinker.FindUtil(const s:string):string;
  509. var
  510. Found : boolean;
  511. FoundBin : string;
  512. UtilExe : string;
  513. begin
  514. if cs_link_on_target in current_settings.globalswitches then
  515. begin
  516. { If linking on target, don't add any path PM }
  517. FindUtil:=ChangeFileExt(s,target_info.exeext);
  518. exit;
  519. end;
  520. UtilExe:=ChangeFileExt(s,source_info.exeext);
  521. FoundBin:='';
  522. Found:=false;
  523. if utilsdirectory<>'' then
  524. Found:=FindFile(utilexe,utilsdirectory,false,Foundbin);
  525. if (not Found) then
  526. Found:=FindExe(utilexe,false,Foundbin);
  527. if (not Found) and not(cs_link_nolink in current_settings.globalswitches) then
  528. begin
  529. Message1(exec_e_util_not_found,utilexe);
  530. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  531. end;
  532. if (FoundBin<>'') then
  533. Message1(exec_t_using_util,FoundBin);
  534. FindUtil:=FoundBin;
  535. end;
  536. Function TExternalLinker.DoExec(const command:string; para:TCmdStr;showinfo,useshell:boolean):boolean;
  537. var
  538. exitcode: longint;
  539. begin
  540. DoExec:=true;
  541. if not(cs_link_nolink in current_settings.globalswitches) then
  542. begin
  543. FlushOutput;
  544. if useshell then
  545. exitcode:=shell(maybequoted(command)+' '+para)
  546. else
  547. try
  548. exitcode:=ExecuteProcess(command,para);
  549. except on E:EOSError do
  550. begin
  551. Message(exec_e_cant_call_linker);
  552. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  553. DoExec:=false;
  554. end;
  555. end;
  556. if (exitcode<>0) then
  557. begin
  558. Message(exec_e_error_while_linking);
  559. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  560. DoExec:=false;
  561. end;
  562. end;
  563. { Update asmres when externmode is set }
  564. if cs_link_nolink in current_settings.globalswitches then
  565. begin
  566. if showinfo then
  567. begin
  568. if DLLsource then
  569. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  570. else
  571. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  572. end
  573. else
  574. AsmRes.AddLinkCommand(Command,Para,'');
  575. end;
  576. end;
  577. Function TExternalLinker.MakeStaticLibrary:boolean;
  578. function GetNextFiles(const maxCmdLength : AInt; var item : TStringListItem) : ansistring;
  579. begin
  580. result := '';
  581. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  582. result := result + ' ' + item.str;
  583. item := TStringListItem(item.next);
  584. end;
  585. end;
  586. var
  587. binstr, scriptfile : string;
  588. success : boolean;
  589. cmdstr, nextcmd, smartpath : TCmdStr;
  590. current : TStringListItem;
  591. script: Text;
  592. scripted_ar : boolean;
  593. begin
  594. MakeStaticLibrary:=false;
  595. { remove the library, to be sure that it is rewritten }
  596. DeleteFile(current_module.staticlibfilename^);
  597. { Call AR }
  598. smartpath:=FixPath(ChangeFileExt(current_module.asmfilename^,target_info.smartext),false);
  599. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  600. binstr := FindUtil(utilsprefix + binstr);
  601. scripted_ar:=target_ar.id=ar_gnu_ar_scripted;
  602. if scripted_ar then
  603. begin
  604. scriptfile := FixFileName(smartpath+'arscript.txt');
  605. Replace(cmdstr,'$SCRIPT',maybequoted(scriptfile));
  606. Assign(script, scriptfile);
  607. Rewrite(script);
  608. try
  609. writeln(script, 'CREATE ' + current_module.staticlibfilename^);
  610. current := TStringListItem(SmartLinkOFiles.First);
  611. while current <> nil do
  612. begin
  613. writeln(script, 'ADDMOD ' + current.str);
  614. current := TStringListItem(current.next);
  615. end;
  616. writeln(script, 'SAVE');
  617. writeln(script, 'END');
  618. finally
  619. Close(script);
  620. end;
  621. success:=DoExec(binstr,cmdstr,false,true);
  622. end
  623. else
  624. begin
  625. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  626. { create AR commands }
  627. success := true;
  628. current := TStringListItem(SmartLinkOFiles.First);
  629. repeat
  630. nextcmd := cmdstr;
  631. Replace(nextcmd,'$FILES',GetNextFiles(2047, current));
  632. success:=DoExec(binstr,nextcmd,false,true);
  633. until (not assigned(current)) or (not success);
  634. end;
  635. if (target_ar.arfinishcmd <> '') then
  636. begin
  637. SplitBinCmd(target_ar.arfinishcmd,binstr,cmdstr);
  638. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  639. success:=DoExec(binstr,cmdstr,false,true);
  640. end;
  641. { Clean up }
  642. if not(cs_asm_leave in current_settings.globalswitches) then
  643. if not(cs_link_nolink in current_settings.globalswitches) then
  644. begin
  645. while not SmartLinkOFiles.Empty do
  646. DeleteFile(SmartLinkOFiles.GetFirst);
  647. if scripted_ar then
  648. DeleteFile(scriptfile);
  649. RemoveDir(smartpath);
  650. end
  651. else
  652. begin
  653. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  654. if scripted_ar then
  655. AsmRes.AddDeleteCommand(scriptfile);
  656. AsmRes.AddDeleteDirCommand(smartpath);
  657. end;
  658. MakeStaticLibrary:=success;
  659. end;
  660. {*****************************************************************************
  661. TINTERNALLINKER
  662. *****************************************************************************}
  663. Constructor TInternalLinker.Create;
  664. begin
  665. inherited Create;
  666. linkscript:=TStringList.Create;
  667. FStaticLibraryList:=TFPHashObjectList.Create(true);
  668. FImportLibraryList:=TFPHashObjectList.Create(true);
  669. exemap:=nil;
  670. exeoutput:=nil;
  671. CObjInput:=TObjInput;
  672. end;
  673. Destructor TInternalLinker.Destroy;
  674. begin
  675. linkscript.free;
  676. StaticLibraryList.Free;
  677. ImportLibraryList.Free;
  678. if assigned(exeoutput) then
  679. begin
  680. exeoutput.free;
  681. exeoutput:=nil;
  682. end;
  683. if assigned(exemap) then
  684. begin
  685. exemap.free;
  686. exemap:=nil;
  687. end;
  688. inherited destroy;
  689. end;
  690. procedure TInternalLinker.AddImportSymbol(const libname,symname:string;OrdNr: longint;isvar:boolean);
  691. var
  692. ImportLibrary : TImportLibrary;
  693. ImportSymbol : TFPHashObject;
  694. begin
  695. ImportLibrary:=TImportLibrary(ImportLibraryList.Find(libname));
  696. if not assigned(ImportLibrary) then
  697. ImportLibrary:=TImportLibrary.Create(ImportLibraryList,libname);
  698. ImportSymbol:=TFPHashObject(ImportLibrary.ImportSymbolList.Find(symname));
  699. if not assigned(ImportSymbol) then
  700. ImportSymbol:=TImportSymbol.Create(ImportLibrary.ImportSymbolList,symname,OrdNr,isvar);
  701. end;
  702. procedure TInternalLinker.Load_ReadObject(const para:string);
  703. var
  704. objdata : TObjData;
  705. objinput : TObjinput;
  706. objreader : TObjectReader;
  707. fn : string;
  708. begin
  709. fn:=FindObjectFile(para,'',false);
  710. Comment(V_Tried,'Reading object '+fn);
  711. objinput:=CObjInput.Create;
  712. objdata:=objinput.newObjData(para);
  713. objreader:=TObjectreader.create;
  714. if objreader.openfile(fn) then
  715. begin
  716. if objinput.ReadObjData(objreader,objdata) then
  717. exeoutput.addobjdata(objdata);
  718. end;
  719. { release input object }
  720. objinput.free;
  721. objreader.free;
  722. end;
  723. procedure TInternalLinker.Load_ReadStaticLibrary(const para:string);
  724. var
  725. objreader : TObjectReader;
  726. begin
  727. {$warning TODO Cleanup ignoring of FPC generated libimp*.a files}
  728. { Don't load import libraries }
  729. if copy(ExtractFileName(para),1,6)='libimp' then
  730. exit;
  731. Comment(V_Tried,'Opening library '+para);
  732. objreader:=TArObjectreader.create(para);
  733. TStaticLibrary.Create(StaticLibraryList,para,objreader,CObjInput);
  734. end;
  735. procedure TInternalLinker.ParseScript_Load;
  736. var
  737. s,
  738. para,
  739. keyword : string;
  740. hp : TStringListItem;
  741. begin
  742. exeoutput.Load_Start;
  743. hp:=tstringlistitem(linkscript.first);
  744. while assigned(hp) do
  745. begin
  746. s:=hp.str;
  747. if (s='') or (s[1]='#') then
  748. continue;
  749. keyword:=Upper(GetToken(s,' '));
  750. para:=GetToken(s,' ');
  751. if keyword='SYMBOL' then
  752. ExeOutput.Load_Symbol(para)
  753. else if keyword='ENTRYNAME' then
  754. ExeOutput.Load_EntryName(para)
  755. else if keyword='ISSHAREDLIBRARY' then
  756. ExeOutput.Load_IsSharedLibrary
  757. else if keyword='IMAGEBASE' then
  758. ExeOutput.Load_ImageBase(para)
  759. else if keyword='READOBJECT' then
  760. Load_ReadObject(para)
  761. else if keyword='READSTATICLIBRARY' then
  762. Load_ReadStaticLibrary(para);
  763. hp:=tstringlistitem(hp.next);
  764. end;
  765. end;
  766. procedure TInternalLinker.ParseScript_Order;
  767. var
  768. s,
  769. para,
  770. keyword : string;
  771. hp : TStringListItem;
  772. begin
  773. exeoutput.Order_Start;
  774. hp:=tstringlistitem(linkscript.first);
  775. while assigned(hp) do
  776. begin
  777. s:=hp.str;
  778. if (s='') or (s[1]='#') then
  779. continue;
  780. keyword:=Upper(GetToken(s,' '));
  781. para:=GetToken(s,' ');
  782. if keyword='EXESECTION' then
  783. ExeOutput.Order_ExeSection(para)
  784. else if keyword='ENDEXESECTION' then
  785. ExeOutput.Order_EndExeSection
  786. else if keyword='OBJSECTION' then
  787. ExeOutput.Order_ObjSection(para)
  788. else if keyword='ZEROS' then
  789. ExeOutput.Order_Zeros(para)
  790. else if keyword='SYMBOL' then
  791. ExeOutput.Order_Symbol(para);
  792. hp:=tstringlistitem(hp.next);
  793. end;
  794. exeoutput.Order_End;
  795. end;
  796. procedure TInternalLinker.ParseScript_CalcPos;
  797. var
  798. s,
  799. para,
  800. keyword : string;
  801. hp : TStringListItem;
  802. begin
  803. exeoutput.CalcPos_Start;
  804. hp:=tstringlistitem(linkscript.first);
  805. while assigned(hp) do
  806. begin
  807. s:=hp.str;
  808. if (s='') or (s[1]='#') then
  809. continue;
  810. keyword:=Upper(GetToken(s,' '));
  811. para:=GetToken(s,' ');
  812. if keyword='EXESECTION' then
  813. ExeOutput.CalcPos_ExeSection(para)
  814. else if keyword='ENDEXESECTION' then
  815. ExeOutput.CalcPos_EndExeSection
  816. else if keyword='HEADER' then
  817. ExeOutput.CalcPos_Header
  818. else if keyword='SYMBOLS' then
  819. ExeOutput.CalcPos_Symbols;
  820. hp:=tstringlistitem(hp.next);
  821. end;
  822. end;
  823. procedure TInternalLinker.PrintLinkerScript;
  824. var
  825. hp : TStringListItem;
  826. begin
  827. if not assigned(exemap) then
  828. exit;
  829. exemap.Add('Used linker script');
  830. exemap.Add('');
  831. hp:=tstringlistitem(linkscript.first);
  832. while assigned(hp) do
  833. begin
  834. exemap.Add(hp.str);
  835. hp:=tstringlistitem(hp.next);
  836. end;
  837. end;
  838. function TInternalLinker.RunLinkScript(const outputname:string):boolean;
  839. label
  840. myexit;
  841. var
  842. bsssize : aint;
  843. begin
  844. result:=false;
  845. Message1(exec_i_linking,outputname);
  846. {$warning TODO Load custom linker script}
  847. DefaultLinkScript;
  848. exeoutput:=CExeOutput.Create;
  849. if (cs_link_map in current_settings.globalswitches) then
  850. exemap:=texemap.create(current_module.mapfilename^);
  851. PrintLinkerScript;
  852. { Load .o files and resolve symbols }
  853. ParseScript_Load;
  854. exeoutput.ResolveSymbols(StaticLibraryList);
  855. { Generate symbols and code to do the importing }
  856. exeoutput.GenerateLibraryImports(ImportLibraryList);
  857. { Fill external symbols data }
  858. exeoutput.FixupSymbols;
  859. if ErrorCount>0 then
  860. goto myexit;
  861. { Create .exe sections and add .o sections }
  862. ParseScript_Order;
  863. exeoutput.RemoveUnreferencedSections;
  864. exeoutput.MergeStabs;
  865. exeoutput.RemoveEmptySections;
  866. if ErrorCount>0 then
  867. goto myexit;
  868. { Calc positions in mem and file }
  869. ParseScript_CalcPos;
  870. exeoutput.FixupRelocations;
  871. exeoutput.PrintMemoryMap;
  872. if ErrorCount>0 then
  873. goto myexit;
  874. exeoutput.WriteExeFile(outputname);
  875. {$warning TODO fixed section names}
  876. status.codesize:=exeoutput.findexesection('.text').size;
  877. status.datasize:=exeoutput.findexesection('.data').size;
  878. bsssize:=exeoutput.findexesection('.bss').size;
  879. { Executable info }
  880. Message1(execinfo_x_codesize,tostr(status.codesize));
  881. Message1(execinfo_x_initdatasize,tostr(status.datasize));
  882. Message1(execinfo_x_uninitdatasize,tostr(bsssize));
  883. Message1(execinfo_x_stackreserve,tostr(stacksize));
  884. myexit:
  885. { close map }
  886. if assigned(exemap) then
  887. begin
  888. exemap.free;
  889. exemap:=nil;
  890. end;
  891. { close exe }
  892. exeoutput.free;
  893. exeoutput:=nil;
  894. result:=true;
  895. end;
  896. function TInternalLinker.MakeExecutable:boolean;
  897. begin
  898. IsSharedLibrary:=false;
  899. result:=RunLinkScript(current_module.exefilename^);
  900. end;
  901. function TInternalLinker.MakeSharedLibrary:boolean;
  902. begin
  903. IsSharedLibrary:=true;
  904. result:=RunLinkScript(current_module.sharedlibfilename^);
  905. end;
  906. {*****************************************************************************
  907. Init/Done
  908. *****************************************************************************}
  909. procedure InitLinker;
  910. var
  911. lk : TlinkerClass;
  912. begin
  913. if (cs_link_extern in current_settings.globalswitches) and
  914. assigned(target_info.linkextern) then
  915. begin
  916. lk:=TlinkerClass(target_info.linkextern);
  917. linker:=lk.Create;
  918. end
  919. else
  920. if assigned(target_info.link) then
  921. begin
  922. lk:=TLinkerClass(target_info.link);
  923. linker:=lk.Create;
  924. end
  925. else
  926. linker:=Tlinker.Create;
  927. end;
  928. procedure DoneLinker;
  929. begin
  930. if assigned(linker) then
  931. Linker.Free;
  932. end;
  933. {*****************************************************************************
  934. Initialize
  935. *****************************************************************************}
  936. const
  937. ar_gnu_ar_info : tarinfo =
  938. (
  939. id : ar_gnu_ar;
  940. arcmd : 'ar qS $LIB $FILES';
  941. arfinishcmd : 'ar s $LIB'
  942. );
  943. ar_gnu_ar_scripted_info : tarinfo =
  944. (
  945. id : ar_gnu_ar_scripted;
  946. arcmd : 'ar -M < $SCRIPT';
  947. arfinishcmd : ''
  948. );
  949. ar_gnu_gar_info : tarinfo =
  950. ( id : ar_gnu_gar;
  951. arcmd : 'gar qS $LIB $FILES';
  952. arfinishcmd : 'gar s $LIB'
  953. );
  954. initialization
  955. RegisterAr(ar_gnu_ar_info);
  956. RegisterAr(ar_gnu_ar_scripted_info);
  957. RegisterAr(ar_gnu_gar_info);
  958. end.