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