link.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  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, obsolete as go32v2 Dos.Exec
  24. now handles LFN names and converts them to SFN PM }
  25. {$endif}
  26. interface
  27. uses
  28. cclasses,
  29. systems,
  30. fmodule;
  31. Type
  32. TLinkerInfo=record
  33. ExeCmd,
  34. DllCmd : array[1..3] of string[100];
  35. ResName : string[12];
  36. ScriptName : string[12];
  37. ExtraOptions : string;
  38. DynamicLinker : string[100];
  39. end;
  40. TLinker = class
  41. public
  42. Info : TLinkerInfo;
  43. ObjectFiles,
  44. SharedLibFiles,
  45. StaticLibFiles : TStringList;
  46. { Methods }
  47. Constructor Create;virtual;
  48. Destructor Destroy;override;
  49. procedure AddModuleFiles(hp:tmodule);
  50. Procedure AddObject(const S,unitpath : String);
  51. Procedure AddStaticLibrary(const S : String);
  52. Procedure AddSharedLibrary(S : String);
  53. Procedure AddStaticCLibrary(const S : String);
  54. Procedure AddSharedCLibrary(S : String);
  55. Function FindUtil(const s:string):String;
  56. Function DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  57. { Virtuals }
  58. procedure SetDefaultInfo;virtual;
  59. Function MakeExecutable:boolean;virtual;
  60. Function MakeSharedLibrary:boolean;virtual;
  61. Function MakeStaticLibrary:boolean;virtual;
  62. end;
  63. TLinkerClass = class of TLinker;
  64. var
  65. CLinker : array[tld] of TLinkerClass;
  66. Linker : TLinker;
  67. function FindObjectFile(s : string;const unitpath:string) : string;
  68. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  69. procedure RegisterLinker(t:tld;c:TLinkerClass);
  70. procedure InitLinker;
  71. procedure DoneLinker;
  72. Implementation
  73. uses
  74. {$ifdef Delphi}
  75. dmisc,
  76. {$else Delphi}
  77. dos,
  78. {$endif Delphi}
  79. cutils,globtype,
  80. script,globals,verbose,ppu;
  81. {*****************************************************************************
  82. Helpers
  83. *****************************************************************************}
  84. { searches an object file }
  85. function FindObjectFile(s:string;const unitpath:string) : string;
  86. var
  87. found : boolean;
  88. foundfile : string;
  89. s1 : string;
  90. begin
  91. findobjectfile:='';
  92. if s='' then
  93. exit;
  94. if pos('.',s)=0 then
  95. s:=s+target_info.objext;
  96. s1:=FixFileName(s);
  97. if FileExists(s1) then
  98. begin
  99. Findobjectfile:=ScriptFixFileName(s);
  100. exit;
  101. end;
  102. { find object file
  103. 1. specified unit path (if specified)
  104. 2. cwd
  105. 3. unit search path
  106. 4. local object path
  107. 5. global object path
  108. 6. exepath }
  109. found:=false;
  110. if unitpath<>'' then
  111. found:=FindFile(s,unitpath,foundfile);
  112. if (not found) then
  113. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  114. if (not found) then
  115. found:=UnitSearchPath.FindFile(s,foundfile);
  116. if (not found) then
  117. found:=current_module.localobjectsearchpath.FindFile(s,foundfile);
  118. if (not found) then
  119. found:=objectsearchpath.FindFile(s,foundfile);
  120. if (not found) then
  121. found:=FindFile(s,exepath,foundfile);
  122. if not(cs_link_extern in aktglobalswitches) and (not found) then
  123. Message1(exec_w_objfile_not_found,s);
  124. findobjectfile:=ScriptFixFileName(foundfile);
  125. end;
  126. { searches an library file }
  127. function FindLibraryFile(s:string;const prefix,ext:string;var foundfile : string) : boolean;
  128. var
  129. found : boolean;
  130. paths : string;
  131. begin
  132. findlibraryfile:=false;
  133. foundfile:=s;
  134. if s='' then
  135. exit;
  136. { split path from filename }
  137. paths:=SplitPath(s);
  138. s:=SplitFileName(s);
  139. { add prefix 'lib' }
  140. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  141. s:=prefix+s;
  142. { add extension }
  143. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  144. s:=s+ext;
  145. { readd the split path }
  146. s:=paths+s;
  147. if FileExists(s) then
  148. begin
  149. foundfile:=ScriptFixFileName(s);
  150. FindLibraryFile:=true;
  151. exit;
  152. end;
  153. { find libary
  154. 1. cwd
  155. 2. local libary dir
  156. 3. global libary dir
  157. 4. exe path of the compiler }
  158. found:=FindFile(s,'.'+source_info.DirSep,foundfile);
  159. if (not found) then
  160. found:=current_module.locallibrarysearchpath.FindFile(s,foundfile);
  161. if (not found) then
  162. found:=librarysearchpath.FindFile(s,foundfile);
  163. if (not found) then
  164. found:=FindFile(s,exepath,foundfile);
  165. foundfile:=ScriptFixFileName(foundfile);
  166. findlibraryfile:=found;
  167. end;
  168. {*****************************************************************************
  169. TLINKER
  170. *****************************************************************************}
  171. Constructor TLinker.Create;
  172. begin
  173. ObjectFiles:=TStringList.Create_no_double;
  174. SharedLibFiles:=TStringList.Create_no_double;
  175. StaticLibFiles:=TStringList.Create_no_double;
  176. { set generic defaults }
  177. FillChar(Info,sizeof(Info),0);
  178. Info.ResName:='link.res';
  179. Info.ScriptName:='script.res';
  180. { set the linker specific defaults }
  181. SetDefaultInfo;
  182. { Allow Parameter overrides for linker info }
  183. with Info do
  184. begin
  185. if ParaLinkOptions<>'' then
  186. ExtraOptions:=ParaLinkOptions;
  187. if ParaDynamicLinker<>'' then
  188. DynamicLinker:=ParaDynamicLinker;
  189. end;
  190. end;
  191. Destructor TLinker.Destroy;
  192. begin
  193. ObjectFiles.Free;
  194. SharedLibFiles.Free;
  195. StaticLibFiles.Free;
  196. end;
  197. Procedure TLinker.SetDefaultInfo;
  198. begin
  199. end;
  200. procedure TLinker.AddModuleFiles(hp:tmodule);
  201. var
  202. mask : longint;
  203. begin
  204. with hp do
  205. begin
  206. { link unit files }
  207. if (flags and uf_no_link)=0 then
  208. begin
  209. { create mask which unit files need linking }
  210. mask:=link_allways;
  211. { static linking ? }
  212. if (cs_link_static in aktglobalswitches) then
  213. begin
  214. if (flags and uf_static_linked)=0 then
  215. begin
  216. { if smart not avail then try static linking }
  217. if (flags and uf_smart_linked)<>0 then
  218. begin
  219. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  220. mask:=mask or link_smart;
  221. end
  222. else
  223. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  224. end
  225. else
  226. mask:=mask or link_static;
  227. end;
  228. { smart linking ? }
  229. if (cs_link_smart in aktglobalswitches) then
  230. begin
  231. if (flags and uf_smart_linked)=0 then
  232. begin
  233. { if smart not avail then try static linking }
  234. if (flags and uf_static_linked)<>0 then
  235. begin
  236. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  237. mask:=mask or link_static;
  238. end
  239. else
  240. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  241. end
  242. else
  243. mask:=mask or link_smart;
  244. end;
  245. { shared linking }
  246. if (cs_link_shared in aktglobalswitches) then
  247. begin
  248. if (flags and uf_shared_linked)=0 then
  249. begin
  250. { if shared not avail then try static linking }
  251. if (flags and uf_static_linked)<>0 then
  252. begin
  253. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  254. mask:=mask or link_static;
  255. end
  256. else
  257. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  258. end
  259. else
  260. mask:=mask or link_shared;
  261. end;
  262. { unit files }
  263. while not linkunitofiles.empty do
  264. AddObject(linkunitofiles.getusemask(mask),path^);
  265. while not linkunitstaticlibs.empty do
  266. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  267. while not linkunitsharedlibs.empty do
  268. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  269. end;
  270. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  271. mask:=link_allways;
  272. while not linkotherofiles.empty do
  273. AddObject(linkotherofiles.Getusemask(mask),path^);
  274. while not linkotherstaticlibs.empty do
  275. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  276. while not linkothersharedlibs.empty do
  277. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  278. end;
  279. end;
  280. Function TLinker.FindUtil(const s:string):string;
  281. var
  282. Found : boolean;
  283. FoundBin : string;
  284. UtilExe : string;
  285. begin
  286. if cs_link_on_target in aktglobalswitches then
  287. begin
  288. { If linking on target, don't add any path PM }
  289. FindUtil:=AddExtension(s,target_info.exeext);
  290. exit;
  291. end;
  292. UtilExe:=AddExtension(s,source_info.exeext);
  293. FoundBin:='';
  294. Found:=false;
  295. if utilsdirectory<>'' then
  296. Found:=FindFile(utilexe,utilsdirectory,Foundbin);
  297. if (not Found) then
  298. Found:=FindExe(utilexe,Foundbin);
  299. if (not Found) and not(cs_link_extern in aktglobalswitches) then
  300. begin
  301. Message1(exec_e_util_not_found,utilexe);
  302. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  303. end;
  304. if (FoundBin<>'') then
  305. Message1(exec_t_using_util,FoundBin);
  306. FindUtil:=FoundBin;
  307. end;
  308. Procedure TLinker.AddObject(const S,unitpath : String);
  309. begin
  310. ObjectFiles.Concat(FindObjectFile(s,unitpath));
  311. end;
  312. Procedure TLinker.AddSharedLibrary(S:String);
  313. begin
  314. if s='' then
  315. exit;
  316. { remove prefix 'lib' }
  317. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  318. Delete(s,1,length(target_info.sharedlibprefix));
  319. { remove extension if any }
  320. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  321. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  322. { ready to be added }
  323. SharedLibFiles.Concat(S);
  324. end;
  325. Procedure TLinker.AddStaticLibrary(const S:String);
  326. var
  327. ns : string;
  328. found : boolean;
  329. begin
  330. if s='' then
  331. exit;
  332. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  333. if not(cs_link_extern in aktglobalswitches) and (not found) then
  334. Message1(exec_w_libfile_not_found,s);
  335. StaticLibFiles.Concat(ns);
  336. end;
  337. Procedure TLinker.AddSharedCLibrary(S:String);
  338. begin
  339. if s='' then
  340. exit;
  341. { remove prefix 'lib' }
  342. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  343. Delete(s,1,length(target_info.sharedclibprefix));
  344. { remove extension if any }
  345. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  346. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  347. { ready to be added }
  348. SharedLibFiles.Concat(S);
  349. end;
  350. Procedure TLinker.AddStaticCLibrary(const S:String);
  351. var
  352. ns : string;
  353. found : boolean;
  354. begin
  355. if s='' then
  356. exit;
  357. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  358. if not(cs_link_extern in aktglobalswitches) and (not found) then
  359. Message1(exec_w_libfile_not_found,s);
  360. StaticLibFiles.Concat(ns);
  361. end;
  362. Function TLinker.DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  363. begin
  364. DoExec:=true;
  365. if not(cs_link_extern in aktglobalswitches) then
  366. begin
  367. swapvectors;
  368. {$ifdef ALWAYSSHELL}
  369. shell(command+' '+para);
  370. {$else}
  371. if useshell then
  372. shell(command+' '+para)
  373. else
  374. exec(command,para);
  375. {$endif}
  376. swapvectors;
  377. if (doserror<>0) then
  378. begin
  379. Message(exec_e_cant_call_linker);
  380. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  381. DoExec:=false;
  382. end
  383. else
  384. if (dosexitcode<>0) then
  385. begin
  386. Message(exec_e_error_while_linking);
  387. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  388. DoExec:=false;
  389. end;
  390. end;
  391. { Update asmres when externmode is set }
  392. if cs_link_extern in aktglobalswitches then
  393. begin
  394. if showinfo then
  395. begin
  396. if DLLsource then
  397. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  398. else
  399. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  400. end
  401. else
  402. AsmRes.AddLinkCommand(Command,Para,'');
  403. end;
  404. end;
  405. function TLinker.MakeExecutable:boolean;
  406. begin
  407. MakeExecutable:=false;
  408. Message(exec_e_exe_not_supported);
  409. end;
  410. Function TLinker.MakeSharedLibrary:boolean;
  411. begin
  412. MakeSharedLibrary:=false;
  413. Message(exec_e_dll_not_supported);
  414. end;
  415. Function TLinker.MakeStaticLibrary:boolean;
  416. var
  417. smartpath,
  418. cmdstr,
  419. binstr : string;
  420. success : boolean;
  421. begin
  422. MakeStaticLibrary:=false;
  423. { remove the library, to be sure that it is rewritten }
  424. RemoveFile(current_module.staticlibfilename^);
  425. { Call AR }
  426. smartpath:=current_module.outputpath^+FixPath(FixFileName(current_module.modulename^)+target_info.smartext,false);
  427. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  428. Replace(cmdstr,'$LIB',current_module.staticlibfilename^);
  429. Replace(cmdstr,'$FILES',ScriptFixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  430. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  431. { Clean up }
  432. if not(cs_asm_leave in aktglobalswitches) then
  433. if not(cs_link_extern in aktglobalswitches) then
  434. begin
  435. while not SmartLinkOFiles.Empty do
  436. RemoveFile(SmartLinkOFiles.GetFirst);
  437. RemoveDir(smartpath);
  438. end
  439. else
  440. begin
  441. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  442. AsmRes.Add('rmdir '+smartpath);
  443. end;
  444. MakeStaticLibrary:=success;
  445. end;
  446. {*****************************************************************************
  447. Init/Done
  448. *****************************************************************************}
  449. procedure RegisterLinker(t:tld;c:TLinkerClass);
  450. begin
  451. CLinker[t]:=c;
  452. end;
  453. procedure InitLinker;
  454. begin
  455. if assigned(CLinker[target_info.link]) then
  456. linker:=CLinker[target_info.link].Create
  457. else
  458. linker:=Tlinker.Create;
  459. end;
  460. procedure DoneLinker;
  461. begin
  462. if assigned(linker) then
  463. Linker.Free;
  464. end;
  465. {*****************************************************************************
  466. Initialize
  467. *****************************************************************************}
  468. const
  469. ar_gnu_ar_info : tarinfo =
  470. (
  471. id : ar_gnu_ar;
  472. arcmd : 'ar rs $LIB $FILES'
  473. );
  474. initialization
  475. RegisterAr(ar_gnu_ar_info);
  476. end.
  477. {
  478. $Log$
  479. Revision 1.25 2002-01-19 11:57:05 peter
  480. * fixed path appending for lib
  481. Revision 1.24 2001/09/18 11:30:48 michael
  482. * Fixes win32 linking problems with import libraries
  483. * LINKLIB Libraries are now looked for using C file extensions
  484. * get_exepath fix
  485. Revision 1.23 2001/09/17 21:29:11 peter
  486. * merged netbsd, fpu-overflow from fixes branch
  487. Revision 1.22 2001/08/30 20:13:53 peter
  488. * rtti/init table updates
  489. * rttisym for reusable global rtti/init info
  490. * support published for interfaces
  491. Revision 1.21 2001/08/19 11:22:22 peter
  492. * palmos support from v10 merged
  493. Revision 1.20 2001/08/13 19:26:03 peter
  494. * fixed ordering of object and libraries
  495. Revision 1.19 2001/08/07 18:47:12 peter
  496. * merged netbsd start
  497. * profile for win32
  498. Revision 1.18 2001/06/28 19:46:25 peter
  499. * added override and virtual for constructors
  500. Revision 1.17 2001/06/03 15:15:31 peter
  501. * dllprt0 stub for linux shared libs
  502. * pass -init and -fini for linux shared libs
  503. * libprefix splitted into staticlibprefix and sharedlibprefix
  504. Revision 1.16 2001/04/18 22:01:54 peter
  505. * registration of targets and assemblers
  506. Revision 1.15 2001/04/13 01:22:08 peter
  507. * symtable change to classes
  508. * range check generation and errors fixed, make cycle DEBUG=1 works
  509. * memory leaks fixed
  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. }