link.pas 28 KB

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