mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 09:39:32 +01:00 
			
		
		
		
	there is no special need anymore for complete scripts in the Makefile.fpc to call fpmake. And it is now possible to combine other targets with a fpmake-target. git-svn-id: trunk@31240 -
		
			
				
	
	
		
			897 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			897 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    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_rsts,
 | 
						|
        sec_compile,sec_install,
 | 
						|
        sec_distinstall,sec_zipinstall,sec_clean,sec_shared,
 | 
						|
        sec_command,sec_exts,sec_dirs,sec_tools,sec_info,sec_makefile,
 | 
						|
        sec_fpmake
 | 
						|
      );
 | 
						|
 | 
						|
      trules=(
 | 
						|
        r_all,r_debug,r_smart,r_release,r_units,
 | 
						|
        r_examples,
 | 
						|
        r_shared,
 | 
						|
        r_install,r_sourceinstall,r_exampleinstall,r_distinstall,
 | 
						|
        r_zipinstall,r_zipsourceinstall,r_zipexampleinstall,r_zipdistinstall,
 | 
						|
        r_clean,r_distclean,r_cleanall,
 | 
						|
        r_info,r_makefiles
 | 
						|
      );
 | 
						|
 | 
						|
 | 
						|
    const
 | 
						|
      rule2str : array[trules] of string=(
 | 
						|
        'all','debug','smart','release','units',
 | 
						|
        'examples',
 | 
						|
        'shared',
 | 
						|
        'install','sourceinstall','exampleinstall','distinstall',
 | 
						|
        'zipinstall','zipsourceinstall','zipexampleinstall','zipdistinstall',
 | 
						|
        'clean','distclean','cleanall',
 | 
						|
        'info','makefiles'
 | 
						|
      );
 | 
						|
 | 
						|
      rule2sec : array[trules] of tsections=(
 | 
						|
        sec_compile,sec_compile,sec_compile,sec_compile,sec_compile,
 | 
						|
        sec_examples,
 | 
						|
        sec_shared,
 | 
						|
        sec_install,sec_install,sec_install,sec_distinstall,
 | 
						|
        sec_zipinstall,sec_zipinstall,sec_zipinstall,sec_zipinstall,
 | 
						|
        sec_clean,sec_clean,sec_clean,
 | 
						|
        sec_info,sec_makefile
 | 
						|
      );
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    type
 | 
						|
 | 
						|
      { TMakefileWriter }
 | 
						|
 | 
						|
      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 AddMainPackage(const pack:string);
 | 
						|
        procedure AddRequiredPackages;
 | 
						|
        procedure AddTool(const varname,exename,altexename:string);
 | 
						|
        procedure AddTools(const inivar:string);
 | 
						|
        procedure AddRules;
 | 
						|
        procedure AddPhony(const s:string);
 | 
						|
        procedure WritePhony;
 | 
						|
        procedure AddTargetDirs(const inivar:string);
 | 
						|
        procedure AddDefaultTools;
 | 
						|
        procedure AddMakefileTargets;
 | 
						|
        procedure OptimizeSections;
 | 
						|
      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 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;
 | 
						|
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                            TMakefileWriter
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
    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;
 | 
						|
 | 
						|
 | 
						|
    procedure TMakefileWriter.AddTargetVariable(const inivar:string);
 | 
						|
      var
 | 
						|
        s : string;
 | 
						|
        T : TOs;
 | 
						|
        C : TCpu;
 | 
						|
      begin
 | 
						|
        for c:=low(TCpu) to high(TCpu) do
 | 
						|
          for t:=low(TOS) to high(TOS) do
 | 
						|
            if FInput.IncludeTargets[c,t] then
 | 
						|
              begin
 | 
						|
                s:=FInput.GetTargetVariable(c,t,IniVar,false);
 | 
						|
                if s<>'' then
 | 
						|
                  begin
 | 
						|
                    FOutput.Add('ifeq ($(FULL_TARGET),'+CPUStr[c]+'-'+OSStr[t]+')');
 | 
						|
                    FOutput.Add('override '+FixVariable(IniVar)+'+='+s);
 | 
						|
                    FOutput.Add('endif');
 | 
						|
                  end;
 | 
						|
              end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TMakefileWriter.AddVariable(const inivar:string);
 | 
						|
      var
 | 
						|
        s : string;
 | 
						|
      begin
 | 
						|
        s:=FInput.GetVariable(IniVar,false);
 | 
						|
        if s<>'' then
 | 
						|
         FOutput.Add('override '+FixVariable(IniVar)+'='+s)
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TMakefileWriter.AddTargetDefines(const inivar,prefix:string):string;
 | 
						|
 | 
						|
        procedure addtokens(s:string);
 | 
						|
        var
 | 
						|
          name : string;
 | 
						|
          k1,k2 : integer;
 | 
						|
        begin
 | 
						|
          repeat
 | 
						|
            Name:=GetToken(s,' ');
 | 
						|
            if Name='' then
 | 
						|
             break;
 | 
						|
            { 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 }
 | 
						|
            AddTokenNoDup(result,name,' ');
 | 
						|
          until false;
 | 
						|
        end;
 | 
						|
 | 
						|
      var
 | 
						|
        s : string;
 | 
						|
        T : TOs;
 | 
						|
        C : TCpu;
 | 
						|
      begin
 | 
						|
        result:='';
 | 
						|
        for c:=low(TCpu) to high(TCpu) do
 | 
						|
          for t:=low(TOS) to high(TOS) do
 | 
						|
            if FInput.IncludeTargets[c,t] then
 | 
						|
              begin
 | 
						|
                s:=FInput.GetTargetVariable(c,t,IniVar,false);
 | 
						|
                if s<>'' then
 | 
						|
                  begin
 | 
						|
                    FOutput.Add('ifeq ($(FULL_TARGET),'+CpuStr[c]+'-'+OSStr[t]+')');
 | 
						|
                    AddTokens(s);
 | 
						|
                    FOutput.Add('endif');
 | 
						|
                  end;
 | 
						|
              end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TMakefileWriter.AddTool(const varname,exename,altexename:string);
 | 
						|
      begin
 | 
						|
        with FOutput do
 | 
						|
         begin
 | 
						|
           Add('ifndef '+varname);
 | 
						|
           Add(varname+':=$(strip $(wildcard $(addsuffix /'+exename+'$(SRCEXEEXT),$(SEARCHPATH))))');
 | 
						|
           if altexename<>'' then
 | 
						|
            begin
 | 
						|
              Add('ifeq ($('+varname+'),)');
 | 
						|
              Add(varname+':=$(strip $(wildcard $(addsuffix /'+altexename+'$(SRCEXEEXT),$(SEARCHPATH))))');
 | 
						|
            end;
 | 
						|
           Add('ifeq ($('+varname+'),)');
 | 
						|
           Add(varname+'= __missing_command_'+varname); {This is to be shure make stops,
 | 
						|
              if the command is not found. Otherwise if the command was set to the
 | 
						|
              empty string, options to the command would be interpreted as command,
 | 
						|
              and because options is preceeded by a "-", make will ignore the error
 | 
						|
              that the command is not found.}
 | 
						|
           Add('else');
 | 
						|
           Add(varname+':=$(firstword $('+varname+'))');
 | 
						|
           Add('endif');
 | 
						|
           if altexename<>'' then
 | 
						|
            begin
 | 
						|
              Add('else');
 | 
						|
              Add(varname+':=$(firstword $('+varname+'))');
 | 
						|
              Add('endif');
 | 
						|
            end;
 | 
						|
           Add('endif');
 | 
						|
           Add('export '+varname);
 | 
						|
         end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TMakefileWriter.AddTools(const inivar:string);
 | 
						|
      var
 | 
						|
        hs,tool : string;
 | 
						|
      begin
 | 
						|
        hs:=FInput.GetVariable(inivar,false);
 | 
						|
        repeat
 | 
						|
          Tool:=GetToken(hs,' ');
 | 
						|
          if Tool='' then
 | 
						|
           break;
 | 
						|
          AddTool(FixVariable(Tool),Tool,'');
 | 
						|
        until false;
 | 
						|
      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, but not for info and targets that
 | 
						|
            call other targets with a only extra settings, if the
 | 
						|
            section was not included, then still process the targets }
 | 
						|
          if FInput.HasTargetVariable('target_dirs') and
 | 
						|
             (not(rule in [r_info,r_shared,r_smart,r_debug,r_release,r_zipdistinstall,r_distinstall]) or
 | 
						|
              not FHasSection[Rule2Sec[rule]]) then
 | 
						|
           begin
 | 
						|
             if FInput.HasVariable('default_dir') then
 | 
						|
              hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(DEFAULT_DIR))'
 | 
						|
             else
 | 
						|
              if not(rule in [r_sourceinstall,r_zipinstall,r_zipsourceinstall,
 | 
						|
                              r_makefiles]) or
 | 
						|
                 not(FInput.HasVariable('package_name')) then
 | 
						|
               hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_DIRS))';
 | 
						|
           end;
 | 
						|
          { include cleaning of example dirs }
 | 
						|
          if (rule=r_clean) and
 | 
						|
             FInput.HasTargetVariable('target_exampledirs') then
 | 
						|
           hs:=hs+' $(addsuffix _'+rule2str[rule]+',$(TARGET_EXAMPLEDIRS))';
 | 
						|
          { Add the rule }
 | 
						|
          AddPhony(Rule2Str[Rule]);
 | 
						|
          FOutput.Add(rule2str[rule]+':'+hs);
 | 
						|
        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(s+'_'+rule2str[j]);
 | 
						|
           end;
 | 
						|
          FOutput.Add(s+':');
 | 
						|
          FOutput.Add(#9+'$(MAKE) -C '+s+' all');
 | 
						|
          AddPhony(s);
 | 
						|
          WritePhony;
 | 
						|
          FOutput.Add('endif');
 | 
						|
        end;
 | 
						|
 | 
						|
      var
 | 
						|
        hs,dir : string;
 | 
						|
        prefix : string;
 | 
						|
      begin
 | 
						|
        prefix:=FixVariable(inivar)+'_';
 | 
						|
        hs:=AddTargetDefines(inivar,prefix);
 | 
						|
        repeat
 | 
						|
          Dir:=GetToken(hs,' ');
 | 
						|
          if Dir='' then
 | 
						|
           break;
 | 
						|
          AddTargetDir(Dir,prefix);
 | 
						|
        until false;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TMakefileWriter.AddMainPackage(const pack:string);
 | 
						|
      var
 | 
						|
        packdirvar : string;
 | 
						|
      begin
 | 
						|
        { create needed variables }
 | 
						|
        packdirvar:='PACKAGEDIR_MAIN';
 | 
						|
        { Search packagedir by looking for Makefile.fpc }
 | 
						|
        FOutput.Add(packdirvar+':=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Makefile.fpc,$(PACKAGESDIR))))))');
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TMakefileWriter.AddRequiredPackages;
 | 
						|
 | 
						|
        procedure AddPackage(const pack,prefix:string);
 | 
						|
        var
 | 
						|
          packdirvar,unitdirvar,unitfpmakedirvar : string;
 | 
						|
          fpcmadedirvar : string;
 | 
						|
        begin
 | 
						|
          FOutput.Add('ifdef '+Prefix+VarName(pack));
 | 
						|
          { create needed variables }
 | 
						|
          packdirvar:='PACKAGEDIR_'+VarName(pack);
 | 
						|
          unitdirvar:='UNITDIR_'+VarName(pack);
 | 
						|
          unitfpmakedirvar:='UNITDIR_FPMAKE_'+VarName(pack);
 | 
						|
          { Search packagedir by looking for Makefile.fpc }
 | 
						|
          FOutput.Add(packdirvar+':=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Makefile.fpc,$(PACKAGESDIR))))))');
 | 
						|
          FOutput.Add('ifneq ($('+packdirvar+'),)');
 | 
						|
          { Create unit dir, check if os dependent dir exists }
 | 
						|
          FOutput.Add('ifneq ($(wildcard $('+packdirvar+')/units/$(TARGETSUFFIX)),)');
 | 
						|
          FOutput.Add(unitdirvar+'=$('+packdirvar+')/units/$(TARGETSUFFIX)');
 | 
						|
          FOutput.Add('else');
 | 
						|
          FOutput.Add(unitdirvar+'=$('+packdirvar+')');
 | 
						|
          FOutput.Add('endif');
 | 
						|
 | 
						|
          FOutput.Add('ifneq ($(wildcard $('+packdirvar+')/units/$(SOURCESUFFIX)),)');
 | 
						|
          FOutput.Add(unitfpmakedirvar+'=$('+packdirvar+')/units/$(SOURCESUFFIX)');
 | 
						|
          FOutput.Add('else');
 | 
						|
 | 
						|
          FOutput.Add('ifneq ($(wildcard $('+packdirvar+')/units_bs/$(SOURCESUFFIX)),)');
 | 
						|
          FOutput.Add(unitfpmakedirvar+'=$('+packdirvar+')/units_bs/$(SOURCESUFFIX)');
 | 
						|
          FOutput.Add('else');
 | 
						|
          FOutput.Add(unitfpmakedirvar+'=$('+packdirvar+')');
 | 
						|
          FOutput.Add('endif');
 | 
						|
 | 
						|
          FOutput.Add('endif');
 | 
						|
 | 
						|
          FOutput.Add('ifdef CHECKDEPEND');
 | 
						|
          { rtl needs special handling for FPCMADE }
 | 
						|
          if pack='rtl' then
 | 
						|
            fpcmadedirvar:='/$(OS_TARGET)'
 | 
						|
          else
 | 
						|
            fpcmadedirvar:='';
 | 
						|
          FOutput.Add('$('+packdirvar+')'+fpcmadedirvar+'/$(FPCMADE):');
 | 
						|
          FOutput.Add(#9'$(MAKE) -C $('+packdirvar+')'+fpcmadedirvar+' $(FPCMADE)');
 | 
						|
          FOutput.Add('override ALLDEPENDENCIES+=$('+packdirvar+')'+fpcmadedirvar+'/$(FPCMADE)');
 | 
						|
          FOutput.Add('endif');
 | 
						|
          { Package dir doesn't exists, check unit dir }
 | 
						|
          FOutput.Add('else');
 | 
						|
          FOutput.Add(packdirvar+'=');
 | 
						|
          FOutput.Add(unitdirvar+':=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /'+pack+'/Package.fpc,$(UNITSDIR)))))');
 | 
						|
          FOutput.Add('ifneq ($('+unitdirvar+'),)');
 | 
						|
          FOutput.Add(unitdirvar+':=$(firstword $('+unitdirvar+'))');
 | 
						|
          FOutput.Add('else');
 | 
						|
          FOutput.Add(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');
 | 
						|
 | 
						|
          FOutput.Add('ifdef '+unitfpmakedirvar);
 | 
						|
          FOutput.Add('override COMPILER_FPMAKE_UNITDIR+=$('+unitfpmakedirvar+')');
 | 
						|
          FOutput.Add('endif');
 | 
						|
 | 
						|
          { endif for package }
 | 
						|
          FOutput.Add('endif');
 | 
						|
        end;
 | 
						|
 | 
						|
      var
 | 
						|
        i  : integer;
 | 
						|
        reqs,req,prefix : string;
 | 
						|
        t : TOS;
 | 
						|
        c : TCpu;
 | 
						|
        sl : TStringList;
 | 
						|
      begin
 | 
						|
        prefix:='REQUIRE_PACKAGES_';
 | 
						|
        reqs:='';
 | 
						|
        { Add target defines }
 | 
						|
        for c:=low(tcpu) to high(tcpu) do
 | 
						|
          for t:=low(tos) to high(tos) do
 | 
						|
            if FInput.IncludeTargets[c,t] then
 | 
						|
              begin
 | 
						|
                sl:=FInput.GetTargetRequires(c,t);
 | 
						|
                { show info }
 | 
						|
                FInput.Verbose(FPCMakeInfo,CpuStr[c]+'-'+OSStr[t]+' requires: '+sl.CommaText);
 | 
						|
                if sl.count>0 then
 | 
						|
                 begin
 | 
						|
                   FOutput.Add('ifeq ($(FULL_TARGET),'+CPUStr[c]+'-'+OSStr[t]+')');
 | 
						|
                   for i:=0 to sl.count-1 do
 | 
						|
                    begin
 | 
						|
                      FOutput.Add(prefix+VarName(sl[i])+'=1');
 | 
						|
                      AddTokenNoDup(reqs,sl[i],' ');
 | 
						|
                    end;
 | 
						|
                   FOutput.Add('endif');
 | 
						|
                 end;
 | 
						|
                sl.Free;
 | 
						|
              end;
 | 
						|
        { Add all require packages }
 | 
						|
        repeat
 | 
						|
          req:=GetToken(reqs,' ');
 | 
						|
          if Req='' then
 | 
						|
           break;
 | 
						|
          AddPackage(req,prefix);
 | 
						|
        until false;
 | 
						|
        WritePhony;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TMakefileWriter.AddDefaultTools;
 | 
						|
      begin
 | 
						|
        AddTool('ECHO','gecho','echo');
 | 
						|
        AddTool('DATE','gdate','date');
 | 
						|
        AddTool('GINSTALL','ginstall','install');
 | 
						|
        AddTool('CPPROG','cp','');
 | 
						|
        AddTool('RMPROG','rm','');
 | 
						|
        AddTool('MVPROG','mv','');
 | 
						|
        AddTool('MKDIRPROG','gmkdir','mkdir');
 | 
						|
        AddIniSection('shelltools');
 | 
						|
        AddTool('PPUMOVE','ppumove','');
 | 
						|
        AddTool('FPCMAKE','fpcmake','');
 | 
						|
        AddTool('ZIPPROG','zip','');
 | 
						|
        AddTool('TARPROG','gtar','tar');
 | 
						|
        AddIniSection('defaulttools');
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure TMakefileWriter.AddMakefileTargets;
 | 
						|
      var
 | 
						|
        s : string;
 | 
						|
        c : TCpu;
 | 
						|
        t : Tos;
 | 
						|
      begin
 | 
						|
        s:='';
 | 
						|
        for c:=low(tcpu) to high(tcpu) do
 | 
						|
         for t:=low(tos) to high(tos) do
 | 
						|
          if FInput.IncludeTargets[c,t] then
 | 
						|
           AddToken(s,CpuStr[c]+'-'+OSStr[t],' ');
 | 
						|
        FOutput.Add('MAKEFILETARGETS='+s);
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure TMakefileWriter.OptimizeSections;
 | 
						|
      var
 | 
						|
        SkippedSecs :integer;
 | 
						|
      begin
 | 
						|
        { Turn some sections off, depending if files are
 | 
						|
          provided }
 | 
						|
        if not FInput.IsPackage then
 | 
						|
         begin
 | 
						|
           FHasSection[sec_zipinstall]:=false;
 | 
						|
           FHasSection[sec_distinstall]:=false;
 | 
						|
         end;
 | 
						|
 | 
						|
        { Remove unused sections for targets }
 | 
						|
        SkippedSecs:=0;
 | 
						|
        if (not FInput.HasTargetVariable('target_units')) and (not FInput.HasTargetVariable('target_implicitunits')) then
 | 
						|
         begin
 | 
						|
           inc(SkippedSecs);
 | 
						|
           FHasSection[sec_units]:=false;
 | 
						|
         end;
 | 
						|
        if (not FInput.HasTargetVariable('target_programs')) then
 | 
						|
         begin
 | 
						|
           inc(SkippedSecs);
 | 
						|
           FHasSection[sec_exes]:=false;
 | 
						|
         end;
 | 
						|
        if (not FInput.HasTargetVariable('target_examples')) then
 | 
						|
         begin
 | 
						|
           inc(SkippedSecs);
 | 
						|
           { example dirs also requires the fpc_examples target, because
 | 
						|
             it also depends on the all target }
 | 
						|
           if (not FInput.HasTargetVariable('target_exampledirs')) then
 | 
						|
            FHasSection[sec_examples]:=false;
 | 
						|
         end;
 | 
						|
        if (not FInput.HasTargetVariable('target_loaders')) then
 | 
						|
         begin
 | 
						|
           inc(SkippedSecs);
 | 
						|
           FHasSection[sec_loaders]:=false;
 | 
						|
         end;
 | 
						|
        if (not FInput.HasTargetVariable('target_fpmake')) then
 | 
						|
         begin
 | 
						|
           inc(SkippedSecs);
 | 
						|
           FHasSection[sec_fpmake]:=false;
 | 
						|
         end;
 | 
						|
        { if all 5 sections are not available we can skip also the
 | 
						|
          generic compile rules }
 | 
						|
        if SkippedSecs=5 then
 | 
						|
         begin
 | 
						|
           FHasSection[sec_shared]:=false;
 | 
						|
           FHasSection[sec_compile]:=false;
 | 
						|
           if (not FInput.HasTargetVariable('package_name')) and
 | 
						|
              (not FInput.HasTargetVariable('install_units')) and
 | 
						|
              (not FInput.HasTargetVariable('install_files')) and
 | 
						|
              (not FInput.HasTargetVariable('install_createpackagefpc')) then
 | 
						|
            FHasSection[sec_install]:=false;
 | 
						|
           { Package.fpc also needs to be cleaned }
 | 
						|
           if (not FInput.HasTargetVariable('clean_units')) and
 | 
						|
              (not FInput.HasTargetVariable('clean_files')) and
 | 
						|
              (not FInput.HasTargetVariable('install_createpackagefpc')) then
 | 
						|
            FHasSection[sec_clean]:=false;
 | 
						|
         end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TMakefileWriter.WriteGenericMakefile;
 | 
						|
      begin
 | 
						|
        { Remove unused sections }
 | 
						|
        OptimizeSections;
 | 
						|
        { Generate Output }
 | 
						|
        with FOutput do
 | 
						|
         begin
 | 
						|
           { Header }
 | 
						|
           Add('#');
 | 
						|
           Add('# Don''t edit, this file is generated by '+TitleDate);
 | 
						|
           Add('#');
 | 
						|
           if FInput.HasVariable('default_rule') then
 | 
						|
            Add('default: '+FInput.GetVariable('default_rule',false))
 | 
						|
           else
 | 
						|
            Add('default: all');
 | 
						|
           { Supported targets by this Makefile }
 | 
						|
           AddMakefileTargets;
 | 
						|
           { Add misc defines }
 | 
						|
           AddIniSection('defines');
 | 
						|
           { Add automatic detect sections }
 | 
						|
           AddIniSection('osdetect');
 | 
						|
           { Forced target }
 | 
						|
           if FInput.HasVariable('require_target') then
 | 
						|
            Add('override OS_TARGET='+FInput.GetVariable('require_target',false))
 | 
						|
           else if FInput.HasVariable('default_target') then
 | 
						|
            Add('override OS_TARGET_DEFAULT='+FInput.GetVariable('default_target',false));
 | 
						|
           if FInput.HasVariable('require_cpu') then
 | 
						|
            Add('override CPU_TARGET='+FInput.GetVariable('require_cpu',false))
 | 
						|
           else if FInput.HasVariable('default_cpu') then
 | 
						|
            Add('override CPU_TARGET_DEFAULT='+FInput.GetVariable('default_cpu',false));
 | 
						|
           { FPC Detection }
 | 
						|
           AddVariable('default_fpcdir');
 | 
						|
           AddIniSection('fpcdetect');
 | 
						|
           AddIniSection('fpcdircheckenv');
 | 
						|
           AddIniSection('fpcdirdetect');
 | 
						|
           AddIniSection('fpmakefpcdetect');
 | 
						|
           { Package }
 | 
						|
           AddVariable('package_name');
 | 
						|
           AddVariable('package_version');
 | 
						|
           AddVariable('package_targets');
 | 
						|
           { Directory of main package }
 | 
						|
           if FInput.HasVariable('package_main') then
 | 
						|
             AddMainPackage(FInput.GetVariable('package_main',false));
 | 
						|
           { LCL rules }
 | 
						|
           if FInput.UsesLCL then
 | 
						|
            begin
 | 
						|
              AddVariable('default_lcldir');
 | 
						|
              AddVariable('lcl_platform');
 | 
						|
              AddIniSection('lclrules');
 | 
						|
            end;
 | 
						|
           { First add the required packages sections }
 | 
						|
//           for i:=0 to FInput.RequireList.Count-1 do
 | 
						|
//            AddCustomSection(FInput.Requirelist[i]);
 | 
						|
           { prerules section }
 | 
						|
           if assigned(FInput['prerules']) then
 | 
						|
            AddStrings(TFPCMakeSection(FInput['prerules']).List);
 | 
						|
           if FHasSection[sec_fpmake] then
 | 
						|
            AddIniSection('fpmakeprerules');
 | 
						|
           { Default }
 | 
						|
           AddVariable('default_dir');
 | 
						|
           { Targets }
 | 
						|
           AddTargetVariable('target_dirs');
 | 
						|
           AddTargetVariable('target_programs');
 | 
						|
           AddTargetVariable('target_units');
 | 
						|
           AddTargetVariable('target_implicitunits');
 | 
						|
           AddTargetVariable('target_loaders');
 | 
						|
           AddTargetVariable('target_rsts');
 | 
						|
           AddTargetVariable('target_examples');
 | 
						|
           AddTargetVariable('target_exampledirs');
 | 
						|
           AddTargetVariable('target_fpmake');
 | 
						|
           { Clean }
 | 
						|
           AddTargetVariable('clean_units');
 | 
						|
           AddTargetVariable('clean_files');
 | 
						|
           AddTargetVariable('clean_programs');
 | 
						|
           { Install }
 | 
						|
           AddTargetVariable('install_units');
 | 
						|
           AddTargetVariable('install_files');
 | 
						|
           AddVariable('install_buildunit');
 | 
						|
           AddVariable('install_prefix');
 | 
						|
           AddVariable('install_basedir');
 | 
						|
           AddVariable('install_datadir');
 | 
						|
           AddVariable('install_fpcpackage');
 | 
						|
           AddVariable('install_fpcsubdir');
 | 
						|
           AddVariable('install_createpackagefpc');
 | 
						|
           { Dist }
 | 
						|
           AddVariable('dist_destdir');
 | 
						|
           AddVariable('dist_zipname');
 | 
						|
           AddVariable('dist_ziptarget');
 | 
						|
           { Compiler }
 | 
						|
           AddTargetVariable('compiler_options');
 | 
						|
           AddTargetVariable('compiler_version');
 | 
						|
           AddTargetVariable('compiler_includedir');
 | 
						|
           AddTargetVariable('compiler_unitdir');
 | 
						|
           AddTargetVariable('compiler_sourcedir');
 | 
						|
           AddTargetVariable('compiler_objectdir');
 | 
						|
           AddTargetVariable('compiler_librarydir');
 | 
						|
           AddTargetVariable('compiler_targetdir');
 | 
						|
           AddTargetVariable('compiler_unittargetdir');
 | 
						|
           { shared }
 | 
						|
           AddVariable('shared_build');
 | 
						|
           AddVariable('shared_libname');
 | 
						|
           AddVariable('shared_libversion');
 | 
						|
           AddVariable('shared_libunits');
 | 
						|
           AddVariable('shared_build');
 | 
						|
           { default Dirs and extensions }
 | 
						|
           AddIniSection('defaultdirs');
 | 
						|
           if FInput.CheckLibcRequire then
 | 
						|
            AddIniSection('dirlibc');
 | 
						|
           AddIniSection('extensions');
 | 
						|
           { Add default tools }
 | 
						|
           AddDefaultTools;
 | 
						|
           { Required packages }
 | 
						|
           AddVariable('require_packages');
 | 
						|
           AddRequiredPackages;
 | 
						|
           { commandline }
 | 
						|
           AddIniSection('command_begin');
 | 
						|
           if FInput.CheckLibcRequire then
 | 
						|
            AddIniSection('command_libc');
 | 
						|
           AddIniSection('command_end');
 | 
						|
           { compile }
 | 
						|
           if FHasSection[sec_fpmake] then
 | 
						|
            AddIniSection('fpmakerules');
 | 
						|
           if FHasSection[sec_loaders] then
 | 
						|
            AddIniSection('loaderrules');
 | 
						|
           if FHasSection[sec_units] then
 | 
						|
            AddIniSection('unitrules');
 | 
						|
           if FHasSection[sec_exes] then
 | 
						|
            AddIniSection('exerules');
 | 
						|
           if FHasSection[sec_rsts] then
 | 
						|
            AddIniSection('rstrules');
 | 
						|
           if FHasSection[sec_examples] then
 | 
						|
            AddIniSection('examplerules');
 | 
						|
           if FHasSection[sec_compile] then
 | 
						|
            AddIniSection('compilerules');
 | 
						|
           if FHasSection[sec_shared] then
 | 
						|
             AddIniSection('sharedrules');
 | 
						|
           { install }
 | 
						|
           if FHasSection[sec_install] then
 | 
						|
            AddIniSection('installrules');
 | 
						|
           if FHasSection[sec_distinstall] then
 | 
						|
            AddIniSection('distinstallrules');
 | 
						|
           if FHasSection[sec_zipinstall] then
 | 
						|
            AddIniSection('zipinstallrules');
 | 
						|
           { clean }
 | 
						|
           AddIniSection('cleanrules');
 | 
						|
           { info }
 | 
						|
           AddIniSection('baseinforules');
 | 
						|
           if FInput.UsesLCL then
 | 
						|
            AddIniSection('lclinforules');
 | 
						|
           AddIniSection('inforules');
 | 
						|
           { info }
 | 
						|
           AddIniSection('makefilerules');
 | 
						|
           { Subdirs }
 | 
						|
           AddTargetDirs('target_dirs');
 | 
						|
           AddTargetDirs('target_exampledirs');
 | 
						|
           { Tools }
 | 
						|
           AddTools('require_tools');
 | 
						|
           { Rules }
 | 
						|
           AddRules;
 | 
						|
           { Users own rules }
 | 
						|
           AddIniSection('localmakefile');
 | 
						|
           AddIniSection('userrules');
 | 
						|
           if assigned(FInput['rules']) then
 | 
						|
            AddStrings(TFPCMakeSection(FInput['rules']).List);
 | 
						|
         end;
 | 
						|
        { write to disk }
 | 
						|
        FInput.Verbose(FPCMakeInfo,'Writing Makefile');
 | 
						|
        Fixtab(FOutput);
 | 
						|
        FOutput.SaveToFile(FFileName);
 | 
						|
      end;
 | 
						|
 | 
						|
end.
 |