link.pas 39 KB

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