link.pas 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  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;ordnumber: longint);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;ordnumber: longint);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. with tprocdef(p) do
  280. if assigned(import_dll) then
  281. if assigned(import_name) then
  282. AddExternalSymbol(import_dll^,import_name^,-import_nr)
  283. else
  284. if import_nr<>0 then
  285. AddExternalSymbol(import_dll^,import_dll^+'_index_'+tostr(import_nr),import_nr);
  286. end;
  287. procedure TLinker.AddModuleFiles(hp:tmodule);
  288. var
  289. mask : longint;
  290. begin
  291. with hp do
  292. begin
  293. if (flags and uf_has_resourcefiles)<>0 then
  294. HasResources:=true;
  295. if (flags and uf_has_exports)<>0 then
  296. HasExports:=true;
  297. { link unit files }
  298. if (flags and uf_no_link)=0 then
  299. begin
  300. { create mask which unit files need linking }
  301. mask:=link_always;
  302. { static linking ? }
  303. if (cs_link_static in aktglobalswitches) then
  304. begin
  305. if (flags and uf_static_linked)=0 then
  306. begin
  307. { if smart not avail then try static linking }
  308. if (flags and uf_smart_linked)<>0 then
  309. begin
  310. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  311. mask:=mask or link_smart;
  312. end
  313. else
  314. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  315. end
  316. else
  317. mask:=mask or link_static;
  318. end;
  319. { smart linking ? }
  320. if (cs_link_smart in aktglobalswitches) then
  321. begin
  322. if (flags and uf_smart_linked)=0 then
  323. begin
  324. { if smart not avail then try static linking }
  325. if (flags and uf_static_linked)<>0 then
  326. begin
  327. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  328. mask:=mask or link_static;
  329. end
  330. else
  331. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  332. end
  333. else
  334. mask:=mask or link_smart;
  335. end;
  336. { shared linking }
  337. if (cs_link_shared in aktglobalswitches) then
  338. begin
  339. if (flags and uf_shared_linked)=0 then
  340. begin
  341. { if shared not avail then try static linking }
  342. if (flags and uf_static_linked)<>0 then
  343. begin
  344. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  345. mask:=mask or link_static;
  346. end
  347. else
  348. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  349. end
  350. else
  351. mask:=mask or link_shared;
  352. end;
  353. { unit files }
  354. while not linkunitofiles.empty do
  355. AddObject(linkunitofiles.getusemask(mask),path^,true);
  356. while not linkunitstaticlibs.empty do
  357. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  358. while not linkunitsharedlibs.empty do
  359. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  360. end;
  361. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  362. mask:=link_always;
  363. while not linkotherofiles.empty do
  364. AddObject(linkotherofiles.Getusemask(mask),path^,false);
  365. while not linkotherstaticlibs.empty do
  366. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  367. while not linkothersharedlibs.empty do
  368. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  369. { Known Library/DLL Imports }
  370. if assigned(globalsymtable) then
  371. globalsymtable.defindex.foreach(@AddProcdefImports,nil);
  372. if assigned(localsymtable) then
  373. localsymtable.defindex.foreach(@AddProcdefImports,nil);
  374. end;
  375. end;
  376. procedure TLinker.AddExternalSymbol(const libname,symname:string;ordnumber: longint);
  377. begin
  378. end;
  379. Procedure TLinker.AddObject(const S,unitpath : String;isunit:boolean);
  380. begin
  381. ObjectFiles.Concat(FindObjectFile(s,unitpath,isunit));
  382. end;
  383. Procedure TLinker.AddSharedLibrary(S:String);
  384. begin
  385. if s='' then
  386. exit;
  387. { remove prefix 'lib' }
  388. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  389. Delete(s,1,length(target_info.sharedlibprefix));
  390. { remove extension if any }
  391. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  392. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  393. { ready to be added }
  394. SharedLibFiles.Concat(S);
  395. end;
  396. Procedure TLinker.AddStaticLibrary(const S:String);
  397. var
  398. ns : string;
  399. found : boolean;
  400. begin
  401. if s='' then
  402. exit;
  403. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  404. if not(cs_link_nolink in aktglobalswitches) and (not found) then
  405. Message1(exec_w_libfile_not_found,s);
  406. StaticLibFiles.Concat(ns);
  407. end;
  408. Procedure TLinker.AddSharedCLibrary(S:String);
  409. begin
  410. if s='' then
  411. exit;
  412. { remove prefix 'lib' }
  413. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  414. Delete(s,1,length(target_info.sharedclibprefix));
  415. { remove extension if any }
  416. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  417. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  418. { ready to be added }
  419. SharedLibFiles.Concat(S);
  420. end;
  421. Procedure TLinker.AddStaticCLibrary(const S:String);
  422. var
  423. ns : string;
  424. found : boolean;
  425. begin
  426. if s='' then
  427. exit;
  428. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  429. if not(cs_link_nolink in aktglobalswitches) and (not found) then
  430. Message1(exec_w_libfile_not_found,s);
  431. StaticLibFiles.Concat(ns);
  432. end;
  433. function TLinker.MakeExecutable:boolean;
  434. begin
  435. MakeExecutable:=false;
  436. Message(exec_e_exe_not_supported);
  437. end;
  438. Function TLinker.MakeSharedLibrary:boolean;
  439. begin
  440. MakeSharedLibrary:=false;
  441. Message(exec_e_dll_not_supported);
  442. end;
  443. Function TLinker.MakeStaticLibrary:boolean;
  444. begin
  445. MakeStaticLibrary:=false;
  446. Message(exec_e_dll_not_supported);
  447. end;
  448. Procedure TLinker.ExpandAndApplyOrder(var Src:TStringList);
  449. var p : TLinkStrMap;
  450. i : Integer;
  451. begin
  452. // call Virtual TLinker method to initialize
  453. LoadPredefinedLibraryOrder;
  454. // something to do?
  455. if (LinkLibraryAliases.count=0) and (LinkLibraryOrder.Count=0) Then
  456. exit;
  457. p:=TLinkStrMap.Create;
  458. // expand libaliases, clears src
  459. LinkLibraryAliases.expand(src,p);
  460. // writeln(src.count,' ',p.count,' ',linklibraryorder.count,' ',linklibraryaliases.count);
  461. // apply order
  462. p.UpdateWeights(LinkLibraryOrder);
  463. p.SortOnWeight;
  464. // put back in src
  465. for i:=0 to p.count-1 do
  466. src.insert(p[i].Key);
  467. p.free;
  468. end;
  469. procedure TLinker.LoadPredefinedLibraryOrder;
  470. begin
  471. end;
  472. function TLinker.ReOrderEntries : boolean;
  473. begin
  474. result:=(LinkLibraryOrder.count>0) or (LinkLibraryAliases.count>0);
  475. end;
  476. {*****************************************************************************
  477. TEXTERNALLINKER
  478. *****************************************************************************}
  479. Constructor TExternalLinker.Create;
  480. begin
  481. inherited Create;
  482. { set generic defaults }
  483. FillChar(Info,sizeof(Info),0);
  484. if cs_link_on_target in aktglobalswitches then
  485. begin
  486. Info.ResName:=outputexedir+inputfile+'_link.res';
  487. Info.ScriptName:=outputexedir+inputfile+'_script.res';
  488. end
  489. else
  490. begin
  491. Info.ResName:='link.res';
  492. Info.ScriptName:='script.res';
  493. end;
  494. { set the linker specific defaults }
  495. SetDefaultInfo;
  496. { Allow Parameter overrides for linker info }
  497. with Info do
  498. begin
  499. if ParaLinkOptions<>'' then
  500. ExtraOptions:=ParaLinkOptions;
  501. if ParaDynamicLinker<>'' then
  502. DynamicLinker:=ParaDynamicLinker;
  503. end;
  504. end;
  505. Destructor TExternalLinker.Destroy;
  506. begin
  507. inherited destroy;
  508. end;
  509. Procedure TExternalLinker.SetDefaultInfo;
  510. begin
  511. end;
  512. Function TExternalLinker.FindUtil(const s:string):string;
  513. var
  514. Found : boolean;
  515. FoundBin : string;
  516. UtilExe : string;
  517. begin
  518. if cs_link_on_target in aktglobalswitches then
  519. begin
  520. { If linking on target, don't add any path PM }
  521. FindUtil:=AddExtension(s,target_info.exeext);
  522. exit;
  523. end;
  524. UtilExe:=AddExtension(s,source_info.exeext);
  525. FoundBin:='';
  526. Found:=false;
  527. if utilsdirectory<>'' then
  528. Found:=FindFile(utilexe,utilsdirectory,Foundbin);
  529. if (not Found) then
  530. Found:=FindExe(utilexe,Foundbin);
  531. if (not Found) and not(cs_link_nolink in aktglobalswitches) then
  532. begin
  533. Message1(exec_e_util_not_found,utilexe);
  534. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  535. end;
  536. if (FoundBin<>'') then
  537. Message1(exec_t_using_util,FoundBin);
  538. FindUtil:=FoundBin;
  539. end;
  540. Function TExternalLinker.DoExec(const command:string; para:TCmdStr;showinfo,useshell:boolean):boolean;
  541. var
  542. exitcode: longint;
  543. begin
  544. DoExec:=true;
  545. if not(cs_link_nolink in aktglobalswitches) then
  546. begin
  547. FlushOutput;
  548. if useshell then
  549. exitcode := shell(maybequoted(command)+' '+para)
  550. else
  551. {$IFDEF USE_SYSUTILS}
  552. try
  553. if ExecuteProcess(command,para) <> 0
  554. then begin
  555. Message(exec_e_error_while_linking);
  556. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  557. DoExec:=false;
  558. end;
  559. except on E:EOSError do
  560. begin
  561. Message(exec_e_cant_call_linker);
  562. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  563. DoExec:=false;
  564. end;
  565. end
  566. end;
  567. {$ELSE USE_SYSUTILS}
  568. begin
  569. swapvectors;
  570. exec(command,para);
  571. swapvectors;
  572. exitcode := dosexitcode;
  573. end;
  574. if (doserror<>0) then
  575. begin
  576. Message(exec_e_cant_call_linker);
  577. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  578. DoExec:=false;
  579. end
  580. else
  581. if (exitcode<>0) then
  582. begin
  583. Message(exec_e_error_while_linking);
  584. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  585. DoExec:=false;
  586. end;
  587. end;
  588. {$ENDIF USE_SYSUTILS}
  589. { Update asmres when externmode is set }
  590. if cs_link_nolink in aktglobalswitches then
  591. begin
  592. if showinfo then
  593. begin
  594. if DLLsource then
  595. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  596. else
  597. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  598. end
  599. else
  600. AsmRes.AddLinkCommand(Command,Para,'');
  601. end;
  602. end;
  603. Function TExternalLinker.MakeStaticLibrary:boolean;
  604. function GetNextFiles(const maxCmdLength : AInt; var item : TStringListItem) : string;
  605. begin
  606. result := '';
  607. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  608. result := result + ' ' + item.str;
  609. item := TStringListItem(item.next);
  610. end;
  611. end;
  612. var
  613. binstr, scriptfile : string;
  614. success : boolean;
  615. cmdstr, nextcmd, smartpath : TCmdStr;
  616. current : TStringListItem;
  617. script: Text;
  618. scripted_ar : boolean;
  619. begin
  620. MakeStaticLibrary:=false;
  621. { remove the library, to be sure that it is rewritten }
  622. RemoveFile(current_module.staticlibfilename^);
  623. { Call AR }
  624. smartpath:=current_module.outputpath^+FixPath(current_module.newfilename^+target_info.smartext,false);
  625. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  626. binstr := FindUtil(utilsprefix + binstr);
  627. scripted_ar:=target_ar.id=ar_gnu_ar_scripted;
  628. if scripted_ar then
  629. begin
  630. scriptfile := FixFileName(smartpath+'arscript.txt');
  631. Replace(cmdstr,'$SCRIPT',maybequoted(scriptfile));
  632. Assign(script, scriptfile);
  633. Rewrite(script);
  634. try
  635. writeln(script, 'CREATE ' + current_module.staticlibfilename^);
  636. current := TStringListItem(SmartLinkOFiles.First);
  637. while current <> nil do
  638. begin
  639. writeln(script, 'ADDMOD ' + current.str);
  640. current := TStringListItem(current.next);
  641. end;
  642. writeln(script, 'SAVE');
  643. writeln(script, 'END');
  644. finally
  645. Close(script);
  646. end;
  647. success:=DoExec(binstr,cmdstr,false,true);
  648. end
  649. else
  650. begin
  651. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  652. { create AR commands }
  653. success := true;
  654. nextcmd := cmdstr;
  655. current := TStringListItem(SmartLinkOFiles.First);
  656. repeat
  657. Replace(nextcmd,'$FILES',GetNextFiles(240 - length(nextcmd) + 6 - length(binstr) - 1, current));
  658. success:=DoExec(binstr,nextcmd,false,true);
  659. nextcmd := cmdstr;
  660. until (not assigned(current)) or (not success);
  661. end;
  662. if (target_ar.arfinishcmd <> '') then
  663. begin
  664. SplitBinCmd(target_ar.arfinishcmd,binstr,cmdstr);
  665. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  666. success:=DoExec(binstr,cmdstr,false,true);
  667. end;
  668. { Clean up }
  669. if not(cs_asm_leave in aktglobalswitches) then
  670. if not(cs_link_nolink in aktglobalswitches) then
  671. begin
  672. while not SmartLinkOFiles.Empty do
  673. RemoveFile(SmartLinkOFiles.GetFirst);
  674. if scripted_ar then
  675. RemoveFile(scriptfile);
  676. RemoveDir(smartpath);
  677. end
  678. else
  679. begin
  680. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  681. if scripted_ar then
  682. AsmRes.AddDeleteCommand(scriptfile);
  683. AsmRes.AddDeleteDirCommand(smartpath);
  684. end;
  685. MakeStaticLibrary:=success;
  686. end;
  687. {*****************************************************************************
  688. TINTERNALLINKER
  689. *****************************************************************************}
  690. Constructor TInternalLinker.Create;
  691. begin
  692. inherited Create;
  693. linkscript:=TStringList.Create;
  694. FStaticLibraryList:=TFPHashObjectList.Create(true);
  695. FExternalLibraryList:=TFPHashObjectList.Create(true);
  696. exemap:=nil;
  697. exeoutput:=nil;
  698. CObjInput:=TObjInput;
  699. end;
  700. Destructor TInternalLinker.Destroy;
  701. begin
  702. linkscript.free;
  703. StaticLibraryList.Free;
  704. ExternalLibraryList.Free;
  705. if assigned(exeoutput) then
  706. begin
  707. exeoutput.free;
  708. exeoutput:=nil;
  709. end;
  710. if assigned(exemap) then
  711. begin
  712. exemap.free;
  713. exemap:=nil;
  714. end;
  715. inherited destroy;
  716. end;
  717. procedure TInternalLinker.AddExternalSymbol(const libname,symname:string;ordnumber: longint);
  718. var
  719. ExtLibrary : TExternalLibrary;
  720. ExtSymbol : TFPHashObject;
  721. begin
  722. ExtLibrary:=TExternalLibrary(ExternalLibraryList.Find(libname));
  723. if not assigned(ExtLibrary) then
  724. ExtLibrary:=TExternalLibrary.Create(ExternalLibraryList,libname);
  725. ExtSymbol:=TFPHashObject(ExtLibrary.ExternalSymbolList.Find(symname));
  726. if not assigned(ExtSymbol) then
  727. ExtSymbol:=TExternalSymbol.Create(ExtLibrary.ExternalSymbolList,symname,ordnumber);
  728. end;
  729. procedure TInternalLinker.Load_ReadObject(const para:string);
  730. var
  731. objdata : TObjData;
  732. objinput : TObjinput;
  733. objreader : TObjectReader;
  734. fn : string;
  735. begin
  736. fn:=FindObjectFile(para,'',false);
  737. Comment(V_Tried,'Reading object '+fn);
  738. objinput:=CObjInput.Create;
  739. objdata:=objinput.newObjData(para);
  740. objreader:=TObjectreader.create;
  741. if objreader.openfile(fn) then
  742. begin
  743. if objinput.ReadObjData(objreader,objdata) then
  744. exeoutput.addobjdata(objdata);
  745. end;
  746. { release input object }
  747. objinput.free;
  748. objreader.free;
  749. end;
  750. procedure TInternalLinker.Load_ReadStaticLibrary(const para:string);
  751. var
  752. objreader : TObjectReader;
  753. begin
  754. {$warning TODO Cleanup ignoring of FPC generated libimp*.a files}
  755. { Don't load import libraries }
  756. if copy(splitfilename(para),1,6)='libimp' then
  757. exit;
  758. Comment(V_Tried,'Opening library '+para);
  759. objreader:=TArObjectreader.create(para);
  760. TStaticLibrary.Create(StaticLibraryList,para,objreader,CObjInput);
  761. end;
  762. procedure TInternalLinker.ParseScript_Load;
  763. var
  764. s,
  765. para,
  766. keyword : string;
  767. hp : TStringListItem;
  768. begin
  769. exeoutput.Load_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='SYMBOL' then
  779. ExeOutput.Load_Symbol(para)
  780. else if keyword='ENTRYNAME' then
  781. ExeOutput.Load_EntryName(para)
  782. else if keyword='ISSHAREDLIBRARY' then
  783. ExeOutput.Load_IsSharedLibrary
  784. else if keyword='IMAGEBASE' then
  785. ExeOutput.Load_ImageBase(para)
  786. else if keyword='READOBJECT' then
  787. Load_ReadObject(para)
  788. else if keyword='READSTATICLIBRARY' then
  789. Load_ReadStaticLibrary(para);
  790. hp:=tstringlistitem(hp.next);
  791. end;
  792. end;
  793. procedure TInternalLinker.ParseScript_Order;
  794. var
  795. s,
  796. para,
  797. keyword : string;
  798. hp : TStringListItem;
  799. begin
  800. exeoutput.Order_Start;
  801. hp:=tstringlistitem(linkscript.first);
  802. while assigned(hp) do
  803. begin
  804. s:=hp.str;
  805. if (s='') or (s[1]='#') then
  806. continue;
  807. keyword:=Upper(GetToken(s,' '));
  808. para:=GetToken(s,' ');
  809. if keyword='EXESECTION' then
  810. ExeOutput.Order_ExeSection(para)
  811. else if keyword='ENDEXESECTION' then
  812. ExeOutput.Order_EndExeSection
  813. else if keyword='OBJSECTION' then
  814. ExeOutput.Order_ObjSection(para)
  815. else if keyword='ZEROS' then
  816. ExeOutput.Order_Zeros(para)
  817. else if keyword='SYMBOL' then
  818. ExeOutput.Order_Symbol(para);
  819. hp:=tstringlistitem(hp.next);
  820. end;
  821. exeoutput.Order_End;
  822. end;
  823. procedure TInternalLinker.ParseScript_CalcPos;
  824. var
  825. s,
  826. para,
  827. keyword : string;
  828. hp : TStringListItem;
  829. begin
  830. exeoutput.CalcPos_Start;
  831. hp:=tstringlistitem(linkscript.first);
  832. while assigned(hp) do
  833. begin
  834. s:=hp.str;
  835. if (s='') or (s[1]='#') then
  836. continue;
  837. keyword:=Upper(GetToken(s,' '));
  838. para:=GetToken(s,' ');
  839. if keyword='EXESECTION' then
  840. ExeOutput.CalcPos_ExeSection(para)
  841. else if keyword='ENDEXESECTION' then
  842. ExeOutput.CalcPos_EndExeSection
  843. else if keyword='HEADER' then
  844. ExeOutput.CalcPos_Header
  845. else if keyword='SYMBOLS' then
  846. ExeOutput.CalcPos_Symbols;
  847. hp:=tstringlistitem(hp.next);
  848. end;
  849. end;
  850. procedure TInternalLinker.PrintLinkerScript;
  851. var
  852. hp : TStringListItem;
  853. begin
  854. if not assigned(exemap) then
  855. exit;
  856. exemap.Add('Used linker script');
  857. exemap.Add('');
  858. hp:=tstringlistitem(linkscript.first);
  859. while assigned(hp) do
  860. begin
  861. exemap.Add(hp.str);
  862. hp:=tstringlistitem(hp.next);
  863. end;
  864. end;
  865. function TInternalLinker.RunLinkScript(const outputname:string):boolean;
  866. label
  867. myexit;
  868. var
  869. bsssize : aint;
  870. begin
  871. result:=false;
  872. Message1(exec_i_linking,outputname);
  873. {$warning TODO Load custom linker script}
  874. DefaultLinkScript;
  875. exeoutput:=CExeOutput.Create;
  876. if (cs_link_map in aktglobalswitches) then
  877. exemap:=texemap.create(current_module.mapfilename^);
  878. PrintLinkerScript;
  879. { Load .o files and resolve symbols }
  880. ParseScript_Load;
  881. exeoutput.ResolveSymbols(StaticLibraryList);
  882. { Generate symbols and code to do the importing }
  883. exeoutput.GenerateLibraryImports(ExternalLibraryList);
  884. { Fill external symbols data }
  885. exeoutput.FixupSymbols;
  886. if ErrorCount>0 then
  887. goto myexit;
  888. { Create .exe sections and add .o sections }
  889. ParseScript_Order;
  890. exeoutput.RemoveUnreferencedSections;
  891. exeoutput.MergeStabs;
  892. exeoutput.RemoveEmptySections;
  893. if ErrorCount>0 then
  894. goto myexit;
  895. { Calc positions in mem and file }
  896. ParseScript_CalcPos;
  897. exeoutput.FixupRelocations;
  898. exeoutput.PrintMemoryMap;
  899. if ErrorCount>0 then
  900. goto myexit;
  901. exeoutput.WriteExeFile(outputname);
  902. {$warning TODO fixed section names}
  903. status.codesize:=exeoutput.findexesection('.text').size;
  904. status.datasize:=exeoutput.findexesection('.data').size;
  905. bsssize:=exeoutput.findexesection('.bss').size;
  906. { Executable info }
  907. Message1(execinfo_x_codesize,tostr(status.codesize));
  908. Message1(execinfo_x_initdatasize,tostr(status.datasize));
  909. Message1(execinfo_x_uninitdatasize,tostr(bsssize));
  910. Message1(execinfo_x_stackreserve,tostr(stacksize));
  911. myexit:
  912. { close map }
  913. if assigned(exemap) then
  914. begin
  915. exemap.free;
  916. exemap:=nil;
  917. end;
  918. { close exe }
  919. exeoutput.free;
  920. exeoutput:=nil;
  921. result:=true;
  922. end;
  923. function TInternalLinker.MakeExecutable:boolean;
  924. begin
  925. IsSharedLibrary:=false;
  926. result:=RunLinkScript(current_module.exefilename^);
  927. end;
  928. function TInternalLinker.MakeSharedLibrary:boolean;
  929. begin
  930. IsSharedLibrary:=true;
  931. result:=RunLinkScript(current_module.sharedlibfilename^);
  932. end;
  933. {*****************************************************************************
  934. Init/Done
  935. *****************************************************************************}
  936. procedure InitLinker;
  937. var
  938. lk : TlinkerClass;
  939. begin
  940. if (cs_link_extern in aktglobalswitches) and
  941. assigned(target_info.linkextern) then
  942. begin
  943. lk:=TlinkerClass(target_info.linkextern);
  944. linker:=lk.Create;
  945. end
  946. else
  947. if assigned(target_info.link) then
  948. begin
  949. lk:=TLinkerClass(target_info.link);
  950. linker:=lk.Create;
  951. end
  952. else
  953. linker:=Tlinker.Create;
  954. end;
  955. procedure DoneLinker;
  956. begin
  957. if assigned(linker) then
  958. Linker.Free;
  959. end;
  960. {*****************************************************************************
  961. Initialize
  962. *****************************************************************************}
  963. const
  964. ar_gnu_ar_info : tarinfo =
  965. (
  966. id : ar_gnu_ar;
  967. arcmd : 'ar qS $LIB $FILES';
  968. arfinishcmd : 'ar s $LIB'
  969. );
  970. ar_gnu_ar_scripted_info : tarinfo =
  971. (
  972. id : ar_gnu_ar_scripted;
  973. arcmd : 'ar -M < $SCRIPT';
  974. arfinishcmd : ''
  975. );
  976. ar_gnu_gar_info : tarinfo =
  977. ( id : ar_gnu_gar;
  978. arcmd : 'gar qS $LIB $FILES';
  979. arfinishcmd : 'gar s $LIB'
  980. );
  981. initialization
  982. RegisterAr(ar_gnu_ar_info);
  983. RegisterAr(ar_gnu_ar_scripted_info);
  984. RegisterAr(ar_gnu_gar_info);
  985. end.