fpcp.pas 12 KB

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