pkgutil.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. {
  2. Copyright (c) 2013-2016 by Free Pascal Development Team
  3. This unit implements basic parts of the package system
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit pkgutil;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. fmodule;
  22. procedure createimportlibfromexports;
  23. Function RewritePPU(const PPUFn,PPLFn:String):Boolean;
  24. procedure export_unit(u:tmodule);
  25. procedure load_packages;
  26. implementation
  27. uses
  28. sysutils,
  29. globtype,systems,
  30. cutils,cclasses,
  31. globals,verbose,
  32. symtype,symconst,symsym,symdef,symbase,symtable,
  33. ppu,entfile,fpcp,fpkg,
  34. export;
  35. procedure procexport(const s : string);
  36. var
  37. hp : texported_item;
  38. begin
  39. hp:=texported_item.create;
  40. hp.name:=stringdup(s);
  41. hp.options:=hp.options+[eo_name];
  42. exportlib.exportprocedure(hp);
  43. end;
  44. procedure varexport(const s : string);
  45. var
  46. hp : texported_item;
  47. begin
  48. hp:=texported_item.create;
  49. hp.name:=stringdup(s);
  50. hp.options:=hp.options+[eo_name];
  51. exportlib.exportvar(hp);
  52. end;
  53. procedure exportprocsym(sym:tprocsym;symtable:tsymtable);
  54. var
  55. i : longint;
  56. item : TCmdStrListItem;
  57. begin
  58. for i:=0 to tprocsym(sym).ProcdefList.Count-1 do
  59. begin
  60. if not(tprocdef(tprocsym(sym).ProcdefList[i]).proccalloption in [pocall_internproc]) and
  61. ((tprocdef(tprocsym(sym).ProcdefList[i]).procoptions*[po_external])=[]) and
  62. ((symtable.symtabletype in [globalsymtable,recordsymtable,objectsymtable]) or
  63. ((symtable.symtabletype=staticsymtable) and (po_public in tprocdef(tprocsym(sym).ProcdefList[i]).procoptions))
  64. ) then
  65. begin
  66. exportallprocdefnames(tprocsym(sym),tprocdef(tprocsym(sym).ProcdefList[i]),[]);
  67. end;
  68. end;
  69. end;
  70. procedure exportabstractrecordsymproc(sym:tobject;arg:pointer);
  71. var
  72. def : tabstractrecorddef;
  73. begin
  74. case tsym(sym).typ of
  75. typesym:
  76. begin
  77. case ttypesym(sym).typedef.typ of
  78. objectdef,
  79. recorddef:
  80. begin
  81. def:=tabstractrecorddef(ttypesym(sym).typedef);
  82. def.symtable.symlist.foreachcall(@exportabstractrecordsymproc,def.symtable);
  83. end;
  84. end;
  85. end;
  86. procsym:
  87. begin
  88. { don't export methods of interfaces }
  89. if is_interface(tdef(tabstractrecordsymtable(arg).defowner)) then
  90. exit;
  91. exportprocsym(tprocsym(sym),tsymtable(arg));
  92. end;
  93. staticvarsym:
  94. begin
  95. varexport(tsym(sym).mangledname);
  96. end;
  97. end;
  98. end;
  99. procedure insert_export(sym : TObject;arg:pointer);
  100. var
  101. i : longint;
  102. item : TCmdStrListItem;
  103. def : tabstractrecorddef;
  104. hp : texported_item;
  105. publiconly : boolean;
  106. begin
  107. publiconly:=tsymtable(arg).symtabletype=staticsymtable;
  108. case TSym(sym).typ of
  109. { ignore: }
  110. unitsym,
  111. syssym,
  112. constsym,
  113. namespacesym,
  114. propertysym,
  115. enumsym:
  116. ;
  117. typesym:
  118. begin
  119. case ttypesym(sym).typedef.typ of
  120. recorddef,
  121. objectdef:
  122. begin
  123. def:=tabstractrecorddef(ttypesym(sym).typedef);
  124. def.symtable.SymList.ForEachCall(@exportabstractrecordsymproc,def.symtable);
  125. if (def.typ=objectdef) and (oo_has_vmt in tobjectdef(def).objectoptions) then
  126. begin
  127. hp:=texported_item.create;
  128. hp.name:=stringdup(tobjectdef(def).vmt_mangledname);
  129. hp.options:=hp.options+[eo_name];
  130. exportlib.exportvar(hp);
  131. end;
  132. end;
  133. end;
  134. end;
  135. procsym:
  136. begin
  137. exportprocsym(tprocsym(sym),tsymtable(arg));
  138. end;
  139. staticvarsym:
  140. begin
  141. if publiconly and not (vo_is_public in tstaticvarsym(sym).varoptions) then
  142. exit;
  143. varexport(tsym(sym).mangledname);
  144. end;
  145. else
  146. begin
  147. writeln('unknown: ',ord(TSym(sym).typ));
  148. end;
  149. end;
  150. end;
  151. procedure export_unit(u: tmodule);
  152. begin
  153. u.globalsymtable.symlist.ForEachCall(@insert_export,u.globalsymtable);
  154. { check localsymtable for exports too to get public symbols }
  155. u.localsymtable.symlist.ForEachCall(@insert_export,u.localsymtable);
  156. { create special exports }
  157. if (u.flags and uf_init)<>0 then
  158. procexport(make_mangledname('INIT$',u.globalsymtable,''));
  159. if (u.flags and uf_finalize)<>0 then
  160. procexport(make_mangledname('FINALIZE$',u.globalsymtable,''));
  161. if (u.flags and uf_threadvars)=uf_threadvars then
  162. varexport(make_mangledname('THREADVARLIST',u.globalsymtable,''));
  163. end;
  164. Function RewritePPU(const PPUFn,PPLFn:String):Boolean;
  165. Var
  166. MakeStatic : Boolean;
  167. Var
  168. buffer : array[0..$1fff] of byte;
  169. inppu,
  170. outppu : tppufile;
  171. b,
  172. untilb : byte;
  173. l,m : longint;
  174. f : file;
  175. ext,
  176. s : string;
  177. ppuversion : dword;
  178. begin
  179. Result:=false;
  180. MakeStatic:=False;
  181. inppu:=tppufile.create(PPUFn);
  182. if not inppu.openfile then
  183. begin
  184. inppu.free;
  185. Comment(V_Error,'Could not open : '+PPUFn);
  186. Exit;
  187. end;
  188. { Check the ppufile }
  189. if not inppu.CheckPPUId then
  190. begin
  191. inppu.free;
  192. Comment(V_Error,'Not a PPU File : '+PPUFn);
  193. Exit;
  194. end;
  195. ppuversion:=inppu.getversion;
  196. if ppuversion<CurrentPPUVersion then
  197. begin
  198. inppu.free;
  199. Comment(V_Error,'Wrong PPU Version '+tostr(ppuversion)+' in '+PPUFn);
  200. Exit;
  201. end;
  202. { No .o file generated for this ppu, just skip }
  203. if (inppu.header.common.flags and uf_no_link)<>0 then
  204. begin
  205. inppu.free;
  206. Result:=true;
  207. Exit;
  208. end;
  209. { Already a lib? }
  210. if (inppu.header.common.flags and uf_in_library)<>0 then
  211. begin
  212. inppu.free;
  213. Comment(V_Error,'PPU is already in a library : '+PPUFn);
  214. Exit;
  215. end;
  216. { We need a static linked unit }
  217. if (inppu.header.common.flags and uf_static_linked)=0 then
  218. begin
  219. inppu.free;
  220. Comment(V_Error,'PPU is not static linked : '+PPUFn);
  221. Exit;
  222. end;
  223. { Check if shared is allowed }
  224. if tsystem(inppu.header.common.target) in [system_i386_go32v2] then
  225. begin
  226. Comment(V_Error,'Shared library not supported for ppu target, switching to static library');
  227. MakeStatic:=true;
  228. end;
  229. { Create the new ppu }
  230. if PPUFn=PPLFn then
  231. outppu:=tppufile.create('ppumove.$$$')
  232. else
  233. outppu:=tppufile.create(PPLFn);
  234. outppu.createfile;
  235. { Create new header, with the new flags }
  236. outppu.header:=inppu.header;
  237. outppu.header.common.flags:=outppu.header.common.flags or uf_in_library;
  238. if MakeStatic then
  239. outppu.header.common.flags:=outppu.header.common.flags or uf_static_linked
  240. else
  241. outppu.header.common.flags:=outppu.header.common.flags or uf_shared_linked;
  242. { read until the object files are found }
  243. untilb:=iblinkunitofiles;
  244. repeat
  245. b:=inppu.readentry;
  246. if b in [ibendinterface,ibend] then
  247. begin
  248. inppu.free;
  249. outppu.free;
  250. Comment(V_Error,'No files to be linked found : '+PPUFn);
  251. Exit;
  252. end;
  253. if b<>untilb then
  254. begin
  255. repeat
  256. inppu.getdatabuf(buffer,sizeof(buffer),l);
  257. outppu.putdata(buffer,l);
  258. until l<sizeof(buffer);
  259. outppu.writeentry(b);
  260. end;
  261. until (b=untilb);
  262. { we have now reached the section for the files which need to be added,
  263. now add them to the list }
  264. case b of
  265. iblinkunitofiles :
  266. begin
  267. { add all o files, and save the entry when not creating a static
  268. library to keep staticlinking possible }
  269. while not inppu.endofentry do
  270. begin
  271. s:=inppu.getstring;
  272. m:=inppu.getlongint;
  273. if not MakeStatic then
  274. begin
  275. outppu.putstring(s);
  276. outppu.putlongint(m);
  277. end;
  278. current_module.linkotherofiles.add(s,link_always);;
  279. end;
  280. if not MakeStatic then
  281. outppu.writeentry(b);
  282. end;
  283. { iblinkunitstaticlibs :
  284. begin
  285. AddToLinkFiles(ExtractLib(inppu.getstring));
  286. if not inppu.endofentry then
  287. begin
  288. repeat
  289. inppu.getdatabuf(buffer^,bufsize,l);
  290. outppu.putdata(buffer^,l);
  291. until l<bufsize;
  292. outppu.writeentry(b);
  293. end;
  294. end; }
  295. end;
  296. { just add a new entry with the new lib }
  297. if MakeStatic then
  298. begin
  299. outppu.putstring('imp'+current_module.realmodulename^);
  300. outppu.putlongint(link_static);
  301. outppu.writeentry(iblinkunitstaticlibs)
  302. end
  303. else
  304. begin
  305. outppu.putstring('imp'+current_module.realmodulename^);
  306. outppu.putlongint(link_shared);
  307. outppu.writeentry(iblinkunitsharedlibs);
  308. end;
  309. { read all entries until the end and write them also to the new ppu }
  310. repeat
  311. b:=inppu.readentry;
  312. { don't write ibend, that's written automatically }
  313. if b<>ibend then
  314. begin
  315. if b=iblinkothersharedlibs then
  316. begin
  317. while not inppu.endofentry do
  318. begin
  319. s:=inppu.getstring;
  320. m:=inppu.getlongint;
  321. outppu.putstring(s);
  322. outppu.putlongint(m);
  323. { strip lib prefix }
  324. if copy(s,1,3)='lib' then
  325. delete(s,1,3);
  326. ext:=ExtractFileExt(s);
  327. if ext<>'' then
  328. delete(s,length(s)-length(ext)+1,length(ext));
  329. current_module.linkOtherSharedLibs.add(s,link_always);
  330. end;
  331. end
  332. else
  333. repeat
  334. inppu.getdatabuf(buffer,sizeof(buffer),l);
  335. outppu.putdata(buffer,l);
  336. until l<sizeof(buffer);
  337. outppu.writeentry(b);
  338. end;
  339. until b=ibend;
  340. { write the last stuff and close }
  341. outppu.flush;
  342. outppu.writeheader;
  343. outppu.free;
  344. inppu.free;
  345. { rename }
  346. if PPUFn=PPLFn then
  347. begin
  348. {$push}{$I-}
  349. assign(f,PPUFn);
  350. erase(f);
  351. assign(f,'ppumove.$$$');
  352. rename(f,PPUFn);
  353. {$pop}
  354. if ioresult<>0 then;
  355. end;
  356. Result:=True;
  357. end;
  358. procedure load_packages;
  359. var
  360. i : longint;
  361. pcp: tpcppackage;
  362. entry : ppackageentry;
  363. begin
  364. if not (tf_supports_packages in target_info.flags) then
  365. exit;
  366. for i:=0 to packagelist.count-1 do
  367. begin
  368. entry:=ppackageentry(packagelist[i]);
  369. if assigned(entry^.package) then
  370. internalerror(2013053104);
  371. Comment(V_Info,'Loading package: '+entry^.realpkgname);
  372. pcp:=tpcppackage.create(entry^.realpkgname);
  373. pcp.loadpcp;
  374. entry^.package:=pcp;
  375. end;
  376. end;
  377. procedure createimportlibfromexports;
  378. var
  379. hp : texported_item;
  380. begin
  381. hp:=texported_item(current_module._exports.first);
  382. while assigned(hp) do
  383. begin
  384. current_module.AddExternalImport(current_module.realmodulename^,hp.name^,hp.name^,hp.index,hp.is_var,false);
  385. hp:=texported_item(hp.next);
  386. end;
  387. end;
  388. end.