link.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Peter Vreman
  4. This unit handles the linker and binder calls for programs and
  5. libraries
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit link;
  20. {$i defines.inc}
  21. { Needed for LFN support in path to the executable }
  22. {$ifdef GO32V2}
  23. { define ALWAYSSHELL, obsolete as go32v2 Dos.Exec
  24. now handles LFN names and converts them to SFN PM }
  25. {$endif}
  26. interface
  27. uses
  28. cclasses,
  29. systems,
  30. fmodule;
  31. Type
  32. TLinkerInfo=record
  33. ExeCmd,
  34. DllCmd : array[1..3] of string[100];
  35. ResName : string[12];
  36. ScriptName : string[12];
  37. ExtraOptions : string;
  38. DynamicLinker : string[100];
  39. end;
  40. TLinker = class
  41. public
  42. Info : TLinkerInfo;
  43. ObjectFiles,
  44. SharedLibFiles,
  45. StaticLibFiles : TStringList;
  46. { Methods }
  47. Constructor Create;virtual;
  48. Destructor Destroy;override;
  49. procedure AddModuleFiles(hp:tmodule);
  50. Procedure AddObject(const S,unitpath : String);
  51. Procedure AddStaticLibrary(const S : String);
  52. Procedure AddSharedLibrary(S : String);
  53. Procedure AddStaticCLibrary(const S : String);
  54. Procedure AddSharedCLibrary(S : String);
  55. Function FindUtil(const s:string):String;
  56. Function DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  57. { Virtuals }
  58. procedure SetDefaultInfo;virtual;
  59. Function MakeExecutable:boolean;virtual;
  60. Function MakeSharedLibrary:boolean;virtual;
  61. Function MakeStaticLibrary:boolean;virtual;
  62. end;
  63. TLinkerClass = class of TLinker;
  64. var
  65. CLinker : array[tld] of TLinkerClass;
  66. Linker : TLinker;
  67. function FindObjectFile(s : string;const unitpath:string) : string;
  68. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  69. procedure RegisterLinker(t:tld;c:TLinkerClass);
  70. procedure InitLinker;
  71. procedure DoneLinker;
  72. Implementation
  73. uses
  74. {$ifdef Delphi}
  75. dmisc,
  76. {$else Delphi}
  77. dos,
  78. {$endif Delphi}
  79. cutils,globtype,
  80. script,globals,verbose,ppu;
  81. {*****************************************************************************
  82. Helpers
  83. *****************************************************************************}
  84. { searches an object file }
  85. function FindObjectFile(s:string;const unitpath:string) : string;
  86. var
  87. found : boolean;
  88. foundfile : string;
  89. s1 : string;
  90. begin
  91. findobjectfile:='';
  92. if s='' then
  93. exit;
  94. if pos('.',s)=0 then
  95. s:=s+target_info.objext;
  96. s1:=FixFileName(s);
  97. if FileExists(s1) then
  98. begin
  99. Findobjectfile:=ScriptFixFileName(s);
  100. exit;
  101. end;
  102. { find object file
  103. 1. specified unit path (if specified)
  104. 2. cwd
  105. 3. unit search path
  106. 4. local object path
  107. 5. global object path
  108. 6. exepath }
  109. found:=false;
  110. if unitpath<>'' then
  111. found:=FindFile(s,unitpath,foundfile);
  112. if (not found) then
  113. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  114. if (not found) then
  115. found:=UnitSearchPath.FindFile(s,foundfile);
  116. if (not found) then
  117. found:=current_module.localobjectsearchpath.FindFile(s,foundfile);
  118. if (not found) then
  119. found:=objectsearchpath.FindFile(s,foundfile);
  120. if (not found) then
  121. found:=FindFile(s,exepath,foundfile);
  122. if not(cs_link_extern in aktglobalswitches) and (not found) then
  123. Message1(exec_w_objfile_not_found,s);
  124. findobjectfile:=ScriptFixFileName(foundfile);
  125. end;
  126. { searches an library file }
  127. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  128. var
  129. found : boolean;
  130. begin
  131. findlibraryfile:=false;
  132. foundfile:=s;
  133. if s='' then
  134. exit;
  135. { add prefix 'lib' }
  136. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  137. s:=prefix+s;
  138. { add extension }
  139. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  140. s:=s+ext;
  141. if FileExists(s) then
  142. begin
  143. foundfile:=ScriptFixFileName(s);
  144. FindLibraryFile:=true;
  145. exit;
  146. end;
  147. { find libary
  148. 1. cwd
  149. 2. local libary dir
  150. 3. global libary dir
  151. 4. exe path of the compiler }
  152. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  153. if (not found) then
  154. found:=current_module.locallibrarysearchpath.FindFile(s,foundfile);
  155. if (not found) then
  156. found:=librarysearchpath.FindFile(s,foundfile);
  157. if (not found) then
  158. found:=FindFile(s,exepath,foundfile);
  159. foundfile:=ScriptFixFileName(foundfile);
  160. findlibraryfile:=found;
  161. end;
  162. {*****************************************************************************
  163. TLINKER
  164. *****************************************************************************}
  165. Constructor TLinker.Create;
  166. begin
  167. ObjectFiles:=TStringList.Create_no_double;
  168. SharedLibFiles:=TStringList.Create_no_double;
  169. StaticLibFiles:=TStringList.Create_no_double;
  170. { set generic defaults }
  171. FillChar(Info,sizeof(Info),0);
  172. Info.ResName:='link.res';
  173. Info.ScriptName:='script.res';
  174. { set the linker specific defaults }
  175. SetDefaultInfo;
  176. { Allow Parameter overrides for linker info }
  177. with Info do
  178. begin
  179. if ParaLinkOptions<>'' then
  180. ExtraOptions:=ParaLinkOptions;
  181. if ParaDynamicLinker<>'' then
  182. DynamicLinker:=ParaDynamicLinker;
  183. end;
  184. end;
  185. Destructor TLinker.Destroy;
  186. begin
  187. ObjectFiles.Free;
  188. SharedLibFiles.Free;
  189. StaticLibFiles.Free;
  190. end;
  191. Procedure TLinker.SetDefaultInfo;
  192. begin
  193. end;
  194. procedure TLinker.AddModuleFiles(hp:tmodule);
  195. var
  196. mask : longint;
  197. begin
  198. with hp do
  199. begin
  200. { link unit files }
  201. if (flags and uf_no_link)=0 then
  202. begin
  203. { create mask which unit files need linking }
  204. mask:=link_allways;
  205. { static linking ? }
  206. if (cs_link_static in aktglobalswitches) then
  207. begin
  208. if (flags and uf_static_linked)=0 then
  209. begin
  210. { if smart not avail then try static linking }
  211. if (flags and uf_smart_linked)<>0 then
  212. begin
  213. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  214. mask:=mask or link_smart;
  215. end
  216. else
  217. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  218. end
  219. else
  220. mask:=mask or link_static;
  221. end;
  222. { smart linking ? }
  223. if (cs_link_smart in aktglobalswitches) then
  224. begin
  225. if (flags and uf_smart_linked)=0 then
  226. begin
  227. { if smart not avail then try static linking }
  228. if (flags and uf_static_linked)<>0 then
  229. begin
  230. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  231. mask:=mask or link_static;
  232. end
  233. else
  234. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  235. end
  236. else
  237. mask:=mask or link_smart;
  238. end;
  239. { shared linking }
  240. if (cs_link_shared in aktglobalswitches) then
  241. begin
  242. if (flags and uf_shared_linked)=0 then
  243. begin
  244. { if shared not avail then try static linking }
  245. if (flags and uf_static_linked)<>0 then
  246. begin
  247. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  248. mask:=mask or link_static;
  249. end
  250. else
  251. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  252. end
  253. else
  254. mask:=mask or link_shared;
  255. end;
  256. { unit files }
  257. while not linkunitofiles.empty do
  258. AddObject(linkunitofiles.getusemask(mask),path^);
  259. while not linkunitstaticlibs.empty do
  260. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  261. while not linkunitsharedlibs.empty do
  262. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  263. end;
  264. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  265. mask:=link_allways;
  266. while not linkotherofiles.empty do
  267. AddObject(linkotherofiles.Getusemask(mask),path^);
  268. while not linkotherstaticlibs.empty do
  269. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  270. while not linkothersharedlibs.empty do
  271. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  272. end;
  273. end;
  274. Function TLinker.FindUtil(const s:string):string;
  275. var
  276. Found : boolean;
  277. FoundBin : string;
  278. UtilExe : string;
  279. begin
  280. if cs_link_on_target in aktglobalswitches then
  281. begin
  282. { If linking on target, don't add any path PM }
  283. FindUtil:=AddExtension(s,target_info.exeext);
  284. exit;
  285. end;
  286. UtilExe:=AddExtension(s,source_info.exeext);
  287. FoundBin:='';
  288. Found:=false;
  289. if utilsdirectory<>'' then
  290. Found:=FindFile(utilexe,utilsdirectory,Foundbin);
  291. if (not Found) then
  292. Found:=FindExe(utilexe,Foundbin);
  293. if (not Found) and not(cs_link_extern in aktglobalswitches) then
  294. begin
  295. Message1(exec_e_util_not_found,utilexe);
  296. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  297. end;
  298. if (FoundBin<>'') then
  299. Message1(exec_t_using_util,FoundBin);
  300. FindUtil:=FoundBin;
  301. end;
  302. Procedure TLinker.AddObject(const S,unitpath : String);
  303. begin
  304. ObjectFiles.Concat(FindObjectFile(s,unitpath));
  305. end;
  306. Procedure TLinker.AddSharedLibrary(S:String);
  307. begin
  308. if s='' then
  309. exit;
  310. { remove prefix 'lib' }
  311. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  312. Delete(s,1,length(target_info.sharedlibprefix));
  313. { remove extension if any }
  314. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  315. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  316. { ready to be added }
  317. SharedLibFiles.Concat(S);
  318. end;
  319. Procedure TLinker.AddStaticLibrary(const S:String);
  320. var
  321. ns : string;
  322. found : boolean;
  323. begin
  324. if s='' then
  325. exit;
  326. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  327. if not(cs_link_extern in aktglobalswitches) and (not found) then
  328. Message1(exec_w_libfile_not_found,s);
  329. StaticLibFiles.Concat(ns);
  330. end;
  331. Procedure TLinker.AddSharedCLibrary(S:String);
  332. begin
  333. if s='' then
  334. exit;
  335. { remove prefix 'lib' }
  336. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  337. Delete(s,1,length(target_info.sharedclibprefix));
  338. { remove extension if any }
  339. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  340. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  341. { ready to be added }
  342. SharedLibFiles.Concat(S);
  343. end;
  344. Procedure TLinker.AddStaticCLibrary(const S:String);
  345. var
  346. ns : string;
  347. found : boolean;
  348. begin
  349. if s='' then
  350. exit;
  351. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  352. if not(cs_link_extern in aktglobalswitches) and (not found) then
  353. Message1(exec_w_libfile_not_found,s);
  354. StaticLibFiles.Concat(ns);
  355. end;
  356. Function TLinker.DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  357. begin
  358. DoExec:=true;
  359. if not(cs_link_extern in aktglobalswitches) then
  360. begin
  361. swapvectors;
  362. {$ifdef ALWAYSSHELL}
  363. shell(command+' '+para);
  364. {$else}
  365. if useshell then
  366. shell(command+' '+para)
  367. else
  368. exec(command,para);
  369. {$endif}
  370. swapvectors;
  371. if (doserror<>0) then
  372. begin
  373. Message(exec_e_cant_call_linker);
  374. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  375. DoExec:=false;
  376. end
  377. else
  378. if (dosexitcode<>0) then
  379. begin
  380. Message(exec_e_error_while_linking);
  381. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  382. DoExec:=false;
  383. end;
  384. end;
  385. { Update asmres when externmode is set }
  386. if cs_link_extern in aktglobalswitches then
  387. begin
  388. if showinfo then
  389. begin
  390. if DLLsource then
  391. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  392. else
  393. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  394. end
  395. else
  396. AsmRes.AddLinkCommand(Command,Para,'');
  397. end;
  398. end;
  399. function TLinker.MakeExecutable:boolean;
  400. begin
  401. MakeExecutable:=false;
  402. Message(exec_e_exe_not_supported);
  403. end;
  404. Function TLinker.MakeSharedLibrary:boolean;
  405. begin
  406. MakeSharedLibrary:=false;
  407. Message(exec_e_dll_not_supported);
  408. end;
  409. Function TLinker.MakeStaticLibrary:boolean;
  410. var
  411. smartpath,
  412. cmdstr,
  413. binstr : string;
  414. success : boolean;
  415. begin
  416. MakeStaticLibrary:=false;
  417. { remove the library, to be sure that it is rewritten }
  418. RemoveFile(current_module.staticlibfilename^);
  419. { Call AR }
  420. smartpath:=current_module.outputpath^+FixPath(FixFileName(current_module.modulename^)+target_info.smartext,false);
  421. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  422. Replace(cmdstr,'$LIB',current_module.staticlibfilename^);
  423. Replace(cmdstr,'$FILES',ScriptFixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  424. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  425. { Clean up }
  426. if not(cs_asm_leave in aktglobalswitches) then
  427. if not(cs_link_extern in aktglobalswitches) then
  428. begin
  429. while not SmartLinkOFiles.Empty do
  430. RemoveFile(SmartLinkOFiles.GetFirst);
  431. RemoveDir(smartpath);
  432. end
  433. else
  434. begin
  435. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  436. AsmRes.Add('rmdir '+smartpath);
  437. end;
  438. MakeStaticLibrary:=success;
  439. end;
  440. {*****************************************************************************
  441. Init/Done
  442. *****************************************************************************}
  443. procedure RegisterLinker(t:tld;c:TLinkerClass);
  444. begin
  445. CLinker[t]:=c;
  446. end;
  447. procedure InitLinker;
  448. begin
  449. if assigned(CLinker[target_info.link]) then
  450. linker:=CLinker[target_info.link].Create
  451. else
  452. linker:=Tlinker.Create;
  453. end;
  454. procedure DoneLinker;
  455. begin
  456. if assigned(linker) then
  457. Linker.Free;
  458. end;
  459. {*****************************************************************************
  460. Initialize
  461. *****************************************************************************}
  462. const
  463. ar_gnu_ar_info : tarinfo =
  464. (
  465. id : ar_gnu_ar;
  466. arcmd : 'ar rs $LIB $FILES'
  467. );
  468. initialization
  469. RegisterAr(ar_gnu_ar_info);
  470. end.
  471. {
  472. $Log$
  473. Revision 1.24 2001-09-18 11:30:48 michael
  474. * Fixes win32 linking problems with import libraries
  475. * LINKLIB Libraries are now looked for using C file extensions
  476. * get_exepath fix
  477. Revision 1.23 2001/09/17 21:29:11 peter
  478. * merged netbsd, fpu-overflow from fixes branch
  479. Revision 1.22 2001/08/30 20:13:53 peter
  480. * rtti/init table updates
  481. * rttisym for reusable global rtti/init info
  482. * support published for interfaces
  483. Revision 1.21 2001/08/19 11:22:22 peter
  484. * palmos support from v10 merged
  485. Revision 1.20 2001/08/13 19:26:03 peter
  486. * fixed ordering of object and libraries
  487. Revision 1.19 2001/08/07 18:47:12 peter
  488. * merged netbsd start
  489. * profile for win32
  490. Revision 1.18 2001/06/28 19:46:25 peter
  491. * added override and virtual for constructors
  492. Revision 1.17 2001/06/03 15:15:31 peter
  493. * dllprt0 stub for linux shared libs
  494. * pass -init and -fini for linux shared libs
  495. * libprefix splitted into staticlibprefix and sharedlibprefix
  496. Revision 1.16 2001/04/18 22:01:54 peter
  497. * registration of targets and assemblers
  498. Revision 1.15 2001/04/13 01:22:08 peter
  499. * symtable change to classes
  500. * range check generation and errors fixed, make cycle DEBUG=1 works
  501. * memory leaks fixed
  502. Revision 1.14 2001/02/26 19:44:52 peter
  503. * merged generic m68k updates from fixes branch
  504. Revision 1.13 2001/02/20 21:41:17 peter
  505. * new fixfilename, findfile for unix. Look first for lowercase, then
  506. NormalCase and last for UPPERCASE names.
  507. Revision 1.12 2001/01/12 19:19:44 peter
  508. * fixed searching for utils
  509. Revision 1.11 2000/12/25 00:07:26 peter
  510. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  511. tlinkedlist objects)
  512. Revision 1.10 2000/11/29 00:30:31 florian
  513. * unused units removed from uses clause
  514. * some changes for widestrings
  515. Revision 1.9 2000/09/24 21:33:46 peter
  516. * message updates merges
  517. Revision 1.8 2000/09/24 15:06:18 peter
  518. * use defines.inc
  519. Revision 1.7 2000/09/16 12:22:52 peter
  520. * freebsd support merged
  521. Revision 1.6 2000/09/11 17:00:23 florian
  522. + first implementation of Netware Module support, thanks to
  523. Armin Diehl ([email protected]) for providing the patches
  524. Revision 1.5 2000/09/04 09:40:23 michael
  525. + merged Patch from peter
  526. Revision 1.4 2000/08/27 16:11:51 peter
  527. * moved some util functions from globals,cobjects to cutils
  528. * splitted files into finput,fmodule
  529. Revision 1.3 2000/07/26 13:08:19 jonas
  530. * merged from fixes branch (v_hint to v_tried changed when attempting
  531. to smart/static/shared link)
  532. Revision 1.2 2000/07/13 11:32:43 michael
  533. + removed logs
  534. }