link.pas 36 KB

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