link.pas 18 KB

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