link.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  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,files;
  26. Type
  27. TLinkerInfo=record
  28. ExeCmd,
  29. DllCmd : array[1..3] of string[80];
  30. ResName : string[12];
  31. ExtraOptions : string;
  32. DynamicLinker : string[80];
  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) : string;
  46. function FindLibraryFile(s:string;const ext:string;var found : boolean) : string;
  47. Procedure AddObject(const S : 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. globtype,systems,
  70. script,globals,verbose,ppu
  71. {$ifdef i386}
  72. {$ifndef NOTARGETLINUX}
  73. ,t_linux
  74. {$endif}
  75. {$ifndef NOTARGETOS2}
  76. ,t_os2
  77. {$endif}
  78. {$ifndef NOTARGETWIN32}
  79. ,t_win32
  80. {$endif}
  81. {$ifndef NOTARGETGO32V1}
  82. ,t_go32v1
  83. {$endif}
  84. {$ifndef NOTARGETGO32V2}
  85. ,t_go32v2
  86. {$endif}
  87. {$endif}
  88. {$ifdef m68k}
  89. {$ifndef NOTARGETLINUX}
  90. ,t_linux
  91. {$endif}
  92. {$endif}
  93. {$ifdef powerpc}
  94. {$ifndef NOTARGETLINUX}
  95. ,t_linux
  96. {$endif}
  97. {$endif}
  98. {$ifdef alpha}
  99. {$ifndef NOTARGETLINUX}
  100. ,t_linux
  101. {$endif}
  102. {$endif}
  103. ,gendef
  104. ;
  105. {*****************************************************************************
  106. TLINKER
  107. *****************************************************************************}
  108. Constructor TLinker.Init;
  109. begin
  110. ObjectFiles.Init_no_double;
  111. SharedLibFiles.Init_no_double;
  112. StaticLibFiles.Init_no_double;
  113. { set generic defaults }
  114. FillChar(Info,sizeof(Info),0);
  115. Info.ResName:='link.res';
  116. { set the linker specific defaults }
  117. SetDefaultInfo;
  118. { Allow Parameter overrides for linker info }
  119. with Info do
  120. begin
  121. if ParaLinkOptions<>'' then
  122. ExtraOptions:=ParaLinkOptions;
  123. if ParaDynamicLinker<>'' then
  124. DynamicLinker:=ParaDynamicLinker;
  125. end;
  126. end;
  127. Destructor TLinker.Done;
  128. begin
  129. ObjectFiles.Done;
  130. SharedLibFiles.Done;
  131. StaticLibFiles.Done;
  132. end;
  133. Procedure TLinker.SetDefaultInfo;
  134. begin
  135. end;
  136. procedure TLinker.AddModuleFiles(hp:pmodule);
  137. var
  138. mask : longint;
  139. begin
  140. with hp^ do
  141. begin
  142. { link unit files }
  143. if (flags and uf_no_link)=0 then
  144. begin
  145. { create mask which unit files need linking }
  146. mask:=link_allways;
  147. { static linking ? }
  148. if (cs_link_static in aktglobalswitches) then
  149. begin
  150. if (flags and uf_static_linked)=0 then
  151. begin
  152. { if smart not avail then try static linking }
  153. if (flags and uf_static_linked)<>0 then
  154. begin
  155. Comment(V_Hint,'unit '+modulename^+' can''t be static linked, switching to smart linking');
  156. mask:=mask or link_smart;
  157. end
  158. else
  159. Comment(V_Error,'unit '+modulename^+' can''t be smart or static linked');
  160. end
  161. else
  162. mask:=mask or link_static;
  163. end;
  164. { smart linking ? }
  165. if (cs_link_smart in aktglobalswitches) then
  166. begin
  167. if (flags and uf_smart_linked)=0 then
  168. begin
  169. { if smart not avail then try static linking }
  170. if (flags and uf_static_linked)<>0 then
  171. begin
  172. Comment(V_Hint,'unit '+modulename^+' can''t be smart linked, switching to static linking');
  173. mask:=mask or link_static;
  174. end
  175. else
  176. Comment(V_Error,'unit '+modulename^+' can''t be smart or static linked');
  177. end
  178. else
  179. mask:=mask or link_smart;
  180. end;
  181. { shared linking }
  182. if (cs_link_shared in aktglobalswitches) then
  183. begin
  184. if (flags and uf_shared_linked)=0 then
  185. begin
  186. { if shared not avail then try static linking }
  187. if (flags and uf_static_linked)<>0 then
  188. begin
  189. Comment(V_Hint,'unit '+modulename^+' can''t be shared linked, switching to static linking');
  190. mask:=mask or link_static;
  191. end
  192. else
  193. Comment(V_Error,'unit '+modulename^+' can''t be shared or static linked');
  194. end
  195. else
  196. mask:=mask or link_shared;
  197. end;
  198. { unit files }
  199. while not linkunitofiles.empty do
  200. AddObject(linkunitofiles.getusemask(mask));
  201. while not linkunitstaticlibs.empty do
  202. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  203. while not linkunitsharedlibs.empty do
  204. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  205. end;
  206. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  207. mask:=link_allways;
  208. while not linkotherofiles.empty do
  209. AddObject(linkotherofiles.Getusemask(mask));
  210. while not linkotherstaticlibs.empty do
  211. AddStaticLibrary(linkotherstaticlibs.Getusemask(mask));
  212. while not linkothersharedlibs.empty do
  213. AddSharedLibrary(linkothersharedlibs.Getusemask(mask));
  214. end;
  215. end;
  216. Function TLinker.FindUtil(const s:string):string;
  217. var
  218. ldfound : boolean;
  219. LastBin : string;
  220. begin
  221. LastBin:='';
  222. if utilsdirectory<>'' then
  223. LastBin:=FindFile(s+source_os.exeext,utilsdirectory,ldfound)+s+source_os.exeext;
  224. if LastBin='' then
  225. LastBin:=FindExe(s,ldfound);
  226. if (not ldfound) and not(cs_link_extern in aktglobalswitches) then
  227. begin
  228. Message1(exec_w_util_not_found,s);
  229. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  230. end;
  231. if ldfound then
  232. Message1(exec_t_using_util,LastBin);
  233. FindUtil:=LastBin;
  234. end;
  235. { searches an object file }
  236. function TLinker.FindObjectFile(s:string) : string;
  237. var
  238. found : boolean;
  239. begin
  240. findobjectfile:='';
  241. if s='' then
  242. exit;
  243. if pos('.',s)=0 then
  244. s:=s+target_info.objext;
  245. s:=FixFileName(s);
  246. if FileExists(s) then
  247. begin
  248. Findobjectfile:=s;
  249. exit;
  250. end;
  251. { find object file
  252. 1. cwd
  253. 2. unit search path
  254. 3. local object path
  255. 4. global object path
  256. 5. exepath }
  257. found:=false;
  258. findobjectfile:=FindFile(s,'.'+DirSep,found)+s;
  259. if (not found) then
  260. findobjectfile:=UnitSearchPath.FindFile(s,found)+s;
  261. if (not found) then
  262. findobjectfile:=current_module^.localobjectsearchpath.FindFile(s,found)+s;
  263. if (not found) then
  264. findobjectfile:=objectsearchpath.FindFile(s,found)+s;
  265. if (not found) then
  266. findobjectfile:=FindFile(s,exepath,found)+s;
  267. if not(cs_link_extern in aktglobalswitches) and (not found) then
  268. Message1(exec_w_objfile_not_found,s);
  269. end;
  270. { searches an library file }
  271. function TLinker.FindLibraryFile(s:string;const ext:string;var found : boolean) : string;
  272. begin
  273. found:=false;
  274. findlibraryfile:='';
  275. if s='' then
  276. exit;
  277. if pos('.',s)=0 then
  278. s:=s+ext;
  279. if FileExists(s) then
  280. begin
  281. found:=true;
  282. FindLibraryFile:=s;
  283. exit;
  284. end;
  285. { find libary
  286. 1. cwd
  287. 2. local libary dir
  288. 3. global libary dir
  289. 4. exe path of the compiler }
  290. found:=false;
  291. findlibraryfile:=FindFile(s,'.'+DirSep,found)+s;
  292. if (not found) then
  293. findlibraryfile:=current_module^.locallibrarysearchpath.FindFile(s,found)+s;
  294. if (not found) then
  295. findlibraryfile:=librarysearchpath.FindFile(s,found)+s;
  296. if (not found) then
  297. findlibraryfile:=FindFile(s,exepath,found)+s;
  298. end;
  299. Procedure TLinker.AddObject(const S : String);
  300. begin
  301. ObjectFiles.Insert(FindObjectFile(s));
  302. end;
  303. Procedure TLinker.AddSharedLibrary(S:String);
  304. begin
  305. { remove prefix 'lib' }
  306. if Copy(s,1,length(target_os.libprefix))=target_os.libprefix then
  307. Delete(s,1,length(target_os.libprefix));
  308. { remove extension if any }
  309. if Copy(s,length(s)-length(target_os.sharedlibext)+1,length(target_os.sharedlibext))=target_os.sharedlibext then
  310. Delete(s,length(s)-length(target_os.sharedlibext)+1,length(target_os.sharedlibext)+1);
  311. { ready to be inserted }
  312. SharedLibFiles.Insert (S);
  313. end;
  314. Procedure TLinker.AddStaticLibrary(const S:String);
  315. var
  316. ns : string;
  317. found : boolean;
  318. begin
  319. ns:=FindLibraryFile(s,target_os.staticlibext,found);
  320. if not(cs_link_extern in aktglobalswitches) and (not found) then
  321. Message1(exec_w_libfile_not_found,s);
  322. StaticLibFiles.Insert(ns);
  323. end;
  324. Function TLinker.DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  325. begin
  326. DoExec:=true;
  327. if not(cs_link_extern in aktglobalswitches) then
  328. begin
  329. swapvectors;
  330. {$ifdef ALWAYSSHELL}
  331. shell(command+' '+para);
  332. {$else}
  333. if useshell then
  334. shell(command+' '+para)
  335. else
  336. exec(command,para);
  337. {$endif}
  338. swapvectors;
  339. if (doserror<>0) then
  340. begin
  341. Message(exec_w_cant_call_linker);
  342. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  343. DoExec:=false;
  344. end
  345. else
  346. if (dosexitcode<>0) then
  347. begin
  348. Message(exec_w_error_while_linking);
  349. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  350. DoExec:=false;
  351. end;
  352. end;
  353. { Update asmres when externmode is set }
  354. if cs_link_extern in aktglobalswitches then
  355. begin
  356. if showinfo then
  357. begin
  358. if DLLsource then
  359. AsmRes.AddLinkCommand(Command,Para,current_module^.sharedlibfilename^)
  360. else
  361. AsmRes.AddLinkCommand(Command,Para,current_module^.exefilename^);
  362. end
  363. else
  364. AsmRes.AddLinkCommand(Command,Para,'');
  365. end;
  366. end;
  367. function TLinker.MakeExecutable:boolean;
  368. begin
  369. MakeExecutable:=false;
  370. Message(exec_e_exe_not_supported);
  371. end;
  372. Function TLinker.MakeSharedLibrary:boolean;
  373. begin
  374. MakeSharedLibrary:=false;
  375. Message(exec_e_dll_not_supported);
  376. end;
  377. Function TLinker.MakeStaticLibrary:boolean;
  378. var
  379. smartpath,
  380. cmdstr,
  381. binstr : string;
  382. success : boolean;
  383. begin
  384. MakeStaticLibrary:=false;
  385. { remove the library, to be sure that it is rewritten }
  386. RemoveFile(current_module^.staticlibfilename^);
  387. { Call AR }
  388. smartpath:=current_module^.outputpath^+FixPath(FixFileName(current_module^.modulename^)+target_info.smartext,false);
  389. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  390. Replace(cmdstr,'$LIB',current_module^.staticlibfilename^);
  391. Replace(cmdstr,'$FILES',FixFileName(smartpath+current_module^.asmprefix^+'*'+target_info.objext));
  392. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  393. { Clean up }
  394. if not(cs_asm_leave in aktglobalswitches) then
  395. if not(cs_link_extern in aktglobalswitches) then
  396. begin
  397. while not SmartLinkOFiles.Empty do
  398. RemoveFile(SmartLinkOFiles.Get);
  399. RemoveDir(smartpath);
  400. end
  401. else
  402. begin
  403. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module^.asmprefix^+'*'+target_info.objext));
  404. AsmRes.Add('rmdir '+smartpath);
  405. end;
  406. MakeStaticLibrary:=success;
  407. end;
  408. {*****************************************************************************
  409. Init/Done
  410. *****************************************************************************}
  411. procedure InitLinker;
  412. begin
  413. case target_info.target of
  414. {$ifdef i386}
  415. {$ifndef NOTARGETLINUX}
  416. target_i386_linux :
  417. linker:=new(plinkerlinux,Init);
  418. {$endif}
  419. {$ifndef NOTARGETWIN32}
  420. target_i386_Win32 :
  421. linker:=new(plinkerwin32,Init);
  422. {$endif}
  423. {$ifndef NOTARGETGO32V1}
  424. target_i386_Go32v1 :
  425. linker:=new(plinkergo32v1,Init);
  426. {$endif}
  427. {$ifndef NOTARGETGO32V2}
  428. target_i386_Go32v2 :
  429. linker:=new(plinkergo32v2,Init);
  430. {$endif}
  431. {$ifndef NOTARGETOS2}
  432. target_i386_os2 :
  433. linker:=new(plinkeros2,Init);
  434. {$endif}
  435. {$endif i386}
  436. {$ifdef m68k}
  437. {$ifndef NOTARGETPALMOS}
  438. target_m68k_palmos:
  439. linker:=new(plinker,Init);
  440. {$endif}
  441. {$ifndef NOTARGETLINUX}
  442. target_m68k_linux :
  443. linker:=new(plinkerlinux,Init);
  444. {$endif}
  445. {$endif m68k}
  446. {$ifdef alpha}
  447. {$ifndef NOTARGETLINUX}
  448. target_alpha_linux :
  449. linker:=new(plinkerlinux,Init);
  450. {$endif}
  451. {$endif alpha}
  452. {$ifdef powerpc}
  453. {$ifndef NOTARGETLINUX}
  454. target_powerpc_linux :
  455. linker:=new(plinkerlinux,Init);
  456. {$endif}
  457. {$endif powerpc}
  458. else
  459. linker:=new(plinker,Init);
  460. end;
  461. end;
  462. procedure DoneLinker;
  463. begin
  464. if assigned(linker) then
  465. dispose(linker,done);
  466. end;
  467. end.
  468. {
  469. $Log$
  470. Revision 1.87 2000-05-03 16:11:57 peter
  471. * also allow smartlinking for main programs
  472. Revision 1.86 2000/04/14 11:16:10 pierre
  473. * partial linklib change
  474. I could not use Pavel's code because it broke the current way
  475. linklib is used, which is messy :(
  476. + add postw32 call if external linking on win32
  477. Revision 1.85 2000/02/28 17:23:57 daniel
  478. * Current work of symtable integration committed. The symtable can be
  479. activated by defining 'newst', but doesn't compile yet. Changes in type
  480. checking and oop are completed. What is left is to write a new
  481. symtablestack and adapt the parser to use it.
  482. Revision 1.84 2000/02/24 18:41:39 peter
  483. * removed warnings/notes
  484. Revision 1.83 2000/02/09 13:22:54 peter
  485. * log truncated
  486. Revision 1.82 2000/01/14 14:40:37 pierre
  487. * use ./ instead of . to look into startup dir
  488. Revision 1.81 2000/01/12 10:38:18 peter
  489. * smartlinking fixes for binary writer
  490. * release alignreg code and moved instruction writing align to cpuasm,
  491. but it doesn't use the specified register yet
  492. Revision 1.80 2000/01/11 09:52:06 peter
  493. * fixed placing of .sl directories
  494. * use -b again for base-file selection
  495. * fixed group writing for linux with smartlinking
  496. Revision 1.79 2000/01/07 01:14:27 peter
  497. * updated copyright to 2000
  498. Revision 1.78 1999/11/22 22:22:30 pierre
  499. * Give better info in script
  500. Revision 1.77 1999/11/12 11:03:50 peter
  501. * searchpaths changed to stringqueue object
  502. Revision 1.76 1999/11/06 14:34:21 peter
  503. * truncated log to 20 revs
  504. Revision 1.75 1999/10/26 12:25:04 peter
  505. * fixed os2 linker
  506. Revision 1.74 1999/10/21 14:29:34 peter
  507. * redesigned linker object
  508. + library support for linux (only procedures can be exported)
  509. Revision 1.72 1999/09/16 23:05:52 florian
  510. * m68k compiler is again compilable (only gas writer, no assembler reader)
  511. Revision 1.71 1999/09/16 11:34:56 pierre
  512. * typo correction
  513. Revision 1.70 1999/09/15 22:09:16 florian
  514. + rtti is now automatically generated for published classes, i.e.
  515. they are handled like an implicit property
  516. Revision 1.69 1999/09/15 20:24:56 daniel
  517. + Dw switch now does something.
  518. Revision 1.68 1999/08/18 17:05:53 florian
  519. + implemented initilizing of data for the new code generator
  520. so it should compile now simple programs
  521. Revision 1.67 1999/08/16 15:35:23 pierre
  522. * fix for DLL relocation problems
  523. * external bss vars had wrong stabs for pecoff
  524. + -WB11000000 to specify default image base, allows to
  525. load several DLLs with debugging info included
  526. (relocatable DLL are stripped because the relocation
  527. of the .Stab section is misplaced by ldw)
  528. Revision 1.66 1999/08/11 17:26:34 peter
  529. * tlinker object is now inherited for win32 and dos
  530. * postprocessexecutable is now a method of tlinker
  531. Revision 1.65 1999/08/10 12:51:16 pierre
  532. * bind_win32_dll removed (Relocsection used instead)
  533. * now relocsection is true by default ! (needs dlltool
  534. for DLL generation)
  535. Revision 1.64 1999/07/30 23:19:45 peter
  536. * fixed placing of dynamiclinker in link.res (should be the last after
  537. all other libraries)
  538. Revision 1.63 1999/07/29 01:31:39 peter
  539. * fixed shared library linking for glibc2 systems
  540. Revision 1.62 1999/07/27 11:05:51 peter
  541. * glibc 2.1.2 support
  542. }