diff --git a/packager/packagedefs.pas b/packager/packagedefs.pas index f14757b0a6..7fa0e78113 100644 --- a/packager/packagedefs.pas +++ b/packager/packagedefs.pas @@ -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); diff --git a/packager/packagesystem.pas b/packager/packagesystem.pas index 4922cec6be..e2c6c0808c 100644 --- a/packager/packagesystem.pas +++ b/packager/packagesystem.pas @@ -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 StateFileAgeStateFileAge) 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 StateFileAgeStateFileAge) 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 StateFileAgeStateFileAge) + 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;