link.pas 15 KB

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