link.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. {
  2. $Id$
  3. Copyright (c) 1998 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. uses cobjects,files;
  22. Type
  23. TLinker = Object
  24. Glibc2,
  25. LinkToC, { Should we link to the C libs? }
  26. Strip : Boolean; { Strip symbols ? }
  27. ObjectFiles,
  28. SharedLibFiles,
  29. StaticLibFiles : TStringContainer;
  30. LibrarySearchPath, { Search path for libraries }
  31. LinkOptions : string; { Additional options to the linker }
  32. DynamicLinker : String[80]; { What Dynamic linker ? }
  33. LinkResName : String[32]; { Name of response file }
  34. { Methods }
  35. Constructor Init;
  36. Destructor Done;
  37. procedure AddModuleFiles(hp:pmodule);
  38. function FindObjectFile(s : string) : string;
  39. function FindLibraryFile(s:string;const ext:string) : string;
  40. Procedure AddObject(const S : String);
  41. Procedure AddStaticLibrary(const S : String);
  42. Procedure AddSharedLibrary(S : String);
  43. Function FindLinker:String; { Find linker, sets Name }
  44. Function DoExec(const command,para:string;info,useshell:boolean):boolean;
  45. Function WriteResponseFile:Boolean;
  46. Function MakeExecutable:boolean;
  47. Procedure MakeStaticLibrary(filescnt:longint);
  48. Procedure MakeSharedLibrary;
  49. end;
  50. PLinker=^TLinker;
  51. Var
  52. Linker : TLinker;
  53. Implementation
  54. uses
  55. Script,globals,systems,verbose
  56. {$ifdef i386}
  57. ,win_targ
  58. {$endif}
  59. {$ifdef linux}
  60. ,linux
  61. {$endif}
  62. ,dos
  63. ;
  64. {$ifndef linux}
  65. Procedure Shell(command:string);
  66. { This is already defined in the linux.ppu for linux, need for the *
  67. expansion under linux }
  68. var
  69. comspec : string;
  70. begin
  71. comspec:=getenv('COMSPEC');
  72. Exec(comspec,' /C '+command);
  73. end;
  74. {$endif}
  75. Constructor TLinker.Init;
  76. begin
  77. ObjectFiles.Init;
  78. SharedLibFiles.Init;
  79. StaticLibFiles.Init;
  80. ObjectFiles.Doubles:=False;
  81. SharedLibFiles.Doubles:=False;
  82. StaticLibFiles.Doubles:=False;
  83. LinkToC:=False;
  84. Glibc2:=false;
  85. Strip:=false;
  86. LinkOptions:='';
  87. {$ifdef linux}
  88. { first try glibc2 }
  89. DynamicLinker:='/lib/ld-linux.so.2';
  90. if FileExists(DynamicLinker) then
  91. Glibc2:=true
  92. else
  93. DynamicLinker:='/lib/ld-linux.so.1';
  94. LibrarySearchPath:='/lib;/usr/lib';
  95. {$else}
  96. DynamicLinker:='';
  97. LibrarySearchPath:='';
  98. {$endif}
  99. LinkResName:='link.res';
  100. end;
  101. Destructor TLinker.Done;
  102. begin
  103. ObjectFiles.Done;
  104. SharedLibFiles.Done;
  105. StaticLibFiles.Done;
  106. end;
  107. procedure TLinker.AddModuleFiles(hp:pmodule);
  108. begin
  109. with hp^ do
  110. begin
  111. while not linkofiles.empty do
  112. AddObject(linkofiles.Get);
  113. while not linksharedlibs.empty do
  114. AddSharedLibrary(linksharedlibs.Get);
  115. while not linkstaticlibs.empty do
  116. AddStaticLibrary(linkstaticlibs.Get);
  117. end;
  118. end;
  119. var
  120. LastLDBin : string;
  121. Function TLinker.FindLinker:string;
  122. var
  123. ldfound : boolean;
  124. begin
  125. if LastLDBin='' then
  126. begin
  127. if utilsdirectory<>'' then
  128. begin
  129. LastLDBin:=Search(target_link.linkbin+source_os.exeext,
  130. utilsdirectory,ldfound)+target_link.linkbin+source_os.exeext;
  131. end
  132. else
  133. LastLDBin:=FindExe(target_link.linkbin,ldfound);
  134. if (not ldfound) and not(cs_link_extern in aktglobalswitches) then
  135. begin
  136. Message1(exec_w_linker_not_found,LastLDBin);
  137. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  138. end;
  139. if ldfound then
  140. Message1(exec_t_using_linker,LastLDBin);
  141. end;
  142. FindLinker:=LastLDBin;
  143. end;
  144. { searches an object file }
  145. function TLinker.FindObjectFile(s:string) : string;
  146. var
  147. found : boolean;
  148. begin
  149. if pos('.',s)=0 then
  150. s:=s+target_info.objext;
  151. s:=FixFileName(s);
  152. if FileExists(s) then
  153. begin
  154. Findobjectfile:=s;
  155. exit;
  156. end;
  157. findobjectfile:=search(s,'.;'+unitsearchpath+';'+exepath,found)+s;
  158. if not(cs_link_extern in aktglobalswitches) and (not found) then
  159. Message1(exec_w_objfile_not_found,s);
  160. end;
  161. { searches an library file }
  162. function TLinker.FindLibraryFile(s:string;const ext:string) : string;
  163. var
  164. found : boolean;
  165. begin
  166. if pos('.',s)=0 then
  167. s:=s+ext;
  168. if FileExists(s) then
  169. begin
  170. FindLibraryFile:=s;
  171. exit;
  172. end;
  173. findlibraryfile:=search(s,'.;'+librarysearchpath+';'+exepath,found)+s;
  174. if not(cs_link_extern in aktglobalswitches) and (not found) then
  175. Message1(exec_w_libfile_not_found,s);
  176. end;
  177. Procedure TLinker.AddObject(const S : String);
  178. begin
  179. ObjectFiles.Insert(FindObjectFile(s));
  180. end;
  181. Procedure TLinker.AddSharedLibrary(S:String);
  182. begin
  183. { remove prefix 'lib' }
  184. if Copy(s,1,length(target_os.libprefix))=target_os.libprefix then
  185. Delete(s,1,length(target_os.libprefix));
  186. { remove extension if any }
  187. if Copy(s,length(s)-length(target_os.sharedlibext)+1,length(target_os.sharedlibext))=target_os.sharedlibext then
  188. Delete(s,length(s)-length(target_os.sharedlibext)+1,length(target_os.sharedlibext)+1);
  189. { ready to be inserted }
  190. SharedLibFiles.Insert (S);
  191. end;
  192. Procedure TLinker.AddStaticLibrary(const S:String);
  193. begin
  194. StaticLibFiles.Insert(FindLibraryFile(s,target_os.staticlibext));
  195. end;
  196. Function TLinker.DoExec(const command,para:string;info,useshell:boolean):boolean;
  197. begin
  198. DoExec:=true;
  199. if not(cs_link_extern in aktglobalswitches) then
  200. begin
  201. swapvectors;
  202. if useshell then
  203. shell(command+' '+para)
  204. else
  205. exec(command,para);
  206. swapvectors;
  207. if (doserror<>0) then
  208. begin
  209. Message(exec_w_cant_call_linker);
  210. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  211. DoExec:=false;
  212. end
  213. else
  214. if (dosexitcode<>0) then
  215. begin
  216. Message(exec_w_error_while_linking);
  217. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  218. DoExec:=false;
  219. end;
  220. end;
  221. { Update asmres when externmode is set }
  222. if cs_link_extern in aktglobalswitches then
  223. begin
  224. if info then
  225. AsmRes.AddLinkCommand(Command,Para,current_module^.exefilename^)
  226. else
  227. AsmRes.AddLinkCommand(Command,Para,'');
  228. end;
  229. end;
  230. Function TLinker.WriteResponseFile : Boolean;
  231. Var
  232. LinkResponse : Text;
  233. i : longint;
  234. prtobj,s,s2 : string;
  235. found,
  236. linklibc : boolean;
  237. procedure WriteRes(const s:string);
  238. begin
  239. if s<>'' then
  240. WriteLn(Linkresponse,s);
  241. end;
  242. begin
  243. WriteResponseFile:=False;
  244. { set special options for some targets }
  245. linklibc:=false;
  246. prtobj:='prt0';
  247. case target_info.target of
  248. target_m68k_Palmos,
  249. target_i386_Win32 :
  250. begin
  251. prtobj:='';
  252. end;
  253. target_m68k_linux,
  254. target_i386_linux :
  255. begin
  256. linklibc:=SharedLibFiles.Find('c');
  257. if cs_profile in aktmoduleswitches then
  258. begin
  259. prtobj:='gprt0';
  260. if not glibc2 then
  261. AddSharedLibrary('gmon');
  262. AddSharedLibrary('c');
  263. linklibc:=true;
  264. end
  265. else
  266. begin
  267. if linklibc then
  268. prtobj:='cprt0';
  269. end;
  270. end;
  271. end;
  272. { Fix command line options }
  273. If not SharedLibFiles.Empty then
  274. LinkOptions:='-dynamic-linker='+DynamicLinker+' '+LinkOptions;
  275. if Strip and not(cs_debuginfo in aktmoduleswitches) then
  276. LinkOptions:=LinkOptions+target_link.stripopt;
  277. { Open linkresponse and write header }
  278. assign(linkresponse,inputdir+LinkResName);
  279. {$I-}
  280. rewrite(linkresponse);
  281. {$I+}
  282. if ioresult<>0 then
  283. exit;
  284. { Write library searchpath }
  285. S2:=LibrarySearchPath;
  286. Repeat
  287. i:=Pos(';',S2);
  288. If i=0 then
  289. i:=255;
  290. S:=Copy(S2,1,i-1);
  291. If S<>'' then
  292. WriteRes(target_link.libpathprefix+s+target_link.libpathsuffix);
  293. Delete (S2,1,i);
  294. until S2='';
  295. WriteRes(target_link.inputstart);
  296. { add objectfiles, start with prt0 always }
  297. if prtobj<>'' then
  298. WriteRes(FindObjectFile(prtobj));
  299. if linklibc then
  300. begin
  301. WriteRes(search('crti.o',librarysearchpath,found)+'crti.o');
  302. WriteRes(search('crtbegin.o',librarysearchpath,found)+'crtbegin.o');
  303. end;
  304. while not ObjectFiles.Empty do
  305. begin
  306. s:=ObjectFiles.Get;
  307. if s<>'' then
  308. WriteRes(s);
  309. end;
  310. if linklibc then
  311. begin
  312. WriteRes(search('crtend.o',librarysearchpath,found)+'crtend.o');
  313. WriteRes(search('crtn.o',librarysearchpath,found)+'crtn.o');
  314. end;
  315. { Write sharedlibraries like -l<lib> }
  316. While not SharedLibFiles.Empty do
  317. begin
  318. S:=SharedLibFiles.Get;
  319. i:=Pos(target_os.sharedlibext,S);
  320. if i>0 then
  321. Delete(S,i,255);
  322. WriteRes(target_link.libprefix+s);
  323. end;
  324. WriteRes(target_link.inputend);
  325. { Write staticlibraries }
  326. if not StaticLibFiles.Empty then
  327. begin
  328. WriteRes(target_link.GroupStart);
  329. While not StaticLibFiles.Empty do
  330. begin
  331. S:=StaticLibFiles.Get;
  332. WriteRes(s)
  333. end;
  334. WriteRes(target_link.GroupEnd);
  335. end;
  336. { Close response }
  337. close(linkresponse);
  338. WriteResponseFile:=True;
  339. end;
  340. function TLinker.MakeExecutable:boolean;
  341. var
  342. bindbin : string[80];
  343. bindfound : boolean;
  344. s : string;
  345. success : boolean;
  346. begin
  347. {$ifdef linux}
  348. if LinkToC then
  349. begin
  350. AddObject('/usr/lib/crt0.o');
  351. AddObject('lprt');
  352. AddStaticLibrary('libc.a');
  353. AddStaticLibrary('libgcc.a');
  354. end;
  355. {$endif Linux}
  356. { Write used files and libraries }
  357. WriteResponseFile;
  358. { Call linker }
  359. if not(cs_link_extern in aktglobalswitches) then
  360. Message1(exec_i_linking,current_module^.exefilename^);
  361. s:=target_link.linkcmd;
  362. Replace(s,'$EXE',current_module^.exefilename^);
  363. Replace(s,'$OPT',LinkOptions);
  364. Replace(s,'$RES',inputdir+LinkResName);
  365. success:=DoExec(FindLinker,s,true,false);
  366. {Bind}
  367. if target_link.bindbin<>'' then
  368. begin
  369. s:=target_link.bindcmd;
  370. Replace(s,'$EXE',current_module^.exefilename^);
  371. {Size of the heap when an EMX program runs in OS/2.}
  372. Replace(s,'$HEAPMB',tostr((maxheapsize+1048575) shr 20));
  373. {Size of the stack when an EMX program runs in OS/2.}
  374. Replace(s,'$STACKKB',tostr((stacksize+1023) shr 10));
  375. {When an EMX program runs in DOS, the heap and stack share the
  376. same memory pool. The heap grows upwards, the stack grows downwards.}
  377. Replace(s,'$DOSHEAPKB',tostr((stacksize+maxheapsize+1023) shr 10));
  378. if utilsdirectory<>'' then
  379. begin
  380. bindbin:=Search(target_link.bindbin+source_os.exeext,
  381. utilsdirectory,bindfound)+target_link.bindbin+source_os.exeext;
  382. end
  383. else
  384. bindbin:=FindExe(target_link.bindbin,bindfound);
  385. if (not bindfound) and not (cs_link_extern in aktglobalswitches) then
  386. begin
  387. Message1(exec_w_binder_not_found,bindbin);
  388. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  389. end;
  390. DoExec(bindbin,s,false,false);
  391. end;
  392. { Post processor executable }
  393. {$ifdef i386}
  394. if target_info.target=target_i386_Win32 then
  395. win_targ.postprocessexecutable;
  396. {$endif}
  397. {Remove ReponseFile}
  398. if (success) and not(cs_link_extern in aktglobalswitches) then
  399. RemoveFile(LinkResName);
  400. MakeExecutable:=success; { otherwise a recursive call to link method }
  401. end;
  402. Procedure TLinker.MakeStaticLibrary(filescnt:longint);
  403. {
  404. FilesCnt holds the amount of .o files created, if filescnt=0 then
  405. no smartlinking is used
  406. }
  407. var
  408. smartpath,
  409. s,
  410. arbin : string;
  411. arfound : boolean;
  412. cnt : longint;
  413. begin
  414. smartpath:=current_module^.path^+FixPath(FixFileName(current_module^.modulename^)+target_info.smartext);
  415. { find ar binary }
  416. if utilsdirectory<>'' then
  417. begin
  418. arbin:=Search(target_ar.arbin+source_os.exeext,
  419. utilsdirectory,arfound)+target_ar.arbin+source_os.exeext;
  420. end
  421. else
  422. arbin:=FindExe(target_ar.arbin,arfound);
  423. if (not arfound) and not(cs_link_extern in aktglobalswitches) then
  424. begin
  425. Message(exec_w_ar_not_found);
  426. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  427. end;
  428. s:=target_ar.arcmd;
  429. Replace(s,'$LIB',current_module^.staticlibfilename^);
  430. if filescnt=0 then
  431. Replace(s,'$FILES',current_module^.objfilename^)
  432. else
  433. Replace(s,'$FILES',FixFileName(smartpath+current_module^.asmprefix^+'*'+target_info.objext));
  434. DoExec(arbin,s,false,true);
  435. { Clean up }
  436. if not(cs_asm_leave in aktglobalswitches) and not(cs_link_extern in aktglobalswitches) then
  437. begin
  438. if filescnt=0 then
  439. RemoveFile(current_module^.objfilename^)
  440. else
  441. begin
  442. for cnt:=1 to filescnt do
  443. if not RemoveFile(FixFileName(smartpath+current_module^.asmprefix^+tostr(cnt)+target_info.objext)) then
  444. RemoveFile(FixFileName(smartpath+current_module^.asmprefix^+'e'+tostr(cnt)+target_info.objext));
  445. RemoveDir(smartpath);
  446. end;
  447. end;
  448. end;
  449. Procedure TLinker.MakeSharedLibrary;
  450. var
  451. s : string;
  452. begin
  453. s:=' -shared -o $LIB $FILES';
  454. Replace(s,'$LIB',current_module^.sharedlibfilename^);
  455. Replace(s,'$FILES',current_module^.objfilename^);
  456. if DoExec(FindLinker,s,false,false) then
  457. RemoveFile(current_module^.objfilename^);
  458. end;
  459. end.
  460. {
  461. $Log$
  462. Revision 1.34 1998-10-16 13:37:18 florian
  463. + switch -FD added to specify the path for utilities
  464. Revision 1.33 1998/10/14 13:38:22 peter
  465. * fixed path with staticlib/objects in ppufiles
  466. Revision 1.32 1998/10/14 11:03:55 daniel
  467. * Forgot to dereference a pointer.
  468. Revision 1.31 1998/10/14 11:01:21 daniel
  469. * Staticlibfilename no longer not include a path. Correction when calling
  470. ar.
  471. Revision 1.30 1998/10/13 13:10:18 peter
  472. * new style for m68k/i386 infos and enums
  473. Revision 1.29 1998/10/13 08:19:34 pierre
  474. + source_os is now set correctly for cross-processor compilers
  475. (tos contains all target_infos and
  476. we use CPU86 and CPU68 conditionnals to
  477. get the source operating system
  478. this only works if you do not undefine
  479. the source target !!)
  480. * several cg68k memory leaks fixed
  481. + started to change the code so that it should be possible to have
  482. a complete compiler (both for m68k and i386 !!)
  483. Revision 1.28 1998/10/08 23:28:56 peter
  484. * -vu shows unit info, -vt shows tried/used files
  485. Revision 1.27 1998/10/06 17:16:52 pierre
  486. * some memory leaks fixed (thanks to Peter for heaptrc !)
  487. Revision 1.26 1998/09/29 15:23:05 peter
  488. * remove also the end files for smartlinking
  489. Revision 1.25 1998/09/10 15:25:31 daniel
  490. + Added maxheapsize.
  491. * Corrected semi-bug in calling the assembler and the linker
  492. Revision 1.24 1998/09/07 18:32:45 peter
  493. * fixed for m68k
  494. Revision 1.23 1998/09/03 17:39:04 florian
  495. + better code for type conversation longint/dword to real type
  496. Revision 1.22 1998/09/01 09:01:00 peter
  497. + glibc2 support
  498. Revision 1.21 1998/08/31 12:26:26 peter
  499. * m68k and palmos updates from surebugfixes
  500. Revision 1.20 1998/08/19 10:06:14 peter
  501. * fixed filenames and removedir which supports slash at the end
  502. Revision 1.19 1998/08/17 09:17:47 peter
  503. * static/shared linking updates
  504. Revision 1.18 1998/08/14 21:56:34 peter
  505. * setting the outputfile using -o works now to create static libs
  506. Revision 1.17 1998/08/14 18:16:08 peter
  507. * return after a failed call will now add it to ppas
  508. Revision 1.16 1998/08/12 19:28:15 peter
  509. * better libc support
  510. Revision 1.15 1998/08/10 14:50:02 peter
  511. + localswitches, moduleswitches, globalswitches splitting
  512. Revision 1.14 1998/06/17 14:10:13 peter
  513. * small os2 fixes
  514. * fixed interdependent units with newppu (remake3 under linux works now)
  515. Revision 1.13 1998/06/08 22:59:46 peter
  516. * smartlinking works for win32
  517. * some defines to exclude some compiler parts
  518. Revision 1.12 1998/06/04 23:51:44 peter
  519. * m68k compiles
  520. + .def file creation moved to gendef.pas so it could also be used
  521. for win32
  522. Revision 1.11 1998/05/27 00:20:31 peter
  523. * some scanner optimizes
  524. * automaticly aout2exe for go32v1
  525. * fixed dynamiclinker option which was added at the wrong place
  526. Revision 1.10 1998/05/22 12:32:47 peter
  527. * fixed -L on the commandline, Dos commandline is only 128 bytes
  528. Revision 1.9 1998/05/12 10:46:59 peter
  529. * moved printstatus to verb_def
  530. + V_Normal which is between V_Error and V_Warning and doesn't have a
  531. prefix like error: warning: and is included in V_Default
  532. * fixed some messages
  533. * first time parameter scan is only for -v and -T
  534. - removed old style messages
  535. Revision 1.8 1998/05/11 13:07:54 peter
  536. + $ifdef NEWPPU for the new ppuformat
  537. + $define GDB not longer required
  538. * removed all warnings and stripped some log comments
  539. * no findfirst/findnext anymore to remove smartlink *.o files
  540. Revision 1.7 1998/05/08 09:21:20 michael
  541. * Added missing -Fl message to messages file.
  542. * Corrected mangling of file names when doing Linklib
  543. * -Fl now actually WORKS.
  544. * Librarysearchpath is now a field in linker object.
  545. Revision 1.6 1998/05/06 09:26:49 peter
  546. * fixed ld call with shell
  547. Revision 1.4 1998/05/04 17:54:25 peter
  548. + smartlinking works (only case jumptable left todo)
  549. * redesign of systems.pas to support assemblers and linkers
  550. + Unitname is now also in the PPU-file, increased version to 14
  551. Revision 1.3 1998/04/16 10:54:30 daniel
  552. * Fixed linking for OS/2.
  553. }