link.pas 16 KB

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