link.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  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. ldfound : boolean;
  226. LastBin : string;
  227. begin
  228. LastBin:='';
  229. if utilsdirectory<>'' then
  230. LastBin:=FindFile(s+source_os.exeext,utilsdirectory,ldfound)+s+source_os.exeext;
  231. if LastBin='' then
  232. LastBin:=FindExe(s,ldfound);
  233. if (not ldfound) and not(cs_link_extern in aktglobalswitches) then
  234. begin
  235. Message1(exec_w_util_not_found,s);
  236. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  237. end;
  238. if ldfound then
  239. Message1(exec_t_using_util,LastBin);
  240. FindUtil:=LastBin;
  241. end;
  242. { searches an object file }
  243. function TLinker.FindObjectFile(s:string;const unitpath:string) : string;
  244. var
  245. found : boolean;
  246. begin
  247. findobjectfile:='';
  248. if s='' then
  249. exit;
  250. if pos('.',s)=0 then
  251. s:=s+target_info.objext;
  252. s:=FixFileName(s);
  253. if FileExists(s) then
  254. begin
  255. Findobjectfile:=s;
  256. exit;
  257. end;
  258. { find object file
  259. 1. specified unit path (if specified)
  260. 2. cwd
  261. 3. unit search path
  262. 4. local object path
  263. 5. global object path
  264. 6. exepath }
  265. found:=false;
  266. if unitpath<>'' then
  267. findobjectfile:=FindFile(s,unitpath,found)+s;
  268. if (not found) then
  269. findobjectfile:=FindFile(s,'.'+DirSep,found)+s;
  270. if (not found) then
  271. findobjectfile:=UnitSearchPath.FindFile(s,found)+s;
  272. if (not found) then
  273. findobjectfile:=current_module.localobjectsearchpath.FindFile(s,found)+s;
  274. if (not found) then
  275. findobjectfile:=objectsearchpath.FindFile(s,found)+s;
  276. if (not found) then
  277. findobjectfile:=FindFile(s,exepath,found)+s;
  278. if not(cs_link_extern in aktglobalswitches) and (not found) then
  279. Message1(exec_w_objfile_not_found,s);
  280. end;
  281. { searches an library file }
  282. function TLinker.FindLibraryFile(s:string;const ext:string;var found : boolean) : string;
  283. begin
  284. found:=false;
  285. findlibraryfile:='';
  286. if s='' then
  287. exit;
  288. if pos('.',s)=0 then
  289. s:=s+ext;
  290. if FileExists(s) then
  291. begin
  292. found:=true;
  293. FindLibraryFile:=s;
  294. exit;
  295. end;
  296. { find libary
  297. 1. cwd
  298. 2. local libary dir
  299. 3. global libary dir
  300. 4. exe path of the compiler }
  301. found:=false;
  302. findlibraryfile:=FindFile(s,'.'+DirSep,found)+s;
  303. if (not found) then
  304. findlibraryfile:=current_module.locallibrarysearchpath.FindFile(s,found)+s;
  305. if (not found) then
  306. findlibraryfile:=librarysearchpath.FindFile(s,found)+s;
  307. if (not found) then
  308. findlibraryfile:=FindFile(s,exepath,found)+s;
  309. end;
  310. Procedure TLinker.AddObject(const S,unitpath : String);
  311. begin
  312. ObjectFiles.Insert(FindObjectFile(s,unitpath));
  313. end;
  314. Procedure TLinker.AddSharedLibrary(S:String);
  315. begin
  316. if s='' then
  317. exit;
  318. { remove prefix 'lib' }
  319. if Copy(s,1,length(target_os.libprefix))=target_os.libprefix then
  320. Delete(s,1,length(target_os.libprefix));
  321. { remove extension if any }
  322. if Copy(s,length(s)-length(target_os.sharedlibext)+1,length(target_os.sharedlibext))=target_os.sharedlibext then
  323. Delete(s,length(s)-length(target_os.sharedlibext)+1,length(target_os.sharedlibext)+1);
  324. { ready to be inserted }
  325. SharedLibFiles.Insert (S);
  326. end;
  327. Procedure TLinker.AddStaticLibrary(const S:String);
  328. var
  329. ns : string;
  330. found : boolean;
  331. begin
  332. if s='' then
  333. exit;
  334. ns:=FindLibraryFile(s,target_os.staticlibext,found);
  335. if not(cs_link_extern in aktglobalswitches) and (not found) then
  336. Message1(exec_w_libfile_not_found,s);
  337. StaticLibFiles.Insert(ns);
  338. end;
  339. Function TLinker.DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  340. begin
  341. DoExec:=true;
  342. if not(cs_link_extern in aktglobalswitches) then
  343. begin
  344. swapvectors;
  345. {$ifdef ALWAYSSHELL}
  346. shell(command+' '+para);
  347. {$else}
  348. if useshell then
  349. shell(command+' '+para)
  350. else
  351. exec(command,para);
  352. {$endif}
  353. swapvectors;
  354. if (doserror<>0) then
  355. begin
  356. Message(exec_w_cant_call_linker);
  357. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  358. DoExec:=false;
  359. end
  360. else
  361. if (dosexitcode<>0) then
  362. begin
  363. Message(exec_w_error_while_linking);
  364. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  365. DoExec:=false;
  366. end;
  367. end;
  368. { Update asmres when externmode is set }
  369. if cs_link_extern in aktglobalswitches then
  370. begin
  371. if showinfo then
  372. begin
  373. if DLLsource then
  374. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  375. else
  376. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  377. end
  378. else
  379. AsmRes.AddLinkCommand(Command,Para,'');
  380. end;
  381. end;
  382. function TLinker.MakeExecutable:boolean;
  383. begin
  384. MakeExecutable:=false;
  385. Message(exec_e_exe_not_supported);
  386. end;
  387. Function TLinker.MakeSharedLibrary:boolean;
  388. begin
  389. MakeSharedLibrary:=false;
  390. Message(exec_e_dll_not_supported);
  391. end;
  392. Function TLinker.MakeStaticLibrary:boolean;
  393. var
  394. smartpath,
  395. cmdstr,
  396. binstr : string;
  397. success : boolean;
  398. begin
  399. MakeStaticLibrary:=false;
  400. { remove the library, to be sure that it is rewritten }
  401. RemoveFile(current_module.staticlibfilename^);
  402. { Call AR }
  403. smartpath:=current_module.outputpath^+FixPath(FixFileName(current_module.modulename^)+target_info.smartext,false);
  404. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  405. Replace(cmdstr,'$LIB',current_module.staticlibfilename^);
  406. Replace(cmdstr,'$FILES',FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  407. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  408. { Clean up }
  409. if not(cs_asm_leave in aktglobalswitches) then
  410. if not(cs_link_extern in aktglobalswitches) then
  411. begin
  412. while not SmartLinkOFiles.Empty do
  413. RemoveFile(SmartLinkOFiles.GetFirst);
  414. RemoveDir(smartpath);
  415. end
  416. else
  417. begin
  418. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  419. AsmRes.Add('rmdir '+smartpath);
  420. end;
  421. MakeStaticLibrary:=success;
  422. end;
  423. {*****************************************************************************
  424. Init/Done
  425. *****************************************************************************}
  426. procedure InitLinker;
  427. begin
  428. case target_info.target of
  429. {$ifdef i386}
  430. {$ifndef NOTARGETLINUX}
  431. target_i386_linux :
  432. linker:=Tlinkerlinux.Create;
  433. {$endif}
  434. {$ifndef NOTARGETFreeBSD}
  435. target_i386_FreeBSD :
  436. linker:=TlinkerFreeBSD.Create;
  437. {$endif}
  438. {$ifndef NOTARGETWIN32}
  439. target_i386_Win32 :
  440. linker:=Tlinkerwin32.Create;
  441. {$endif}
  442. {$ifndef NOTARGETNETWARE}
  443. target_i386_Netware :
  444. linker:=Tlinkernetware.Create;
  445. {$endif}
  446. {$ifndef NOTARGETGO32V1}
  447. target_i386_Go32v1 :
  448. linker:=TLinkergo32v1.Create;
  449. {$endif}
  450. {$ifndef NOTARGETGO32V2}
  451. target_i386_Go32v2 :
  452. linker:=TLinkergo32v2.Create;
  453. {$endif}
  454. {$ifndef NOTARGETOS2}
  455. target_i386_os2 :
  456. linker:=TLinkeros2.Create;
  457. {$endif}
  458. {$endif i386}
  459. {$ifdef m68k}
  460. {$ifndef NOTARGETPALMOS}
  461. target_m68k_palmos:
  462. linker:=Tlinker.Create;
  463. {$endif}
  464. {$ifndef NOTARGETLINUX}
  465. target_m68k_linux :
  466. linker:=Tlinkerlinux.Create;
  467. {$endif}
  468. {$endif m68k}
  469. {$ifdef alpha}
  470. {$ifndef NOTARGETLINUX}
  471. target_alpha_linux :
  472. linker:=Tlinkerlinux.Create;
  473. {$endif}
  474. {$endif alpha}
  475. {$ifdef powerpc}
  476. {$ifndef NOTARGETLINUX}
  477. target_powerpc_linux :
  478. linker:=Tlinkerlinux.Create;
  479. {$endif}
  480. {$endif powerpc}
  481. else
  482. linker:=Tlinker.Create;
  483. end;
  484. end;
  485. procedure DoneLinker;
  486. begin
  487. if assigned(linker) then
  488. Linker.Free;
  489. end;
  490. end.
  491. {
  492. $Log$
  493. Revision 1.11 2000-12-25 00:07:26 peter
  494. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  495. tlinkedlist objects)
  496. Revision 1.10 2000/11/29 00:30:31 florian
  497. * unused units removed from uses clause
  498. * some changes for widestrings
  499. Revision 1.9 2000/09/24 21:33:46 peter
  500. * message updates merges
  501. Revision 1.8 2000/09/24 15:06:18 peter
  502. * use defines.inc
  503. Revision 1.7 2000/09/16 12:22:52 peter
  504. * freebsd support merged
  505. Revision 1.6 2000/09/11 17:00:23 florian
  506. + first implementation of Netware Module support, thanks to
  507. Armin Diehl ([email protected]) for providing the patches
  508. Revision 1.5 2000/09/04 09:40:23 michael
  509. + merged Patch from peter
  510. Revision 1.4 2000/08/27 16:11:51 peter
  511. * moved some util functions from globals,cobjects to cutils
  512. * splitted files into finput,fmodule
  513. Revision 1.3 2000/07/26 13:08:19 jonas
  514. * merged from fixes branch (v_hint to v_tried changed when attempting
  515. to smart/static/shared link)
  516. Revision 1.2 2000/07/13 11:32:43 michael
  517. + removed logs
  518. }