link.pas 31 KB

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