link.pas 30 KB

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