link.pas 31 KB

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