link.pas 32 KB

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