link.pas 37 KB

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