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_nolink 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_nolink 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_nolink 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_nolink in aktglobalswitches) then
  492. begin
  493. Message1(exec_e_util_not_found,utilexe);
  494. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  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_nolink in aktglobalswitches) then
  506. begin
  507. FlushOutput;
  508. if useshell then
  509. exitcode := shell(maybequoted(command)+' '+para)
  510. else
  511. {$IFDEF USE_SYSUTILS}
  512. try
  513. if ExecuteProcess(command,para) <> 0
  514. then begin
  515. Message(exec_e_error_while_linking);
  516. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  517. DoExec:=false;
  518. end;
  519. except on E:EOSError do
  520. begin
  521. Message(exec_e_cant_call_linker);
  522. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  523. DoExec:=false;
  524. end;
  525. end
  526. end;
  527. {$ELSE USE_SYSUTILS}
  528. begin
  529. swapvectors;
  530. exec(command,para);
  531. swapvectors;
  532. exitcode := dosexitcode;
  533. end;
  534. if (doserror<>0) then
  535. begin
  536. Message(exec_e_cant_call_linker);
  537. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  538. DoExec:=false;
  539. end
  540. else
  541. if (exitcode<>0) then
  542. begin
  543. Message(exec_e_error_while_linking);
  544. aktglobalswitches:=aktglobalswitches+[cs_link_nolink];
  545. DoExec:=false;
  546. end;
  547. end;
  548. {$ENDIF USE_SYSUTILS}
  549. { Update asmres when externmode is set }
  550. if cs_link_nolink in aktglobalswitches then
  551. begin
  552. if showinfo then
  553. begin
  554. if DLLsource then
  555. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  556. else
  557. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  558. end
  559. else
  560. AsmRes.AddLinkCommand(Command,Para,'');
  561. end;
  562. end;
  563. Function TExternalLinker.MakeStaticLibrary:boolean;
  564. function GetNextFiles(const maxCmdLength : AInt; var item : TStringListItem) : string;
  565. begin
  566. result := '';
  567. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  568. result := result + ' ' + item.str;
  569. item := TStringListItem(item.next);
  570. end;
  571. end;
  572. var
  573. binstr, scriptfile : string;
  574. success : boolean;
  575. cmdstr, nextcmd, smartpath : TCmdStr;
  576. current : TStringListItem;
  577. script: Text;
  578. scripted_ar : boolean;
  579. begin
  580. MakeStaticLibrary:=false;
  581. { remove the library, to be sure that it is rewritten }
  582. RemoveFile(current_module.staticlibfilename^);
  583. { Call AR }
  584. smartpath:=current_module.outputpath^+FixPath(current_module.newfilename^+target_info.smartext,false);
  585. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  586. binstr := FindUtil(utilsprefix + binstr);
  587. scripted_ar:=target_ar.id=ar_gnu_ar_scripted;
  588. if scripted_ar then
  589. begin
  590. scriptfile := FixFileName(smartpath+'arscript.txt');
  591. Replace(cmdstr,'$SCRIPT',maybequoted(scriptfile));
  592. Assign(script, scriptfile);
  593. Rewrite(script);
  594. try
  595. writeln(script, 'CREATE ' + current_module.staticlibfilename^);
  596. current := TStringListItem(SmartLinkOFiles.First);
  597. while current <> nil do
  598. begin
  599. writeln(script, 'ADDMOD ' + current.str);
  600. current := TStringListItem(current.next);
  601. end;
  602. writeln(script, 'SAVE');
  603. writeln(script, 'END');
  604. finally
  605. Close(script);
  606. end;
  607. success:=DoExec(binstr,cmdstr,false,true);
  608. end
  609. else
  610. begin
  611. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  612. { create AR commands }
  613. success := true;
  614. nextcmd := cmdstr;
  615. current := TStringListItem(SmartLinkOFiles.First);
  616. repeat
  617. Replace(nextcmd,'$FILES',GetNextFiles(240 - length(nextcmd) + 6 - length(binstr) - 1, current));
  618. success:=DoExec(binstr,nextcmd,false,true);
  619. nextcmd := cmdstr;
  620. until (not assigned(current)) or (not success);
  621. end;
  622. if (target_ar.arfinishcmd <> '') then
  623. begin
  624. SplitBinCmd(target_ar.arfinishcmd,binstr,cmdstr);
  625. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  626. success:=DoExec(binstr,cmdstr,false,true);
  627. end;
  628. { Clean up }
  629. if not(cs_asm_leave in aktglobalswitches) then
  630. if not(cs_link_nolink in aktglobalswitches) then
  631. begin
  632. while not SmartLinkOFiles.Empty do
  633. RemoveFile(SmartLinkOFiles.GetFirst);
  634. if scripted_ar then
  635. RemoveFile(scriptfile);
  636. RemoveDir(smartpath);
  637. end
  638. else
  639. begin
  640. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  641. if scripted_ar then
  642. AsmRes.AddDeleteCommand(scriptfile);
  643. AsmRes.Add('rmdir '+smartpath);
  644. end;
  645. MakeStaticLibrary:=success;
  646. end;
  647. {*****************************************************************************
  648. TINTERNALLINKER
  649. *****************************************************************************}
  650. Constructor TInternalLinker.Create;
  651. begin
  652. inherited Create;
  653. linkscript:=TStringList.Create;
  654. FExternalLibraryList:=TFPHashObjectList.Create(true);
  655. exemap:=nil;
  656. exeoutput:=nil;
  657. CObjInput:=TObjInput;
  658. end;
  659. Destructor TInternalLinker.Destroy;
  660. begin
  661. linkscript.free;
  662. ExternalLibraryList.Free;
  663. if assigned(exeoutput) then
  664. begin
  665. exeoutput.free;
  666. exeoutput:=nil;
  667. end;
  668. if assigned(exemap) then
  669. begin
  670. exemap.free;
  671. exemap:=nil;
  672. end;
  673. inherited destroy;
  674. end;
  675. procedure TInternalLinker.AddExternalSymbol(const libname,symname:string);
  676. var
  677. ExtLibrary : TExternalLibrary;
  678. ExtSymbol : TFPHashObject;
  679. begin
  680. ExtLibrary:=TExternalLibrary(ExternalLibraryList.Find(libname));
  681. if not assigned(ExtLibrary) then
  682. ExtLibrary:=TExternalLibrary.Create(ExternalLibraryList,libname);
  683. ExtSymbol:=TFPHashObject(ExtLibrary.ExternalSymbolList.Find(symname));
  684. if not assigned(ExtSymbol) then
  685. ExtSymbol:=TFPHashObject.Create(ExtLibrary.ExternalSymbolList,symname);
  686. end;
  687. procedure TInternalLinker.Load_ReadObject(const para:string);
  688. var
  689. objdata : TObjData;
  690. objinput : TObjinput;
  691. fn : string;
  692. begin
  693. fn:=FindObjectFile(para,'',false);
  694. Comment(V_Tried,'Reading object '+fn);
  695. objinput:=CObjInput.Create;
  696. objdata:=objinput.newObjData(para);
  697. if objinput.readobjectfile(fn,objdata) then
  698. exeoutput.addobjdata(objdata);
  699. { release input object }
  700. objinput.free;
  701. end;
  702. procedure TInternalLinker.Load_ReadUnitObjects;
  703. var
  704. s : string;
  705. begin
  706. while not ObjectFiles.Empty do
  707. begin
  708. s:=ObjectFiles.GetFirst;
  709. if s<>'' then
  710. Load_ReadObject(s);
  711. end;
  712. end;
  713. procedure TInternalLinker.ParseScript_Load;
  714. var
  715. s,
  716. para,
  717. keyword : string;
  718. hp : TStringListItem;
  719. begin
  720. exeoutput.Load_Start;
  721. hp:=tstringlistitem(linkscript.first);
  722. while assigned(hp) do
  723. begin
  724. s:=hp.str;
  725. if (s='') or (s[1]='#') then
  726. continue;
  727. keyword:=Upper(GetToken(s,' '));
  728. para:=GetToken(s,' ');
  729. if keyword='SYMBOL' then
  730. ExeOutput.Load_Symbol(para)
  731. else if keyword='ENTRYNAME' then
  732. ExeOutput.Load_EntryName(para)
  733. else if keyword='READOBJECT' then
  734. Load_ReadObject(para)
  735. else if keyword='READUNITOBJECTS' then
  736. Load_ReadUnitObjects;
  737. hp:=tstringlistitem(hp.next);
  738. end;
  739. end;
  740. procedure TInternalLinker.ParseScript_Order;
  741. var
  742. s,
  743. para,
  744. keyword : string;
  745. hp : TStringListItem;
  746. begin
  747. exeoutput.Order_Start;
  748. hp:=tstringlistitem(linkscript.first);
  749. while assigned(hp) do
  750. begin
  751. s:=hp.str;
  752. if (s='') or (s[1]='#') then
  753. continue;
  754. keyword:=Upper(GetToken(s,' '));
  755. para:=GetToken(s,' ');
  756. if keyword='EXESECTION' then
  757. ExeOutput.Order_ExeSection(para)
  758. else if keyword='ENDEXESECTION' then
  759. ExeOutput.Order_EndExeSection
  760. else if keyword='OBJSECTION' then
  761. ExeOutput.Order_ObjSection(para)
  762. else if keyword='ZEROS' then
  763. ExeOutput.Order_Zeros(para)
  764. else if keyword='SYMBOL' then
  765. ExeOutput.Order_Symbol(para);
  766. hp:=tstringlistitem(hp.next);
  767. end;
  768. exeoutput.Order_End;
  769. end;
  770. procedure TInternalLinker.ParseScript_CalcPos;
  771. var
  772. s,
  773. para,
  774. keyword : string;
  775. hp : TStringListItem;
  776. begin
  777. exeoutput.CalcPos_Start;
  778. hp:=tstringlistitem(linkscript.first);
  779. while assigned(hp) do
  780. begin
  781. s:=hp.str;
  782. if (s='') or (s[1]='#') then
  783. continue;
  784. keyword:=Upper(GetToken(s,' '));
  785. para:=GetToken(s,' ');
  786. if keyword='EXESECTION' then
  787. ExeOutput.CalcPos_ExeSection(para)
  788. else if keyword='ENDEXESECTION' then
  789. ExeOutput.CalcPos_EndExeSection
  790. else if keyword='HEADER' then
  791. ExeOutput.CalcPos_Header
  792. else if keyword='SYMBOLS' then
  793. ExeOutput.CalcPos_Symbols;
  794. hp:=tstringlistitem(hp.next);
  795. end;
  796. end;
  797. procedure TInternalLinker.PrintLinkerScript;
  798. var
  799. hp : TStringListItem;
  800. begin
  801. if not assigned(exemap) then
  802. exit;
  803. exemap.Add('Used linker script');
  804. exemap.Add('');
  805. hp:=tstringlistitem(linkscript.first);
  806. while assigned(hp) do
  807. begin
  808. exemap.Add(hp.str);
  809. hp:=tstringlistitem(hp.next);
  810. end;
  811. end;
  812. function TInternalLinker.MakeExecutable:boolean;
  813. label
  814. myexit;
  815. var
  816. s,s2 : string;
  817. begin
  818. MakeExecutable:=false;
  819. Message1(exec_i_linking,current_module.exefilename^);
  820. {$warning TODO Load custom linker script}
  821. DefaultLinkScript;
  822. exeoutput:=CExeOutput.Create;
  823. if (cs_link_map in aktglobalswitches) then
  824. exemap:=texemap.create(current_module.mapfilename^);
  825. PrintLinkerScript;
  826. { Load .o files and resolve symbols }
  827. ParseScript_Load;
  828. exeoutput.ResolveSymbols;
  829. { Generate symbols and code to do the importing }
  830. exeoutput.GenerateLibraryImports(ExternalLibraryList);
  831. { Fill external symbols data }
  832. exeoutput.FixupSymbols;
  833. if ErrorCount>0 then
  834. goto myexit;
  835. { Create .exe sections and add .o sections }
  836. ParseScript_Order;
  837. exeoutput.RemoveUnreferencedSections;
  838. exeoutput.MergeStabs;
  839. exeoutput.RemoveEmptySections;
  840. if ErrorCount>0 then
  841. goto myexit;
  842. { Calc positions in mem and file }
  843. ParseScript_CalcPos;
  844. exeoutput.FixupRelocations;
  845. exeoutput.PrintMemoryMap;
  846. if ErrorCount>0 then
  847. goto myexit;
  848. exeoutput.WriteExeFile(current_module.exefilename^);
  849. {$warning TODO fixed section names}
  850. status.codesize:=exeoutput.findexesection('.text').size;
  851. status.datasize:=exeoutput.findexesection('.data').size;
  852. myexit:
  853. { close map }
  854. if assigned(exemap) then
  855. begin
  856. exemap.free;
  857. exemap:=nil;
  858. end;
  859. { close exe }
  860. exeoutput.free;
  861. exeoutput:=nil;
  862. MakeExecutable:=true;
  863. end;
  864. {*****************************************************************************
  865. Init/Done
  866. *****************************************************************************}
  867. procedure InitLinker;
  868. var
  869. lk : TlinkerClass;
  870. begin
  871. if (cs_link_extern in aktglobalswitches) and
  872. assigned(target_info.linkextern) then
  873. begin
  874. lk:=TlinkerClass(target_info.linkextern);
  875. linker:=lk.Create;
  876. end
  877. else
  878. if assigned(target_info.link) then
  879. begin
  880. lk:=TLinkerClass(target_info.link);
  881. linker:=lk.Create;
  882. end
  883. else
  884. linker:=Tlinker.Create;
  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.