link.pas 16 KB

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