fpcp.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. {
  2. Copyright (c) 2013-2014 by Free Pascal development team
  3. This unit implements the loading and searching of package files
  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 fpcp;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,
  22. globtype,
  23. pcp,finput,fpkg;
  24. type
  25. tpcppackage=class(tpackage)
  26. private
  27. loaded : boolean;
  28. pcpfile : tpcpfile;
  29. private
  30. function openpcp:boolean;
  31. function search_package(ashortname:boolean):boolean;
  32. function search_package_file:boolean;
  33. procedure setfilename(const fn:string;allowoutput:boolean);
  34. procedure writecontainernames;
  35. procedure writecontainedunits;
  36. procedure readcontainernames;
  37. procedure readcontainedunits;
  38. public
  39. constructor create(const pn:string);
  40. destructor destroy; override;
  41. procedure loadpcp;
  42. procedure savepcp;
  43. procedure initmoduleinfo(module:tmodulebase);
  44. procedure addunit(module:tmodulebase);
  45. end;
  46. implementation
  47. uses
  48. sysutils,
  49. cfileutl,cutils,
  50. systems,globals,version,
  51. verbose,
  52. entfile,fppu;
  53. { tpcppackage }
  54. function tpcppackage.openpcp: boolean;
  55. var
  56. pcpfiletime : longint;
  57. begin
  58. result:=false;
  59. Writeln('Loading pcp ',pcpfilename);
  60. //Message1(unit_t_ppu_loading,ppufilename,@queuecomment);
  61. { Get pcpfile time (also check if the file exists) }
  62. pcpfiletime:=getnamedfiletime(pcpfilename);
  63. if pcpfiletime=-1 then
  64. exit;
  65. { Open the pcpfile }
  66. //Message1(unit_u_ppu_name,ppufilename);
  67. pcpfile:=tpcpfile.create(pcpfilename);
  68. if not pcpfile.openfile then
  69. begin
  70. pcpfile.free;
  71. pcpfile:=nil;
  72. //Message(unit_u_ppu_file_too_short);
  73. Writeln('File to short');
  74. exit;
  75. end;
  76. { check for a valid PPU file }
  77. if not pcpfile.checkpcpid then
  78. begin
  79. pcpfile.free;
  80. pcpfile:=nil;
  81. //Message(unit_u_ppu_invalid_header);
  82. Writeln('Invalid PCP header');
  83. exit;
  84. end;
  85. { check for allowed PCP versions }
  86. if not (pcpfile.getversion=CurrentPCPVersion) then
  87. begin
  88. Writeln('Invalid PCP version: ',pcpfile.getversion);
  89. //Message1(unit_u_ppu_invalid_version,tostr(ppufile.GetPPUVersion),@queuecomment);
  90. pcpfile.free;
  91. pcpfile:=nil;
  92. exit;
  93. end;
  94. { check the target processor }
  95. if tsystemcpu(pcpfile.header.common.cpu)<>target_cpu then
  96. begin
  97. pcpfile.free;
  98. pcpfile:=nil;
  99. Writeln('Invalid processor');
  100. //Message(unit_u_ppu_invalid_processor,@queuecomment);
  101. exit;
  102. end;
  103. { check target }
  104. if tsystem(pcpfile.header.common.target)<>target_info.system then
  105. begin
  106. pcpfile.free;
  107. pcpfile:=nil;
  108. Writeln('Invalid target OS');
  109. //Message(unit_u_ppu_invalid_target,@queuecomment);
  110. exit;
  111. end;
  112. {$ifdef cpufpemu}
  113. { check if floating point emulation is on?
  114. fpu emulation isn't unit levelwise because it affects calling convention }
  115. if ((pcpfile.header.common.flags and uf_fpu_emulation)<>0) xor
  116. (cs_fp_emulation in current_settings.moduleswitches) then
  117. begin
  118. pcpfile.free;
  119. pcpfile:=nil;
  120. Writeln('Invalid FPU mode');
  121. //Message(unit_u_ppu_invalid_fpumode,@queuecomment);
  122. exit;
  123. end;
  124. {$endif cpufpemu}
  125. { Load values to be access easier }
  126. //flags:=pcpfile.header.common.flags;
  127. //crc:=pcpfile.header.checksum;
  128. { Show Debug info }
  129. (*Message1(unit_u_ppu_time,filetimestring(ppufiletime));
  130. Message1(unit_u_ppu_flags,tostr(flags));
  131. Message1(unit_u_ppu_crc,hexstr(ppufile.header.checksum,8));
  132. Message1(unit_u_ppu_crc,hexstr(ppufile.header.interface_checksum,8)+' (intfc)');
  133. Message1(unit_u_ppu_crc,hexstr(ppufile.header.indirect_checksum,8)+' (indc)');
  134. Comment(V_used,'Number of definitions: '+tostr(ppufile.header.deflistsize));
  135. Comment(V_used,'Number of symbols: '+tostr(ppufile.header.symlistsize));
  136. do_compile:=false;*)
  137. result:=true;
  138. end;
  139. function tpcppackage.search_package(ashortname:boolean):boolean;
  140. var
  141. singlepathstring,
  142. filename : TCmdStr;
  143. function package_exists(const ext:string;var foundfile:TCmdStr):boolean;
  144. begin
  145. if CheckVerbosity(V_Tried) then
  146. Writeln('Looking for package ',singlepathstring+filename+ext);
  147. {Message1(unit_t_unitsearch,Singlepathstring+filename+ext)};
  148. result:=FindFile(filename+ext,singlepathstring,true,foundfile);
  149. end;
  150. function package_search_path(const s:TCmdStr):boolean;
  151. var
  152. found : boolean;
  153. hs : TCmdStr;
  154. begin
  155. found:=false;
  156. singlepathstring:=FixPath(s,false);
  157. { Check for package file }
  158. { TODO }
  159. found:=package_exists({target_info.pkginfoext}'.pcp',hs);
  160. if found then
  161. begin
  162. setfilename(hs,false);
  163. found:=openpcp;
  164. end;
  165. result:=found;
  166. end;
  167. function search_path_list(list:TSearchPathList):boolean;
  168. var
  169. hp : TCmdStrListItem;
  170. found : boolean;
  171. begin
  172. found:=false;
  173. hp:=TCmdStrListItem(list.First);
  174. while assigned(hp) do
  175. begin
  176. found:=package_search_path(hp.Str);
  177. if found then
  178. break;
  179. hp:=TCmdStrListItem(hp.next);
  180. end;
  181. result:=found;
  182. end;
  183. begin
  184. filename:=packagename^;
  185. result:=search_path_list(packagesearchpath);
  186. end;
  187. function tpcppackage.search_package_file: boolean;
  188. var
  189. found : boolean;
  190. begin
  191. found:=false;
  192. if search_package(false) then
  193. found:=true;
  194. if not found and
  195. (length(packagename^)>8) and
  196. search_package(true) then
  197. found:=true;
  198. result:=found;
  199. end;
  200. procedure tpcppackage.setfilename(const fn:string;allowoutput:boolean);
  201. var
  202. p,n : tpathstr;
  203. begin
  204. p:=FixPath(ExtractFilePath(fn),false);
  205. n:=FixFileName(ChangeFileExt(ExtractFileName(fn),''));
  206. { pcp name }
  207. if allowoutput then
  208. if (OutputUnitDir<>'') then
  209. p:=OutputUnitDir
  210. else
  211. if (OutputExeDir<>'') then
  212. p:=OutputExeDir;
  213. pcpfilename:=p+n+{target_info.pkginfoext}'.pcp';
  214. end;
  215. procedure tpcppackage.writecontainernames;
  216. begin
  217. pcpfile.putstring(pplfilename);
  218. //pcpfile.putstring(ppafilename);
  219. pcpfile.writeentry(ibpackagefiles);
  220. end;
  221. procedure tpcppackage.writecontainedunits;
  222. var
  223. p : pcontainedunit;
  224. i : longint;
  225. begin
  226. pcpfile.putlongint(containedmodules.count);
  227. pcpfile.writeentry(ibstartcontained);
  228. { for now we write the unit name and the ppu file name }
  229. for i:=0 to containedmodules.count-1 do
  230. begin
  231. p:=pcontainedunit(containedmodules.items[i]);
  232. pcpfile.putstring(p^.module.modulename^);
  233. pcpfile.putstring(p^.ppufile);
  234. end;
  235. pcpfile.writeentry(ibendcontained);
  236. end;
  237. procedure tpcppackage.readcontainernames;
  238. begin
  239. if pcpfile.readentry<>ibpackagefiles then
  240. begin
  241. writeln('Error reading pcp file');
  242. internalerror(424242);
  243. end;
  244. pplfilename:=pcpfile.getstring;
  245. writeln('PPL filename: ',pplfilename);
  246. end;
  247. procedure tpcppackage.readcontainedunits;
  248. var
  249. cnt,i : longint;
  250. name,path : string;
  251. p : pcontainedunit;
  252. begin
  253. if pcpfile.readentry<>ibstartcontained then
  254. begin
  255. Writeln('Error reading pcp file');
  256. internalerror(424242);
  257. end;
  258. cnt:=pcpfile.getlongint;
  259. if pcpfile.readentry<>ibendcontained then
  260. begin
  261. Writeln('Error reading pcp file');
  262. internalerror(424242);
  263. end;
  264. for i:=0 to cnt-1 do
  265. begin
  266. name:=pcpfile.getstring;
  267. path:=ChangeFileExt(pcpfile.getstring,'.ppl.ppu');
  268. new(p);
  269. p^.module:=nil;
  270. p^.ppufile:=path;
  271. containedmodules.add(name,p);
  272. Writeln('Found module ',name);
  273. end;
  274. end;
  275. constructor tpcppackage.create(const pn: string);
  276. begin
  277. inherited create(pn);
  278. setfilename(pn,true);
  279. end;
  280. destructor tpcppackage.destroy;
  281. begin
  282. pcpfile.free;
  283. inherited destroy;
  284. end;
  285. procedure tpcppackage.loadpcp;
  286. var
  287. newpackagename : string;
  288. begin
  289. if loaded then
  290. exit;
  291. if not search_package_file then
  292. begin
  293. Message1(package_f_cant_find_pcp,realpackagename^);
  294. exit;
  295. end
  296. else
  297. Message1(package_u_pcp_found,realpackagename^);
  298. if not assigned(pcpfile) then
  299. internalerror(2013053101);
  300. if pcpfile.readentry<>ibpackagename then
  301. Comment(V_Error,'Error reading package: '+realpackagename^);
  302. newpackagename:=pcpfile.getstring;
  303. if upper(newpackagename)<>packagename^ then
  304. Comment(V_Error,'Package was renamed: '+realpackagename^);
  305. readcontainernames;
  306. //readrequiredpackages
  307. readcontainedunits;
  308. end;
  309. procedure tpcppackage.savepcp;
  310. begin
  311. { create new ppufile }
  312. pcpfile:=tpcpfile.create(pcpfilename);
  313. if not pcpfile.createfile then
  314. Writeln('Error creating PCP file');
  315. //Message(unit_f_ppu_cannot_write);
  316. pcpfile.putstring(realpackagename^);
  317. pcpfile.writeentry(ibpackagename);
  318. writecontainernames;
  319. //writerequiredpackages;
  320. writecontainedunits;
  321. //writeppus;
  322. { the last entry ibend is written automatically }
  323. { flush to be sure }
  324. pcpfile.flush;
  325. { create and write header }
  326. pcpfile.header.common.size:=pcpfile.size;
  327. pcpfile.header.checksum:=pcpfile.crc;
  328. pcpfile.header.common.compiler:=wordversion;
  329. pcpfile.header.common.cpu:=word(target_cpu);
  330. pcpfile.header.common.target:=word(target_info.system);
  331. //pcpfile.header.flags:=flags;
  332. pcpfile.header.ppulistsize:=containedmodules.count;
  333. pcpfile.header.requiredlistsize:=requiredpackages.count;
  334. pcpfile.writeheader;
  335. { save crc in current module also }
  336. //crc:=pcpfile.crc;
  337. pcpfile.closefile;
  338. pcpfile.free;
  339. pcpfile:=nil;
  340. end;
  341. procedure tpcppackage.initmoduleinfo(module: tmodulebase);
  342. begin
  343. pplfilename:=extractfilename(module.sharedlibfilename);
  344. end;
  345. procedure tpcppackage.addunit(module: tmodulebase);
  346. var
  347. containedunit : pcontainedunit;
  348. begin
  349. new(containedunit);
  350. containedunit^.module:=module;
  351. containedunit^.ppufile:=extractfilename(module.ppufilename);
  352. containedmodules.add(module.modulename^,containedunit);
  353. end;
  354. end.