link.pas 15 KB

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