link.pas 16 KB

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