LazPkgGen.dpr 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. program LazPkgGen;
  2. {$APPTYPE CONSOLE}
  3. uses
  4. ShellAPI,
  5. Windows,
  6. Classes,
  7. SysUtils,
  8. DModule in 'DModule.pas' {DM: TDataModule};
  9. {
  10. I can't use PkgGen to create packages at all.
  11. There are two reasons:
  12. 1) We are only going to make one complete set of .lpk (Lazarus package files.
  13. The same .lpk file will be used for Linux, FreeBSD, Windows, and whatever else
  14. because we will NOT list any system-specific units. We let the compiler link
  15. those in. I am doing this to provide developers a way to cross-compile
  16. Indy units and have more than one set of binaries for different
  17. platform/operating system combinations. I also do not have to know
  18. what system Indy will be compiled on. I'm thinking a hierarchy such as this:
  19. ===
  20. System
  21. lib
  22. i386-win32
  23. arm-wince
  24. i386-linux
  25. x64-linux
  26. sparc-linux
  27. ppc-linux
  28. Core
  29. lib
  30. i386-win32
  31. arm-wince
  32. i386-linux
  33. x64-linux
  34. sparc-linux
  35. ppc-linux
  36. Protocols
  37. lib
  38. i386-win32
  39. arm-wince
  40. i386-linux
  41. x64-linux
  42. sparc-linux
  43. ppc-linux
  44. ===
  45. 2) The program assumes all you pass to a code generation
  46. procedure is a unit file name. In Lazarus, this is NOT so. In Lazarus,
  47. each file is listed as an XML entry. This entry has attributes such as
  48. "hasregisterproc". Then for a few design-time packages, there is an associated
  49. (.LRS file that contains resources such as our XPM component icons and that an
  50. additional entry.
  51. Not only do you need file entries but a count of the entries.
  52. The format is like this:
  53. ===
  54. <Files Count="9">
  55. <Item1>
  56. <Filename Value="IdAbout.pas"/>
  57. <UnitName Value="IdAbout"/>
  58. </Item1>
  59. <Item2>
  60. <Filename Value="IdAboutVCL.pas"/>
  61. <UnitName Value="IdAboutVCL"/>
  62. </Item2>
  63. <Item3>
  64. <Filename Value="IdAboutVCL.lrs"/>
  65. <Type Value="LRS"/>
  66. </Item3>
  67. <Item4>
  68. <Filename Value="IdAntiFreeze.pas"/>
  69. <UnitName Value="IdAntiFreeze"/>
  70. </Item4>
  71. <Item5>
  72. <Filename Value="IdDsnBaseCmpEdt.pas"/>
  73. <UnitName Value="IdDsnBaseCmpEdt"/>
  74. </Item5>
  75. <Item6>
  76. <Filename Value="IdDsnCoreResourceStrings.pas"/>
  77. <UnitName Value="IdDsnCoreResourceStrings"/>
  78. </Item6>
  79. <Item7>
  80. <Filename Value="IdRegisterCore.pas"/>
  81. <HasRegisterProc Value="True"/>
  82. <UnitName Value="IdRegisterCore"/>
  83. </Item7>
  84. <Item8>
  85. <Filename Value="IdRegisterCore.lrs"/>
  86. <Type Value="LRS"/>
  87. </Item8>
  88. <Item9>
  89. <Filename Value="IdCoreDsnRegister.pas"/>
  90. <HasRegisterProc Value="True"/>
  91. <UnitName Value="IdCoreDsnRegister"/>
  92. </Item9>
  93. </Files>
  94. ===
  95. }
  96. const
  97. LF = #10;
  98. CR = #13;
  99. EOL = CR + LF;
  100. //i is a var that this procedure will cmanage for the main loop.
  101. procedure WriteLRSEntry(const AFile: String; var VEntryCount : Integer; var VOutput : String);
  102. var
  103. s : String;
  104. begin
  105. Inc(VEntryCount);
  106. s := ' <Item'+IntToStr(VEntryCount)+'>'+EOL;
  107. s := s +' <Filename Value="' + AFile + '.pas"/>'+EOL;
  108. if StrToBoolDef(DM.Ini.ReadString(AFile, 'FPCHasRegProc', ''), False) then
  109. begin
  110. s := s +' <HasRegisterProc Value="True"/>'+EOL;
  111. end;
  112. s := s +' <UnitName Value="'+ AFile + '"/>'+EOL;
  113. s := s +' </Item'+IntToStr(VEntryCount)+'>'+EOL;
  114. if StrToBoolDef(DM.Ini.ReadString(AFile, 'FPCHasLRSFile', ''), False) then
  115. begin
  116. Inc(VEntryCount);
  117. s := s +' <Item'+IntToStr(VEntryCount)+'>'+EOL;
  118. s := s +' <Filename Value="' + AFile +'.lrs"/>'+EOL;
  119. s := s +' <Type Value="LRS"/>'+EOL;
  120. s := s +' </Item'+IntToStr(VEntryCount)+'>'+EOL;
  121. end;
  122. VOutput := VOutput + s;
  123. end;
  124. function MakeLRS(const ACriteria: string; const AFileName : String) : String;
  125. var
  126. i, cnt : Integer;
  127. s : String;
  128. LFiles, LS : TStringList;
  129. begin
  130. LS := TStringList.Create;
  131. try
  132. LS.LoadFromFile(DM.OutputPath+ '\Builder\Package Generator\LazTemplates\' + AFileName);
  133. Result := LS.Text;
  134. finally
  135. LS.Free;
  136. end;
  137. cnt := 0;
  138. s := '';
  139. LFiles := TStringList.Create;
  140. try
  141. DM.GetFileList(ACriteria, LFiles);
  142. for I := 0 to LFiles.Count-1 do
  143. begin
  144. WriteLRSEntry(LFiles[i], cnt, s);
  145. end;
  146. finally
  147. LFiles.Free;
  148. end;
  149. s := ' <Files Count="'+IntToStr(cnt)+'">'+ EOL +
  150. s +' </Files>';
  151. Result := StringReplace(Result,'{%FILES}', s, [rfReplaceAll]);
  152. end;
  153. procedure WriteFile(const AContents, AFileName : String);
  154. var
  155. LCodeOld: string;
  156. begin
  157. if FileExists(AFileName) then begin
  158. with TStringList.Create do try
  159. LoadFromFile(AFileName);
  160. LCodeOld := Text;
  161. finally Free; end;
  162. end;
  163. // Only write out the code if its different. This prevents unnecessary checkins as well
  164. // as not requiring user to lock all packages
  165. if (LCodeOld = '') or (LCodeOld <> AContents) then begin
  166. with TStringList.Create do try
  167. Text := AContents;
  168. SaveToFile(AFileName);
  169. finally Free; end;
  170. WriteLn('Generated ' + AFileName);
  171. end;
  172. end;
  173. procedure MakeFPCMasterPackage(const ACriteria: string; const AFileName : String;
  174. const AOutPath : String);
  175. var
  176. LFiles, LS : TStringList;
  177. Lst : String;
  178. i : Integer;
  179. LTemp : String;
  180. begin
  181. LFiles := TStringList.Create;
  182. try
  183. DM.GetFileList(ACriteria, LFiles);
  184. //construct our make file
  185. LS := TStringList.Create;
  186. try
  187. LS.LoadFromFile(DM.OutputPath + '\Builder\Package Generator\LazTemplates\' + AFileName + '-Makefile.fpc');
  188. LTemp := LS.Text;
  189. finally
  190. FreeAndNil(LS);
  191. end;
  192. Lst := '';
  193. for i := 0 to LFiles.Count -1 do
  194. begin
  195. if (i = LFiles.Count -1) then
  196. begin
  197. LSt := Lst + ' ' + LFiles[i] + EOL;
  198. end else begin
  199. LSt := Lst + ' ' + LFiles[i] + ' \' + EOL;
  200. end;
  201. end;
  202. Lst := 'implicitunits=' + TrimLeft(Lst);
  203. LTemp := StringReplace(LTemp, '{%FILES}', LSt, [rfReplaceAll]);
  204. WriteFile(LTemp, AOutPath + '\' + AFileName + '-Makefile.fpc');
  205. finally
  206. LFiles.Free;
  207. end;
  208. end;
  209. procedure MakeFPCPackage(const ACriteria: string; const AFileName : String;
  210. const AOutPath : String);
  211. var
  212. LCode, LS : TStringList;
  213. Lst : String;
  214. i : Integer;
  215. LTemp : String;
  216. begin
  217. LCode := TStringList.Create;
  218. try
  219. DM.GetFileList(ACriteria, LCode);
  220. //construct our make file
  221. LS := TStringList.Create;
  222. try
  223. LS.LoadFromFile(GIndyPath + 'Builder\Package Generator\LazTemplates\' + AFileName + '-Makefile.fpc');
  224. LTemp := LS.Text;
  225. finally
  226. LS.Free;
  227. end;
  228. //now make our package file. This is basically a dummy unit that lists
  229. Lst := '';
  230. for i := 0 to LCode.Count -1 do
  231. begin
  232. if (i = LCode.Count -1) then
  233. begin
  234. LSt := Lst + ' ' + LCode[i] + EOL;
  235. end else begin
  236. LSt := Lst + ' ' + LCode[i]+ ' \' + EOL;
  237. end;
  238. end;
  239. Lst := 'implicitunits=' + TrimLeft(Lst);
  240. LTemp := StringReplace(LTemp, '{%FILES}', LSt, [rfReplaceAll]);
  241. WriteFile(LTemp, AOutPath + '\Makefile.fpc');
  242. //all of the files.
  243. for i := 0 to LCode.Count -1 do
  244. begin
  245. if (i = LCode.Count-1) then
  246. begin
  247. LCode[i] := ' ' + LCode[i] + ';';
  248. end else begin
  249. LCode[i] := ' ' + LCode[i] + ',';
  250. end;
  251. end;
  252. LCode.Insert(0, 'uses');
  253. LCode.Insert(0, '');
  254. LCode.Insert(0, 'interface');
  255. LCode.Insert(0, '');
  256. LCode.Insert(0, 'unit ' + AFileName + ';');
  257. //
  258. LCode.Add('');
  259. LCode.Add('implementation');
  260. LCode.Add('');
  261. LCode.Add('{');
  262. LCode.Add('disable hints about unused units. This unit just causes');
  263. LCode.Add('FreePascal to compile implicitly listed units in a package.');
  264. LCode.Add('}');
  265. LCode.Add('{$hints off}');
  266. LCode.Add('');
  267. LCode.Add('end.');
  268. WriteFile(LCode.Text, AOutPath + '\' + AFileName + '.pas');
  269. finally
  270. LCode.Free;
  271. end;
  272. end;
  273. procedure WriteLPK(const ACriteria: string; const AFileName : String; const AOutPath : String);
  274. begin
  275. WriteFile(MakeLRS(ACriteria, AFileName), AOutPath + '\' + AFileName);
  276. end;
  277. procedure MakeFileDistList;
  278. var
  279. LFiles, s : TStringList;
  280. i: Integer;
  281. begin
  282. s := TStringList.Create;
  283. try
  284. LFiles := TStringList.Create;
  285. try
  286. DM.GetFileList('FPC=True, DesignUnit=False', LFiles);
  287. for i := 0 to LFiles.Count-1 do
  288. begin
  289. s.Add(DM.Ini.ReadString(LFiles[i], 'Pkg', '') + '\' + LFiles[i] + '.pas');
  290. if StrToBoolDef(DM.Ini.ReadString(LFiles[i], 'FPCHasLRSFile', ''), False) then
  291. begin
  292. s.Add(DM.Ini.ReadString(LFiles[i], 'Pkg', '') + '\' + LFiles[i] + '.lrs');
  293. end;
  294. end;
  295. s.SaveToFile(DM.OutputPath + '\Lib\RTFileList.txt');
  296. s.Clear;
  297. DM.GetFileList('FPC=True, DesignUnit=True', LFiles);
  298. for i := 0 to LFiles.Count-1 do
  299. begin
  300. s.Add(DM.Ini.ReadString(LFiles[i], 'Pkg', '') + '\' + LFiles[i] + '.pas');
  301. if StrToBoolDef(DM.Ini.ReadString(LFiles[i], 'FPCHasLRSFile', ''), False) then
  302. begin
  303. s.Add(DM.Ini.ReadString(LFiles[i], 'Pkg', '') + '\' + LFiles[i] + '.lrs');
  304. end;
  305. end;
  306. s.SaveToFile(DM.OutputPath + '\Lib\DTFileList.txt');
  307. finally
  308. LFiles.Free;
  309. end;
  310. finally
  311. s.Free;
  312. end;
  313. end;
  314. procedure Main;
  315. begin
  316. { TODO -oUser -cConsole Main : Insert code here }
  317. DM := TDM.Create(nil); try
  318. with DM do begin
  319. WriteLn('Path: '+ Ini.FileName );
  320. if FindCmdLineSwitch('checkini') then begin
  321. CheckForMissingFiles;
  322. Exit;
  323. end;
  324. MakeFPCPackage('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=System', 'indysystemfpc', OutputPath + '\Lib\System');
  325. WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=System', 'indysystemlaz.lpk', OutputPath + '\Lib\System');
  326. MakeFPCPackage('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=Core', 'indycorefpc', OutputPath + '\Lib\Core');
  327. WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=Core', 'indycorelaz.lpk', OutputPath + '\Lib\Core');
  328. WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=True, Pkg=Core', 'dclindycorelaz.lpk', OutputPath + '\Lib\Core');
  329. MakeFPCPackage('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=Protocols', 'indyprotocolsfpc', OutputPath + '\Lib\Protocols');
  330. WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=Protocols', 'indyprotocolslaz.lpk', OutputPath + '\Lib\Protocols');
  331. WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=True, Pkg=Protocols', 'dclindyprotocolslaz.lpk', OutputPath + '\Lib\Protocols');
  332. WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=True', 'indylaz.lpk', OutputPath + '\Lib');
  333. MakeFileDistList;
  334. MakeFPCMasterPackage('FPC=True, FPCListInPkg=True, DesignUnit=False', 'indymaster', OutputPath + '\Lib');
  335. end;
  336. finally
  337. FreeAndNil(DM);
  338. end;
  339. end;
  340. begin
  341. try
  342. Main;
  343. except
  344. on E: Exception do begin
  345. WriteLn(E.Message);
  346. // raise;
  347. end;
  348. end;
  349. WriteLn('Done! Press ENTER to exit...');
  350. ReadLn;
  351. end.