ide: package compiled file: store lazarusversion and switch between fallback on check not on prepare

This commit is contained in:
mattias 2023-08-15 10:59:04 +02:00
parent fffdea39bb
commit ec5726dc18
2 changed files with 249 additions and 210 deletions

View File

@ -447,7 +447,7 @@ type
podwWritable,
podwNotWritable
);
TPkgLastCompileStats = record
TPkgLastCompileStats = class
StateFileLoaded: boolean;
StateFileName: string; // the .compiled file
StateFileDate: longint;
@ -458,8 +458,8 @@ type
MainPPUExists: boolean; // main ppu file was there after compile
ViaMakefile: boolean; // compiled via make
DirectoryWritable: TPkgOutputDirWritable;
LazarusVersion: string;
end;
PPkgLastCompileStats = ^TPkgLastCompileStats;
TPkgOutputDir = (
podDefault,
podFallback // used when podDefault is not writable
@ -2619,6 +2619,8 @@ begin
end;
constructor TLazPackage.Create;
var
pod: TPkgOutputDir;
begin
inherited Create;
FComponents:=TFPList.Create;
@ -2638,6 +2640,8 @@ begin
FDefineTemplates:=TLazPackageDefineTemplates.Create(Self);
fPublishOptions:=TPublishPackageOptions.Create(Self);
FProvides:=TStringList.Create;
for pod in TPkgOutputDir do
LastCompile[pod]:=TPkgLastCompileStats.Create;
FUsageOptions.ParsedOpts.InvalidateParseOnChange:=true;
end;
@ -2648,9 +2652,13 @@ begin
end;
destructor TLazPackage.Destroy;
var
pod: TPkgOutputDir;
begin
Include(FFlags,lpfDestroying);
Clear;
for pod in TPkgOutputDir do
FreeAndNil(LastCompile[pod]);
FreeAndNil(FOptionsBackup);
FreeAndNil(fPublishOptions);
FreeAndNil(FProvides);

View File

@ -243,6 +243,8 @@ type
CheckDependencies, SkipDesignTimePackages, GroupCompile: boolean;
out NeedBuildAllFlag, ConfigChanged, DependenciesChanged: boolean;
var Note: string): TModalResult;
function LoadPackageCompiledStateFile(APackage: TLazPackage; o: TPkgOutputDir;
StateFile: string; IgnoreErrors, ShowAbort: boolean): TModalResult;
procedure InvalidateStateFile(APackage: TLazPackage);
procedure OnExtToolBuildStopped(Sender: TObject);
procedure PkgModify(Sender: TObject);
@ -3214,7 +3216,7 @@ var
StateFile: String;
CompilerFileDate: Integer;
o: TPkgOutputDir;
stats: PPkgLastCompileStats;
Stats: TPkgLastCompileStats;
begin
Result:=mrCancel;
StateFile:=APackage.GetStateFilename;
@ -3222,15 +3224,17 @@ begin
CompilerFileDate:=FileAgeCached(CompilerFilename);
o:=APackage.GetOutputDirType;
stats:=@APackage.LastCompile[o];
stats^.CompilerFilename:=CompilerFilename;
stats^.CompilerFileDate:=CompilerFileDate;
stats^.Params:=CompilerParams;
stats^.Complete:=Complete;
stats^.ViaMakefile:=false;
Stats:=APackage.LastCompile[o];
Stats.LazarusVersion:=LazarusVersionStr;
Stats.CompilerFilename:=CompilerFilename;
Stats.CompilerFileDate:=CompilerFileDate;
Stats.Params:=CompilerParams;
Stats.Complete:=Complete;
Stats.ViaMakefile:=false;
XMLConfig:=TXMLConfig.CreateClean(StateFile);
try
XMLConfig.SetValue('Lazarus/Version',Stats.LazarusVersion);
XMLConfig.SetValue('Compiler/Value',CompilerFilename);
XMLConfig.SetValue('Compiler/Date',CompilerFileDate);
XMLConfig.SetValue('Params/Value',CompilerParams);
@ -3241,9 +3245,9 @@ begin
finally
XMLConfig.Free;
end;
stats^.StateFileName:=StateFile;
stats^.StateFileDate:=FileAgeCached(StateFile);
APackage.LastCompile[o].StateFileLoaded:=true;
Stats.StateFileName:=StateFile;
Stats.StateFileDate:=FileAgeCached(StateFile);
Stats.StateFileLoaded:=true;
except
on E: Exception do begin
Result:=IDEMessageDialogAb(lisPkgMangErrorWritingFile,
@ -3260,83 +3264,12 @@ end;
function TLazPackageGraph.LoadPackageCompiledState(APackage: TLazPackage;
IgnoreErrors, ShowAbort: boolean): TModalResult;
var
XMLConfig: TXMLConfig;
StateFile: String;
StateFileAge: Integer;
stats: PPkgLastCompileStats;
o: TPkgOutputDir;
MakefileValue: String;
MakefileVersion: Integer;
begin
o:=APackage.GetOutputDirType;
stats:=@APackage.LastCompile[o];
StateFile:=APackage.GetStateFilename;
if not FileExistsCached(StateFile) then begin
//DebugLn('TLazPackageGraph.LoadPackageCompiledState Statefile not found: ',StateFile);
stats^.StateFileLoaded:=false;
Result:=mrOk;
exit;
end;
// read the state file
StateFileAge:=FileAgeCached(StateFile);
if (not stats^.StateFileLoaded)
or (stats^.StateFileDate<>StateFileAge)
or (stats^.StateFileName<>StateFile) then begin
stats^.StateFileLoaded:=false;
try
XMLConfig:=TXMLConfig.Create(StateFile);
try
stats^.CompilerFilename:=XMLConfig.GetValue('Compiler/Value','');
stats^.CompilerFileDate:=XMLConfig.GetValue('Compiler/Date',0);
stats^.Params:=XMLConfig.GetValue('Params/Value','');
stats^.Complete:=XMLConfig.GetValue('Complete/Value',true);
stats^.MainPPUExists:=XMLConfig.GetValue('Complete/MainPPUExists',true);
MakefileValue:=XMLConfig.GetValue('Makefile/Value','');
if (MakefileValue='') then
stats^.ViaMakefile:=false
else begin
stats^.ViaMakefile:=true;
MakefileVersion:=StrToIntDef(MakefileValue,0);
if MakefileVersion<2 then begin
// old versions used %(
stats^.CompilerFilename:=StringReplace(stats^.CompilerFilename,'%(','$(',[rfReplaceAll]);
stats^.Params:=StringReplace(stats^.Params,'%(','$(',[rfReplaceAll]);
end;
ForcePathDelims(stats^.CompilerFilename);
ForcePathDelims(stats^.Params);
end;
finally
XMLConfig.Free;
end;
stats^.StateFileName:=StateFile;
stats^.StateFileDate:=StateFileAge;
stats^.StateFileLoaded:=true;
except
on E: EXMLReadError do begin
// invalid XML
debugln(['Warning: (lazarus) package "',APackage.IDAsString,'": syntax error in ',StateFile,' => need clean build.']);
stats^.Complete:=false;
stats^.CompilerFilename:='';
stats^.StateFileName:=StateFile;
stats^.StateFileDate:=StateFileAge;
stats^.StateFileLoaded:=true;
end;
on E: Exception do begin
if IgnoreErrors then begin
Result:=mrOk;
end else begin
Result:=IDEMessageDialogAb(lisPkgMangErrorReadingFile,
Format(lisPkgMangUnableToReadStateFileOfPackageError,
[StateFile, LineEnding, APackage.IDAsString, LineEnding, E.Message]),
mtError,[mbCancel],ShowAbort);
end;
exit;
end;
end;
end;
Result:=mrOk;
o:=APackage.GetOutputDirType;
Result:=LoadPackageCompiledStateFile(APackage,o,StateFile,IgnoreErrors,ShowAbort);
end;
function TLazPackageGraph.CheckCompileNeedDueToFPCUnits(TheOwner: TObject;
@ -3454,59 +3387,59 @@ begin
if Dependency.DependencyType=pdtFPMake
then begin
// skip
end else if SkipDesignTimePackages and (RequiredPackage.PackageType=lptDesignTime)
then begin
end else if SkipDesignTimePackages and (RequiredPackage.PackageType=lptDesignTime) then
// skip
end else begin
else if RequiredPackage.IsVirtual then
// skip
else if RequiredPackage.Missing then
// skip
else begin
// check compile state file of required package
if (not RequiredPackage.IsVirtual) and (not RequiredPackage.Missing)
then begin
Result:=LoadPackageCompiledState(RequiredPackage,false,true);
if Result<>mrOk then begin
// file broken, user was told that file is broken and user had a
// choice of cancel or cancel all (=mrAbort).
// File broken means that the pkgname.compiled file has an invalid
// format, syntax error. The user or some external tool has altered
// the file. Maybe on purpose.
// The IDE should not silently replace the file.
// => pass the mrcancel/mrabort to the caller
Note+='unable to load state file of '+RequiredPackage.IDAsString;
Result:=LoadPackageCompiledState(RequiredPackage,false,true);
if Result<>mrOk then begin
// file broken, user was told that file is broken and user had a
// choice of cancel or cancel all (=mrAbort).
// File broken means that the pkgname.compiled file has an invalid
// format, syntax error. The user or some external tool has altered
// the file. Maybe on purpose.
// The IDE should not silently replace the file.
// => pass the mrcancel/mrabort to the caller
Note+='unable to load state file of '+RequiredPackage.IDAsString;
exit;
end;
Result:=mrYes;
o:=RequiredPackage.GetOutputDirType;
if not RequiredPackage.LastCompile[o].StateFileLoaded then begin
DebugLn('Hint: (lazarus) Missing state file for ',RequiredPackage.IDAsString,': ',RequiredPackage.GetStateFilename);
Note+='Package '+RequiredPackage.IDAsString+' has no state file "'+RequiredPackage.GetStateFilename+'".'+LineEnding;
exit;
end;
if StateFileAge<RequiredPackage.LastCompile[o].StateFileDate then begin
DebugLn('Hint: (lazarus) State file of ',RequiredPackage.IDAsString,' is newer than state file of ',GetOwnerID);
Note+='State file of '+RequiredPackage.IDAsString+' is newer than state file of '+GetOwnerID+LineEnding
+' '+RequiredPackage.IDAsString+'='+FileAgeToStr(RequiredPackage.LastCompile[o].StateFileDate)+LineEnding
+' '+GetOwnerID+'='+FileAgeToStr(StateFileAge)+LineEnding;
exit;
end;
// check output state file of required package
if RequiredPackage.OutputStateFile<>'' then begin
OtherStateFile:=RequiredPackage.OutputStateFile;
GlobalMacroList.SubstituteStr(OtherStateFile);
if not FilenameIsAbsolute(OtherStateFile) then
OtherStateFile:=AppendPathDelim(RequiredPackage.Directory)+OtherStateFile;
if FilenameIsAbsolute(OtherStateFile)
and FileExistsCached(OtherStateFile)
and (FileAgeCached(OtherStateFile)>StateFileAge) then begin
DebugLn('Hint: (lazarus) State file of ',RequiredPackage.IDAsString,' "',OtherStateFile,'" (',
FileAgeToStr(FileAgeCached(OtherStateFile)),')'
,' is newer than state file ',GetOwnerID,'(',FileAgeToStr(StateFileAge),')');
Note+='State file of used package is newer than state file:'+LineEnding
+' Used package '+RequiredPackage.IDAsString+', file="'+OtherStateFile+'", '
+' age='+FileAgeToStr(FileAgeCached(OtherStateFile))+LineEnding
+' package '+GetOwnerID+', age='+FileAgeToStr(StateFileAge)+LineEnding;
Result:=mrYes;
exit;
end;
Result:=mrYes;
o:=RequiredPackage.GetOutputDirType;
if not RequiredPackage.LastCompile[o].StateFileLoaded then begin
DebugLn('Hint: (lazarus) Missing state file for ',RequiredPackage.IDAsString,': ',RequiredPackage.GetStateFilename);
Note+='Package '+RequiredPackage.IDAsString+' has no state file "'+RequiredPackage.GetStateFilename+'".'+LineEnding;
exit;
end;
if StateFileAge<RequiredPackage.LastCompile[o].StateFileDate then begin
DebugLn('Hint: (lazarus) State file of ',RequiredPackage.IDAsString,' is newer than state file of ',GetOwnerID);
Note+='State file of '+RequiredPackage.IDAsString+' is newer than state file of '+GetOwnerID+LineEnding
+' '+RequiredPackage.IDAsString+'='+FileAgeToStr(RequiredPackage.LastCompile[o].StateFileDate)+LineEnding
+' '+GetOwnerID+'='+FileAgeToStr(StateFileAge)+LineEnding;
exit;
end;
// check output state file of required package
if RequiredPackage.OutputStateFile<>'' then begin
OtherStateFile:=RequiredPackage.OutputStateFile;
GlobalMacroList.SubstituteStr(OtherStateFile);
if not FilenameIsAbsolute(OtherStateFile) then
OtherStateFile:=AppendPathDelim(RequiredPackage.Directory)+OtherStateFile;
if FilenameIsAbsolute(OtherStateFile)
and FileExistsCached(OtherStateFile)
and (FileAgeCached(OtherStateFile)>StateFileAge) then begin
DebugLn('Hint: (lazarus) State file of ',RequiredPackage.IDAsString,' "',OtherStateFile,'" (',
FileAgeToStr(FileAgeCached(OtherStateFile)),')'
,' is newer than state file ',GetOwnerID,'(',FileAgeToStr(StateFileAge),')');
Note+='State file of used package is newer than state file:'+LineEnding
+' Used package '+RequiredPackage.IDAsString+', file="'+OtherStateFile+'", '
+' age='+FileAgeToStr(FileAgeCached(OtherStateFile))+LineEnding
+' package '+GetOwnerID+', age='+FileAgeToStr(StateFileAge)+LineEnding;
Result:=mrYes;
exit;
end;
end;
end;
end;
end;
@ -3524,7 +3457,7 @@ var
ConfigChanged: boolean;
DependenciesChanged: boolean;
DefResult: TModalResult;
OldNeedBuildAllFlag: Boolean;
OldNeedBuildAllFlag, IsDefDirWritable: Boolean;
OldOverride: String;
begin
Result:=mrYes;
@ -3546,11 +3479,13 @@ begin
end;
// the current output directory needs compilation
OutputDir:=APackage.GetOutputDirectory(false);
IsDefDirWritable:=OutputDirectoryIsWritable(APackage,OutputDir,false);
if APackage.CompilerOptions.ParsedOpts.OutputDirectoryOverride='' then
begin
// the last compile was put to the normal/default output directory
OutputDir:=APackage.GetOutputDirectory(false);
if OutputDirectoryIsWritable(APackage,OutputDir,false) then
if IsDefDirWritable then
begin
// the normal output directory is writable => keep using it
exit;
@ -3570,33 +3505,41 @@ begin
NeedBuildAllFlag,ConfigChanged,DependenciesChanged,Note);
end else begin
// the last compile was put to the fallback output directory
if not ConfigChanged then begin
// some source files have changed, not the compiler parameters
// => keep using the fallback directory
exit;
if not IsDefDirWritable then begin
if not ConfigChanged then begin
// some source files have changed, not the compiler parameters
// => keep using the fallback directory
exit;
end;
if DependenciesChanged then begin
// dependencies have changed
// => switching to the not writable default output directory is not possible
// => keep using the fallback directory
exit;
end;
// maybe the user switched the settings back to default
// => try using the default output directory
end;
if DependenciesChanged then begin
// dependencies have changed
// => switching to the not writable default output directory is not possible
// => keep using the fallback directory
exit;
end;
// maybe the user switched the settings back to default
// => try using the default output directory
OldOverride:=APackage.CompilerOptions.ParsedOpts.OutputDirectoryOverride;
APackage.CompilerOptions.ParsedOpts.OutputDirectoryOverride:='';
if ConsoleVerbosity>=0 then
debugln(['Hint: (lazarus) trying the default output directory of package ',APackage.IDAsString]);
OldNeedBuildAllFlag:=NeedBuildAllFlag;
DefResult:=CheckIfCurPkgOutDirNeedsCompile(APackage,
true,SkipDesignTimePackages,GroupCompile,
NeedBuildAllFlag,ConfigChanged,DependenciesChanged,Note);
if DefResult=mrNo then begin
// switching back to the not writable output directory requires no compile
if IsDefDirWritable or (DefResult=mrNo) then begin
// switching back to the default output directory
debugln(['Hint: (lazarus) switching back to the normal output directory: "',APackage.GetOutputDirectory,'" Package ',APackage.IDAsString]);
Note+='Switching back to not writable output directory.'+LineEnding;
exit(mrNo);
Note+='Switching back to default output directory.'+LineEnding;
exit(DefResult);
end;
// neither the default nor the fallback is valid
// => switch back to the fallback
if ConsoleVerbosity>=0 then
debugln(['Hint: (lazarus) switching back to fallback output directory package ',APackage.IDAsString]);
APackage.CompilerOptions.ParsedOpts.OutputDirectoryOverride:=OldOverride;
NeedBuildAllFlag:=OldNeedBuildAllFlag;
end;
@ -3618,7 +3561,7 @@ var
OldValue: string;
NewValue: string;
o: TPkgOutputDir;
Stats: PPkgLastCompileStats;
Stats: TPkgLastCompileStats;
SrcPPUFile: String;
AFilename: String;
CompilerFilename, CompilerParams, SrcFilename: string;
@ -3642,14 +3585,14 @@ begin
CompilerParams:=GetPackageCompilerParams(APackage);
o:=APackage.GetOutputDirType;
Stats:=@APackage.LastCompile[o];
Stats:=APackage.LastCompile[o];
//debugln(['TLazPackageGraph.CheckIfCurPkgOutDirNeedsCompile Last="',ExtractCompilerParamsForBuildAll(APackage.LastCompilerParams),'" Now="',ExtractCompilerParamsForBuildAll(CompilerParams),'"']);
// check state file
StateFilename:=APackage.GetStateFilename;
Result:=LoadPackageCompiledState(APackage,false,true);
if Result<>mrOk then exit; // read error and user aborted
if not Stats^.StateFileLoaded then begin
if not Stats.StateFileLoaded then begin
// package was not compiled via Lazarus nor via Makefile/fpmake
DebugLn('Hint: (lazarus) Missing state file of ',APackage.IDAsString,': ',StateFilename);
Note+='Missing state file "'+StateFilename+'".'+LineEnding;
@ -3658,13 +3601,23 @@ begin
exit(mrYes);
end;
if (o=podFallback) and (Stats.LazarusVersion<>LazarusVersionStr) then
begin
// package in fallback directory was compiled by another Lazarus -> rebuild
DebugLn('Hint: (lazarus) State file of ',APackage.IDAsString,' from Lazarus "',Stats.LazarusVersion,'" instead of "',LazarusVersionStr,'": ',StateFilename);
Note+='State file "'+StateFilename+'" from another Lazarus version "'+Stats.LazarusVersion+'".'+LineEnding;
NeedBuildAllFlag:=true;
ConfigChanged:=true;
exit(mrYes);
end;
// check if build all (-B) is needed
if (Stats^.CompilerFilename<>CompilerFilename)
or (ExtractFPCParamsForBuildAll(Stats^.Params)
if (Stats.CompilerFilename<>CompilerFilename)
or (ExtractFPCParamsForBuildAll(Stats.Params)
<>ExtractFPCParamsForBuildAll(CompilerParams))
or ((Stats^.CompilerFileDate>0)
or ((Stats.CompilerFileDate>0)
and FileExistsCached(CompilerFilename)
and (FileAgeCached(CompilerFilename)<>Stats^.CompilerFileDate))
and (FileAgeCached(CompilerFilename)<>Stats.CompilerFileDate))
then begin
NeedBuildAllFlag:=true;
ConfigChanged:=true;
@ -3681,7 +3634,7 @@ begin
// check compiler and params
LastParams:=APackage.GetLastCompilerParams(o);
if Stats^.ViaMakefile then begin
if Stats.ViaMakefile then begin
// the package was compiled via Makefile/fpmake
if ConsoleVerbosity>=1 then
debugln(['Hint: (lazarus) package ',APackage.IDAsString,' was compiled via "make" with parameters "',LastParams,'"']);
@ -3700,11 +3653,11 @@ begin
DebugLn('Hint: (lazarus) Compiler custom params changed for ',APackage.IDAsString);
DebugLn(' Old="',OldValue,'"');
DebugLn(' Now="',NewValue,'"');
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='Compiler custom parameters changed:'+LineEnding
+' Old="'+OldValue+'"'+LineEnding
+' Now="'+NewValue+'"'+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding;
+' State file="'+Stats.StateFileName+'"'+LineEnding;
ConfigChanged:=true;
exit(mrYes);
end;
@ -3715,11 +3668,11 @@ begin
DebugLn('Hint: (lazarus) Compiler unit paths changed for ',APackage.IDAsString);
DebugLn(' Old="',OldValue,'"');
DebugLn(' Now="',NewValue,'"');
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='Compiler unit paths changed:'+LineEnding
+' Old="'+OldValue+'"'+LineEnding
+' Now="'+NewValue+'"'+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding;
+' State file="'+Stats.StateFileName+'"'+LineEnding;
ConfigChanged:=true;
exit(mrYes);
end;
@ -3730,11 +3683,11 @@ begin
DebugLn('Hint: (lazarus) Compiler include paths changed for ',APackage.IDAsString);
DebugLn(' Old="',OldValue,'"');
DebugLn(' Now="',NewValue,'"');
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='Compiler include paths changed:'+LineEnding
+' Old="'+OldValue+'"'+LineEnding
+' Now="'+NewValue+'"'+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding;
+' State file="'+Stats.StateFileName+'"'+LineEnding;
ConfigChanged:=true;
exit(mrYes);
end;
@ -3750,44 +3703,44 @@ begin
DebugLn('Hint: (lazarus) Compiler params changed for ',APackage.IDAsString);
DebugLn(' Old="',dbgstr(ReducedLastParams),'"');
DebugLn(' Now="',dbgstr(ReducedParams),'"');
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='Compiler parameters changed:'+LineEnding
+' Old="'+dbgstr(ReducedLastParams)+'"'+LineEnding
+' Now="'+dbgstr(ReducedParams)+'"'+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding;
+' State file="'+Stats.StateFileName+'"'+LineEnding;
ConfigChanged:=true;
exit(mrYes);
end;
end;
if (not Stats^.ViaMakefile)
and (CompilerFilename<>Stats^.CompilerFilename) then begin
if (not Stats.ViaMakefile)
and (CompilerFilename<>Stats.CompilerFilename) then begin
DebugLn('Hint: (lazarus) Compiler filename changed for ',APackage.IDAsString);
DebugLn(' Old="',Stats^.CompilerFilename,'"');
DebugLn(' Old="',Stats.CompilerFilename,'"');
DebugLn(' Now="',CompilerFilename,'"');
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='Compiler filename changed:'+LineEnding
+' Old="'+Stats^.CompilerFilename+'"'+LineEnding
+' Old="'+Stats.CompilerFilename+'"'+LineEnding
+' Now="'+CompilerFilename+'"'+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding;
+' State file="'+Stats.StateFileName+'"'+LineEnding;
exit(mrYes);
end;
if not FileExistsCached(CompilerFilename) then begin
DebugLn('Hint: (lazarus) Compiler filename not found for ',APackage.IDAsString);
DebugLn(' File="',CompilerFilename,'"');
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='Compiler file "'+CompilerFilename+'" not found.'+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding;
+' State file="'+Stats.StateFileName+'"'+LineEnding;
exit(mrYes);
end;
if (not Stats^.ViaMakefile)
and (FileAgeCached(CompilerFilename)<>Stats^.CompilerFileDate) then begin
if (not Stats.ViaMakefile)
and (FileAgeCached(CompilerFilename)<>Stats.CompilerFileDate) then begin
DebugLn('Hint: (lazarus) Compiler file changed for ',APackage.IDAsString);
DebugLn(' File="',CompilerFilename,'"');
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='Compiler file "'+CompilerFilename+'" changed:'+LineEnding
+' Old='+FileAgeToStr(Stats^.CompilerFileDate)+LineEnding
+' Old='+FileAgeToStr(Stats.CompilerFileDate)+LineEnding
+' Now='+FileAgeToStr(FileAgeCached(CompilerFilename))+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding;
+' State file="'+Stats.StateFileName+'"'+LineEnding;
exit(mrYes);
end;
@ -3803,7 +3756,7 @@ begin
DebugLn('Hint: (lazarus) source disk file modified of ',APackage.IDAsString,': ',SrcFilename);
Note+='Source file "'+SrcFilename+'" modified:'+LineEnding
+' Source file age='+FileAgeToStr(FileAgeCached(SrcFilename))+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding
+' State file="'+Stats.StateFileName+'"'+LineEnding
+' State file age='+FileAgeToStr(StateFileAge)+LineEnding;
exit(mrYes);
end;
@ -3813,7 +3766,7 @@ begin
exit(mrYes);
end;
// check main source ppu file
if Stats^.MainPPUExists then begin
if Stats.MainPPUExists then begin
SrcPPUFile:=APackage.GetSrcPPUFilename;
if not FileExistsCached(SrcPPUFile) then begin
DebugLn('Hint: (lazarus) main ppu file missing of ',APackage.IDAsString,': ',SrcPPUFile);
@ -3830,11 +3783,11 @@ begin
// quick compile is possible
NeedBuildAllFlag:=false;
if not Stats^.Complete then begin
if not Stats.Complete then begin
DebugLn('Hint: (lazarus) Last compile was incomplete for ',APackage.IDAsString);
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='Last compile was incomplete.'+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding;
+' State file="'+Stats.StateFileName+'"'+LineEnding;
exit(mrYes);
end;
@ -3852,10 +3805,10 @@ begin
// check package files
if StateFileAge<FileAgeCached(APackage.Filename) then begin
DebugLn('Hint: (lazarus) State file older than lpk ',APackage.IDAsString);
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='State file older than lpk:'+LineEnding
+' State file age='+FileAgeToStr(StateFileAge)+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding
+' State file="'+Stats.StateFileName+'"'+LineEnding
+' LPK age='+FileAgeToStr(FileAgeCached(APackage.Filename))+LineEnding;
exit(mrYes);
end;
@ -3870,10 +3823,10 @@ begin
if FileExistsCached(AFilename)
and (StateFileAge<FileAgeCached(AFilename)) then begin
DebugLn('Hint: (lazarus) Source file has changed ',APackage.IDAsString,' ',CurFile.Filename);
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='State file older than source "'+AFilename+'"'+LineEnding
+' State file age='+FileAgeToStr(StateFileAge)+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding
+' State file="'+Stats.StateFileName+'"'+LineEnding
+' Src file age='+FileAgeToStr(FileAgeCached(AFilename))+LineEnding;
exit(mrYes);
end;
@ -3882,10 +3835,10 @@ begin
if FileExistsCached(LFMFilename)
and (StateFileAge<FileAgeCached(LFMFilename)) then begin
DebugLn('Hint: (lazarus) LFM has changed ',APackage.IDAsString,' ',LFMFilename);
DebugLn(' State file="',Stats^.StateFileName,'"');
DebugLn(' State file="',Stats.StateFileName,'"');
Note+='State file older than resource "'+LFMFilename+'"'+LineEnding
+' State file age='+FileAgeToStr(StateFileAge)+LineEnding
+' State file="'+Stats^.StateFileName+'"'+LineEnding
+' State file="'+Stats.StateFileName+'"'+LineEnding
+' Resource file age='+FileAgeToStr(FileAgeCached(LFMFilename))+LineEnding;
exit(mrYes);
end;
@ -3898,6 +3851,89 @@ begin
Result:=mrNo;
end;
function TLazPackageGraph.LoadPackageCompiledStateFile(APackage: TLazPackage;
o: TPkgOutputDir; StateFile: string; IgnoreErrors, ShowAbort: boolean
): TModalResult;
var
Stats: TPkgLastCompileStats;
StateFileAge, MakefileVersion: LongInt;
XMLConfig: TXMLConfig;
MakefileValue, Params: String;
begin
Stats:=APackage.LastCompile[o];
if not FileExistsCached(StateFile) then begin
//DebugLn('TLazPackageGraph.LoadPackageCompiledStateFile file not found: ',StateFile);
Stats.StateFileLoaded:=false;
Result:=mrOk;
exit;
end;
// read the state file
StateFileAge:=FileAgeCached(StateFile);
if (not Stats.StateFileLoaded)
or (Stats.StateFileDate<>StateFileAge)
or (Stats.StateFileName<>StateFile) then begin
Stats.StateFileLoaded:=false;
Stats.LazarusVersion:='';
Stats.Complete:=false;
Stats.CompilerFilename:='';
Stats.StateFileName:=StateFile;
Stats.StateFileDate:=StateFileAge;
try
XMLConfig:=TXMLConfig.Create(StateFile);
try
Stats.LazarusVersion:=XMLConfig.GetValue('Lazarus/Version','');
Stats.CompilerFilename:=XMLConfig.GetValue('Compiler/Value','');
Stats.CompilerFileDate:=XMLConfig.GetValue('Compiler/Date',0);
Stats.Complete:=XMLConfig.GetValue('Complete/Value',true);
Stats.MainPPUExists:=XMLConfig.GetValue('Complete/MainPPUExists',true);
MakefileValue:=XMLConfig.GetValue('Makefile/Value','');
Params:=XMLConfig.GetValue('Params/Value','');
if (MakefileValue='') then
Stats.ViaMakefile:=false
else begin
Stats.ViaMakefile:=true;
MakefileVersion:=StrToIntDef(MakefileValue,0);
if MakefileVersion<2 then begin
// old versions used %(
Stats.CompilerFilename:=StringReplace(Stats.CompilerFilename,'%(','$(',[rfReplaceAll]);
Params:=StringReplace(Params,'%(','$(',[rfReplaceAll]);
end;
ForcePathDelims(Stats.CompilerFilename);
ForcePathDelims(Params);
Params:=StringReplace(Params,'$(CPU_TARGET)','$(TargetCPU)',[rfReplaceAll]);
Params:=StringReplace(Params,'$(OS_TARGET)','$(TargetOS)',[rfReplaceAll]);
Params:=StringReplace(Params,'$(LCL_PLATFORM)','$(LCLWidgetType)',[rfReplaceAll]);
Params:=APackage.SubstitutePkgMacros(Params,false);
end;
Stats.Params:=Params;
finally
XMLConfig.Free;
end;
Stats.StateFileLoaded:=true;
except
on E: EXMLReadError do begin
// invalid XML
debugln(['Warning: (lazarus) package "',APackage.IDAsString,'": syntax error in ',StateFile,' => need clean build.']);
Stats.StateFileLoaded:=true;
end;
on E: Exception do begin
if IgnoreErrors then begin
Result:=mrOk;
end else begin
Result:=IDEMessageDialogAb(lisPkgMangErrorReadingFile,
Format(lisPkgMangUnableToReadStateFileOfPackageError,
[StateFile, LineEnding, APackage.IDAsString, LineEnding, E.Message]),
mtError,[mbCancel],ShowAbort);
end;
exit;
end;
end;
end;
Result:=mrOk;
end;
procedure TLazPackageGraph.InvalidateStateFile(APackage: TLazPackage);
begin
APackage.LastCompile[APackage.GetOutputDirType].StateFileLoaded:=false
@ -5237,13 +5273,12 @@ end;
function TLazPackageGraph.PreparePackageOutputDirectory(APackage: TLazPackage;
CleanUp: boolean): TModalResult;
var
OutputDir: String;
OutputDir, NewOutputDir: String;
StateFile: String;
PkgSrcDir: String;
i: Integer;
CurFile: TPkgFile;
OutputFileName: String;
NewOutputDir: String;
DeleteAllFilesInOutputDir: Boolean;
DirCache: TCTDirectoryCache;
CleanFiles: TStrings;
@ -5252,30 +5287,26 @@ begin
OutputDir:=APackage.GetOutputDirectory;
//debugln(['TLazPackageGraph.PreparePackageOutputDirectory OutputDir="',OutputDir,'"']);
// Note: The OutputDirectoryOverride is set prior in CheckIfPackageNeedsCompilation
DeleteAllFilesInOutputDir:=false;
if not OutputDirectoryIsWritable(APackage,OutputDir,false) then
begin
// the normal output directory is not writable
// => use the fallback directory
NewOutputDir:=GetFallbackOutputDir(APackage);
if (NewOutputDir=OutputDir) or (NewOutputDir='') then begin
debugln(['Error: (lazarus) [TLazPackageGraph.PreparePackageOutputDirectory] failed to create writable directory: ',OutputDir]);
exit(mrCancel);
end;
APackage.CompilerOptions.ParsedOpts.OutputDirectoryOverride:=NewOutputDir;
OutputDir:=APackage.GetOutputDirectory;
if not OutputDirectoryIsWritable(APackage,OutputDir,true) then
begin
debugln(['Error: (lazarus) [TLazPackageGraph.PreparePackageOutputDirectory] failed to create writable directory: ',OutputDir]);
Result:=mrCancel;
end;
DeleteAllFilesInOutputDir:=true;
// the output directory is not writable
debugln(['Error: (lazarus) [TLazPackageGraph.PreparePackageOutputDirectory] failed to create writable directory (',APackage.IDAsString,'): ',OutputDir]);
Result:=mrCancel;
end else if APackage.CompilerOptions.ParsedOpts.OutputDirectoryOverride<>''
then
// package is already using the fallback directory
DeleteAllFilesInOutputDir:=true
else if CleanUp then begin
// package is not using the fallback directory
// delete fallback if it exists
NewOutputDir:=GetFallbackOutputDir(APackage);
if DirPathExistsCached(NewOutputDir) then
DeleteDirectory(NewOutputDir,false);
// check if the output directory contains sources
DeleteAllFilesInOutputDir:=APackage.HasSeparateOutputDirectory;
end;