link.pas 16 KB

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