link.pas 15 KB

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