link.pas 17 KB

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