pkgutil.pas 12 KB

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