link.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  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[100];
  30. ResName : string[12];
  31. ExtraOptions : string;
  32. DynamicLinker : string[100];
  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;const unitpath:string) : string;
  46. function FindLibraryFile(s:string;const ext:string;var found : boolean) : string;
  47. Procedure AddObject(const S,unitpath : 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. { static linking ? }
  148. if (cs_link_static in aktglobalswitches) then
  149. begin
  150. if (flags and uf_static_linked)=0 then
  151. begin
  152. { if smart not avail then try static linking }
  153. if (flags and uf_static_linked)<>0 then
  154. begin
  155. Comment(V_Hint,'unit '+modulename^+' can''t be static linked, switching to smart linking');
  156. mask:=mask or link_smart;
  157. end
  158. else
  159. Comment(V_Error,'unit '+modulename^+' can''t be smart or static linked');
  160. end
  161. else
  162. mask:=mask or link_static;
  163. end;
  164. { smart linking ? }
  165. if (cs_link_smart in aktglobalswitches) then
  166. begin
  167. if (flags and uf_smart_linked)=0 then
  168. begin
  169. { if smart not avail then try static linking }
  170. if (flags and uf_static_linked)<>0 then
  171. begin
  172. Comment(V_Hint,'unit '+modulename^+' can''t be smart linked, switching to static linking');
  173. mask:=mask or link_static;
  174. end
  175. else
  176. Comment(V_Error,'unit '+modulename^+' can''t be smart or static linked');
  177. end
  178. else
  179. mask:=mask or link_smart;
  180. end;
  181. { shared linking }
  182. if (cs_link_shared in aktglobalswitches) then
  183. begin
  184. if (flags and uf_shared_linked)=0 then
  185. begin
  186. { if shared not avail then try static linking }
  187. if (flags and uf_static_linked)<>0 then
  188. begin
  189. Comment(V_Hint,'unit '+modulename^+' can''t be shared linked, switching to static linking');
  190. mask:=mask or link_static;
  191. end
  192. else
  193. Comment(V_Error,'unit '+modulename^+' can''t be shared or static linked');
  194. end
  195. else
  196. mask:=mask or link_shared;
  197. end;
  198. { unit files }
  199. while not linkunitofiles.empty do
  200. AddObject(linkunitofiles.getusemask(mask),path^);
  201. while not linkunitstaticlibs.empty do
  202. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  203. while not linkunitsharedlibs.empty do
  204. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  205. end;
  206. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  207. mask:=link_allways;
  208. while not linkotherofiles.empty do
  209. AddObject(linkotherofiles.Getusemask(mask),path^);
  210. while not linkotherstaticlibs.empty do
  211. AddStaticLibrary(linkotherstaticlibs.Getusemask(mask));
  212. while not linkothersharedlibs.empty do
  213. AddSharedLibrary(linkothersharedlibs.Getusemask(mask));
  214. end;
  215. end;
  216. Function TLinker.FindUtil(const s:string):string;
  217. var
  218. ldfound : boolean;
  219. LastBin : string;
  220. begin
  221. LastBin:='';
  222. if utilsdirectory<>'' then
  223. LastBin:=FindFile(s+source_os.exeext,utilsdirectory,ldfound)+s+source_os.exeext;
  224. if LastBin='' then
  225. LastBin:=FindExe(s,ldfound);
  226. if (not ldfound) and not(cs_link_extern in aktglobalswitches) then
  227. begin
  228. Message1(exec_w_util_not_found,s);
  229. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  230. end;
  231. if ldfound then
  232. Message1(exec_t_using_util,LastBin);
  233. FindUtil:=LastBin;
  234. end;
  235. { searches an object file }
  236. function TLinker.FindObjectFile(s:string;const unitpath:string) : string;
  237. var
  238. found : boolean;
  239. begin
  240. findobjectfile:='';
  241. if s='' then
  242. exit;
  243. if pos('.',s)=0 then
  244. s:=s+target_info.objext;
  245. s:=FixFileName(s);
  246. if FileExists(s) then
  247. begin
  248. Findobjectfile:=s;
  249. exit;
  250. end;
  251. { find object file
  252. 1. specified unit path (if specified)
  253. 2. cwd
  254. 3. unit search path
  255. 4. local object path
  256. 5. global object path
  257. 6. exepath }
  258. found:=false;
  259. if unitpath<>'' then
  260. findobjectfile:=FindFile(s,unitpath,found)+s;
  261. if (not found) then
  262. findobjectfile:=FindFile(s,'.'+DirSep,found)+s;
  263. if (not found) then
  264. findobjectfile:=UnitSearchPath.FindFile(s,found)+s;
  265. if (not found) then
  266. findobjectfile:=current_module^.localobjectsearchpath.FindFile(s,found)+s;
  267. if (not found) then
  268. findobjectfile:=objectsearchpath.FindFile(s,found)+s;
  269. if (not found) then
  270. findobjectfile:=FindFile(s,exepath,found)+s;
  271. if not(cs_link_extern in aktglobalswitches) and (not found) then
  272. Message1(exec_w_objfile_not_found,s);
  273. end;
  274. { searches an library file }
  275. function TLinker.FindLibraryFile(s:string;const ext:string;var found : boolean) : string;
  276. begin
  277. found:=false;
  278. findlibraryfile:='';
  279. if s='' then
  280. exit;
  281. if pos('.',s)=0 then
  282. s:=s+ext;
  283. if FileExists(s) then
  284. begin
  285. found:=true;
  286. FindLibraryFile:=s;
  287. exit;
  288. end;
  289. { find libary
  290. 1. cwd
  291. 2. local libary dir
  292. 3. global libary dir
  293. 4. exe path of the compiler }
  294. found:=false;
  295. findlibraryfile:=FindFile(s,'.'+DirSep,found)+s;
  296. if (not found) then
  297. findlibraryfile:=current_module^.locallibrarysearchpath.FindFile(s,found)+s;
  298. if (not found) then
  299. findlibraryfile:=librarysearchpath.FindFile(s,found)+s;
  300. if (not found) then
  301. findlibraryfile:=FindFile(s,exepath,found)+s;
  302. end;
  303. Procedure TLinker.AddObject(const S,unitpath : String);
  304. begin
  305. ObjectFiles.Insert(FindObjectFile(s,unitpath));
  306. end;
  307. Procedure TLinker.AddSharedLibrary(S:String);
  308. begin
  309. if s='' then
  310. exit;
  311. { remove prefix 'lib' }
  312. if Copy(s,1,length(target_os.libprefix))=target_os.libprefix then
  313. Delete(s,1,length(target_os.libprefix));
  314. { remove extension if any }
  315. if Copy(s,length(s)-length(target_os.sharedlibext)+1,length(target_os.sharedlibext))=target_os.sharedlibext then
  316. Delete(s,length(s)-length(target_os.sharedlibext)+1,length(target_os.sharedlibext)+1);
  317. { ready to be inserted }
  318. SharedLibFiles.Insert (S);
  319. end;
  320. Procedure TLinker.AddStaticLibrary(const S:String);
  321. var
  322. ns : string;
  323. found : boolean;
  324. begin
  325. if s='' then
  326. exit;
  327. ns:=FindLibraryFile(s,target_os.staticlibext,found);
  328. if not(cs_link_extern in aktglobalswitches) and (not found) then
  329. Message1(exec_w_libfile_not_found,s);
  330. StaticLibFiles.Insert(ns);
  331. end;
  332. Function TLinker.DoExec(const command,para:string;showinfo,useshell:boolean):boolean;
  333. begin
  334. DoExec:=true;
  335. if not(cs_link_extern in aktglobalswitches) then
  336. begin
  337. swapvectors;
  338. {$ifdef ALWAYSSHELL}
  339. shell(command+' '+para);
  340. {$else}
  341. if useshell then
  342. shell(command+' '+para)
  343. else
  344. exec(command,para);
  345. {$endif}
  346. swapvectors;
  347. if (doserror<>0) then
  348. begin
  349. Message(exec_w_cant_call_linker);
  350. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  351. DoExec:=false;
  352. end
  353. else
  354. if (dosexitcode<>0) then
  355. begin
  356. Message(exec_w_error_while_linking);
  357. aktglobalswitches:=aktglobalswitches+[cs_link_extern];
  358. DoExec:=false;
  359. end;
  360. end;
  361. { Update asmres when externmode is set }
  362. if cs_link_extern in aktglobalswitches then
  363. begin
  364. if showinfo then
  365. begin
  366. if DLLsource then
  367. AsmRes.AddLinkCommand(Command,Para,current_module^.sharedlibfilename^)
  368. else
  369. AsmRes.AddLinkCommand(Command,Para,current_module^.exefilename^);
  370. end
  371. else
  372. AsmRes.AddLinkCommand(Command,Para,'');
  373. end;
  374. end;
  375. function TLinker.MakeExecutable:boolean;
  376. begin
  377. MakeExecutable:=false;
  378. Message(exec_e_exe_not_supported);
  379. end;
  380. Function TLinker.MakeSharedLibrary:boolean;
  381. begin
  382. MakeSharedLibrary:=false;
  383. Message(exec_e_dll_not_supported);
  384. end;
  385. Function TLinker.MakeStaticLibrary:boolean;
  386. var
  387. smartpath,
  388. cmdstr,
  389. binstr : string;
  390. success : boolean;
  391. begin
  392. MakeStaticLibrary:=false;
  393. { remove the library, to be sure that it is rewritten }
  394. RemoveFile(current_module^.staticlibfilename^);
  395. { Call AR }
  396. smartpath:=current_module^.outputpath^+FixPath(FixFileName(current_module^.modulename^)+target_info.smartext,false);
  397. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  398. Replace(cmdstr,'$LIB',current_module^.staticlibfilename^);
  399. Replace(cmdstr,'$FILES',FixFileName(smartpath+current_module^.asmprefix^+'*'+target_info.objext));
  400. success:=DoExec(FindUtil(binstr),cmdstr,false,true);
  401. { Clean up }
  402. if not(cs_asm_leave in aktglobalswitches) then
  403. if not(cs_link_extern in aktglobalswitches) then
  404. begin
  405. while not SmartLinkOFiles.Empty do
  406. RemoveFile(SmartLinkOFiles.Get);
  407. RemoveDir(smartpath);
  408. end
  409. else
  410. begin
  411. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module^.asmprefix^+'*'+target_info.objext));
  412. AsmRes.Add('rmdir '+smartpath);
  413. end;
  414. MakeStaticLibrary:=success;
  415. end;
  416. {*****************************************************************************
  417. Init/Done
  418. *****************************************************************************}
  419. procedure InitLinker;
  420. begin
  421. case target_info.target of
  422. {$ifdef i386}
  423. {$ifndef NOTARGETLINUX}
  424. target_i386_linux :
  425. linker:=new(plinkerlinux,Init);
  426. {$endif}
  427. {$ifndef NOTARGETWIN32}
  428. target_i386_Win32 :
  429. linker:=new(plinkerwin32,Init);
  430. {$endif}
  431. {$ifndef NOTARGETGO32V1}
  432. target_i386_Go32v1 :
  433. linker:=new(plinkergo32v1,Init);
  434. {$endif}
  435. {$ifndef NOTARGETGO32V2}
  436. target_i386_Go32v2 :
  437. linker:=new(plinkergo32v2,Init);
  438. {$endif}
  439. {$ifndef NOTARGETOS2}
  440. target_i386_os2 :
  441. linker:=new(plinkeros2,Init);
  442. {$endif}
  443. {$endif i386}
  444. {$ifdef m68k}
  445. {$ifndef NOTARGETPALMOS}
  446. target_m68k_palmos:
  447. linker:=new(plinker,Init);
  448. {$endif}
  449. {$ifndef NOTARGETLINUX}
  450. target_m68k_linux :
  451. linker:=new(plinkerlinux,Init);
  452. {$endif}
  453. {$endif m68k}
  454. {$ifdef alpha}
  455. {$ifndef NOTARGETLINUX}
  456. target_alpha_linux :
  457. linker:=new(plinkerlinux,Init);
  458. {$endif}
  459. {$endif alpha}
  460. {$ifdef powerpc}
  461. {$ifndef NOTARGETLINUX}
  462. target_powerpc_linux :
  463. linker:=new(plinkerlinux,Init);
  464. {$endif}
  465. {$endif powerpc}
  466. else
  467. linker:=new(plinker,Init);
  468. end;
  469. end;
  470. procedure DoneLinker;
  471. begin
  472. if assigned(linker) then
  473. dispose(linker,done);
  474. end;
  475. end.
  476. {
  477. $Log$
  478. Revision 1.2 2000-07-13 11:32:43 michael
  479. + removed logs
  480. }