{ $Id$ Copyright (c) 1999-2000 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 {$ifdef go32v2} dpmiexcp, {$endif} dos, sysutils,classes,makeini; const Version='v1.00'; Title='fpcmake '+Version; TitleDate=Title+' ['+{$i %DATE}+']'; { Include default fpcmake.ini } {$i fpcmake.inc} type tsections=(sec_none, sec_units,sec_exes,sec_loaders,sec_examples,sec_package, sec_compile,sec_require,sec_install,sec_sourceinstall,sec_exampleinstall, sec_zipinstall,sec_zipsourceinstall,sec_zipexampleinstall, sec_clean,sec_libs,sec_command,sec_exts,sec_dirs,sec_tools,sec_info ); tbic=(bic_none,bic_build,bic_install,bic_zipinstall,bic_clean); tspecialdir=record dir,unitdir,packdir : string; end; const EnvVar='FPCMAKEINI'; sectionstr : array[tsections] of string=('none', 'units','exes','loaders','examples','package', 'compile','require','install','sourceinstall','exampleinstall', 'zipinstall','zipsourceinstall','zipexampleinstall', 'clean','libs','command','exts','dirs','tools','info' ); sectiondef : array[tsections] of boolean=(false, true,true,false,false,false, true,false,true,true,true, true,true,true, true,true,true,true,true,true,true ); targets=5; targetstr : array[1..targets] of string=( 'linux','go32v2','win32','os2','freebsd' ); rules=18; rulestr : array[1..rules] of string=( 'all','debug', 'examples','test', 'smart','shared', 'showinstall','install','sourceinstall','exampleinstall', 'zipinstall','zipsourceinstall','zipexampleinstall', 'clean','distclean','cleanall', 'require','info' ); rule2sec : array[1..rules] of tsections=( sec_compile,sec_compile, sec_examples,sec_examples, sec_libs,sec_libs, sec_install,sec_install,sec_sourceinstall,sec_exampleinstall, sec_zipinstall,sec_zipsourceinstall,sec_zipexampleinstall, sec_clean,sec_clean,sec_clean, sec_require,sec_info ); rule2bic : array[1..rules] of tbic=( bic_build,bic_build, bic_build,bic_build, bic_build,bic_build, bic_install,bic_install,bic_install,bic_install,bic_zipinstall,bic_zipinstall,bic_zipinstall, bic_clean,bic_clean,bic_clean, bic_none,bic_none ); rulediralso : array[1..rules] of boolean=( true,true, true,true, true,true, true,true,true,true, false,false,false, true,true,true, true,false ); 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') ); { Sections in Makefile.fpc } ini_sections='sections'; ini_install='install'; ini_zip='zip'; ini_clean='clean'; ini_dirs='dirs'; ini_require='require'; ini_libs='libs'; ini_targets='targets'; ini_info='info'; ini_defaults='defaults'; ini_tools='tools'; type TTargetsString=array[0..targets] of string; TFpcMake=record TargetDirs, TargetLoaders, TargetUnits, TargetPrograms, TargetExamples, TargetExampleDirs, TargetPkgs, TargetRST : TTargetsString; Installexamplesubdirs, InstallSourceSubdirs : boolean; InstallPackageName, InstallUnitSubDir, InstallExampleSubDir, InstallPrefixDir, InstallDataDir, InstallBaseDir : string; InstallUnits, InstallFiles : TTargetsString; CleanUnits, CleanFiles : TTargetsString; ZipName, ZipTarget : string; DefaultRule, DefaultBuildDir, DefaultInstallDir, DefaultZipInstallDir, DefaultCleanDir, DefaultDir, DefaultTarget, DefaultCPU : string; DirFpc, DirPackage, DirToolkit, DirComponent, DirUnit, DirLib, DirObj, DirTarget, DirUnitTarget, DirSources, DirInc : string; RequireRTL : boolean; RequireOptions : string; RequireToolkits, RequirePackages, RequireComponents : TTargetsString; LibName, LibVersion, LibUnits : string; LibGCC, LibOther : boolean; InfoCfg, InfoDirs, InfoTools, InfoInstall, InfoObjects : boolean; Section : array[tsections] of boolean; ToolsPPDep, ToolsPPUMove, ToolsPPUFiles, ToolsData2Inc, ToolsSed, ToolsDiff, ToolsCmp, ToolsUpx, ToolsDate, ToolsZip, ToolsTar : boolean; MultiPacks, PreSettings, PostSettings, Rules : TStringList; end; TMyMemoryStream=class(TMemoryStream) public constructor Create(p:pointer;mysize:integer); end; var userini : TFpcMake; fpcini : TIniFile; IniStream : TMyMemoryStream; {***************************************************************************** Helpers *****************************************************************************} procedure Verbose(s:string); begin writeln(s); end; procedure Error(s:string); begin Writeln(s); Halt(1); 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; function TargetStringEmpty(const t:TTargetsString):boolean; var i : integer; begin for i:=0 to targets do if t[i]<>'' then begin TargetStringEmpty:=false; exit; end; TargetStringEmpty:=true; 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; {***************************************************************************** TMyMemoryStream *****************************************************************************} constructor TMyMemoryStream.Create(p:pointer;mysize:integer); begin inherited Create; SetPointer(p,mysize); end; {***************************************************************************** Makefile.fpc reading *****************************************************************************} function ReadMakefilefpc(const fn:string):boolean; var ini : TIniFile; procedure ReadTargetsString(var t:Ttargetsstring;const sec,name,def:string); var i : integer; begin t[0]:=ini.ReadString(sec,name,def); for i:=1 to targets do t[i]:=ini.ReadString(sec,name+'_'+targetstr[i],''); end; var sec : tsections; b : boolean; begin ReadMakefilefpc:=false; Verbose('Reading '+fn); ini:=TIniFile.Create(fn); ini.escapelinefeeds:=True; with userini,ini do begin { targets } ReadTargetsString(TargetDirs,ini_targets,'dirs',''); ReadTargetsString(TargetLoaders,ini_targets,'loaders',''); ReadTargetsString(TargetUnits,ini_targets,'units',''); ReadTargetsString(TargetPrograms,ini_targets,'programs',''); ReadTargetsString(TargetExamples,ini_targets,'examples',''); ReadTargetsString(TargetExampleDirs,ini_targets,'exampledirs',''); ReadTargetsString(TargetRST,ini_targets,'rst',''); ReadTargetsString(TargetPkgs,ini_targets,'pkgs',''); if not TargetStringEmpty(TargetPkgs) then TargetPkgs[0]:='all '+TargetPkgs[0]; { clean } ReadTargetsString(CleanUnits,ini_clean,'units',''); ReadTargetsString(CleanFiles,ini_clean,'files',''); { install } InstallPackageName:=ReadString(ini_install,'packagename',''); InstallPrefixDir:=ReadString(ini_install,'dirprefix',''); InstallBaseDir:=ReadString(ini_install,'basedir',''); InstallDataDir:=ReadString(ini_install,'datadir',''); InstallUnitSubDir:=ReadString(ini_install,'unitsubdir',''); Installexamplesubdir:=ReadString(ini_install,'examplesubdir',''); InstallSourceSubdirs:=ReadBool(ini_install,'sourcesubdirs',false); Installexamplesubdirs:=ReadBool(ini_install,'examplesubdirs',false); ReadTargetsString(InstallUnits,ini_install,'units',''); ReadTargetsString(InstallFiles,ini_install,'files',''); { zip } ZipName:=ReadString(ini_zip,'zipname',''); ZipTarget:=ReadString(ini_zip,'ziptarget','install'); { defaults } DefaultDir:=ReadString(ini_defaults,'defaultdir',''); DefaultBuildDir:=ReadString(ini_defaults,'defaultbuilddir',''); DefaultInstallDir:=ReadString(ini_defaults,'defaultinstalldir',''); DefaultZipInstallDir:=ReadString(ini_defaults,'defaultzipinstalldir',''); DefaultCleanDir:=ReadString(ini_defaults,'defaultcleandir',''); DefaultRule:=ReadString(ini_defaults,'defaultrule','all'); DefaultTarget:=ReadString(ini_defaults,'defaulttarget',''); DefaultCPU:=ReadString(ini_defaults,'defaultcpu',''); { require } b:=not(TargetStringEmpty(targetunits) and TargetStringEmpty(targetprograms) and TargetStringEmpty(targetexamples)); RequireRTL:=ReadBool(ini_require,'rtl',b); RequireOptions:=ReadString(ini_require,'options',''); ReadTargetsString(requireToolkits,ini_require,'toolkit',''); ReadTargetsString(requirePackages,ini_require,'packages',''); ReadTargetsString(requireComponents,ini_require,'components',''); if userini.RequireRTL then begin if userini.Requirepackages[0]<>'' then userini.Requirepackages[0]:='rtl '+userini.Requirepackages[0] else userini.Requirepackages[0]:='rtl'; end; { sections, but allow overriding the 'none' option to include a few sects only } for sec:=low(tsections) to high(tsections) do Section[sec]:=sectiondef[sec]; Section[sec_None]:=ReadBool(ini_sections,sectionstr[sec_none],sectiondef[sec_none]); if Section[sec_None] then FillChar(Section,sizeof(Section),0); for sec:=low(tsections) to high(tsections) do Section[sec]:=ReadBool(ini_sections,sectionstr[sec],section[sec]); { turn on needed sections } if not TargetStringEmpty(TargetLoaders) then section[sec_loaders]:=true; if not TargetStringEmpty(TargetUnits) then section[sec_units]:=true; if not TargetStringEmpty(TargetPrograms) then section[sec_exes]:=true; if not(TargetStringEmpty(TargetExamples) and TargetStringEmpty(TargetExampleDirs)) then section[sec_examples]:=true; { dependencies } if section[sec_zipsourceinstall] then begin section[sec_zipinstall]:=true; section[sec_sourceinstall]:=true; end; if section[sec_zipexampleinstall] then begin section[sec_zipinstall]:=true; section[sec_exampleinstall]:=true; end; if section[sec_sourceinstall] or section[sec_exampleinstall] then begin section[sec_tools]:=true; section[sec_dirs]:=true; end; { dirs } DirFpc:=ReadString(ini_dirs,'fpcdir',''); DirPackage:=ReadString(ini_dirs,'packagedir','$(FPCDIR)/packages'); DirToolkit:=ReadString(ini_dirs,'toolkitdir',''); DirComponent:=ReadString(ini_dirs,'componentdir',''); DirUnit:=ReadString(ini_dirs,'unitdir',''); DirLib:=ReadString(ini_dirs,'libdir',''); DirObj:=ReadString(ini_dirs,'objdir',''); DirTarget:=ReadString(ini_dirs,'targetdir',''); DirSources:=ReadString(ini_dirs,'sourcesdir',''); DirUnitTarget:=ReadString(ini_dirs,'unittargetdir',''); DirInc:=ReadString(ini_dirs,'incdir',''); { libs } LibName:=ReadString(ini_libs,'libname',''); LibVersion:=ReadString(ini_libs,'libversion',''); LibUnits:=ReadString(ini_libs,'libunits',''); LibGcc:=ReadBool(ini_libs,'libgcc',false); LibOther:=ReadBool(ini_libs,'libother',false); { tools } ToolsPPUMove:=ReadBool(ini_tools,'toolppumove',section[sec_compile]); ToolsPPUFiles:=ReadBool(ini_tools,'toolppufiles',section[sec_install] or section[sec_clean]); ToolsUpx:=ReadBool(ini_tools,'toolupx',section[sec_install]); ToolsZip:=ReadBool(ini_tools,'toolzip',section[sec_zipinstall]); ToolsTar:=ReadBool(ini_tools,'tooltar',section[sec_zipinstall]); ToolsPPDep:=ReadBool(ini_tools,'toolppdep',false); ToolsSed:=ReadBool(ini_tools,'toolsed',false); ToolsData2Inc:=ReadBool(ini_tools,'tooldata2inc',false); ToolsDiff:=ReadBool(ini_tools,'tooldiff',false); ToolsCmp:=ReadBool(ini_tools,'toolcmp',false); ToolsDate:=ReadBool(ini_tools,'tooldate',false); { info } InfoCfg:=ReadBool(ini_info,'infoconfig',true); InfoDirs:=ReadBool(ini_info,'infodirs',false); InfoTools:=ReadBool(ini_info,'infotools',false); InfoInstall:=ReadBool(ini_info,'infoinstall',true); InfoObjects:=ReadBool(ini_info,'infoobjects',true); { multipacks } MultiPacks:=TStringList.Create; ReadSectionRaw('multipack',MultiPacks); { rules } PreSettings:=TStringList.Create; ReadSectionRaw('presettings',PreSettings); { rules } PostSettings:=TStringList.Create; ReadSectionRaw('postsettings',PostSettings); { rules } rules:=TStringList.Create; ReadSectionRaw('rules',rules); end; ini.Destroy; ReadMakefilefpc:=true; end; {***************************************************************************** userini.ini loading *****************************************************************************} function ReadFpcMakeIni:TIniFile; var fn : string; begin ReadFpcMakeIni:=nil; if FileExists('fpcmake.ini') then fn:='fpcmake.ini' else if (FileExists(GetEnv(envvar))) then fn:=GetEnv(envvar) else {$ifdef linux} if FileExists('/usr/lib/fpc/fpcmake.ini') then fn:='/usr/lib/fpc/fpcmake.ini' {$else} if FileExists(ChangeFileExt(paramstr(0),'.ini')) then fn:=ChangeFileExt(paramstr(0),'.ini') {$endif} else fn:=''; if fn='' then begin Verbose('Opening internal ini'); IniStream:=TMyMemoryStream.Create(@fpcmakeini,sizeof(fpcmakeini)); result:=TIniFile.Create(IniStream); end else begin Verbose('Opening '+fn); result:=TIniFile.Create(fn); end; result.Escapelinefeeds:=True; end; {***************************************************************************** Makefile writing *****************************************************************************} function VarName(const s:string):string; var i,j : longint; begin i:=0; result:=s; while i0 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; function WriteMakefile(const fn:string):boolean; var mf : TStringList; ss : TStringList; Phony : string; procedure FixTab(sl:TStringList); var i,j,k : integer; s,s2 : string; begin i:=0; while (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; procedure AddHead(const s:string); begin mf.Add(''); mf.Add('# '+s); mf.Add(''); end; procedure AddSection(b:boolean;s:string); begin if b then begin ss.Clear; fpcini.ReadSectionRaw(s,ss); mf.AddStrings(ss); mf.Add(''); end; end; procedure AddRule(rule:integer); var i : integer; hs : string; begin i:=0; while (ilength(rulestr[rule])) and (userini.rules[i][1]=rulestr[rule][1]) and ((userini.rules[i][length(rulestr[rule])+1]=':') or ((length(userini.rules[i])>length(rulestr[rule])+1) and (userini.rules[i][length(rulestr[rule])+2]=':'))) and (Copy(userini.rules[i],1,length(rulestr[rule]))=rulestr[rule]) then exit; inc(i); end; hs:=''; { zipinstall,exampleinstall are special, it allows packages } if ((not userini.installsourcesubdirs) and ((rulestr[rule]='zipsourceinstall') or (rulestr[rule]='sourceinstall'))) or ((not userini.installexamplesubdirs) and ((rulestr[rule]='examples') or (rulestr[rule]='test') or (rulestr[rule]='zipexampleinstall') or (rulestr[rule]='exampleinstall'))) then begin if userini.section[rule2sec[rule]] then hs:=hs+' fpc_'+rulestr[rule]; end else if ((rulestr[rule]='zipinstall') or (rulestr[rule]='zipsourceinstall')) and (not TargetStringEmpty(userini.targetpkgs)) then hs:=hs+' $(addsuffix _'+rulestr[rule]+',$(PKGOBJECTS))' else begin if userini.section[rule2sec[rule]] then hs:=hs+' fpc_'+rulestr[rule]; if rulediralso[rule] then begin if userini.DefaultDir<>'' then hs:=hs+' $(addsuffix _'+rulestr[rule]+','+userini.defaultdir+')' else if (userini.DefaultBuildDir<>'') and (rule2bic[rule]=bic_build) then hs:=hs+' $(addsuffix _'+rulestr[rule]+','+userini.defaultbuilddir+')' else if (userini.DefaultInstallDir<>'') and (rule2bic[rule]=bic_install) then hs:=hs+' $(addsuffix _'+rulestr[rule]+','+userini.defaultinstalldir+')' else if (userini.DefaultZipInstallDir<>'') and (rule2bic[rule]=bic_zipinstall) then hs:=hs+' $(addsuffix _'+rulestr[rule]+','+userini.defaultzipinstalldir+')' else if (userini.DefaultCleanDir<>'') and (rule2bic[rule]=bic_clean) then hs:=hs+' $(addsuffix _'+rulestr[rule]+','+userini.defaultcleandir+')' else if (not TargetStringEmpty(userini.targetdirs)) then hs:=hs+' $(addsuffix _'+rulestr[rule]+',$(DIROBJECTS))'; end; { include cleaning of example dirs } if (rulestr[rule]='clean') and (not TargetStringEmpty(userini.targetexampledirs)) then hs:=hs+' $(addsuffix _'+rulestr[rule]+',$(EXAMPLEDIROBJECTS))'; end; if hs<>'' then begin Phony:=Phony+' '+rulestr[rule]; mf.Add(rulestr[rule]+':'+hs); mf.Add(''); end; end; procedure AddTargets(const pre:string;var t:TTargetsString;wildcard:boolean); var i : integer; begin for i:=0 to targets do if (t[i]<>'') then begin if i<>0 then mf.Add('ifeq ($(OS_TARGET),'+targetstr[i]+')'); if t[i]<>'' then begin if wildcard then mf.Add('override '+pre+'+=$(wildcard '+t[i]+')') else mf.Add('override '+pre+'+='+t[i]); end; if i<>0 then mf.Add('endif'); end; end; procedure AddTargetDir(const s,defpref:string); var j : integer; hs : string; begin AddHead('Dir '+s); mf.Add('ifdef '+defpref+VarName(s)); hs:='.PHONY: '; for j:=1to rules do hs:=hs+' '+s+'_'+rulestr[j]; mf.Add(hs); mf.Add(''); for j:=1to rules do begin mf.Add(s+'_'+rulestr[j]+':'); mf.Add(#9+'$(MAKE) -C '+s+' '+rulestr[j]); if j'') then begin if j<>0 then mf.Add('ifeq ($(OS_TARGET),'+targetstr[j]+')'); hs:=ts[j]; repeat i:=pos(' ',hs); if i=0 then i:=length(hs)+1; name:=Copy(hs,1,i-1); k1:=pos('{',name); if k1>0 then begin k2:=PosIdx('}',name,k1); if k2=0 then begin Writeln('Error: missing closing } for "',name,'"'); k2:=length(name)+1; end; hs3:=Copy(name,k1+1,k2-k1-1); for k3:=1to length(hs3) do if hs3[k3]=',' then hs3[k3]:=' '; name:=Copy(name,1,k1-1); mf.Add(prefix+VarName(name)+'='+hs3); end else mf.Add(prefix+VarName(name)+'=1'); { add to the list of dirs without duplicates } AddStrNoDup(hs2,name); system.delete(hs,1,i); until hs=''; if j<>0 then mf.Add('endif'); end; AddTargetDefines:=hs2; end; procedure AddPackage(const path,pack:string); var k : integer; packdirvar,unitdirvar,unitdir,packdir : string; begin mf.Add('ifdef PACKAGE'+VarName(pack)); { create needed variables } packdirvar:='PACKAGEDIR_'+VarName(pack); unitdirvar:='UNITDIR_'+VarName(pack); packdir:=path+'/'+pack; unitdir:='$(UNITSDIR)/'+pack; for k:=1to specialdirs do begin if specialdir[k].dir=pack then begin packdir:=specialdir[k].packdir; unitdir:=specialdir[k].unitdir; break; end; end; mf.Add('ifneq ($(wildcard '+packdir+'),)'); { Use Package dir, add build rules } mf.Add('ifneq ($(wildcard '+packdir+'/$(OS_TARGET)),)'); mf.Add(packdirvar+'='+packdir+'/$(OS_TARGET)'); mf.Add('else'); mf.Add(packdirvar+'='+packdir); mf.Add('endif'); mf.Add('ifeq ($(wildcard $('+packdirvar+')/$(FPCMADE)),)'); mf.Add('override COMPILEPACKAGES+=package_'+pack); Phony:=Phony+'package_'+pack; mf.Add('package_'+pack+':'); mf.Add(#9'$(MAKE) -C $('+packdirvar+') all'); mf.Add('endif'); mf.Add(unitdirvar+'=$('+packdirvar+')'); mf.Add('else'); { Package dir doesn''t exists, create unit dir } mf.Add(packdirvar+'='); mf.Add('ifneq ($(wildcard '+unitdir+'),)'); mf.Add('ifneq ($(wildcard '+unitdir+'/$(OS_TARGET)),)'); mf.Add(unitdirvar+'='+unitdir+'/$(OS_TARGET)'); mf.Add('else'); mf.Add(unitdirvar+'='+unitdir); mf.Add('endif'); mf.Add('else'); mf.Add(unitdirvar+'='); mf.Add('endif'); mf.Add('endif'); { Add Unit dir to the command line -Fu } mf.Add('ifdef '+unitdirvar); mf.Add('override NEEDUNITDIR+=$('+unitdirvar+')'); mf.Add('endif'); mf.Add('endif'); end; procedure AddTargetsPackages(const path:string;const ts:TTargetsString); var Phony,hs : string; i : integer; begin { Components } Phony:=''; if not TargetStringEmpty(ts) then begin AddHead(VarName(path)+' packages'); hs:=AddTargetDefines(ts,'PACKAGE'); mf.Add(''); repeat i:=pos(' ',hs); if i=0 then i:=length(hs)+1; AddPackage(path,Copy(hs,1,i-1)); system.delete(hs,1,i); until hs=''; mf.Add(''); end; if Phony<>'' then begin mf.Add('.PHONY: '+Phony); mf.Add(''); end; end; procedure AddPkg(const pack:string); var j : integer; packname,pkgdirsvar,hs : string; begin packname:=pack; AddHead('Pkg '+packname); mf.Add('ifdef PKG'+VarName(packname)); hs:='.PHONY: '; for j:=1 to rules do hs:=hs+' pkg'+packname+'_'+rulestr[j]; mf.Add(hs); mf.Add(''); { pkgall is special which processes all directories } if pack='all' then pkgdirsvar:='DIROBJECTS' else begin mf.Add('override PKGOBJECTS+=pkg'+packname); pkgdirsvar:='PKG'+VarName(packname); end; for j:=1to rules do if rulediralso[j] then begin mf.Add('pkg'+packname+'_'+rulestr[j]+': $(addsuffix _'+rulestr[j]+',$('+pkgdirsvar+'))'); if j'' then begin mf.Add('.PHONY: '+Phony); mf.Add(''); end; end; var hs : string; i : integer; begin { Open the Makefile } mf:=TStringList.Create; { Buffer for reading and writing the sections } ss:=TStringList.Create; with mf do begin { write header & autodetection } Add('#'); Add('# Makefile generated by '+titledate); Add('#'); Add(''); Add('defaultrule: '+userini.defaultrule); Add(''); AddSection(true,'osdetect'); { set the forced target os/cpu } if (userini.defaulttarget<>'') or (userini.defaultcpu<>'') then begin AddSection(true,'defaulttarget'); if userini.defaulttarget<>'' then Add('override OS_TARGET:='+userini.defaulttarget); if userini.defaultcpu<>'' then Add('override CPU_TARGET:='+userini.defaultcpu); Add(''); end; { fpc detection } AddSection(true,'fpcdetect'); { Pre Settings } if userini.PreSettings.count>0 then begin AddSection(true,'presettings'); AddStrings(userini.PreSettings); end; { fpc dir } AddSection(true,'fpcdircheckenv'); if userini.dirfpc<>'' then begin Add('# Default FPCDIR'); Add('ifeq ($(FPCDIR),wrong)'); Add('override FPCDIR='+userini.dirfpc); Add('ifeq ($(wildcard $(FPCDIR)/rtl),)'); Add('ifeq ($(wildcard $(FPCDIR)/units),)'); Add('override FPCDIR=wrong'); Add('endif'); Add('endif'); Add('endif'); Add(''); end; AddSection(true,'fpcdirdetect'); { fpcdir subdirs } if userini.RequireRTL then begin Add('ifndef PACKAGESDIR'); Add('PACKAGESDIR='+userini.dirpackage); Add('endif'); Add('ifndef TOOLKITSDIR'); Add('TOOLKITSDIR='+userini.dirtoolkit); Add('endif'); Add('ifndef COMPONENTSDIR'); Add('COMPONENTSDIR='+userini.dircomponent); Add('endif'); Add(''); AddSection(true,'fpcdirsubs'); end; { write the default & user settings } AddSection(true,'usersettings'); { Targets } AddHead('Targets'); AddTargets('DIROBJECTS',userini.targetdirs,true); AddTargets('LOADEROBJECTS',userini.targetloaders,false); AddTargets('UNITOBJECTS',userini.targetunits,false); AddTargets('EXEOBJECTS',userini.targetprograms,false); AddTargets('EXAMPLEOBJECTS',userini.targetexamples,false); AddTargets('EXAMPLEDIROBJECTS',userini.targetexampledirs,false); AddTargets('RSTOBJECTS',userini.targetrst,false); { Clean } AddHead('Clean'); AddTargets('EXTRACLEANUNITS',userini.cleanunits,false); AddTargets('EXTRACLEANFILES',userini.cleanfiles,false); { Install } AddHead('Install'); AddTargets('EXTRAINSTALLUNITS',userini.installunits,false); AddTargets('EXTRAINSTALLFILES',userini.installfiles,false); if userini.installprefixdir<>'' then Add('PREFIXINSTALLDIR='+userini.installprefixdir); if userini.installbasedir<>'' then Add('BASEINSTALLDIR='+userini.installbasedir); if userini.installdatadir<>'' then Add('DATAINSTALLDIR='+userini.installdatadir); if userini.InstallUnitSubDir<>'' then Add('UNITSUBDIR='+userini.InstallUnitSubDir); if userini.InstallExampleSubDir<>'' then Add('EXAMPLESUBDIR='+userini.InstallExampleSubDir); if userini.installpackagename<>'' then Add('PACKAGENAME='+userini.installpackagename); { Zip } if userini.zipname<>'' then Add('ZIPNAME='+userini.zipname); if userini.ziptarget<>'' then Add('ZIPTARGET='+userini.ziptarget); { Defaults } AddHead('Defaults'); if userini.Requireoptions<>'' then Add('override NEEDOPT='+userini.Requireoptions); { Dirs } AddHead('Directories'); if userini.dirsources<>'' then Add('vpath %$(PASEXT) '+userini.dirsources); if userini.dirunit<>'' then Add('override NEEDUNITDIR='+userini.dirunit); if userini.dirlib<>'' then Add('override NEEDLIBDIR='+userini.dirlib); if userini.dirobj<>'' then Add('override NEEDOBJDIR='+userini.dirobj); if userini.dirinc<>'' then Add('override NEEDINCDIR='+userini.dirinc); if userini.dirtarget<>'' then begin Add('ifndef TARGETDIR'); Add('TARGETDIR='+userini.dirtarget); Add('endif'); end; if userini.dirunittarget<>'' then begin Add('ifndef UNITTARGETDIR'); Add('UNITTARGETDIR='+userini.dirunittarget); Add('endif'); end; { Packages } AddHead('Packages'); Phony:=''; AddTargets('PACKAGES',userini.Requirepackages,false); AddTargets('TOOLKITS',userini.Requiretoolkits,false); AddTargets('COMPONENTS',userini.Requirecomponents,false); if Phony<>'' then begin Add('.PHONY: '+Phony); Add(''); end; { Libs } AddHead('Libraries'); if userini.libname<>'' then Add('LIBNAME='+userini.libname); if userini.libversion<>'' then Add('LIBVERSION='+userini.libversion); if userini.libunits<>'' then Add('SHAREDLIBUNITOBJECTS='+userini.libunits); if userini.libgcc then Add('override NEEDGCCLIB=1'); if userini.libother then Add('override NEEDOTHERLIB=1'); { Info } if userini.Section[sec_Info] then begin AddHead('Info'); hs:=''; if userini.infocfg then hs:=hs+'fpc_infocfg '; if userini.infodirs then hs:=hs+'fpc_infodirs '; if userini.infotools then hs:=hs+'fpc_infotools '; if userini.infoobjects then hs:=hs+'fpc_infoobjects '; if userini.infoinstall then hs:=hs+'fpc_infoinstall '; Add('INFOTARGET='+hs); end; Add(''); { Post Settings } if userini.PostSettings.count>0 then begin AddSection(true,'postsettings'); AddStrings(userini.PostSettings); Add(''); end; { shell tools like copy,del,echo } AddSection(userini.section[sec_command] or userini.section[sec_tools],'shelltools'); { write tools } AddSection(userini.section[sec_tools],'tool_default'); AddSection(userini.toolsppdep,'tool_ppdep'); AddSection(userini.toolsppumove,'tool_ppumove'); AddSection(userini.toolsppufiles,'tool_ppufiles'); AddSection(userini.toolsdata2inc,'tool_data2inc'); AddSection(userini.toolsupx,'tool_upx'); AddSection(userini.toolssed,'tool_sed'); AddSection(userini.toolscmp,'tool_cmp'); AddSection(userini.toolsdiff,'tool_diff'); AddSection(userini.toolsdate,'tool_date'); AddSection(userini.toolszip,'tool_zip'); AddSection(userini.toolstar,'tool_tar'); { extensions } if userini.section[sec_exts] then AddSection(true,'extensions'); { package/component dirs } AddSection(true,'packagerequirerules'); AddSection(userini.requirertl,'checkfpcdirsubs'); AddTargetsPackages('$(PACKAGESDIR)',userini.Requirepackages); AddTargetsPackages('$(TOOLKITSDIR)',userini.Requiretoolkits); AddTargetsPackages('$(COMPONENTSDIR)',userini.Requirecomponents); Add(''); { Pkgs } AddTargetsPkgs(userini.targetpkgs); { write dirs } AddSection(true,'dir_default'); if userini.section[sec_dirs] then begin AddSection(userini.libgcc,'dir_gcclib'); AddSection(userini.libother,'dir_otherlib'); AddSection(true,'dir_install'); end; { redirection } AddSection(true,'redir'); { commandline } if userini.section[sec_command] then begin Add(''); AddSection(true,'command_begin'); AddSection((userini.Requireoptions<>''),'command_needopt'); AddSection((userini.dirunit<>'') or (not TargetStringEmpty(userini.Requiretoolkits)) or (not TargetStringEmpty(userini.Requirepackages)) or (not TargetStringEmpty(userini.Requirecomponents)) ,'command_needunit'); AddSection(true,'command_unitsdir'); AddSection((userini.dirlib<>''),'command_needlib'); AddSection((userini.dirobj<>''),'command_needobj'); AddSection((userini.dirinc<>''),'command_needinc'); AddSection(userini.libgcc,'command_gcclib'); AddSection(userini.libother,'command_otherlib'); AddSection((userini.dirinc<>''),'command_inc'); AddSection(true,'command_target'); AddSection(true,'command_end'); AddSection(true,'command_win32env'); AddSection(true,'command_compiler'); end; { add default rules } AddSection(true,'standardrules'); Phony:=''; for i:=1 to rules do AddRule(i); if Phony<>'' then begin Add('.PHONY: '+Phony); Add(''); end; { compile rules for making loaders/units/exes/examples } AddSection(not TargetStringEmpty(userini.targetloaders),'loaderrules'); AddSection(not TargetStringEmpty(userini.targetunits),'unitrules'); AddSection(not TargetStringEmpty(userini.targetprograms),'exerules'); AddSection(not(TargetStringEmpty(userini.targetexamples) and TargetStringEmpty(userini.targetexampledirs)),'examplerules'); AddSection(not TargetStringEmpty(userini.targetrst),'rstrules'); { default fpc_ rules } AddSection(userini.Section[sec_Compile],'compilerules'); AddSection(userini.Section[sec_Libs],'libraryrules'); AddSection(userini.Section[sec_Install],'installrules'); AddSection(userini.Section[sec_SourceInstall],'sourceinstallrules'); AddSection(userini.Section[sec_ExampleInstall],'exampleinstallrules'); AddSection(userini.Section[sec_ZipInstall],'zipinstallrules'); AddSection(userini.Section[sec_ZipSourceInstall],'zipsourceinstallrules'); AddSection(userini.Section[sec_ZipExampleInstall],'zipexampleinstallrules'); AddSection(userini.Section[sec_Clean],'cleanrules'); AddSection(userini.Section[sec_require],'requirerules'); if userini.Section[sec_Info] then begin AddSection(true,'inforules'); AddSection(userini.infocfg,'info_cfg'); AddSection(userini.infodirs,'info_dirs'); AddSection(userini.infotools,'info_tools'); AddSection(userini.infoobjects,'info_objects'); AddSection(userini.infoinstall,'info_install'); end; { Target dirs } if not(TargetStringEmpty(userini.targetdirs) and TargetStringEmpty(userini.targetexampledirs)) then begin AddSection(true,'directorytargets'); hs:=AddTargetDefines(userini.targetdirs,'OBJECTDIR'); while hs<>'' do begin i:=pos(' ',hs); if i=0 then i:=length(hs)+1; AddTargetDir(Copy(hs,1,i-1),'OBJECTDIR'); system.delete(hs,1,i); end; hs:=AddTargetDefines(userini.targetexampledirs,'EXAMPLEDIR'); while hs<>'' do begin i:=pos(' ',hs); if i=0 then i:=length(hs)+1; AddTargetDir(Copy(hs,1,i-1),'EXAMPLEDIR'); system.delete(hs,1,i); end; Add(''); end; { local makefile } AddSection(true,'localmakefile'); { insert users rules } if userini.rules.count>0 then begin AddSection(true,'userrules'); AddStrings(userini.rules); end; end; { Write the Makefile and cleanup } Verbose('Writing '+fn); FixTab(mf); mf.SaveToFile(fn); mf.Destroy; ss.Destroy; WriteMakefile:=true; end; procedure UseMakefilefpc; var fn : string; begin if FileExists('Makefile.fpc') then fn:='Makefile.fpc' else fn:='makefile.fpc'; { Open Makefile.fpc } if not ReadMakefilefpc(fn) then Error('Can''t read '+fn); { Write Makefile } if not WriteMakefile('Makefile') then Error('Can''t write Makefile'); end; procedure UseParameters; var i : integer; fn : string; begin for i:=1 to ParamCount do begin fn:=ParamStr(i); { Open Makefile.fpc } if not ReadMakefilefpc(fn) then Error('Can''t read '+fn); { Write Makefile } if not WriteMakefile(ExtractFilePath(fn)+'Makefile') then Error('Can''t write '+ExtractFilePath(fn)+'Makefile'); end; end; begin { Open userini.ini } fpcini:=ReadFpcMakeIni; if not assigned(fpcini) then Error('Can''t read fpcmake.ini'); if ParamCount=0 then UseMakefilefpc else UseParameters; fpcini.destroy; end. { $Log$ Revision 1.3 2000-10-26 22:39:34 peter * freebsd updates Revision 1.2 2000/09/01 21:37:30 peter * targetdir support (merged) Revision 1.1 2000/07/13 10:16:22 michael + Initial import Revision 1.38 2000/07/04 19:05:54 peter * be optimistic: version 1.00 for some utils Revision 1.37 2000/07/01 23:03:32 peter * exampleinstall target added Revision 1.36 2000/06/01 12:35:04 peter * library support including symlink of .so to .so.1.0 Revision 1.35 2000/05/11 17:59:12 peter * makeini unit added as replacement for old inifiles unit Revision 1.34 2000/04/11 15:34:58 peter * added extra ifdef to check if there are some objects else some targets aren't added anymore Revision 1.33 2000/03/11 15:58:56 michael + Added escapelinefeeds:=true after inifile.create Revision 1.32 2000/02/09 16:44:14 peter * log truncated Revision 1.31 2000/02/08 00:03:35 peter * fixed zipinstall with defaultdir Revision 1.30 2000/02/02 11:30:00 peter * fixed sharedlibunitobjects typo Revision 1.29 2000/01/28 12:10:46 peter * reinserted lost diff of rev 1.30 * distclean target Revision 1.28 2000/01/26 21:16:26 peter * SMARTLINK=1 split into CREATESMART=1 and LINKSMART=1 * FPCDIR checks enhanced Revision 1.27 2000/01/16 22:26:47 peter * use environment variable again for win32, the file writing gives to much trouble Revision 1.26 2000/01/14 12:14:41 peter * sourceinstall updates Revision 1.25 2000/01/13 21:08:46 peter * zipsourcesinstall * zip fixes, bzip2 support with USETAR=bz2 * multi pkg's support to include several dirs Revision 1.24 2000/01/13 11:34:26 peter * better package dep creation Revision 1.23 2000/01/12 23:20:37 peter * gecho support * use foreach to write fpcext.cmd * add fpcext.cmd to clean targets Revision 1.22 2000/01/10 22:55:49 peter * zipname creation from packagename Revision 1.21 2000/01/08 16:31:04 peter * support variable in packagenames * fpcmake.loc support * fixed place of presettings which must be before FPCDIR is set Revision 1.20 2000/01/07 16:46:02 daniel * copyright 2000 Revision 1.19 2000/01/06 15:49:23 peter * rtldir removed, it's now handled like any other package Revision 1.18 2000/01/06 01:29:59 peter * FPCDIR setting/detect * lot of other updates to create .deb files correctly Revision 1.17 2000/01/04 00:00:23 peter * Makefile updates again Revision 1.16 2000/01/03 19:42:41 peter * regenerated Revision 1.15 1999/12/23 19:32:28 peter * automatic support for package/target dir structure Revision 1.14 1999/12/23 13:52:23 peter + default[install,build,clean]dir Revision 1.13 1999/12/21 16:06:47 peter * don't call dirobjects for zipisntall,info Revision 1.12 1999/12/19 15:15:04 peter * fpcmade. added * parameter support. So it can be using with "find -name 'Makefile.fpc'" }