link.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  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,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. var
  551. smartpath : TCmdStr;
  552. function GetNextFiles(const maxCmdLength : AInt; var item : TStringListItem) : string;
  553. begin
  554. result := '';
  555. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  556. result := result + ' ' + item.str;
  557. item := TStringListItem(item.next);
  558. end;
  559. end;
  560. var
  561. binstr : string;
  562. success : boolean;
  563. cmdstr, nextcmd : TCmdStr;
  564. current : TStringListItem;
  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. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  574. { create AR commands }
  575. success := true;
  576. nextcmd := cmdstr;
  577. current := TStringListItem(SmartLinkOFiles.First);
  578. repeat
  579. Replace(nextcmd,'$FILES',GetNextFiles(240 - length(nextcmd) + 6 - length(binstr) - 1, current));
  580. success:=DoExec(binstr,nextcmd,false,true);
  581. nextcmd := cmdstr;
  582. until (not assigned(current)) or (not success);
  583. { Clean up }
  584. if not(cs_asm_leave in aktglobalswitches) then
  585. if not(cs_link_extern in aktglobalswitches) then
  586. begin
  587. while not SmartLinkOFiles.Empty do
  588. RemoveFile(SmartLinkOFiles.GetFirst);
  589. RemoveDir(smartpath);
  590. end
  591. else
  592. begin
  593. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  594. AsmRes.Add('rmdir '+smartpath);
  595. end;
  596. MakeStaticLibrary:=success;
  597. end;
  598. {*****************************************************************************
  599. TINTERNALLINKER
  600. *****************************************************************************}
  601. Constructor TInternalLinker.Create;
  602. begin
  603. inherited Create;
  604. linkscript:=TStringList.Create;
  605. exemap:=nil;
  606. exeoutput:=nil;
  607. CObjInput:=TObjInput;
  608. end;
  609. Destructor TInternalLinker.Destroy;
  610. begin
  611. linkscript.free;
  612. exeoutput.free;
  613. exeoutput:=nil;
  614. inherited destroy;
  615. end;
  616. procedure TInternalLinker.Load_ReadObject(const para:string);
  617. var
  618. objdata : TObjData;
  619. objinput : TObjinput;
  620. fn : string;
  621. begin
  622. fn:=FindObjectFile(para,'',false);
  623. Comment(V_Tried,'Reading object '+fn);
  624. objinput:=CObjInput.Create;
  625. objdata:=objinput.newObjData(para);
  626. if objinput.readobjectfile(fn,objdata) then
  627. exeoutput.addobjdata(objdata);
  628. { release input object }
  629. objinput.free;
  630. end;
  631. procedure TInternalLinker.Load_ReadUnitObjects;
  632. var
  633. s : string;
  634. begin
  635. while not ObjectFiles.Empty do
  636. begin
  637. s:=ObjectFiles.GetFirst;
  638. if s<>'' then
  639. Load_ReadObject(s);
  640. end;
  641. end;
  642. procedure TInternalLinker.ParseScript_Load;
  643. var
  644. s,
  645. para,
  646. keyword : string;
  647. hp : TStringListItem;
  648. begin
  649. exeoutput.Load_Start;
  650. hp:=tstringlistitem(linkscript.first);
  651. while assigned(hp) do
  652. begin
  653. s:=hp.str;
  654. if (s='') or (s[1]='#') then
  655. continue;
  656. keyword:=Upper(GetToken(s,' '));
  657. para:=GetToken(s,' ');
  658. if keyword='SYMBOL' then
  659. ExeOutput.Load_Symbol(para)
  660. else if keyword='ENTRYNAME' then
  661. ExeOutput.Load_EntryName(para)
  662. else if keyword='READOBJECT' then
  663. Load_ReadObject(para)
  664. else if keyword='READUNITOBJECTS' then
  665. Load_ReadUnitObjects;
  666. hp:=tstringlistitem(hp.next);
  667. end;
  668. end;
  669. procedure TInternalLinker.ParseScript_Order;
  670. var
  671. s,
  672. para,
  673. keyword : string;
  674. hp : TStringListItem;
  675. begin
  676. exeoutput.Order_Start;
  677. hp:=tstringlistitem(linkscript.first);
  678. while assigned(hp) do
  679. begin
  680. s:=hp.str;
  681. if (s='') or (s[1]='#') then
  682. continue;
  683. keyword:=Upper(GetToken(s,' '));
  684. para:=GetToken(s,' ');
  685. if keyword='EXESECTION' then
  686. ExeOutput.Order_ExeSection(para)
  687. else if keyword='ENDEXESECTION' then
  688. ExeOutput.Order_EndExeSection
  689. else if keyword='OBJSECTION' then
  690. ExeOutput.Order_ObjSection(para)
  691. else if keyword='ZEROS' then
  692. ExeOutput.Order_Zeros(para)
  693. else if keyword='SYMBOL' then
  694. ExeOutput.Order_Symbol(para)
  695. else if keyword='STABS' then
  696. ExeOutput.Order_Stabs;
  697. hp:=tstringlistitem(hp.next);
  698. end;
  699. end;
  700. procedure TInternalLinker.ParseScript_CalcPos;
  701. var
  702. s,
  703. para,
  704. keyword : string;
  705. hp : TStringListItem;
  706. begin
  707. exeoutput.CalcPos_Start;
  708. hp:=tstringlistitem(linkscript.first);
  709. while assigned(hp) do
  710. begin
  711. s:=hp.str;
  712. if (s='') or (s[1]='#') then
  713. continue;
  714. keyword:=Upper(GetToken(s,' '));
  715. para:=GetToken(s,' ');
  716. if keyword='EXESECTION' then
  717. ExeOutput.CalcPos_ExeSection(para)
  718. else if keyword='ENDEXESECTION' then
  719. ExeOutput.CalcPos_EndExeSection
  720. else if keyword='HEADER' then
  721. ExeOutput.CalcPos_Header
  722. else if keyword='SYMBOLS' then
  723. ExeOutput.CalcPos_Symbols;
  724. hp:=tstringlistitem(hp.next);
  725. end;
  726. end;
  727. procedure TInternalLinker.PrintLinkerScript;
  728. var
  729. hp : TStringListItem;
  730. begin
  731. if not assigned(exemap) then
  732. exit;
  733. exemap.Add('Used linker script');
  734. exemap.Add('');
  735. hp:=tstringlistitem(linkscript.first);
  736. while assigned(hp) do
  737. begin
  738. exemap.Add(hp.str);
  739. hp:=tstringlistitem(hp.next);
  740. end;
  741. end;
  742. function TInternalLinker.MakeExecutable:boolean;
  743. label
  744. myexit;
  745. var
  746. s,s2 : string;
  747. begin
  748. MakeExecutable:=false;
  749. Message1(exec_i_linking,current_module.exefilename^);
  750. {$warning TODO Load custom linker script}
  751. DefaultLinkScript;
  752. exeoutput:=CExeOutput.Create;
  753. if (cs_link_map in aktglobalswitches) then
  754. exemap:=texemap.create(current_module.mapfilename^);
  755. PrintLinkerScript;
  756. { Load .o files and resolve symbols }
  757. ParseScript_Load;
  758. if ErrorCount>0 then
  759. goto myexit;
  760. exeoutput.ResolveSymbols;
  761. { DLL Linking }
  762. While not DLLFiles.Empty do
  763. begin
  764. s:=DLLFiles.GetFirst;
  765. if FindDLL(s,s2) then
  766. exeoutput.ResolveExternals(s2)
  767. else
  768. Comment(V_Error,'DLL not found: '+s);
  769. end;
  770. { Create .exe sections and add .o sections }
  771. ParseScript_Order;
  772. exeoutput.RemoveEmptySections;
  773. if ErrorCount>0 then
  774. goto myexit;
  775. { Calc positions in mem and file }
  776. ParseScript_CalcPos;
  777. exeoutput.FixupSymbols;
  778. exeoutput.FixupRelocations;
  779. exeoutput.PrintMemoryMap;
  780. exeoutput.WriteExeFile(current_module.exefilename^);
  781. {$warning TODO fixed section names}
  782. status.codesize:=exeoutput.findexesection('.text').size;
  783. status.datasize:=exeoutput.findexesection('.data').size;
  784. myexit:
  785. { close map }
  786. if assigned(exemap) then
  787. begin
  788. exemap.free;
  789. exemap:=nil;
  790. end;
  791. MakeExecutable:=true;
  792. end;
  793. {*****************************************************************************
  794. Init/Done
  795. *****************************************************************************}
  796. procedure InitLinker;
  797. var
  798. lk : TlinkerClass;
  799. begin
  800. if (cs_link_internal in aktglobalswitches) and
  801. assigned(target_info.link) then
  802. begin
  803. lk:=TLinkerClass(target_info.link);
  804. linker:=lk.Create;
  805. end
  806. else if assigned(target_info.linkextern) then
  807. begin
  808. lk:=TlinkerClass(target_info.linkextern);
  809. linker:=lk.Create;
  810. end
  811. else
  812. begin
  813. linker:=Tlinker.Create;
  814. end;
  815. end;
  816. procedure DoneLinker;
  817. begin
  818. if assigned(linker) then
  819. Linker.Free;
  820. end;
  821. {*****************************************************************************
  822. Initialize
  823. *****************************************************************************}
  824. const
  825. ar_gnu_ar_info : tarinfo =
  826. (
  827. id : ar_gnu_ar;
  828. arcmd : 'ar rs $LIB $FILES'
  829. );
  830. initialization
  831. RegisterAr(ar_gnu_ar_info);
  832. end.