link.pas 15 KB

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