link.pas 30 KB

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