mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-27 20:11:02 +02:00
* first commit of new fpcmake
This commit is contained in:
parent
ddd5f168eb
commit
8126674229
1285
utils/fpcm/fpcmake.inc
Normal file
1285
utils/fpcm/fpcmake.inc
Normal file
File diff suppressed because it is too large
Load Diff
1235
utils/fpcm/fpcmake.ini
Normal file
1235
utils/fpcm/fpcmake.ini
Normal file
File diff suppressed because it is too large
Load Diff
63
utils/fpcm/fpcmake.pp
Normal file
63
utils/fpcm/fpcmake.pp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
$Id$
|
||||||
|
Copyright (c) 2001 by Peter Vreman
|
||||||
|
|
||||||
|
Convert Makefile.fpc to Makefile
|
||||||
|
|
||||||
|
See the file COPYING.FPC, included in this distribution,
|
||||||
|
for details about the copyright.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
**********************************************************************}
|
||||||
|
{$ifdef fpc}{$mode objfpc}{$endif}
|
||||||
|
{$H+}
|
||||||
|
program fpcmake;
|
||||||
|
|
||||||
|
uses
|
||||||
|
dos,sysutils,
|
||||||
|
fpcmmain,fpcmwr;
|
||||||
|
|
||||||
|
procedure ProcessFile(const fn:string);
|
||||||
|
var
|
||||||
|
CurrFPCMake : TFPCMake;
|
||||||
|
CurrMakefile : TMakefileWriter;
|
||||||
|
s : string;
|
||||||
|
begin
|
||||||
|
CurrFPCMake:=nil;
|
||||||
|
// try
|
||||||
|
CurrFPCMake:=TFPCMake.Create(fn);
|
||||||
|
s:=GetEnv('FPCDIR');
|
||||||
|
if s<>'' then
|
||||||
|
CurrFPCMake.Variables.Add('FPCDIR',s)
|
||||||
|
else
|
||||||
|
CurrFPCMake.Variables.Add('FPCDIR','c:/pp');
|
||||||
|
CurrFPCMake.Variables.Add('UNITSDIR','$(FPCDIR)/units');
|
||||||
|
CurrFPCMake.Variables.Add('PACKAGESDIR','$(FPCDIR)/packages');
|
||||||
|
CurrFPCMake.LoadMakefileFPC;
|
||||||
|
CurrFPCMake.LoadPackageSection;
|
||||||
|
CurrFPCMake.LoadRequires(CurrFPCMake);
|
||||||
|
// CurrFPCMake.Print;
|
||||||
|
|
||||||
|
CurrMakefile:=TMakefileWriter.Create(CurrFPCMake,'Makefile');
|
||||||
|
CurrMakefile.WriteGenericMakefile;
|
||||||
|
CurrMakefile.Free;
|
||||||
|
|
||||||
|
// except
|
||||||
|
// on e : exception do
|
||||||
|
// writeln('Error: ',e.message);
|
||||||
|
// end;
|
||||||
|
CurrFPCMake.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ProcessFile('Makefile.fpc');
|
||||||
|
end.
|
||||||
|
{
|
||||||
|
$Log$
|
||||||
|
Revision 1.1 2001-01-24 21:59:36 peter
|
||||||
|
* first commit of new fpcmake
|
||||||
|
|
||||||
|
}
|
544
utils/fpcm/fpcmdic.pp
Normal file
544
utils/fpcm/fpcmdic.pp
Normal file
@ -0,0 +1,544 @@
|
|||||||
|
{
|
||||||
|
$Id$
|
||||||
|
Copyright (c) 2001 by Peter Vreman
|
||||||
|
|
||||||
|
TDictionary class
|
||||||
|
|
||||||
|
See the file COPYING.FPC, included in this distribution,
|
||||||
|
for details about the copyright.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
**********************************************************************}
|
||||||
|
{$ifdef fpc}{$mode objfpc}{$endif}
|
||||||
|
{$H+}
|
||||||
|
unit fpcmdic;
|
||||||
|
interface
|
||||||
|
|
||||||
|
const { the real size will be [-hasharray..hasharray] ! }
|
||||||
|
hasharraysize = 2047;
|
||||||
|
|
||||||
|
type
|
||||||
|
{ namedindexobect for use with dictionary and indexarray }
|
||||||
|
TDictionaryItem=class
|
||||||
|
private
|
||||||
|
Fname : string;
|
||||||
|
FSpeedValue : cardinal;
|
||||||
|
protected
|
||||||
|
procedure SetName(const n:string);
|
||||||
|
public
|
||||||
|
left,
|
||||||
|
right : TDictionaryItem;
|
||||||
|
constructor create(const n:string);
|
||||||
|
property Name:string read FName write SetName;
|
||||||
|
property SpeedValue:cardinal read FSpeedValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Pdictionaryhasharray=^Tdictionaryhasharray;
|
||||||
|
Tdictionaryhasharray=array[-hasharraysize..hasharraysize] of TDictionaryItem;
|
||||||
|
|
||||||
|
Tnamedindexcallback = procedure(p:TDictionaryItem) of object;
|
||||||
|
|
||||||
|
Tdictionary=class
|
||||||
|
private
|
||||||
|
FRoot : TDictionaryItem;
|
||||||
|
FHashArray : Pdictionaryhasharray;
|
||||||
|
procedure cleartree(obj:TDictionaryItem);
|
||||||
|
function insertNode(NewNode:TDictionaryItem;var currNode:TDictionaryItem):TDictionaryItem;
|
||||||
|
procedure inserttree(currtree,currroot:TDictionaryItem);
|
||||||
|
public
|
||||||
|
noclear : boolean;
|
||||||
|
replace_existing : boolean;
|
||||||
|
constructor Create;
|
||||||
|
destructor Destroy;override;
|
||||||
|
procedure usehash;
|
||||||
|
procedure clear;
|
||||||
|
function delete(const s:string):TDictionaryItem;
|
||||||
|
function empty:boolean;
|
||||||
|
procedure foreach(proc2call:Tnamedindexcallback);
|
||||||
|
function insert(obj:TDictionaryItem):TDictionaryItem;
|
||||||
|
function rename(const olds,News : string):TDictionaryItem;
|
||||||
|
function search(const s:string):TDictionaryItem;
|
||||||
|
function speedsearch(const s:string;SpeedValue:integer):TDictionaryItem;
|
||||||
|
property Items[const s:string]:TDictionaryItem read Search;default;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Speed/Hash value }
|
||||||
|
Function GetSpeedValue(Const s:String):cardinal;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
|
||||||
|
{*****************************************************************************
|
||||||
|
GetSpeedValue
|
||||||
|
*****************************************************************************}
|
||||||
|
|
||||||
|
var
|
||||||
|
Crc32Tbl : array[0..255] of cardinal;
|
||||||
|
|
||||||
|
procedure MakeCRC32Tbl;
|
||||||
|
var
|
||||||
|
crc : cardinal;
|
||||||
|
i,n : integer;
|
||||||
|
begin
|
||||||
|
for i:=0 to 255 do
|
||||||
|
begin
|
||||||
|
crc:=i;
|
||||||
|
for n:=1 to 8 do
|
||||||
|
if odd(crc) then
|
||||||
|
crc:=(crc shr 1) xor $edb88320
|
||||||
|
else
|
||||||
|
crc:=crc shr 1;
|
||||||
|
Crc32Tbl[i]:=crc;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Function GetSpeedValue(Const s:String):cardinal;
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
InitCrc : cardinal;
|
||||||
|
begin
|
||||||
|
if Crc32Tbl[1]=0 then
|
||||||
|
MakeCrc32Tbl;
|
||||||
|
InitCrc:=$ffffffff;
|
||||||
|
for i:=1 to Length(s) do
|
||||||
|
InitCrc:=Crc32Tbl[byte(InitCrc) xor ord(s[i])] xor (InitCrc shr 8);
|
||||||
|
GetSpeedValue:=InitCrc;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{****************************************************************************
|
||||||
|
TDictionaryItem
|
||||||
|
****************************************************************************}
|
||||||
|
|
||||||
|
constructor TDictionaryItem.Create(const n:string);
|
||||||
|
begin
|
||||||
|
left:=nil;
|
||||||
|
right:=nil;
|
||||||
|
FSpeedValue:=-1;
|
||||||
|
FName:=n;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TDictionaryItem.Setname(const n:string);
|
||||||
|
begin
|
||||||
|
if FSpeedValue=-1 then
|
||||||
|
FName:=n;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{****************************************************************************
|
||||||
|
TDICTIONARY
|
||||||
|
****************************************************************************}
|
||||||
|
|
||||||
|
constructor Tdictionary.Create;
|
||||||
|
begin
|
||||||
|
FRoot:=nil;
|
||||||
|
FHashArray:=nil;
|
||||||
|
noclear:=false;
|
||||||
|
replace_existing:=false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Tdictionary.usehash;
|
||||||
|
begin
|
||||||
|
if not(assigned(FRoot)) and
|
||||||
|
not(assigned(FHashArray)) then
|
||||||
|
begin
|
||||||
|
New(FHashArray);
|
||||||
|
fillchar(FHashArray^,sizeof(FHashArray^),0);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor Tdictionary.destroy;
|
||||||
|
begin
|
||||||
|
if not noclear then
|
||||||
|
clear;
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
dispose(FHashArray);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Tdictionary.cleartree(obj:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
if assigned(obj.left) then
|
||||||
|
cleartree(obj.left);
|
||||||
|
if assigned(obj.right) then
|
||||||
|
cleartree(obj.right);
|
||||||
|
obj.free;
|
||||||
|
obj:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Tdictionary.clear;
|
||||||
|
var
|
||||||
|
w : integer;
|
||||||
|
begin
|
||||||
|
if assigned(FRoot) then
|
||||||
|
cleartree(FRoot);
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
for w:=-hasharraysize to hasharraysize do
|
||||||
|
if assigned(FHashArray^[w]) then
|
||||||
|
cleartree(FHashArray^[w]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function Tdictionary.delete(const s:string):TDictionaryItem;
|
||||||
|
var
|
||||||
|
p,SpeedValue : cardinal;
|
||||||
|
n : TDictionaryItem;
|
||||||
|
|
||||||
|
procedure insert_right_bottom(var root,Atree:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
while root.right<>nil do
|
||||||
|
root:=root.right;
|
||||||
|
root.right:=Atree;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function delete_from_tree(root:TDictionaryItem):TDictionaryItem;
|
||||||
|
type
|
||||||
|
leftright=(left,right);
|
||||||
|
var
|
||||||
|
lr : leftright;
|
||||||
|
oldroot : TDictionaryItem;
|
||||||
|
begin
|
||||||
|
oldroot:=nil;
|
||||||
|
while (root<>nil) and (root.SpeedValue<>SpeedValue) do
|
||||||
|
begin
|
||||||
|
oldroot:=root;
|
||||||
|
if SpeedValue<root.SpeedValue then
|
||||||
|
begin
|
||||||
|
root:=root.right;
|
||||||
|
lr:=right;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
root:=root.left;
|
||||||
|
lr:=left;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
while (root<>nil) and (root.name<>s) do
|
||||||
|
begin
|
||||||
|
oldroot:=root;
|
||||||
|
if s<root.name then
|
||||||
|
begin
|
||||||
|
root:=root.right;
|
||||||
|
lr:=right;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
root:=root.left;
|
||||||
|
lr:=left;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if root.left<>nil then
|
||||||
|
begin
|
||||||
|
{ Now the Node pointing to root must point to the left
|
||||||
|
subtree of root. The right subtree of root must be
|
||||||
|
connected to the right bottom of the left subtree.}
|
||||||
|
if lr=left then
|
||||||
|
oldroot.left:=root.left
|
||||||
|
else
|
||||||
|
oldroot.right:=root.left;
|
||||||
|
if root.right<>nil then
|
||||||
|
insert_right_bottom(root.left,root.right);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{ There is no left subtree. So we can just replace the Node to
|
||||||
|
delete with the right subtree.}
|
||||||
|
if lr=left then
|
||||||
|
oldroot.left:=root.right
|
||||||
|
else
|
||||||
|
oldroot.right:=root.right;
|
||||||
|
end;
|
||||||
|
delete_from_tree:=root;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
SpeedValue:=GetSpeedValue(s);
|
||||||
|
n:=FRoot;
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
begin
|
||||||
|
{ First, check if the Node to delete directly located under
|
||||||
|
the hasharray.}
|
||||||
|
p:=SpeedValue mod hasharraysize;
|
||||||
|
n:=FHashArray^[p];
|
||||||
|
if (n<>nil) and (n.SpeedValue=SpeedValue) and
|
||||||
|
(n.name=s) then
|
||||||
|
begin
|
||||||
|
{ The Node to delete is directly located under the
|
||||||
|
hasharray. Make the hasharray point to the left
|
||||||
|
subtree of the Node and place the right subtree on
|
||||||
|
the right-bottom of the left subtree.}
|
||||||
|
if n.left<>nil then
|
||||||
|
begin
|
||||||
|
FHashArray^[p]:=n.left;
|
||||||
|
if n.right<>nil then
|
||||||
|
insert_right_bottom(n.left,n.right);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
FHashArray^[p]:=n.right;
|
||||||
|
delete:=n;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
{ First check if the Node to delete is the root.}
|
||||||
|
if (FRoot<>nil) and (n.SpeedValue=SpeedValue) and
|
||||||
|
(n.name=s) then
|
||||||
|
begin
|
||||||
|
if n.left<>nil then
|
||||||
|
begin
|
||||||
|
FRoot:=n.left;
|
||||||
|
if n.right<>nil then
|
||||||
|
insert_right_bottom(n.left,n.right);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
FRoot:=n.right;
|
||||||
|
delete:=n;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
delete:=delete_from_tree(n);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Tdictionary.empty:boolean;
|
||||||
|
var
|
||||||
|
w : integer;
|
||||||
|
begin
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
begin
|
||||||
|
empty:=false;
|
||||||
|
for w:=-hasharraysize to hasharraysize do
|
||||||
|
if assigned(FHashArray^[w]) then
|
||||||
|
exit;
|
||||||
|
empty:=true;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
empty:=(FRoot=nil);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure Tdictionary.foreach(proc2call:Tnamedindexcallback);
|
||||||
|
|
||||||
|
procedure a(p:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
proc2call(p);
|
||||||
|
if assigned(p.left) then
|
||||||
|
a(p.left);
|
||||||
|
if assigned(p.right) then
|
||||||
|
a(p.right);
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
begin
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
begin
|
||||||
|
for i:=-hasharraysize to hasharraysize do
|
||||||
|
if assigned(FHashArray^[i]) then
|
||||||
|
a(FHashArray^[i]);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if assigned(FRoot) then
|
||||||
|
a(FRoot);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function Tdictionary.insert(obj:TDictionaryItem):TDictionaryItem;
|
||||||
|
begin
|
||||||
|
obj.FSpeedValue:=GetSpeedValue(obj.name);
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
insert:=insertNode(obj,FHashArray^[obj.SpeedValue mod hasharraysize])
|
||||||
|
else
|
||||||
|
insert:=insertNode(obj,FRoot);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function tdictionary.insertNode(NewNode:TDictionaryItem;var currNode:TDictionaryItem):TDictionaryItem;
|
||||||
|
begin
|
||||||
|
if currNode=nil then
|
||||||
|
begin
|
||||||
|
currNode:=NewNode;
|
||||||
|
insertNode:=NewNode;
|
||||||
|
end
|
||||||
|
{ First check SpeedValue, to allow a fast insert }
|
||||||
|
else
|
||||||
|
if currNode.SpeedValue>NewNode.SpeedValue then
|
||||||
|
insertNode:=insertNode(NewNode,currNode.right)
|
||||||
|
else
|
||||||
|
if currNode.SpeedValue<NewNode.SpeedValue then
|
||||||
|
insertNode:=insertNode(NewNode,currNode.left)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if currNode.name>NewNode.name then
|
||||||
|
insertNode:=insertNode(NewNode,currNode.right)
|
||||||
|
else
|
||||||
|
if currNode.name<NewNode.name then
|
||||||
|
insertNode:=insertNode(NewNode,currNode.left)
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if replace_existing and
|
||||||
|
assigned(currNode) then
|
||||||
|
begin
|
||||||
|
NewNode.left:=currNode.left;
|
||||||
|
NewNode.right:=currNode.right;
|
||||||
|
currNode:=NewNode;
|
||||||
|
insertNode:=NewNode;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
insertNode:=currNode;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure tdictionary.inserttree(currtree,currroot:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
if assigned(currtree) then
|
||||||
|
begin
|
||||||
|
inserttree(currtree.left,currroot);
|
||||||
|
inserttree(currtree.right,currroot);
|
||||||
|
currtree.right:=nil;
|
||||||
|
currtree.left:=nil;
|
||||||
|
insertNode(currtree,currroot);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function tdictionary.rename(const olds,News : string):TDictionaryItem;
|
||||||
|
var
|
||||||
|
spdval : integer;
|
||||||
|
lasthp,
|
||||||
|
hp,hp2,hp3 : TDictionaryItem;
|
||||||
|
begin
|
||||||
|
spdval:=GetSpeedValue(olds);
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
hp:=FHashArray^[spdval mod hasharraysize]
|
||||||
|
else
|
||||||
|
hp:=FRoot;
|
||||||
|
lasthp:=nil;
|
||||||
|
while assigned(hp) do
|
||||||
|
begin
|
||||||
|
if spdval>hp.SpeedValue then
|
||||||
|
begin
|
||||||
|
lasthp:=hp;
|
||||||
|
hp:=hp.left
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if spdval<hp.SpeedValue then
|
||||||
|
begin
|
||||||
|
lasthp:=hp;
|
||||||
|
hp:=hp.right
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (hp.name=olds) then
|
||||||
|
begin
|
||||||
|
{ Get in hp2 the replacer for the root or hasharr }
|
||||||
|
hp2:=hp.left;
|
||||||
|
hp3:=hp.right;
|
||||||
|
if not assigned(hp2) then
|
||||||
|
begin
|
||||||
|
hp2:=hp.right;
|
||||||
|
hp3:=hp.left;
|
||||||
|
end;
|
||||||
|
{ remove entry from the tree }
|
||||||
|
if assigned(lasthp) then
|
||||||
|
begin
|
||||||
|
if lasthp.left=hp then
|
||||||
|
lasthp.left:=hp2
|
||||||
|
else
|
||||||
|
lasthp.right:=hp2;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
FHashArray^[spdval mod hasharraysize]:=hp2
|
||||||
|
else
|
||||||
|
FRoot:=hp2;
|
||||||
|
end;
|
||||||
|
{ reinsert the hp3 in the tree from hp2 }
|
||||||
|
inserttree(hp3,hp2);
|
||||||
|
{ reset Node with New values }
|
||||||
|
hp.name:=newS;
|
||||||
|
hp.FSpeedValue:=GetSpeedValue(newS);
|
||||||
|
hp.left:=nil;
|
||||||
|
hp.right:=nil;
|
||||||
|
{ reinsert }
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
rename:=insertNode(hp,FHashArray^[hp.SpeedValue mod hasharraysize])
|
||||||
|
else
|
||||||
|
rename:=insertNode(hp,FRoot);
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if olds>hp.name then
|
||||||
|
begin
|
||||||
|
lasthp:=hp;
|
||||||
|
hp:=hp.left
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
lasthp:=hp;
|
||||||
|
hp:=hp.right;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function Tdictionary.search(const s:string):TDictionaryItem;
|
||||||
|
begin
|
||||||
|
search:=speedsearch(s,GetSpeedValue(s));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function Tdictionary.speedsearch(const s:string;SpeedValue:integer):TDictionaryItem;
|
||||||
|
var
|
||||||
|
NewNode:TDictionaryItem;
|
||||||
|
begin
|
||||||
|
if assigned(FHashArray) then
|
||||||
|
NewNode:=FHashArray^[SpeedValue mod hasharraysize]
|
||||||
|
else
|
||||||
|
NewNode:=FRoot;
|
||||||
|
while assigned(NewNode) do
|
||||||
|
begin
|
||||||
|
if SpeedValue>NewNode.SpeedValue then
|
||||||
|
NewNode:=NewNode.left
|
||||||
|
else
|
||||||
|
if SpeedValue<NewNode.SpeedValue then
|
||||||
|
NewNode:=NewNode.right
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (NewNode.name=s) then
|
||||||
|
begin
|
||||||
|
speedsearch:=NewNode;
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if s>NewNode.name then
|
||||||
|
NewNode:=NewNode.left
|
||||||
|
else
|
||||||
|
NewNode:=NewNode.right;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
speedsearch:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
||||||
|
{
|
||||||
|
$Log$
|
||||||
|
Revision 1.1 2001-01-24 21:59:36 peter
|
||||||
|
* first commit of new fpcmake
|
||||||
|
|
||||||
|
}
|
828
utils/fpcm/fpcmmain.pp
Normal file
828
utils/fpcm/fpcmmain.pp
Normal file
@ -0,0 +1,828 @@
|
|||||||
|
{
|
||||||
|
$Id$
|
||||||
|
Copyright (c) 2001 by Peter Vreman
|
||||||
|
|
||||||
|
FPCMake - Main module
|
||||||
|
|
||||||
|
See the file COPYING.FPC, included in this distribution,
|
||||||
|
for details about the copyright.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
**********************************************************************}
|
||||||
|
{$ifdef fpc}{$mode objfpc}{$endif}
|
||||||
|
{$H+}
|
||||||
|
unit fpcmmain;
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
sysutils,classes,
|
||||||
|
fpcmdic;
|
||||||
|
|
||||||
|
const
|
||||||
|
Version='v1.99.0';
|
||||||
|
Title='fpcmake '+Version;
|
||||||
|
TitleDate=Title+' ['+{$ifdef fpc}{$i %DATE}{$else}'n/a'{$endif}+']';
|
||||||
|
type
|
||||||
|
TTarget=(t_all,
|
||||||
|
t_linux,t_go32v2,t_win32,t_os2,t_freebsd
|
||||||
|
);
|
||||||
|
|
||||||
|
const
|
||||||
|
TargetStr : array[TTarget] of string=('all',
|
||||||
|
'linux','go32v2','win32','os2','freebsd'
|
||||||
|
);
|
||||||
|
|
||||||
|
TargetSuffix : array[TTarget] of string=('',
|
||||||
|
'_linux','_go32v2','_win32','_os2','_freebsd'
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
TKeyValueItem = class(TDictionaryItem)
|
||||||
|
private
|
||||||
|
FValue : string;
|
||||||
|
public
|
||||||
|
constructor Create(const k,v:string);
|
||||||
|
property Value:string read FValue write FValue;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TKeyValue = class(TDictionary)
|
||||||
|
private
|
||||||
|
function GetKey(const k:string):string;
|
||||||
|
public
|
||||||
|
procedure Add(const k,v:String);
|
||||||
|
property Key[const s:string]:string read GetKey;default;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TFPCMakeSection = class(TDictionaryItem)
|
||||||
|
private
|
||||||
|
FList : TStringList;
|
||||||
|
FDictionary : TKeyValue;
|
||||||
|
procedure PrintDic(p:TDictionaryItem);
|
||||||
|
procedure BuildIniDic(p:TDictionaryItem);
|
||||||
|
procedure BuildMakefileDic(p:TDictionaryItem);
|
||||||
|
function GetKey(const k:string):string;
|
||||||
|
public
|
||||||
|
constructor Create(const n:string);
|
||||||
|
constructor CreateKeyValue(const n:string);
|
||||||
|
destructor Destroy;override;
|
||||||
|
procedure AddLine(const s:string);
|
||||||
|
procedure AddKey(const k,v:string);
|
||||||
|
procedure ParseIni;
|
||||||
|
procedure BuildIni;
|
||||||
|
procedure BuildMakefile;
|
||||||
|
procedure Print;
|
||||||
|
property Key[const s:string]:string read GetKey;default;
|
||||||
|
property List:TStringList read FList;
|
||||||
|
property Dictionary:TKeyValue read FDictionary;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TFPCMake = class
|
||||||
|
private
|
||||||
|
FStream : TStream;
|
||||||
|
FFileName : string;
|
||||||
|
FCommentChars : TSysCharSet;
|
||||||
|
FEmptyLines : boolean;
|
||||||
|
FSections : TDictionary;
|
||||||
|
FPackageSec,
|
||||||
|
FExportSec : TFPCMakeSection;
|
||||||
|
FPackageName,
|
||||||
|
FPackageVersion : string;
|
||||||
|
FRequireList : TStringList;
|
||||||
|
FVariables : TKeyValue;
|
||||||
|
procedure Init;
|
||||||
|
procedure ParseSec(p:TDictionaryItem);
|
||||||
|
procedure PrintSec(p:TDictionaryItem);
|
||||||
|
function GetSec(const AName:string):TDictionaryItem;
|
||||||
|
public
|
||||||
|
constructor Create(const AFileName:string);
|
||||||
|
constructor CreateFromStream(s:TStream;const AFileName:string);
|
||||||
|
destructor Destroy;override;
|
||||||
|
procedure LoadSections;
|
||||||
|
procedure LoadMakefileFPC;
|
||||||
|
procedure LoadPackageSection;
|
||||||
|
procedure LoadRequiredPackage(const ReqName,ReqVersion:string);
|
||||||
|
procedure LoadRequires(FromFPCMake:TFPCMake);
|
||||||
|
function GetTargetRequires(t:TTarget):TStringList;
|
||||||
|
procedure CreateExportSection;
|
||||||
|
procedure SubstVariables(var s:string);
|
||||||
|
function GetVariable(const inivar:string):string;
|
||||||
|
procedure Print;
|
||||||
|
property Section[const s:string]:TDictionaryItem read GetSec;default;
|
||||||
|
property RequireList:TStringList read FRequireList;
|
||||||
|
property Variables:TKeyValue read FVariables;
|
||||||
|
property PackageName:string read FPackageName;
|
||||||
|
property PackageVersion:string read FPackageVersion;
|
||||||
|
property PackageSec:TFPCMakeSection read FPackageSec;
|
||||||
|
property ExportSec:TFPCMakeSection read FExportSec;
|
||||||
|
property CommentChars:TSysCharSet read FCommentChars write FCommentChars;
|
||||||
|
property EmptyLines:Boolean read FEmptyLines write FEmptyLines;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function posidx(const substr,s : string;idx:integer):integer;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
resourcestring
|
||||||
|
s_not_list_sec='Not a list section "%s"';
|
||||||
|
s_not_key_value_sec='Not a key-value section "%s"';
|
||||||
|
s_err_section_start='%s:%d: Wrong section start';
|
||||||
|
s_err_not_key_value='Parse error key=value excepted: "%s"';
|
||||||
|
s_err_no_section='%s:%d: Entries without section';
|
||||||
|
s_no_package_section='No package section found';
|
||||||
|
s_no_package_name='No package name set';
|
||||||
|
s_no_package_version='No package version set';
|
||||||
|
s_err_require_format='Wrong require format "%s"';
|
||||||
|
|
||||||
|
type
|
||||||
|
tspecialdir=record
|
||||||
|
dir,unitdir,packdir : string;
|
||||||
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
specialdirs = 4;
|
||||||
|
specialdir : array[1..specialdirs] of tspecialdir=(
|
||||||
|
(dir: 'rtl'; unitdir: '$(UNITSDIR)/rtl'; packdir: '$(FPCDIR)/rtl'),
|
||||||
|
(dir: 'fcl'; unitdir: '$(UNITSDIR)/fcl'; packdir: '$(FPCDIR)/fcl'),
|
||||||
|
(dir: 'api'; unitdir: '$(UNITSDIR)/api'; packdir: '$(FPCDIR)/api'),
|
||||||
|
(dir: 'fv'; unitdir: '$(UNITSDIR)/fv'; packdir: '$(FPCDIR)/fv')
|
||||||
|
);
|
||||||
|
|
||||||
|
{****************************************************************************
|
||||||
|
Helpers
|
||||||
|
****************************************************************************}
|
||||||
|
|
||||||
|
Function PathExists ( F : String) : Boolean;
|
||||||
|
Var
|
||||||
|
Info : TSearchRec;
|
||||||
|
begin
|
||||||
|
if F[Length(f)] in ['/','\'] then
|
||||||
|
Delete(f,length(f),1);
|
||||||
|
PathExists:=(findfirst(F,fareadonly+faarchive+fahidden+fadirectory,info)=0) and
|
||||||
|
((info.attr and fadirectory)=fadirectory);
|
||||||
|
findclose(Info);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function posidx(const substr,s : string;idx:integer):integer;
|
||||||
|
var
|
||||||
|
i,j : integer;
|
||||||
|
e : boolean;
|
||||||
|
begin
|
||||||
|
i:=idx;
|
||||||
|
j:=0;
|
||||||
|
e:=(length(SubStr)>0);
|
||||||
|
while e and (i<=Length(s)-Length(SubStr)) do
|
||||||
|
begin
|
||||||
|
inc(i);
|
||||||
|
if (SubStr[1]=s[i]) and (Substr=Copy(s,i,Length(SubStr))) then
|
||||||
|
begin
|
||||||
|
j:=i;
|
||||||
|
e:=false;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
PosIdx:=j;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{****************************************************************************
|
||||||
|
TKeyValueItem
|
||||||
|
****************************************************************************}
|
||||||
|
|
||||||
|
constructor TKeyValueItem.Create(const k,v:string);
|
||||||
|
begin
|
||||||
|
inherited Create(k);
|
||||||
|
value:=v;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{****************************************************************************
|
||||||
|
TKeyValue
|
||||||
|
****************************************************************************}
|
||||||
|
|
||||||
|
function TKeyValue.GetKey(const k:string):string;
|
||||||
|
var
|
||||||
|
p : TKeyValueItem;
|
||||||
|
begin
|
||||||
|
p:=TKeyValueItem(Search(k));
|
||||||
|
if p=nil then
|
||||||
|
GetKey:=''
|
||||||
|
else
|
||||||
|
GetKey:=p.Value;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TKeyValue.Add(const k,v:string);
|
||||||
|
begin
|
||||||
|
Insert(TKeyValueItem.Create(k,v));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{****************************************************************************
|
||||||
|
TFPCMakeSection
|
||||||
|
****************************************************************************}
|
||||||
|
|
||||||
|
constructor TFPCMakeSection.Create(const n:string);
|
||||||
|
begin
|
||||||
|
inherited Create(n);
|
||||||
|
FList:=TStringList.Create;
|
||||||
|
FDictionary:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
constructor TFPCMakeSection.CreateKeyValue(const n:string);
|
||||||
|
begin
|
||||||
|
inherited Create(n);
|
||||||
|
FList:=nil;
|
||||||
|
FDictionary:=TKeyValue.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TFPCMakeSection.Destroy;
|
||||||
|
begin
|
||||||
|
inherited Destroy;
|
||||||
|
FList.Free;
|
||||||
|
FDictionary.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.AddLine(const s:string);
|
||||||
|
begin
|
||||||
|
if FList=nil then
|
||||||
|
raise Exception.Create(Format(s_not_list_sec,[Name]));
|
||||||
|
FList.Add(s);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.AddKey(const k,v:string);
|
||||||
|
begin
|
||||||
|
if FDictionary=nil then
|
||||||
|
raise Exception.Create(Format(s_not_key_value_sec,[Name]));
|
||||||
|
{ Don't add empty values }
|
||||||
|
if v<>'' then
|
||||||
|
FDictionary.Add(k,v);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.PrintDic(p:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
with TKeyValueItem(p) do
|
||||||
|
begin
|
||||||
|
writeln(' ',name,' = "',value,'"');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFPCMakeSection.GetKey(const k:string):string;
|
||||||
|
begin
|
||||||
|
if FDictionary=nil then
|
||||||
|
raise Exception.Create(Format(s_not_key_value_sec,[Name]));
|
||||||
|
GetKey:=FDictionary[k];
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.Print;
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
begin
|
||||||
|
writeln('[',Name,']');
|
||||||
|
if assigned(FList) then
|
||||||
|
begin
|
||||||
|
writeln(' List:');
|
||||||
|
for i:=0 to FList.Count-1 do
|
||||||
|
Writeln(' "'+FList[i],'"');
|
||||||
|
if assigned(FDictionary) then
|
||||||
|
writeln('');
|
||||||
|
end;
|
||||||
|
if assigned(FDictionary) then
|
||||||
|
begin
|
||||||
|
writeln(' Dictionary:');
|
||||||
|
FDictionary.Foreach(@PrintDic);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.ParseIni;
|
||||||
|
var
|
||||||
|
p : TKeyValueItem;
|
||||||
|
i,j,len,maxi : integer;
|
||||||
|
s,newkey,value : string;
|
||||||
|
begin
|
||||||
|
{ If already processed skip }
|
||||||
|
if assigned(FDictionary) then
|
||||||
|
exit;
|
||||||
|
{ Don't process rules section }
|
||||||
|
if (Name='rules') then
|
||||||
|
exit;
|
||||||
|
{ Parse the section }
|
||||||
|
FDictionary:=TKeyValue.Create;
|
||||||
|
{ Parse the list }
|
||||||
|
maxi:=FList.Count;
|
||||||
|
i:=0;
|
||||||
|
while (i<maxi) do
|
||||||
|
begin
|
||||||
|
s:=Trim(FList[i]);
|
||||||
|
len:=Length(s);
|
||||||
|
{ Concat lines ending with \ }
|
||||||
|
while s[len]='\' do
|
||||||
|
begin
|
||||||
|
Delete(s,len,1);
|
||||||
|
if i+1<maxi then
|
||||||
|
begin
|
||||||
|
inc(i);
|
||||||
|
s:=s+Trim(FList[i]);
|
||||||
|
len:=Length(s);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{ Parse key=value line }
|
||||||
|
j:=0;
|
||||||
|
while (j<len) and (s[j+1] in ['A'..'Z','a'..'z','0'..'9','_']) do
|
||||||
|
inc(j);
|
||||||
|
NewKey:=Copy(s,1,j);
|
||||||
|
While (j<len) and (s[j+1] in [' ',#9]) do
|
||||||
|
inc(j);
|
||||||
|
inc(j);
|
||||||
|
if s[j]<>'=' then
|
||||||
|
Raise Exception.Create(Format(s_err_not_key_value,[s]));
|
||||||
|
While (j<len) and (s[j+1] in [' ',#9]) do
|
||||||
|
inc(j);
|
||||||
|
if j=len then
|
||||||
|
Raise Exception.Create(Format(s_err_not_key_value,[s]));
|
||||||
|
Value:=Copy(s,j+1,len-j);
|
||||||
|
p:=TKeyValueItem(FDictionary[NewKey]);
|
||||||
|
{ Concat values if key already exists }
|
||||||
|
if assigned(p) then
|
||||||
|
p.Value:=p.Value+' '+Value
|
||||||
|
else
|
||||||
|
FDictionary.Add(NewKey,Value);
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
{ List is not used anymore }
|
||||||
|
FList.Free;
|
||||||
|
FList:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.BuildIniDic(p:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
with TKeyValueItem(p) do
|
||||||
|
begin
|
||||||
|
FList.Add(Name+'='+Value);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.BuildIni;
|
||||||
|
begin
|
||||||
|
if assigned(FList) then
|
||||||
|
exit;
|
||||||
|
FList:=TStringList.Create;
|
||||||
|
FDictionary.Foreach(@BuildIniDic);
|
||||||
|
FDictionary.Free;
|
||||||
|
FDictionary:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.BuildMakefileDic(p:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
FList.Add(Uppercase(Name+'_'+TKeyValueItem(p).Name)+'='+TKeyValueItem(p).Value);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMakeSection.BuildMakefile;
|
||||||
|
begin
|
||||||
|
if assigned(FList) then
|
||||||
|
exit;
|
||||||
|
FList:=TStringList.Create;
|
||||||
|
FDictionary.Foreach(@BuildMakefileDic);
|
||||||
|
FDictionary.Free;
|
||||||
|
FDictionary:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{****************************************************************************
|
||||||
|
TFPCMake
|
||||||
|
****************************************************************************}
|
||||||
|
|
||||||
|
constructor TFPCMake.Create(const AFileName:string);
|
||||||
|
begin
|
||||||
|
FFileName:=AFileName;
|
||||||
|
FStream:=nil;
|
||||||
|
Init;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
constructor TFPCMake.CreateFromStream(s:TStream;const AFileName:string);
|
||||||
|
begin
|
||||||
|
FFileName:=AFileName;
|
||||||
|
FStream:=s;
|
||||||
|
Init;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.Init;
|
||||||
|
begin
|
||||||
|
FSections:=TDictionary.Create;
|
||||||
|
FRequireList:=TStringList.Create;
|
||||||
|
FVariables:=TKeyValue.Create;
|
||||||
|
FCommentChars:=[';','#'];
|
||||||
|
FEmptyLines:=false;
|
||||||
|
FPackageName:='';
|
||||||
|
FPackageVersion:='';
|
||||||
|
FPackageSec:=nil;
|
||||||
|
FExportSec:=nil;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TFPCMake.Destroy;
|
||||||
|
begin
|
||||||
|
FSections.Free;
|
||||||
|
FRequireList.Free;
|
||||||
|
FVariables.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.LoadSections;
|
||||||
|
var
|
||||||
|
SLInput : TStringList;
|
||||||
|
i,j,n : integer;
|
||||||
|
s,
|
||||||
|
SecName : string;
|
||||||
|
CurrSec : TFPCMakeSection;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
SLInput:=TStringList.Create;
|
||||||
|
if assigned(FStream) then
|
||||||
|
SLInput.LoadFromStream(FStream)
|
||||||
|
else
|
||||||
|
SLInput.LoadFromFile(FFileName);
|
||||||
|
{ Load Input into sections list }
|
||||||
|
n:=SLInput.Count;
|
||||||
|
i:=0;
|
||||||
|
while (i<n) do
|
||||||
|
begin
|
||||||
|
s:=Trim(SLInput[i]);
|
||||||
|
if (EmptyLines and (s='')) or
|
||||||
|
((s<>'') and not(s[1] in FCommentChars)) then
|
||||||
|
begin
|
||||||
|
{ section start? }
|
||||||
|
if (s<>'') and (s[1]='[') then
|
||||||
|
begin
|
||||||
|
j:=pos(']',s);
|
||||||
|
if j=0 then
|
||||||
|
raise Exception.Create(Format(s_err_section_start,[FFileName,i]));
|
||||||
|
SecName:=Copy(s,2,j-2);
|
||||||
|
CurrSec:=TFPCMakeSection(FSections[SecName]);
|
||||||
|
if CurrSec=nil then
|
||||||
|
CurrSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(SecName)));
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if CurrSec=nil then
|
||||||
|
raise Exception.Create(Format(s_err_no_section,[FFileName,i]));
|
||||||
|
{ Insert string without spaces stripped }
|
||||||
|
CurrSec.AddLine(SLInput[i]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
SLInput.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.LoadMakefileFPC;
|
||||||
|
begin
|
||||||
|
LoadSections;
|
||||||
|
{ Parse all sections }
|
||||||
|
FSections.Foreach(@ParseSec);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.LoadPackageSection;
|
||||||
|
begin
|
||||||
|
{ Get package info from package section }
|
||||||
|
FPackageSec:=TFPCMakeSection(FSections['package']);
|
||||||
|
if FPackageSec=nil then
|
||||||
|
begin
|
||||||
|
Writeln('Note: no package section');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
{ Parse the section to key=value pairs }
|
||||||
|
FPackageSec.ParseIni;
|
||||||
|
{ mandatory name }
|
||||||
|
FPackageName:=FPackageSec['name'];
|
||||||
|
if FPackageName='' then
|
||||||
|
Raise Exception.Create(s_no_package_name);
|
||||||
|
{ mandatory version }
|
||||||
|
FPackageVersion:=FPackageSec['version'];
|
||||||
|
if FPackageVersion='' then
|
||||||
|
Raise Exception.Create(s_no_package_version);
|
||||||
|
{ Set the ExportSec }
|
||||||
|
FExportSec:=TFPCMakeSection(FSections[Lowercase(FPackageName)]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.CreateExportSection;
|
||||||
|
var
|
||||||
|
t : TTarget;
|
||||||
|
begin
|
||||||
|
{ Don't create a section twice }
|
||||||
|
if FExportSec<>nil then
|
||||||
|
exit;
|
||||||
|
{ Look if we've already an own section, else create a new
|
||||||
|
key-value section }
|
||||||
|
FExportSec:=TFPCMakeSection(FSections[LowerCase(FPackageName)]);
|
||||||
|
if FExportSec=nil then
|
||||||
|
FExportSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.CreateKeyValue(LowerCase(FPackageName))));
|
||||||
|
{ Add default the values to the export section }
|
||||||
|
FExportSec.AddKey('name',FPackageName);
|
||||||
|
FExportSec.AddKey('version',FPackageVersion);
|
||||||
|
{ Add required packages }
|
||||||
|
for t:=low(TTarget) to high(TTarget) do
|
||||||
|
FExportSec.AddKey('require'+TargetSuffix[t],FPackageSec['require'+TargetSuffix[t]]);
|
||||||
|
{ Unit dir }
|
||||||
|
{FExportSec.AddKey('unitdir','$(UNITSDIR)/'+Lowercase(PackageName));}
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.LoadRequiredPackage(const ReqName,ReqVersion:string);
|
||||||
|
|
||||||
|
function TryFile(const fn:string):boolean;
|
||||||
|
var
|
||||||
|
ReqFPCMake : TFPCMake;
|
||||||
|
HList : TStringList;
|
||||||
|
NewSec,ReqSec,Sec : TFPCMakeSection;
|
||||||
|
begin
|
||||||
|
TryFile:=false;
|
||||||
|
if FileExists(fn) then
|
||||||
|
begin
|
||||||
|
writeln('Package ',ReqName,': ',fn);
|
||||||
|
|
||||||
|
ReqFPCMake:=TFPCMake.Create(fn);
|
||||||
|
ReqFPCMake.LoadMakefileFPC;
|
||||||
|
ReqFPCMake.LoadPackageSection;
|
||||||
|
{ Check package name and version }
|
||||||
|
if LowerCase(ReqFPCMake.PackageName)<>ReqName then
|
||||||
|
raise Exception.Create('s_wrong_package_name');
|
||||||
|
if (ReqVersion<>'') and (ReqFPCMake.PackageVersion<ReqVersion) then
|
||||||
|
raise Exception.Create('s_wrong_package_version');
|
||||||
|
{ First load the requirements of this package }
|
||||||
|
LoadRequires(ReqFPCMake);
|
||||||
|
{ Get a copy of the export section }
|
||||||
|
if assigned(ReqFPCMake.ExportSec) then
|
||||||
|
begin
|
||||||
|
ReqFPCMake.ExportSec.BuildIni;
|
||||||
|
NewSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(ReqName)));
|
||||||
|
NewSec.List.AddStrings(ReqFPCMake.ExportSec.List);
|
||||||
|
NewSec.ParseIni;
|
||||||
|
end;
|
||||||
|
{ Get a copy of the require section }
|
||||||
|
ReqSec:=TFPCMakeSection(ReqFPCMake['require']);
|
||||||
|
if assigned(ReqSec) then
|
||||||
|
begin
|
||||||
|
ReqSec.BuildIni;
|
||||||
|
NewSec:=TFPCMakeSection(FSections.Insert(TFPCMakeSection.Create(ReqName+'_require')));
|
||||||
|
NewSec.List.AddStrings(ReqSec.List);
|
||||||
|
NewSec.ParseIni;
|
||||||
|
end;
|
||||||
|
{ Free }
|
||||||
|
ReqFPCMake.Free;
|
||||||
|
TryFile:=true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
s : string;
|
||||||
|
i : integer;
|
||||||
|
begin
|
||||||
|
writeln(ReqName,' - ',ReqVersion);
|
||||||
|
|
||||||
|
s:='$(PACKAGESDIR)/'+ReqName;
|
||||||
|
For i:=1 to SpecialDirs do
|
||||||
|
if SpecialDir[i].Dir=ReqName then
|
||||||
|
begin
|
||||||
|
s:=SpecialDir[i].PackDir;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
SubstVariables(s);
|
||||||
|
if TryFile(s+'/Makefile.fpc') then
|
||||||
|
exit;
|
||||||
|
Raise Exception.Create('s_package_not_found');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.LoadRequires(FromFPCMake:TFPCMake);
|
||||||
|
var
|
||||||
|
s,
|
||||||
|
ReqName,
|
||||||
|
ReqVersion : string;
|
||||||
|
i,j : integer;
|
||||||
|
t : TTarget;
|
||||||
|
Sec : TFPCMakeSection;
|
||||||
|
begin
|
||||||
|
Sec:=TFPCMakeSection(FromFPCMake['require']);
|
||||||
|
if Sec=nil then
|
||||||
|
exit;
|
||||||
|
for t:=low(TTarget) to high(TTarget) do
|
||||||
|
begin
|
||||||
|
s:=Sec['packages'+TargetSuffix[t]];
|
||||||
|
repeat
|
||||||
|
i:=pos(' ',s);
|
||||||
|
if i=0 then
|
||||||
|
begin
|
||||||
|
ReqName:=Trim(s);
|
||||||
|
s:='';
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
ReqName:=Trim(Copy(s,1,i));
|
||||||
|
Delete(s,1,i);
|
||||||
|
s:=TrimLeft(s);
|
||||||
|
end;
|
||||||
|
if ReqName<>'' then
|
||||||
|
begin
|
||||||
|
i:=Pos('(',ReqName);
|
||||||
|
if i>0 then
|
||||||
|
begin
|
||||||
|
j:=Pos(')',ReqName);
|
||||||
|
if (i=1) or (j=0) then
|
||||||
|
Raise Exception.Create(Format(s_err_require_format,[ReqName]));
|
||||||
|
ReqVersion:=Copy(ReqName,i+1,j-i-1);
|
||||||
|
ReqName:=Copy(ReqName,1,i-1);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
ReqVersion:='';
|
||||||
|
{ We only use lowercase names }
|
||||||
|
ReqName:=Lowercase(ReqName);
|
||||||
|
{ Already loaded ? }
|
||||||
|
if not RequireList.Find(ReqName,i) then
|
||||||
|
begin
|
||||||
|
LoadRequiredPackage(ReqName,ReqVersion);
|
||||||
|
RequireList.Add(ReqName);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
until s='';
|
||||||
|
end;
|
||||||
|
{ Force an rtl dependency }
|
||||||
|
if not RequireList.Find('rtl',i) then
|
||||||
|
begin
|
||||||
|
LoadRequiredPackage('rtl','');
|
||||||
|
RequireList.Add('rtl');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFPCMake.GetTargetRequires(t:TTarget):TStringList;
|
||||||
|
var
|
||||||
|
ReqSec : TFPCMakeSection;
|
||||||
|
ReqList : TStringList;
|
||||||
|
|
||||||
|
procedure AddReqSec(t:TTarget;Sec:TFPCMakeSection);
|
||||||
|
var
|
||||||
|
s,
|
||||||
|
ReqName : string;
|
||||||
|
RSec : TFPCMakeSection;
|
||||||
|
i,j : integer;
|
||||||
|
begin
|
||||||
|
s:=Sec['packages'+TargetSuffix[t]];
|
||||||
|
while s<>'' do
|
||||||
|
begin
|
||||||
|
i:=pos(' ',s);
|
||||||
|
if i=0 then
|
||||||
|
begin
|
||||||
|
ReqName:=Trim(s);
|
||||||
|
s:='';
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
ReqName:=Trim(Copy(s,1,i));
|
||||||
|
Delete(s,1,i);
|
||||||
|
s:=TrimLeft(s);
|
||||||
|
end;
|
||||||
|
if ReqName<>'' then
|
||||||
|
begin
|
||||||
|
i:=Pos('(',ReqName);
|
||||||
|
if i>0 then
|
||||||
|
ReqName:=Copy(ReqName,1,i-1);
|
||||||
|
{ We only use lowercase names }
|
||||||
|
ReqName:=Lowercase(ReqName);
|
||||||
|
{ Already loaded ? }
|
||||||
|
if not ReqList.Find(ReqName,i) then
|
||||||
|
begin
|
||||||
|
RSec:=TFPCMakeSection(FSections[ReqName+'_require']);
|
||||||
|
if assigned(RSec) then
|
||||||
|
begin
|
||||||
|
{ for packages we depend on always include the
|
||||||
|
target and all keys }
|
||||||
|
if t<>t_all then
|
||||||
|
AddReqSec(t_all,RSec);
|
||||||
|
AddReqSec(t,RSec);
|
||||||
|
end;
|
||||||
|
ReqList.Add(ReqName);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ReqList:=TStringList.Create;
|
||||||
|
ReqSec:=TFPCMakeSection(FSections['require']);
|
||||||
|
if assigned(ReqSec) then
|
||||||
|
AddReqSec(t,ReqSec);
|
||||||
|
GetTargetRequires:=ReqList;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.SubstVariables(var s:string);
|
||||||
|
var
|
||||||
|
i,j,k : integer;
|
||||||
|
s2,s3 : string;
|
||||||
|
Sec : TFPCMakeSection;
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
i:=Pos('$(',s);
|
||||||
|
if i=0 then
|
||||||
|
break;
|
||||||
|
j:=PosIdx(')',s,i+2);
|
||||||
|
s2:=Copy(s,i+2,j-i-2);
|
||||||
|
k:=pos('.',s2);
|
||||||
|
if k>0 then
|
||||||
|
begin
|
||||||
|
s3:=Copy(s2,k+1,Length(s2)-k);
|
||||||
|
s2:=Copy(s2,1,k-1);
|
||||||
|
Sec:=TFPCMakeSection(Section[s2]);
|
||||||
|
if assigned(Sec) then
|
||||||
|
s2:=Sec[s3]
|
||||||
|
else
|
||||||
|
s2:='';
|
||||||
|
end
|
||||||
|
else
|
||||||
|
s2:=Variables[s2];
|
||||||
|
Delete(s,i,j-i+1);
|
||||||
|
Insert(s2,s,i);
|
||||||
|
until false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFPCMake.GetVariable(const inivar:string):string;
|
||||||
|
var
|
||||||
|
Sec : TFPCMakeSection;
|
||||||
|
Dic : TKeyValue;
|
||||||
|
i : integer;
|
||||||
|
begin
|
||||||
|
Result:='';
|
||||||
|
i:=Pos('.',inivar);
|
||||||
|
if i<>0 then
|
||||||
|
begin
|
||||||
|
Sec:=TFPCMakeSection(FSections[Copy(Inivar,1,i-1)]);
|
||||||
|
if assigned(Sec) then
|
||||||
|
begin
|
||||||
|
Dic:=TKeyValue(Sec.Dictionary);
|
||||||
|
Result:=Dic[Copy(IniVar,i+1,Length(IniVar)-i)];
|
||||||
|
end
|
||||||
|
else
|
||||||
|
exit;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Result:=Variables[IniVar];
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.ParseSec(p:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
TFPCMakeSection(p).ParseIni;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.PrintSec(p:TDictionaryItem);
|
||||||
|
begin
|
||||||
|
TFPCMakeSection(p).Print;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFPCMake.Print;
|
||||||
|
begin
|
||||||
|
FSections.Foreach(@PrintSec);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFPCMake.GetSec(const AName:string):TDictionaryItem;
|
||||||
|
begin
|
||||||
|
GetSec:=FSections.Search(AName);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
{
|
||||||
|
$Log$
|
||||||
|
Revision 1.1 2001-01-24 21:59:36 peter
|
||||||
|
* first commit of new fpcmake
|
||||||
|
|
||||||
|
}
|
713
utils/fpcm/fpcmwr.pp
Normal file
713
utils/fpcm/fpcmwr.pp
Normal file
@ -0,0 +1,713 @@
|
|||||||
|
{
|
||||||
|
$Id$
|
||||||
|
Copyright (c) 2001 by Peter Vreman
|
||||||
|
|
||||||
|
FPCMake - Makefile writer
|
||||||
|
|
||||||
|
See the file COPYING.FPC, included in this distribution,
|
||||||
|
for details about the copyright.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
**********************************************************************}
|
||||||
|
{$ifdef fpc}{$mode objfpc}{$endif}
|
||||||
|
{$H+}
|
||||||
|
unit fpcmwr;
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
sysutils,classes,
|
||||||
|
fpcmmain;
|
||||||
|
|
||||||
|
type
|
||||||
|
tsections=(sec_none,
|
||||||
|
sec_units,sec_exes,sec_loaders,sec_examples,
|
||||||
|
sec_compile,sec_install,sec_exampleinstall,
|
||||||
|
sec_zipinstall,sec_clean,sec_libs,
|
||||||
|
sec_command,sec_exts,sec_dirs,sec_tools,sec_info
|
||||||
|
);
|
||||||
|
|
||||||
|
tRules=(
|
||||||
|
r_all,r_debug,
|
||||||
|
r_examples,
|
||||||
|
r_smart,r_shared,
|
||||||
|
r_install,r_sourceinstall,r_exampleinstall,
|
||||||
|
r_zipinstall,r_zipsourceinstall,r_zipexampleinstall,
|
||||||
|
r_clean,r_distclean,r_cleanall,
|
||||||
|
r_info
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
rule2str : array[trules] of string=(
|
||||||
|
'all','debug',
|
||||||
|
'examples',
|
||||||
|
'smart','shared',
|
||||||
|
'install','sourceinstall','exampleinstall',
|
||||||
|
'zipinstall','zipsourceinstall','zipexampleinstall',
|
||||||
|
'clean','distclean','cleanall',
|
||||||
|
'info'
|
||||||
|
);
|
||||||
|
|
||||||
|
rule2sec : array[trules] of tsections=(
|
||||||
|
sec_compile,sec_compile,
|
||||||
|
sec_examples,
|
||||||
|
sec_libs,sec_libs,
|
||||||
|
sec_install,sec_install,sec_exampleinstall,
|
||||||
|
sec_zipinstall,sec_zipinstall,sec_zipinstall,
|
||||||
|
sec_clean,sec_clean,sec_clean,
|
||||||
|
sec_info
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
TMakefileWriter=class
|
||||||
|
private
|
||||||
|
FFileName : string;
|
||||||
|
FIni : TFPCMake;
|
||||||
|
FInput : TFPCMake;
|
||||||
|
FOutput : TStringList;
|
||||||
|
FPhony : string;
|
||||||
|
FHasSection : array[tsections] of boolean;
|
||||||
|
procedure LoadFPCMakeIni;
|
||||||
|
procedure AddIniSection(const s:string);
|
||||||
|
procedure AddCustomSection(const s:string);
|
||||||
|
procedure AddTargetVariable(const inivar:string);
|
||||||
|
procedure AddVariable(const inivar:string);
|
||||||
|
function AddTargetDefines(const inivar,prefix:string):string;
|
||||||
|
procedure AddRequiredPackages;
|
||||||
|
procedure AddTool(const exename:string);
|
||||||
|
procedure AddRules;
|
||||||
|
procedure AddPhony(const s:string);
|
||||||
|
procedure WritePhony;
|
||||||
|
procedure AddTargetDirs(const inivar:string);
|
||||||
|
function CheckTargetVariable(const inivar:string):boolean;
|
||||||
|
function CheckVariable(const inivar:string):boolean;
|
||||||
|
public
|
||||||
|
constructor Create(AFPCMake:TFPCMake;const AFileName:string);
|
||||||
|
destructor Destroy;override;
|
||||||
|
procedure WriteGenericMakefile;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$i fpcmake.inc}
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyMemoryStream=class(TMemoryStream)
|
||||||
|
public
|
||||||
|
constructor Create(p:pointer;mysize:integer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{*****************************************************************************
|
||||||
|
Helpers
|
||||||
|
*****************************************************************************}
|
||||||
|
|
||||||
|
function FixVariable(s:string):string;
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
begin
|
||||||
|
Result:=UpperCase(s);
|
||||||
|
i:=pos('.',Result);
|
||||||
|
if i>0 then
|
||||||
|
Result[i]:='_';
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function VarName(const s:string):string;
|
||||||
|
var
|
||||||
|
i,j : longint;
|
||||||
|
begin
|
||||||
|
i:=0;
|
||||||
|
result:=s;
|
||||||
|
while i<length(result) do
|
||||||
|
begin
|
||||||
|
inc(i);
|
||||||
|
case result[i] of
|
||||||
|
'{' :
|
||||||
|
begin
|
||||||
|
{ this are pkgs which are hold the dirs between the accolades }
|
||||||
|
j:=PosIdx('}',result,i);
|
||||||
|
if j>0 then
|
||||||
|
Delete(result,i,j-i+1)
|
||||||
|
else
|
||||||
|
Delete(result,i,1);
|
||||||
|
dec(i);
|
||||||
|
end;
|
||||||
|
'$','(',')' :
|
||||||
|
begin
|
||||||
|
Delete(result,i,1);
|
||||||
|
dec(i);
|
||||||
|
end;
|
||||||
|
'a'..'z' :
|
||||||
|
result[i]:=chr(ord(result[i])-32);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure AddStrNoDup(var s:string;const s2:string);
|
||||||
|
var
|
||||||
|
i,idx : longint;
|
||||||
|
again,add : boolean;
|
||||||
|
begin
|
||||||
|
add:=false;
|
||||||
|
idx:=0;
|
||||||
|
repeat
|
||||||
|
again:=false;
|
||||||
|
i:=posidx(s2,s,idx);
|
||||||
|
if (i=0) then
|
||||||
|
add:=true
|
||||||
|
else
|
||||||
|
if (i=1) then
|
||||||
|
begin
|
||||||
|
if (length(s)>length(s2)) and
|
||||||
|
(s[length(s2)+1]<>' ') then
|
||||||
|
add:=true;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if (i>1) and
|
||||||
|
((s[i-1]<>' ') or
|
||||||
|
((length(s)>=i+length(s2)) and (s[i+length(s2)]<>' '))) then
|
||||||
|
begin
|
||||||
|
idx:=i+length(s2);
|
||||||
|
again:=true;
|
||||||
|
end;
|
||||||
|
until not again;
|
||||||
|
if add then
|
||||||
|
begin
|
||||||
|
if s='' then
|
||||||
|
s:=s2
|
||||||
|
else
|
||||||
|
s:=s+' '+s2;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
procedure FixTab(sl:TStringList);
|
||||||
|
var
|
||||||
|
i,j,k : integer;
|
||||||
|
s,s2 : string;
|
||||||
|
begin
|
||||||
|
i:=0;
|
||||||
|
while (i<sl.Count) do
|
||||||
|
begin
|
||||||
|
if (sl[i]<>'') and (sl[i][1] in [' ',#9]) then
|
||||||
|
begin
|
||||||
|
s:=sl[i];
|
||||||
|
k:=0;
|
||||||
|
j:=0;
|
||||||
|
repeat
|
||||||
|
inc(j);
|
||||||
|
case s[j] of
|
||||||
|
' ' :
|
||||||
|
inc(k);
|
||||||
|
#9 :
|
||||||
|
k:=(k+7) and not(7);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
until (j=length(s));
|
||||||
|
if k>7 then
|
||||||
|
begin
|
||||||
|
s2:='';
|
||||||
|
Delete(s,1,j-1);
|
||||||
|
while (k>7) do
|
||||||
|
begin
|
||||||
|
s2:=s2+#9;
|
||||||
|
dec(k,8);
|
||||||
|
end;
|
||||||
|
while (k>0) do
|
||||||
|
begin
|
||||||
|
s2:=s2+' ';
|
||||||
|
dec(k);
|
||||||
|
end;
|
||||||
|
sl[i]:=s2+s;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{*****************************************************************************
|
||||||
|
TMyMemoryStream
|
||||||
|
*****************************************************************************}
|
||||||
|
|
||||||
|
constructor TMyMemoryStream.Create(p:pointer;mysize:integer);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
SetPointer(p,mysize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{*****************************************************************************
|
||||||
|
TMyMemoryStream
|
||||||
|
*****************************************************************************}
|
||||||
|
|
||||||
|
constructor TMakefileWriter.Create(AFPCMake:TFPCMake;const AFileName:string);
|
||||||
|
begin
|
||||||
|
FInput:=AFPCMake;
|
||||||
|
FFileName:=AFileName;
|
||||||
|
FOutput:=TStringList.Create;
|
||||||
|
FPhony:='';
|
||||||
|
FillChar(FHasSection,sizeof(FHasSection),1);
|
||||||
|
LoadFPCMakeIni;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TMakefileWriter.Destroy;
|
||||||
|
begin
|
||||||
|
FOutput.Free;
|
||||||
|
FIni.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.LoadFPCMakeIni;
|
||||||
|
var
|
||||||
|
IniStream : TStream;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
IniStream:=TMyMemoryStream.Create(@fpcmakeini,sizeof(fpcmakeini));
|
||||||
|
FIni:=TFPCMake.CreateFromStream(IniStream,'fpcmake.ini');
|
||||||
|
{ Leave the '#' comments in the output }
|
||||||
|
// FIni.CommentChars:=[';'];
|
||||||
|
FIni.LoadSections;
|
||||||
|
finally
|
||||||
|
IniStream.Destroy;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddIniSection(const s:string);
|
||||||
|
var
|
||||||
|
Sec : TFPCMakeSection;
|
||||||
|
begin
|
||||||
|
Sec:=TFPCMakeSection(FIni[s]);
|
||||||
|
if assigned(Sec) then
|
||||||
|
FOutput.AddStrings(Sec.List)
|
||||||
|
else
|
||||||
|
Raise Exception.Create(Format('Section "%s" doesn''t exists in fpcmake.ini',[s]));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddCustomSection(const s:string);
|
||||||
|
var
|
||||||
|
Sec : TFPCMakeSection;
|
||||||
|
begin
|
||||||
|
Sec:=TFPCMakeSection(FInput[s]);
|
||||||
|
if assigned(Sec) then
|
||||||
|
begin
|
||||||
|
Sec.BuildMakefile;
|
||||||
|
FOutput.AddStrings(Sec.List);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TMakefileWriter.CheckTargetVariable(const inivar:string):boolean;
|
||||||
|
var
|
||||||
|
t : TTarget;
|
||||||
|
begin
|
||||||
|
result:=false;
|
||||||
|
for t:=low(TTarget) to high(TTarget) do
|
||||||
|
if FInput.GetVariable(IniVar+TargetSuffix[t])<>'' then
|
||||||
|
begin
|
||||||
|
result:=true;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TMakefileWriter.CheckVariable(const inivar:string):boolean;
|
||||||
|
begin
|
||||||
|
Result:=(FInput.GetVariable(IniVar)<>'');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddTargetVariable(const inivar:string);
|
||||||
|
var
|
||||||
|
s : string;
|
||||||
|
T : TTarget;
|
||||||
|
begin
|
||||||
|
for t:=low(TTarget) to high(TTarget) do
|
||||||
|
begin
|
||||||
|
s:=FInput.GetVariable(IniVar+TargetSuffix[t]);
|
||||||
|
if s<>'' then
|
||||||
|
begin
|
||||||
|
if t<>t_all then
|
||||||
|
FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
|
||||||
|
FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
|
||||||
|
if t<>t_all then
|
||||||
|
FOutput.Add('endif');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddVariable(const inivar:string);
|
||||||
|
var
|
||||||
|
s : string;
|
||||||
|
begin
|
||||||
|
s:=FInput.GetVariable(IniVar);
|
||||||
|
if s<>'' then
|
||||||
|
FOutput.Add('override '+FixVariable(IniVar)+'='+s)
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TMakefileWriter.AddTargetDefines(const inivar,prefix:string):string;
|
||||||
|
var
|
||||||
|
s : string;
|
||||||
|
T : TTarget;
|
||||||
|
name : string;
|
||||||
|
i,k1,k2 : integer;
|
||||||
|
begin
|
||||||
|
result:='';
|
||||||
|
for t:=low(TTarget) to high(TTarget) do
|
||||||
|
begin
|
||||||
|
s:=FInput.GetVariable(IniVar+TargetSuffix[t]);
|
||||||
|
while (s<>'') do
|
||||||
|
begin
|
||||||
|
i:=pos(' ',s);
|
||||||
|
if i=0 then
|
||||||
|
i:=length(s)+1;
|
||||||
|
name:=Copy(s,1,i-1);
|
||||||
|
s:=TrimLeft(Copy(s,i+1,Length(s)-i));
|
||||||
|
{ Remove (..) }
|
||||||
|
k1:=pos('(',name);
|
||||||
|
if k1>0 then
|
||||||
|
begin
|
||||||
|
k2:=PosIdx(')',name,k1);
|
||||||
|
if k2=0 then
|
||||||
|
k2:=length(name)+1;
|
||||||
|
Delete(Name,k1,k2);
|
||||||
|
end;
|
||||||
|
FOutput.Add(prefix+VarName(name)+'=1');
|
||||||
|
{ add to the list of dirs without duplicates }
|
||||||
|
AddStrNoDup(result,name);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddTool(const exename:string);
|
||||||
|
var
|
||||||
|
varname : string;
|
||||||
|
begin
|
||||||
|
with FOutput do
|
||||||
|
begin
|
||||||
|
varname:=FixVariable(exename);
|
||||||
|
Add('ifndef '+varname);
|
||||||
|
Add(varname+':=$(strip $(wildcard $(addsuffix /'+exename+'$(SRCEXEEXT),$(SEARCHPATH))))');
|
||||||
|
Add('ifeq ($('+varname+'),)');
|
||||||
|
Add(varname+'=');
|
||||||
|
Add('else');
|
||||||
|
Add(varname+':=$(firstword $('+varname+'))');
|
||||||
|
Add('endif');
|
||||||
|
Add('endif');
|
||||||
|
Add('export '+varname);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddRules;
|
||||||
|
|
||||||
|
procedure AddRule(rule:trules);
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
hs : string;
|
||||||
|
Sec : TFPCMakeSection;
|
||||||
|
Rules : TStringList;
|
||||||
|
begin
|
||||||
|
Sec:=TFPCMakeSection(FInput['rules']);
|
||||||
|
if assigned(Sec) then
|
||||||
|
begin
|
||||||
|
Rules:=Sec.List;
|
||||||
|
for i:=0 to Rules.Count-1 do
|
||||||
|
begin
|
||||||
|
if (length(rules[i])>length(rule2str[rule])) and
|
||||||
|
(rules[i][1]=rule2str[rule][1]) and
|
||||||
|
((rules[i][length(rule2str[rule])+1]=':') or
|
||||||
|
((length(rules[i])>length(rule2str[rule])+1) and
|
||||||
|
(rules[i][length(rule2str[rule])+2]=':'))) and
|
||||||
|
(Copy(rules[i],1,length(rule2str[rule]))=rule2str[rule]) then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
hs:='';
|
||||||
|
if FHasSection[Rule2Sec[rule]] then
|
||||||
|
hs:=hs+' fpc_'+rule2str[rule];
|
||||||
|
{ include target dirs }
|
||||||
|
if CheckTargetVariable('target.dirs') then
|
||||||
|
begin
|
||||||
|
if not(rule in [r_sourceinstall,r_zipinstall,r_zipsourceinstall]) or
|
||||||
|
not(CheckVariable('package.name')) then
|
||||||
|
hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_DIRS))';
|
||||||
|
end;
|
||||||
|
{ include cleaning of example dirs }
|
||||||
|
if (rule=r_clean) and
|
||||||
|
CheckTargetVariable('target.exampledirs') then
|
||||||
|
hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_EXAMPLEDIRS))';
|
||||||
|
if hs<>'' then
|
||||||
|
begin
|
||||||
|
AddPhony(Rule2Str[Rule]);
|
||||||
|
FOutput.Add(rule2str[rule]+':'+hs);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
rule : trules;
|
||||||
|
begin
|
||||||
|
for rule:=low(trules) to high(trules) do
|
||||||
|
AddRule(rule);
|
||||||
|
WritePhony;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddPhony(const s:string);
|
||||||
|
begin
|
||||||
|
FPhony:=FPhony+' '+s;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.WritePhony;
|
||||||
|
begin
|
||||||
|
if FPhony<>'' then
|
||||||
|
begin
|
||||||
|
FOutput.Add('.PHONY:'+FPhony);
|
||||||
|
FPhony:='';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddTargetDirs(const inivar:string);
|
||||||
|
|
||||||
|
procedure AddTargetDir(const s,defpref:string);
|
||||||
|
var
|
||||||
|
j : trules;
|
||||||
|
begin
|
||||||
|
FOutput.Add('ifdef '+defpref+VarName(s));
|
||||||
|
for j:=low(trules) to high(trules) do
|
||||||
|
begin
|
||||||
|
FOutput.Add(s+'_'+rule2str[j]+':');
|
||||||
|
FOutput.Add(#9+'$(MAKE) -C '+s+' '+rule2str[j]);
|
||||||
|
AddPhony(rule2str[j]);
|
||||||
|
end;
|
||||||
|
WritePhony;
|
||||||
|
FOutput.Add('endif');
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
hs : string;
|
||||||
|
prefix : string;
|
||||||
|
begin
|
||||||
|
prefix:=FixVariable(inivar)+'_';
|
||||||
|
hs:=AddTargetDefines(inivar,prefix);
|
||||||
|
while hs<>'' do
|
||||||
|
begin
|
||||||
|
i:=pos(' ',hs);
|
||||||
|
if i=0 then
|
||||||
|
i:=length(hs)+1;
|
||||||
|
AddTargetDir(Copy(hs,1,i-1),prefix);
|
||||||
|
delete(hs,1,i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMakefileWriter.AddRequiredPackages;
|
||||||
|
|
||||||
|
procedure AddPackage(const pack,prefix:string);
|
||||||
|
var
|
||||||
|
packdirvar,unitdirvar : string;
|
||||||
|
begin
|
||||||
|
FOutput.Add('ifdef '+Prefix+VarName(pack));
|
||||||
|
{ create needed variables }
|
||||||
|
packdirvar:='PACKAGEDIR_'+VarName(pack);
|
||||||
|
unitdirvar:='UNITDIR_'+VarName(pack);
|
||||||
|
{ Search packagedir by looking for Makefile.fpc }
|
||||||
|
FOutput.Add(packdirvar+':=$(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/$(OS_TARGET)/Makefile.fpc,$(PACKAGESDIR)))))');
|
||||||
|
FOutput.Add('ifeq ($('+packdirvar+'),)');
|
||||||
|
FOutput.Add(packdirvar+':=$(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Makefile.fpc,$(PACKAGESDIR)))))');
|
||||||
|
FOutput.Add('ifeq ($('+packdirvar+'),)');
|
||||||
|
FOutput.Add(packdirvar+'=');
|
||||||
|
FOutput.Add('else');
|
||||||
|
FOutput.Add(packdirvar+':=$(firstword $('+packdirvar+'))');
|
||||||
|
FOutput.Add('endif');
|
||||||
|
FOutput.Add('else');
|
||||||
|
FOutput.Add(packdirvar+':=$(firstword $('+packdirvar+'))');
|
||||||
|
FOutput.Add('endif');
|
||||||
|
{ If Packagedir found look for FPCMade }
|
||||||
|
FOutput.Add('ifdef '+packdirvar);
|
||||||
|
FOutput.Add('ifeq ($(wildcard $('+packdirvar+')/$(FPCMADE)),)');
|
||||||
|
FOutput.Add('override COMPILEPACKAGES+=package_'+pack);
|
||||||
|
AddPhony('package_'+pack);
|
||||||
|
FOutput.Add('package_'+pack+':');
|
||||||
|
FOutput.Add(#9'$(MAKE) -C $('+packdirvar+') all');
|
||||||
|
FOutput.Add('endif');
|
||||||
|
FOutput.Add(unitdirvar+'=$('+packdirvar+')');
|
||||||
|
{ Package dir doesn''t exists, use unit dir }
|
||||||
|
FOutput.Add('else');
|
||||||
|
FOutput.Add(packdirvar+'=');
|
||||||
|
FOutput.Add(unitdirvar+':=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Package.fpc,$(UNITSDIR)))))');
|
||||||
|
FOutput.Add('ifeq ($('+unitdirvar+'),)');
|
||||||
|
FOutput.Add(unitdirvar+'=');
|
||||||
|
FOutput.Add('else');
|
||||||
|
FOutput.Add(unitdirvar+':=$(firstword $('+unitdirvar+'))');
|
||||||
|
FOutput.Add('endif');
|
||||||
|
FOutput.Add('endif');
|
||||||
|
{ Add Unit dir to the command line -Fu }
|
||||||
|
FOutput.Add('ifdef '+unitdirvar);
|
||||||
|
FOutput.Add('override COMPILER_UNITDIR+=$('+unitdirvar+')');
|
||||||
|
FOutput.Add('endif');
|
||||||
|
{ endif for package }
|
||||||
|
FOutput.Add('endif');
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
hs : string;
|
||||||
|
prefix : string;
|
||||||
|
t : Ttarget;
|
||||||
|
sl : TStringList;
|
||||||
|
begin
|
||||||
|
prefix:='REQUIRE_PACKAGES_';
|
||||||
|
{ Add target defines }
|
||||||
|
for t:=low(ttarget) to high(ttarget) do
|
||||||
|
begin
|
||||||
|
sl:=FInput.GetTargetRequires(t);
|
||||||
|
if sl.count>0 then
|
||||||
|
begin
|
||||||
|
writeln(TargetStr[t]+' requires:');
|
||||||
|
if t<>t_all then
|
||||||
|
FOutput.Add('ifeq ($(OS_TARGET),'+TargetStr[t]+')');
|
||||||
|
for i:=0 to sl.count-1 do
|
||||||
|
begin
|
||||||
|
FOutput.Add(prefix+VarName(sl[i])+'=1');
|
||||||
|
writeln(sl[i]);
|
||||||
|
end;
|
||||||
|
if t<>t_all then
|
||||||
|
FOutput.Add('endif');
|
||||||
|
end;
|
||||||
|
sl.Free;
|
||||||
|
end;
|
||||||
|
{ Add all require packages }
|
||||||
|
for i:=0 to FInput.RequireList.Count-1 do
|
||||||
|
AddPackage(FInput.RequireList[i],prefix);
|
||||||
|
WritePhony;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMakefileWriter.WriteGenericMakefile;
|
||||||
|
var
|
||||||
|
i : integer;
|
||||||
|
rule : trules;
|
||||||
|
begin
|
||||||
|
with FOutput do
|
||||||
|
begin
|
||||||
|
{ Header }
|
||||||
|
Add('#');
|
||||||
|
Add('# Don''t edit, this file is generated by '+TitleDate);
|
||||||
|
Add('#');
|
||||||
|
Add('default: all');
|
||||||
|
{ Add automatic detect sections }
|
||||||
|
AddIniSection('osdetect');
|
||||||
|
AddIniSection('fpcdetect');
|
||||||
|
AddIniSection('fpcdirdetect');
|
||||||
|
{ Package }
|
||||||
|
AddVariable('package.name');
|
||||||
|
AddVariable('package.version');
|
||||||
|
{ First add the required packages sections }
|
||||||
|
for i:=0 to FInput.RequireList.Count-1 do
|
||||||
|
AddCustomSection(FInput.Requirelist[i]);
|
||||||
|
{ Targets }
|
||||||
|
AddTargetVariable('target.dirs');
|
||||||
|
AddTargetVariable('target.programs');
|
||||||
|
AddTargetVariable('target.units');
|
||||||
|
AddTargetVariable('target.rsts');
|
||||||
|
AddTargetVariable('target.examples');
|
||||||
|
AddTargetVariable('target.exampledirs');
|
||||||
|
{ Clean }
|
||||||
|
AddTargetVariable('clean.units');
|
||||||
|
AddTargetVariable('clean.files');
|
||||||
|
{ Install }
|
||||||
|
AddTargetVariable('install.units');
|
||||||
|
AddTargetVariable('install.files');
|
||||||
|
AddVariable('install.prefixdir');
|
||||||
|
AddVariable('install.basedir');
|
||||||
|
AddVariable('install.datadir');
|
||||||
|
{ Dist }
|
||||||
|
AddVariable('dist.zipname');
|
||||||
|
AddVariable('dist.ziptarget');
|
||||||
|
{ Compiler }
|
||||||
|
AddVariable('compiler.options');
|
||||||
|
AddVariable('compiler.version');
|
||||||
|
AddVariable('compiler.includedir');
|
||||||
|
AddVariable('compiler.sourcedir');
|
||||||
|
AddVariable('compiler.objectdir');
|
||||||
|
AddVariable('compiler.librarydir');
|
||||||
|
AddVariable('compiler.targetdir');
|
||||||
|
AddVariable('compiler.unittargetdir');
|
||||||
|
{ Require packages }
|
||||||
|
AddRequiredPackages;
|
||||||
|
{ default dirs/tools/extensions }
|
||||||
|
AddIniSection('shelltools');
|
||||||
|
AddIniSection('defaulttools');
|
||||||
|
AddIniSection('extensions');
|
||||||
|
AddIniSection('defaultdirs');
|
||||||
|
if CheckVariable('require.libc') then
|
||||||
|
AddIniSection('dirlibc');
|
||||||
|
{ commandline }
|
||||||
|
AddIniSection('command_begin');
|
||||||
|
if CheckVariable('require.libc') then
|
||||||
|
AddIniSection('command_libc');
|
||||||
|
AddIniSection('command_end');
|
||||||
|
{ compile }
|
||||||
|
if CheckTargetVariable('target.loaders') then
|
||||||
|
AddIniSection('loaderrules');
|
||||||
|
if CheckTargetVariable('target.units') then
|
||||||
|
AddIniSection('unitrules');
|
||||||
|
if CheckTargetVariable('target.programs') then
|
||||||
|
AddIniSection('exerules');
|
||||||
|
if CheckTargetVariable('target.rsts') then
|
||||||
|
AddIniSection('rstrules');
|
||||||
|
if CheckTargetVariable('target.examples') or
|
||||||
|
CheckTargetVariable('target.exampledirs') then
|
||||||
|
AddIniSection('examplerules');
|
||||||
|
AddIniSection('compilerules');
|
||||||
|
if CheckVariable('lib.name') then
|
||||||
|
AddIniSection('libraryrules');
|
||||||
|
{ install }
|
||||||
|
AddIniSection('installrules');
|
||||||
|
if CheckTargetVariable('target.examples') or
|
||||||
|
CheckTargetVariable('target.exampledirs') then
|
||||||
|
AddIniSection('exampleinstallrules');
|
||||||
|
if CheckVariable('package.name') then
|
||||||
|
AddIniSection('zipinstallrules');
|
||||||
|
{ clean }
|
||||||
|
AddIniSection('cleanrules');
|
||||||
|
{ info }
|
||||||
|
AddIniSection('inforules');
|
||||||
|
{ Subdirs }
|
||||||
|
AddTargetDirs('target.dirs');
|
||||||
|
AddTargetDirs('target.exampledirs');
|
||||||
|
{ Rules }
|
||||||
|
AddRules;
|
||||||
|
{ Users own rules }
|
||||||
|
AddIniSection('localmakefile');
|
||||||
|
AddIniSection('userrules');
|
||||||
|
if assigned(FInput['rules']) then
|
||||||
|
AddStrings(TFPCMakeSection(FInput['rules']).List);
|
||||||
|
end;
|
||||||
|
{ write to disk }
|
||||||
|
Fixtab(FOutput);
|
||||||
|
FOutput.SaveToFile(FFileName);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
{
|
||||||
|
$Log$
|
||||||
|
Revision 1.1 2001-01-24 21:59:36 peter
|
||||||
|
* first commit of new fpcmake
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user