program LazPkgGen;
{$APPTYPE CONSOLE}
uses
ShellAPI,
Windows,
Classes,
SysUtils,
DModule in 'DModule.pas' {DM: TDataModule};
{
I can't use PkgGen to create packages at all.
There are two reasons:
1) We are only going to make one complete set of .lpk (Lazarus package files.
The same .lpk file will be used for Linux, FreeBSD, Windows, and whatever else
because we will NOT list any system-specific units. We let the compiler link
those in. I am doing this to provide developers a way to cross-compile
Indy units and have more than one set of binaries for different
platform/operating system combinations. I also do not have to know
what system Indy will be compiled on. I'm thinking a hierarchy such as this:
===
System
lib
i386-win32
arm-wince
i386-linux
x64-linux
sparc-linux
ppc-linux
Core
lib
i386-win32
arm-wince
i386-linux
x64-linux
sparc-linux
ppc-linux
Protocols
lib
i386-win32
arm-wince
i386-linux
x64-linux
sparc-linux
ppc-linux
===
2) The program assumes all you pass to a code generation
procedure is a unit file name. In Lazarus, this is NOT so. In Lazarus,
each file is listed as an XML entry. This entry has attributes such as
"hasregisterproc". Then for a few design-time packages, there is an associated
(.LRS file that contains resources such as our XPM component icons and that an
additional entry.
Not only do you need file entries but a count of the entries.
The format is like this:
===
===
}
const
LF = #10;
CR = #13;
EOL = CR + LF;
//i is a var that this procedure will cmanage for the main loop.
procedure WriteLRSEntry(const AFile: String; var VEntryCount : Integer; var VOutput : String);
var
s : String;
begin
Inc(VEntryCount);
s := ' - '+EOL;
s := s +' '+EOL;
if StrToBoolDef(DM.Ini.ReadString(AFile, 'FPCHasRegProc', ''), False) then
begin
s := s +' '+EOL;
end;
s := s +' '+EOL;
s := s +'
'+EOL;
if StrToBoolDef(DM.Ini.ReadString(AFile, 'FPCHasLRSFile', ''), False) then
begin
Inc(VEntryCount);
s := s +' - '+EOL;
s := s +' '+EOL;
s := s +' '+EOL;
s := s +'
'+EOL;
end;
VOutput := VOutput + s;
end;
function MakeLRS(const ACriteria: string; const AFileName : String) : String;
var
i, cnt : Integer;
s : String;
LFiles, LS : TStringList;
begin
LS := TStringList.Create;
try
LS.LoadFromFile(DM.OutputPath+ '\Builder\Package Generator\LazTemplates\' + AFileName);
Result := LS.Text;
finally
LS.Free;
end;
cnt := 0;
s := '';
LFiles := TStringList.Create;
try
DM.GetFileList(ACriteria, LFiles);
for I := 0 to LFiles.Count-1 do
begin
WriteLRSEntry(LFiles[i], cnt, s);
end;
finally
LFiles.Free;
end;
s := ' '+ EOL +
s +' ';
Result := StringReplace(Result,'{%FILES}', s, [rfReplaceAll]);
end;
procedure WriteFile(const AContents, AFileName : String);
var
LCodeOld: string;
begin
if FileExists(AFileName) then begin
with TStringList.Create do try
LoadFromFile(AFileName);
LCodeOld := Text;
finally Free; end;
end;
// Only write out the code if its different. This prevents unnecessary checkins as well
// as not requiring user to lock all packages
if (LCodeOld = '') or (LCodeOld <> AContents) then begin
with TStringList.Create do try
Text := AContents;
SaveToFile(AFileName);
finally Free; end;
WriteLn('Generated ' + AFileName);
end;
end;
procedure MakeFPCMasterPackage(const ACriteria: string; const AFileName : String;
const AOutPath : String);
var
LFiles, LS : TStringList;
Lst : String;
i : Integer;
LTemp : String;
begin
LFiles := TStringList.Create;
try
DM.GetFileList(ACriteria, LFiles);
//construct our make file
LS := TStringList.Create;
try
LS.LoadFromFile(DM.OutputPath + '\Builder\Package Generator\LazTemplates\' + AFileName + '-Makefile.fpc');
LTemp := LS.Text;
finally
FreeAndNil(LS);
end;
Lst := '';
for i := 0 to LFiles.Count -1 do
begin
if (i = LFiles.Count -1) then
begin
LSt := Lst + ' ' + LFiles[i] + EOL;
end else begin
LSt := Lst + ' ' + LFiles[i] + ' \' + EOL;
end;
end;
Lst := 'implicitunits=' + TrimLeft(Lst);
LTemp := StringReplace(LTemp, '{%FILES}', LSt, [rfReplaceAll]);
WriteFile(LTemp, AOutPath + '\' + AFileName + '-Makefile.fpc');
finally
LFiles.Free;
end;
end;
procedure MakeFPCPackage(const ACriteria: string; const AFileName : String;
const AOutPath : String);
var
LCode, LS : TStringList;
Lst : String;
i : Integer;
LTemp : String;
begin
LCode := TStringList.Create;
try
DM.GetFileList(ACriteria, LCode);
//construct our make file
LS := TStringList.Create;
try
LS.LoadFromFile(GIndyPath + 'Builder\Package Generator\LazTemplates\' + AFileName + '-Makefile.fpc');
LTemp := LS.Text;
finally
LS.Free;
end;
//now make our package file. This is basically a dummy unit that lists
Lst := '';
for i := 0 to LCode.Count -1 do
begin
if (i = LCode.Count -1) then
begin
LSt := Lst + ' ' + LCode[i] + EOL;
end else begin
LSt := Lst + ' ' + LCode[i]+ ' \' + EOL;
end;
end;
Lst := 'implicitunits=' + TrimLeft(Lst);
LTemp := StringReplace(LTemp, '{%FILES}', LSt, [rfReplaceAll]);
WriteFile(LTemp, AOutPath + '\Makefile.fpc');
//all of the files.
for i := 0 to LCode.Count -1 do
begin
if (i = LCode.Count-1) then
begin
LCode[i] := ' ' + LCode[i] + ';';
end else begin
LCode[i] := ' ' + LCode[i] + ',';
end;
end;
LCode.Insert(0, 'uses');
LCode.Insert(0, '');
LCode.Insert(0, 'interface');
LCode.Insert(0, '');
LCode.Insert(0, 'unit ' + AFileName + ';');
//
LCode.Add('');
LCode.Add('implementation');
LCode.Add('');
LCode.Add('{');
LCode.Add('disable hints about unused units. This unit just causes');
LCode.Add('FreePascal to compile implicitly listed units in a package.');
LCode.Add('}');
LCode.Add('{$hints off}');
LCode.Add('');
LCode.Add('end.');
WriteFile(LCode.Text, AOutPath + '\' + AFileName + '.pas');
finally
LCode.Free;
end;
end;
procedure WriteLPK(const ACriteria: string; const AFileName : String; const AOutPath : String);
begin
WriteFile(MakeLRS(ACriteria, AFileName), AOutPath + '\' + AFileName);
end;
procedure MakeFileDistList;
var
LFiles, s : TStringList;
i: Integer;
begin
s := TStringList.Create;
try
LFiles := TStringList.Create;
try
DM.GetFileList('FPC=True, DesignUnit=False', LFiles);
for i := 0 to LFiles.Count-1 do
begin
s.Add(DM.Ini.ReadString(LFiles[i], 'Pkg', '') + '\' + LFiles[i] + '.pas');
if StrToBoolDef(DM.Ini.ReadString(LFiles[i], 'FPCHasLRSFile', ''), False) then
begin
s.Add(DM.Ini.ReadString(LFiles[i], 'Pkg', '') + '\' + LFiles[i] + '.lrs');
end;
end;
s.SaveToFile(DM.OutputPath + '\Lib\RTFileList.txt');
s.Clear;
DM.GetFileList('FPC=True, DesignUnit=True', LFiles);
for i := 0 to LFiles.Count-1 do
begin
s.Add(DM.Ini.ReadString(LFiles[i], 'Pkg', '') + '\' + LFiles[i] + '.pas');
if StrToBoolDef(DM.Ini.ReadString(LFiles[i], 'FPCHasLRSFile', ''), False) then
begin
s.Add(DM.Ini.ReadString(LFiles[i], 'Pkg', '') + '\' + LFiles[i] + '.lrs');
end;
end;
s.SaveToFile(DM.OutputPath + '\Lib\DTFileList.txt');
finally
LFiles.Free;
end;
finally
s.Free;
end;
end;
procedure Main;
begin
{ TODO -oUser -cConsole Main : Insert code here }
DM := TDM.Create(nil); try
with DM do begin
WriteLn('Path: '+ Ini.FileName );
if FindCmdLineSwitch('checkini') then begin
CheckForMissingFiles;
Exit;
end;
MakeFPCPackage('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=System', 'indysystemfpc', OutputPath + '\Lib\System');
WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=System', 'indysystemlaz.lpk', OutputPath + '\Lib\System');
MakeFPCPackage('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=Core', 'indycorefpc', OutputPath + '\Lib\Core');
WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=Core', 'indycorelaz.lpk', OutputPath + '\Lib\Core');
WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=True, Pkg=Core', 'dclindycorelaz.lpk', OutputPath + '\Lib\Core');
MakeFPCPackage('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=Protocols', 'indyprotocolsfpc', OutputPath + '\Lib\Protocols');
WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=False, Pkg=Protocols', 'indyprotocolslaz.lpk', OutputPath + '\Lib\Protocols');
WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=True, Pkg=Protocols', 'dclindyprotocolslaz.lpk', OutputPath + '\Lib\Protocols');
WriteLPK('FPC=True, FPCListInPkg=True, DesignUnit=True', 'indylaz.lpk', OutputPath + '\Lib');
MakeFileDistList;
MakeFPCMasterPackage('FPC=True, FPCListInPkg=True, DesignUnit=False', 'indymaster', OutputPath + '\Lib');
end;
finally
FreeAndNil(DM);
end;
end;
begin
try
Main;
except
on E: Exception do begin
WriteLn(E.Message);
// raise;
end;
end;
WriteLn('Done! Press ENTER to exit...');
ReadLn;
end.