link.pas 15 KB

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