diff --git a/components/codetools/definetemplates.pas b/components/codetools/definetemplates.pas index e607af91fb..69b488fb53 100644 --- a/components/codetools/definetemplates.pas +++ b/components/codetools/definetemplates.pas @@ -2548,6 +2548,7 @@ begin +'designer'+ds+'jitform;' +'debugger;' +'packager;' + +'packager'+ds+'registration;' +'components'+ds+'synedit;' +'components'+ds+'codetools;' +'components'+ds+'custom;' @@ -2629,7 +2630,8 @@ begin DirTempl.AddChild(TDefineTemplate.Create('components path addition', Format(ctsAddsDirToSourcePath,['synedit']), ExternalMacroStart+'SrcPath', - '..'+ds+'components'+ds+'synedit;' + 'registration;' + +'..'+ds+'components'+ds+'synedit;' +'..'+ds+'components'+ds+'codetools;' +'..'+ds+'components'+ds+'custom;' +SrcPath diff --git a/ide/compiler.pp b/ide/compiler.pp index 49e92dc643..bea4aee0d2 100644 --- a/ide/compiler.pp +++ b/ide/compiler.pp @@ -133,7 +133,7 @@ begin if BuildAll then CmdLine := CmdLine+' -B'; CmdLine := CmdLine - + ' '+ AProject.CompilerOptions.MakeOptionsString(ProjectFilename) + + ' '+ AProject.CompilerOptions.MakeOptionsString(ProjectFilename,[]) + ' '+ PrepareCmdLineOption(ProjectFilename); if Assigned(FOnCmdLineCreate) then begin Abort:=false; @@ -190,6 +190,9 @@ end. { $Log$ + Revision 1.41 2003/04/17 18:56:10 mattias + implemented compilation of dependencies + Revision 1.40 2003/03/13 23:27:22 mattias localized codetools options diff --git a/ide/compileroptions.pp b/ide/compileroptions.pp index 3c6c2031d8..f9bbc8c66c 100644 --- a/ide/compileroptions.pp +++ b/ide/compileroptions.pp @@ -116,10 +116,16 @@ type { TBaseCompilerOptions } + + TCompilerCmdLineOption = ( + ccloNoLinkerOpts // exclude linker options + ); + TCompilerCmdLineOptions = set of TCompilerCmdLineOption; TBaseCompilerOptions = class private FBaseDirectory: string; + FDefaultMakeOptionsFlags: TCompilerCmdLineOptions; fInheritedOptions: array[TInheritedCompilerOption] of string; fInheritedOptParseStamps: integer; fInheritedOptGraphStamps: integer; @@ -211,6 +217,7 @@ type fAdditionalConfigFile: Boolean; fConfigFilePath: String; fCustomOptions: string; + procedure SetDefaultMakeOptionsFlags(const AValue: TCompilerCmdLineOptions); protected procedure SetBaseDirectory(const AValue: string); virtual; procedure SetCompilerPath(const AValue: String); virtual; @@ -239,8 +246,9 @@ type procedure Assign(CompOpts: TBaseCompilerOptions); virtual; function IsEqual(CompOpts: TBaseCompilerOptions): boolean; virtual; - function MakeOptionsString: String; - function MakeOptionsString(const MainSourceFileName: string): String; virtual; + function MakeOptionsString(Flags: TCompilerCmdLineOptions): String; + function MakeOptionsString(const MainSourceFileName: string; + Flags: TCompilerCmdLineOptions): String; virtual; function CustomOptionsAsString: string; function ConvertSearchPathToCmdLine(const switch, paths: String): String; function ConvertOptionsToCmdLine(const Delim, Switch, OptionStr: string): string; @@ -253,6 +261,7 @@ type function MergeLinkerOptions(const OldOptions, AddOptions: string): string; function MergeCustomOptions(const OldOptions, AddOptions: string): string; function GetDefaultMainSourceFileName: string; virtual; + function NeedsLinkerOpts: boolean; public { Properties } property Owner: TObject read fOwner write fOwner; @@ -261,6 +270,7 @@ type property ParsedOpts: TParsedCompilerOptions read FParsedOpts; property BaseDirectory: string read FBaseDirectory write SetBaseDirectory; property TargetFilename: String read fTargetFilename write fTargetFilename; + property DefaultMakeOptionsFlags: TCompilerCmdLineOptions read FDefaultMakeOptionsFlags write SetDefaultMakeOptionsFlags; property XMLFile: String read fXMLFile write fXMLFile; property XMLConfigFile: TXMLConfig read xmlconfig write xmlconfig; @@ -733,6 +743,13 @@ begin ParsedOpts.SetUnparsedValue(pcosCompilerPath,fCompilerPath); end; +procedure TBaseCompilerOptions.SetDefaultMakeOptionsFlags( + const AValue: TCompilerCmdLineOptions); +begin + if FDefaultMakeOptionsFlags=AValue then exit; + FDefaultMakeOptionsFlags:=AValue; +end; + procedure TBaseCompilerOptions.SetBaseDirectory(const AValue: string); begin if FBaseDirectory=AValue then exit; @@ -1160,20 +1177,26 @@ begin Result:=''; end; +function TBaseCompilerOptions.NeedsLinkerOpts: boolean; +begin + Result:=not (ccloNoLinkerOpts in fDefaultMakeOptionsFlags); +end; + {------------------------------------------------------------------------------ TBaseCompilerOptions MakeOptionsString ------------------------------------------------------------------------------} -function TBaseCompilerOptions.MakeOptionsString: String; +function TBaseCompilerOptions.MakeOptionsString(Flags: TCompilerCmdLineOptions + ): String; begin - Result:=MakeOptionsString(GetDefaultMainSourceFileName) + Result:=MakeOptionsString(GetDefaultMainSourceFileName,Flags); end; {------------------------------------------------------------------------------ function TBaseCompilerOptions.MakeOptionsString( - const MainSourceFilename: string): String; + const MainSourceFilename: string; Flags: TCompilerCmdLineOptions): String; ------------------------------------------------------------------------------} function TBaseCompilerOptions.MakeOptionsString( - const MainSourceFilename: string): String; + const MainSourceFilename: string; Flags: TCompilerCmdLineOptions): String; var switches, tempsw: String; InhLinkerOpts: String; @@ -1509,7 +1532,7 @@ Processor specific options: switches := switches + ' -gl'; { Use Heaptrc Unit } - if (UseHeaptrc) then + if (UseHeaptrc) and (not (ccloNoLinkerOpts in Flags)) then switches := switches + ' -gh'; { Generate code gprof } @@ -1517,7 +1540,7 @@ Processor specific options: switches := switches + ' -pg'; { Strip Symbols } - if (StripSymbols) then + if (StripSymbols) and (not (ccloNoLinkerOpts in Flags)) then switches := switches + ' -Xs'; { Link Style @@ -1525,23 +1548,26 @@ Processor specific options: -XS = Link with static libraries -XX = Link smart } - case (LinkStyle) of - 1: switches := switches + ' -XD'; - 2: switches := switches + ' -XS'; - 3: switches := switches + ' -XX'; - end; + if (not (ccloNoLinkerOpts in Flags)) then + case (LinkStyle) of + 1: switches := switches + ' -XD'; + 2: switches := switches + ' -XS'; + 3: switches := switches + ' -XX'; + end; // additional Linker options - if PassLinkerOptions then begin + if PassLinkerOptions and (not (ccloNoLinkerOpts in Flags)) then begin CurLinkerOptions:=ParsedOpts.GetParsedValue(pcosLinkerOptions); if (CurLinkerOptions<>'') then switches := switches + ' ' + ConvertOptionsToCmdLine(' ','-k', CurLinkerOptions); end; // inherited Linker options - InhLinkerOpts:=GetInheritedOption(icoLinkerOptions,true); - if InhLinkerOpts<>'' then - switches := switches + ' ' + ConvertOptionsToCmdLine(' ','-k', InhLinkerOpts); + if (not (ccloNoLinkerOpts in Flags)) then begin + InhLinkerOpts:=GetInheritedOption(icoLinkerOptions,true); + if InhLinkerOpts<>'' then + switches := switches + ' ' + ConvertOptionsToCmdLine(' ','-k', InhLinkerOpts); + end; { ---------------- Other Tab -------------------- } @@ -1617,14 +1643,18 @@ Processor specific options: switches := switches + ' ' + ConvertSearchPathToCmdLine('-Fi', InhIncludePath); // library path - CurLibraryPath:=ParsedOpts.GetParsedValue(pcosLibraryPath); - if (CurLibraryPath <> '') then - switches := switches + ' ' + ConvertSearchPathToCmdLine('-Fl', CurLibraryPath); + if (not (ccloNoLinkerOpts in Flags)) then begin + CurLibraryPath:=ParsedOpts.GetParsedValue(pcosLibraryPath); + if (CurLibraryPath <> '') then + switches := switches + ' ' + ConvertSearchPathToCmdLine('-Fl', CurLibraryPath); + end; // inherited library path - InhLibraryPath:=GetInheritedOption(icoLibraryPath,true); - if (InhLibraryPath <> '') then - switches := switches + ' ' + ConvertSearchPathToCmdLine('-Fl', InhLibraryPath); + if (not (ccloNoLinkerOpts in Flags)) then begin + InhLibraryPath:=GetInheritedOption(icoLibraryPath,true); + if (InhLibraryPath <> '') then + switches := switches + ' ' + ConvertSearchPathToCmdLine('-Fl', InhLibraryPath); + end; // object path CurObjectPath:=ParsedOpts.GetParsedValue(pcosObjectPath); @@ -1653,7 +1683,8 @@ Processor specific options: { Unit output directory } if UnitOutputDirectory<>'' then - CurOutputDir:=ParsedOpts.GetParsedValue(pcosOutputDir) + CurOutputDir:=CreateRelativePath(ParsedOpts.GetParsedValue(pcosOutputDir), + BaseDirectory) else CurOutputDir:=''; if CurOutputDir<>'' then @@ -2203,20 +2234,20 @@ begin ModalResult:=mrCancel; end; -{------------------------------------------------------------------------------} -{ TfrmCompilerOptions ButtonApplyClicked } -{------------------------------------------------------------------------------} +{------------------------------------------------------------------------------ + TfrmCompilerOptions ButtonApplyClicked +------------------------------------------------------------------------------} procedure TfrmCompilerOptions.ButtonApplyClicked(Sender: TObject); begin // Apply any changes PutCompilerOptions; end; -{------------------------------------------------------------------------------} -{ TfrmCompilerOptions ButtonTestClicked } -{ This function is for testing the MakeOptionsString function only. Remove } -{ this function and its button when the function is working correctly. } -{------------------------------------------------------------------------------} +{------------------------------------------------------------------------------ + TfrmCompilerOptions ButtonTestClicked + This function is for testing the MakeOptionsString function only. Remove + this function and its button when the function is working correctly. +------------------------------------------------------------------------------} procedure TfrmCompilerOptions.ButtonTestClicked(Sender: TObject); var teststr: String; @@ -2226,7 +2257,7 @@ begin Assert(False, 'Trace:Test MakeOptionsString function'); PutCompilerOptions; - teststr := CompilerOpts.MakeOptionsString; + teststr := CompilerOpts.MakeOptionsString(CompilerOpts.DefaultMakeOptionsFlags); WriteLn('CompilerOpts.MakeOptionsString: ' + teststr); i:=1; LineLen:=0; @@ -2281,8 +2312,12 @@ end; TfrmCompilerOptions GetCompilerOptions ------------------------------------------------------------------------------} procedure TfrmCompilerOptions.GetCompilerOptions; -var i: integer; +var + i: integer; + EnabledLinkerOpts: Boolean; begin + EnabledLinkerOpts:=CompilerOpts.NeedsLinkerOpts; + { Get the compiler options and apply them to the dialog } case CompilerOpts.Style of 1: radStyleIntel.Checked := true; @@ -2310,6 +2345,7 @@ begin chkChecksOverflow.Checked := CompilerOpts.OverflowChecks; chkChecksStack.Checked := CompilerOpts.StackChecks; + grpHeapSize.Enabled:=EnabledLinkerOpts; edtHeapSize.Text := IntToStr(CompilerOpts.HeapSize); case CompilerOpts.Generate of @@ -2336,18 +2372,22 @@ begin chkDebugDBX.Checked := CompilerOpts.GenerateDebugDBX; chkUseLineInfoUnit.Checked := CompilerOpts.UseLineInfoUnit; chkUseHeaptrc.Checked := CompilerOpts.UseHeaptrc; + chkUseHeaptrc.Enabled:=EnabledLinkerOpts; chkGenGProfCode.Checked := CompilerOpts.GenGProfCode; chkSymbolsStrip.Checked := CompilerOpts.StripSymbols; + chkSymbolsStrip.Enabled:=EnabledLinkerOpts; case CompilerOpts.LinkStyle of 1: radLibsLinkDynamic.Checked := true; 2: radLibsLinkStatic.Checked := true; 3: radLibsLinkSmart.Checked := true; end; + grpLinkLibraries.Enabled:=EnabledLinkerOpts; chkOptionsLinkOpt.Checked := CompilerOpts.PassLinkerOptions; edtOptionsLinkOpt.Text := CompilerOpts.LinkerOptions; - + grpOptions.Enabled:=EnabledLinkerOpts; + chkErrors.Checked := CompilerOpts.ShowErrors; chkWarnings.Checked := CompilerOpts.ShowWarn; chkNotes.Checked := CompilerOpts.ShowNotes; @@ -2379,6 +2419,7 @@ begin edtOtherUnits.Text := CompilerOpts.OtherUnitFiles; edtIncludeFiles.Text := CompilerOpts.IncludeFiles; edtLibraries.Text := CompilerOpts.Libraries; + grpLibraries.Enabled:=EnabledLinkerOpts; edtCompiler.Text := CompilerOpts.CompilerPath; edtUnitOutputDir.Text := CompilerOpts.UnitOutputDirectory; @@ -2410,13 +2451,13 @@ begin OldCompOpts.Assign(CompilerOpts); if (radStyleIntel.Checked) then - CompilerOpts.Style := 1 + CompilerOpts.Style := 1 else if (radStyleATT.Checked) then - CompilerOpts.Style := 2 + CompilerOpts.Style := 2 else if (radStyleAsIs.Checked) then - CompilerOpts.Style := 3 + CompilerOpts.Style := 3 else - CompilerOpts.Style := 1; + CompilerOpts.Style := 1; CompilerOpts.D2Extensions := chkSymD2Ext.Checked; CompilerOpts.CStyleOperators := chkSymCOper.Checked; @@ -2446,32 +2487,32 @@ begin CompilerOpts.HeapSize := hs; if (radGenFaster.Checked) then - CompilerOpts.Generate := 1 + CompilerOpts.Generate := 1 else if (radGenSmaller.Checked) then - CompilerOpts.Generate := 2 + CompilerOpts.Generate := 2 else - CompilerOpts.Generate := 1; + CompilerOpts.Generate := 1; if (radTarget386.Checked) then - CompilerOpts.TargetProcessor := 1 + CompilerOpts.TargetProcessor := 1 else if (radTargetPent.Checked) then - CompilerOpts.TargetProcessor := 2 + CompilerOpts.TargetProcessor := 2 else if (radTargetPentPro.Checked) then - CompilerOpts.TargetProcessor := 3 + CompilerOpts.TargetProcessor := 3 else - CompilerOpts.TargetProcessor := 1; + CompilerOpts.TargetProcessor := 1; CompilerOpts.VariablesInRegisters := chkOptVarsInReg.Checked; CompilerOpts.UncertainOptimizations := chkOptUncertain.Checked; if (radOptLevel1.Checked) then - CompilerOpts.OptimizationLevel := 1 + CompilerOpts.OptimizationLevel := 1 else if (radOptLevel2.Checked) then - CompilerOpts.OptimizationLevel := 2 + CompilerOpts.OptimizationLevel := 2 else if (radOptLevel3.Checked) then - CompilerOpts.OptimizationLevel := 3 + CompilerOpts.OptimizationLevel := 3 else - CompilerOpts.OptimizationLevel := 1; + CompilerOpts.OptimizationLevel := 1; CompilerOpts.GenerateDebugInfo := chkDebugGDB.Checked; CompilerOpts.GenerateDebugDBX := chkDebugDBX.Checked; diff --git a/packager/basepkgmanager.pas b/packager/basepkgmanager.pas index bee83545dc..670208c7a9 100644 --- a/packager/basepkgmanager.pas +++ b/packager/basepkgmanager.pas @@ -59,7 +59,10 @@ type TPkgOpenFlags = set of TPkgOpenFlag; TPkgCompileFlag = ( - pcfCompileAll + pcfCleanCompile, // append -B to the compiler options + pcfDoNotCompileDependencies, + pcfOnlyIfNeeded, + pcfAutomatic ); TPkgCompileFlags = set of TPkgCompileFlag; @@ -92,9 +95,69 @@ type var PkgBoss: TBasePkgManager; + +const + PkgSaveFlagNames: array[TPkgSaveFlag] of string = ( + 'psfSaveAs', + 'psfAskBeforeSaving' + ); + + PkgOpenFlagNames: array[TPkgOpenFlag] of string = ( + 'pofAddToRecent' + ); + + PkgCompileFlagNames: array[TPkgCompileFlag] of string = ( + 'pcfCleanCompile', + 'pcfDoNotCompileDependencies', + 'pcfOnlyIfNeeded', + 'pcfAutomatic' + ); + +function PkgSaveFlagsToString(Flags: TPkgSaveFlags): string; +function PkgOpenFlagsToString(Flags: TPkgOpenFlags): string; +function PkgCompileFlagsToString(Flags: TPkgCompileFlags): string; implementation +function PkgSaveFlagsToString(Flags: TPkgSaveFlags): string; +var + f: TPkgSaveFlag; +begin + Result:=''; + for f:=Low(TPkgSaveFlag) to High(TPkgSaveFlag) do begin + if not (f in Flags) then continue; + if Result<>'' then Result:=Result+','; + Result:=Result+PkgSaveFlagNames[f]; + end; + Result:='['+Result+']'; +end; + +function PkgOpenFlagsToString(Flags: TPkgOpenFlags): string; +var + f: TPkgOpenFlag; +begin + Result:=''; + for f:=Low(TPkgOpenFlag) to High(TPkgOpenFlag) do begin + if not (f in Flags) then continue; + if Result<>'' then Result:=Result+','; + Result:=Result+PkgOpenFlagNames[f]; + end; + Result:='['+Result+']'; +end; + +function PkgCompileFlagsToString(Flags: TPkgCompileFlags): string; +var + f: TPkgCompileFlag; +begin + Result:=''; + for f:=Low(TPkgCompileFlag) to High(TPkgCompileFlag) do begin + if not (f in Flags) then continue; + if Result<>'' then Result:=Result+','; + Result:=Result+PkgCompileFlagNames[f]; + end; + Result:='['+Result+']'; +end; + initialization PkgBoss:=nil; diff --git a/packager/packagedefs.pas b/packager/packagedefs.pas index 173e4284a3..6c639e9e4f 100644 --- a/packager/packagedefs.pas +++ b/packager/packagedefs.pas @@ -337,8 +337,9 @@ type // package requires this package) lpfVisited, // Used by the PackageGraph to avoid double checking lpfDestroying, // set during destruction - lpfSkipSaving, - lpfCircle + lpfSkipSaving, // Used by PkgBoss to skip saving + lpfCircle, // Used by the PackageGraph to mark circles + lpfStateFileLoaded // state file data valid ); TLazPackageFlags = set of TLazPackageFlag; @@ -372,6 +373,8 @@ type FFlags: TLazPackageFlags; FIconFile: string; FInstalled: TPackageInstallType; + FLastCompilerFilename: string; + FLastCompilerParams: string; FMacros: TTransferMacroList; FModifiedLock: integer; FPackageEditor: TBasePackageEditor; @@ -379,6 +382,7 @@ type FReadOnly: boolean; FRemovedFiles: TList; // TList of TPkgFile FRegistered: boolean; + FStateFileDate: longint; FUsageOptions: TPkgAdditionalCompilerOptions; function GetAutoIncrementVersionOnBuild: boolean; function GetAutoUpdate: boolean; @@ -429,6 +433,8 @@ type procedure GetInheritedCompilerOptions(var OptionsList: TList); function GetCompileSourceFilename: string; function GetOutputDirectory: string; + function GetStateFilename: string; + function GetCompilerFilename: string; // files function FindPkgFile(const AFilename: string; ResolveLinks, IgnoreRemoved: boolean): TPkgFile; @@ -491,13 +497,18 @@ type property Flags: TLazPackageFlags read FFlags write SetFlags; property IconFile: string read FIconFile write SetIconFile; property Installed: TPackageInstallType read FInstalled write SetInstalled; - property Registered: boolean read FRegistered write SetRegistered; + property LastCompilerFilename: string read FLastCompilerFilename + write FLastCompilerFilename; + property LastCompilerParams: string read FLastCompilerParams + write FLastCompilerParams; + property Macros: TTransferMacroList read FMacros; property Modified: boolean read GetModified write SetModified; property PackageType: TLazPackageType read FPackageType write SetPackageType; property ReadOnly: boolean read FReadOnly write SetReadOnly; + property Registered: boolean read FRegistered write SetRegistered; property RemovedFilesCount: integer read GetRemovedCount; property RemovedFiles[Index: integer]: TPkgFile read GetRemovedFiles; - property Macros: TTransferMacroList read FMacros; + property StateFileDate: longint read FStateFileDate write FStateFileDate; property UsageOptions: TPkgAdditionalCompilerOptions read FUsageOptions; end; @@ -529,7 +540,8 @@ const 'RunTime', 'DesignTime', 'RunAndDesignTime'); LazPackageFlagNames: array[TLazPackageFlag] of string = ( 'lpfAutoIncrementVersionOnBuild', 'lpfModified', 'lpfAutoUpdate', - 'lpfNeeded', 'lpfVisited', 'lpfDestroying', 'lpfSkipSaving', 'lpfCircle'); + 'lpfNeeded', 'lpfVisited', 'lpfDestroying', 'lpfSkipSaving', 'lpfCircle', + 'lpfStateFileLoaded'); var // All TPkgDependency are added to this AVL tree (sorted for names, not version!) @@ -1499,6 +1511,7 @@ begin FCompilerOptions:=TPkgCompilerOptions.Create(Self); FCompilerOptions.ParsedOpts.OnLocalSubstitute:=@SubstitutePkgMacro; FCompilerOptions.ParsedOpts.InvalidateGraphOnChange:=true; + FCompilerOptions.DefaultMakeOptionsFlags:=[ccloNoLinkerOpts]; FUsageOptions:=TPkgAdditionalCompilerOptions.Create(Self); FUsageOptions.ParsedOpts.OnLocalSubstitute:=@SubstitutePkgMacro; Clear; @@ -2072,6 +2085,17 @@ begin Result:=''; end; +function TLazPackage.GetStateFilename: string; +begin + Result:=GetOutputDirectory + +ChangeFileExt(GetCompileSourceFilename,'.compiled'); +end; + +function TLazPackage.GetCompilerFilename: string; +begin + Result:=CompilerOptions.ParsedOpts.GetParsedValue(pcosCompilerPath); +end; + { TPkgComponent } procedure TPkgComponent.SetPkgFile(const AValue: TPkgFile); diff --git a/packager/packagesystem.pas b/packager/packagesystem.pas index 2a527b1eed..6d7128f5d2 100644 --- a/packager/packagesystem.pas +++ b/packager/packagesystem.pas @@ -154,6 +154,7 @@ type procedure MarkNeededPackages; function FindBrokenDependencyPath(APackage: TLazPackage): TList; function FindCircleDependencyPath(APackage: TLazPackage): TList; + function GetAutoCompilationOrder(APackage: TLazPackage): TList; public // packages handling function CreateNewPackage(const Prefix: string): TLazPackage; @@ -1036,6 +1037,40 @@ begin FindCircle(APackage,Result); end; +function TLazPackageGraph.GetAutoCompilationOrder(APackage: TLazPackage + ): TList; + + procedure GetTopologicalOrder(const FirstDependency: TPkgDependency); + var + Dependency: TPkgDependency; + RequiredPackage: TLazPackage; + begin + Dependency:=FirstDependency; + while Dependency<>nil do begin + if Dependency.LoadPackageResult=lprSuccess then begin + RequiredPackage:=Dependency.RequiredPackage; + if not (lpfVisited in RequiredPackage.Flags) then begin + RequiredPackage.Flags:=RequiredPackage.Flags+[lpfVisited]; + if RequiredPackage.AutoUpdate then begin + // add first all needed packages + GetTopologicalOrder(RequiredPackage.FirstRequiredDependency); + // then add this package + if Result=nil then Result:=TList.Create; + Result.Add(RequiredPackage); + end; + end; + end; + Dependency:=Dependency.NextRequiresDependency; + end; + end; + +begin + Result:=nil; + MarkAllPackagesAsNotVisited; + APackage.Flags:=APackage.Flags+[lpfVisited]; + GetTopologicalOrder(APackage.FirstRequiredDependency); +end; + procedure TLazPackageGraph.MarkAllPackagesAsNotVisited; var i: Integer; diff --git a/packager/pkgmanager.pas b/packager/pkgmanager.pas index 05bb50947b..1c0a746b69 100644 --- a/packager/pkgmanager.pas +++ b/packager/pkgmanager.pas @@ -84,6 +84,12 @@ type procedure OnApplicationIdle(Sender: TObject); private function DoShowSavePackageAsDialog(APackage: TLazPackage): TModalResult; + function CompileRequiredPackages(APackage: TLazPackage): TModalResult; + function CheckPackageGraphForCompilation(APackage: TLazPackage): TModalResult; + function DoPreparePackageOutputDirectory(APackage: TLazPackage): TModalResult; + function DoSavePackageCompiledState(APackage: TLazPackage; + const CompilerFilename, CompilerParams: string): TModalResult; + function CheckIfPackageNeedsCompilation(APackage: TLazPackage): boolean; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; @@ -96,7 +102,7 @@ type procedure LoadInstalledPackages; override; function AddPackageToGraph(APackage: TLazPackage): TModalResult; - + function ShowConfigureCustomComponents: TModalResult; override; function DoNewPackage: TModalResult; override; function DoShowOpenInstalledPckDlg: TModalResult; override; @@ -159,7 +165,7 @@ var Flags: TPkgCompileFlags; begin Flags:=[]; - if CompileAll then Include(Flags,pcfCompileAll); + if CompileAll then Include(Flags,pcfCleanCompile); Result:=DoCompilePackage(APackage,Flags); end; @@ -525,6 +531,197 @@ begin Result:=mrOk; end; +function TPkgManager.CompileRequiredPackages(APackage: TLazPackage + ): TModalResult; +var + AutoPackages: TList; + i: Integer; +begin + AutoPackages:=PackageGraph.GetAutoCompilationOrder(APackage); + if AutoPackages<>nil then begin + try + i:=0; + while imrOk then exit; + inc(i); + end; + finally + AutoPackages.Free; + end; + end; + Result:=mrOk; +end; + +function TPkgManager.CheckPackageGraphForCompilation(APackage: TLazPackage + ): TModalResult; +var + PathList: TList; +begin + // check for broken dependencies + PathList:=PackageGraph.FindBrokenDependencyPath(APackage); + if PathList<>nil then begin + DoShowPackageGraphPathList(PathList); + Result:=MessageDlg('Broken dependency', + 'A required packages was not found. See package graph.', + mtError,[mbCancel,mbAbort],0); + exit; + end; + + // check for circle dependencies + PathList:=PackageGraph.FindCircleDependencyPath(APackage); + if PathList<>nil then begin + DoShowPackageGraphPathList(PathList); + Result:=MessageDlg('Circle in package dependencies', + 'There is a circle in the required packages. See package graph.', + mtError,[mbCancel,mbAbort],0); + exit; + end; + + Result:=mrOk; +end; + +function TPkgManager.DoSavePackageCompiledState(APackage: TLazPackage; + const CompilerFilename, CompilerParams: string): TModalResult; +var + XMLConfig: TXMLConfig; + StateFile: String; +begin + StateFile:=APackage.GetStateFilename; + try + ClearFile(StateFile,true); + XMLConfig:=TXMLConfig.Create(StateFile); + try + XMLConfig.SetValue('Compiler/Value',CompilerFilename); + XMLConfig.SetValue('Params/Value',CompilerParams); + XMLConfig.Flush; + finally + XMLConfig.Free; + end; + APackage.LastCompilerFilename:=CompilerFilename; + APackage.LastCompilerParams:=CompilerParams; + APackage.StateFileDate:=FileAge(StateFile); + APackage.Flags:=APackage.Flags+[lpfStateFileLoaded]; + except + on E: Exception do begin + Result:=MessageDlg('Error writing file', + 'Unable to write state file "'+StateFile+'"'#13 + +'of package '+APackage.IDAsString+'.', + mtError,[mbAbort,mbCancel],0); + exit; + end; + end; + + Result:=MainIDE.DoDeleteAmbigiousFiles(StateFile); + if Result<>mrOk then exit; +end; + +function TPkgManager.DoPreparePackageOutputDirectory(APackage: TLazPackage + ): TModalResult; +var + OutputDir: String; + StateFile: String; +begin + OutputDir:=APackage.GetOutputDirectory; + StateFile:=APackage.GetStateFilename; + + // create the output directory + if not ForceDirectory(OutputDir) then begin + Result:=MessageDlg('Unable to create directory', + 'Unable to create output directory "'+OutputDir+'"'#13 + +'for package '+APackage.IDAsString+'.', + mtError,[mbCancel,mbAbort],0); + exit; + end; + + // delete old Compile State file + if FileExists(StateFile) and not DeleteFile(StateFile) then begin + Result:=MessageDlg('Unable to delete file', + 'Unable to delete old state file "'+StateFile+'"'#13 + +'for package '+APackage.IDAsString+'.', + mtError,[mbCancel,mbAbort],0); + exit; + end; + APackage.Flags:=APackage.Flags-[lpfStateFileLoaded]; + + Result:=mrOk; +end; + +function TPkgManager.CheckIfPackageNeedsCompilation(APackage: TLazPackage + ): boolean; +var + OutputDir: String; + SrcFilename: String; + CompilerFilename: String; + CompilerParams: String; + StateFilename: String; + StateFileAge: Integer; + i: Integer; + XMLConfig: TXMLConfig; + CurFile: TPkgFile; +begin + Result:=true; + +writeln('TPkgManager.CheckIfPackageNeedsCompilation A ',APackage.IDAsString); + // check state file + StateFilename:=APackage.GetStateFilename; + if not FileExists(StateFilename) then exit; + + StateFileAge:=FileAge(StateFilename); + + // read the state file + if (not (lpfStateFileLoaded in APackage.Flags)) + or (APackage.StateFileDate<>StateFileAge) then begin + try + XMLConfig:=TXMLConfig.Create(StateFilename); + try + APackage.LastCompilerFilename:= + XMLConfig.GetValue('Compiler/Value',''); + APackage.LastCompilerParams:= + XMLConfig.GetValue('Params/Value',''); + finally + XMLConfig.Free; + end; + APackage.StateFileDate:=StateFileAge; + except + on E: Exception do begin + MessageDlg('Error reading file', + 'Unable to read state file "'+StateFilename+'"'#13 + +'of package '+APackage.IDAsString+'.', + mtError,[mbCancel],0); + exit; + end; + end; + APackage.Flags:=APackage.Flags+[lpfStateFileLoaded]; + end; + + OutputDir:=APackage.GetOutputDirectory; + SrcFilename:=OutputDir+APackage.GetCompileSourceFilename; + CompilerFilename:=APackage.GetCompilerFilename; + CompilerParams:=APackage.CompilerOptions.MakeOptionsString( + APackage.CompilerOptions.DefaultMakeOptionsFlags) + +' '+CreateRelativePath(SrcFilename,APackage.Directory); + + // check compiler command + if CompilerFilename<>APackage.LastCompilerFilename then exit; + if CompilerParams<>APackage.LastCompilerParams then exit; + + // check main source file + if StateFileAgemrOk then exit; end; - // check for circle dependencies - PathList:=PackageGraph.FindCircleDependencyPath(APackage); - if PathList<>nil then begin - DoShowPackageGraphPathList(PathList); - Result:=MessageDlg('Circle in package dependencies', - 'There is a circle in the required packages. See package graph.', - mtError,[mbCancel,mbAbort],0); - exit; + // save all open files + if not (pcfAutomatic in Flags) then begin + Result:=MainIDE.DoSaveForBuild; + if Result<>mrOk then exit; end; - - // create the output directory - OutputDir:=APackage.GetOutputDirectory; - if not ForceDirectory(OutputDir) then begin - Result:=MessageDlg('Unable to create directory', - 'Unable to create output directory "'+OutputDir+'"'#13 - +'for package '+APackage.IDAsString+'.', - mtError,[mbCancel,mbAbort],0); + + // automatically compile required packages + if not (pcfDoNotCompileDependencies in Flags) then begin + Result:=CompileRequiredPackages(APackage); + if Result<>mrOk then exit; + end; + + // check if compilation is neccessary + if ([pcfOnlyIfNeeded,pcfCleanCompile]*Flags<>[]) + and (not CheckIfPackageNeedsCompilation(APackage)) then begin + Result:=mrOk; exit; end; - // save everything - Result:=MainIDE.DoSaveForBuild; + Result:=DoPreparePackageOutputDirectory(APackage); if Result<>mrOk then exit; - - // update dependencies - - // ToDo - - + // create package main source file Result:=DoSavePackageMainSource(APackage,Flags); if Result<>mrOk then exit; - SrcFilename:=CreateRelativePath(OutputDir+APackage.GetCompileSourceFilename, - APackage.Directory); // create external tool to run the compiler + OutputDir:=APackage.GetOutputDirectory; + SrcFilename:=CreateRelativePath(OutputDir+APackage.GetCompileSourceFilename, + APackage.Directory); + CompilerFilename:=APackage.GetCompilerFilename; + CompilerParams:=APackage.CompilerOptions.MakeOptionsString( + APackage.CompilerOptions.DefaultMakeOptionsFlags) + +' '+SrcFilename; + PkgCompileTool:=TExternalToolOptions.Create; - PkgCompileTool.Title:='Compiling package '+APackage.IDAsString; - PkgCompileTool.Filename:=APackage.CompilerOptions.CompilerPath; - PkgCompileTool.ScanOutputForFPCMessages:=true; - PkgCompileTool.ScanOutputForMakeMessages:=true; - PkgCompileTool.WorkingDirectory:=APackage.Directory; - PkgCompileTool.CmdLineParams:=APackage.CompilerOptions.MakeOptionsString - +' '+SrcFilename; + try + PkgCompileTool.Title:='Compiling package '+APackage.IDAsString; + PkgCompileTool.Filename:=CompilerFilename; + PkgCompileTool.ScanOutputForFPCMessages:=true; + PkgCompileTool.ScanOutputForMakeMessages:=true; + PkgCompileTool.WorkingDirectory:=APackage.Directory; + PkgCompileTool.CmdLineParams:=CompilerParams; - // clear old errors - SourceNotebook.ClearErrorLines; + // clear old errors + SourceNotebook.ClearErrorLines; - // compile package - Result:=EnvironmentOptions.ExternalTools.Run(PkgCompileTool,MainIDE.MacroList); + // compile package + Result:=EnvironmentOptions.ExternalTools.Run(PkgCompileTool,MainIDE.MacroList); + if Result=mrOk then begin + // compilation succeded -> write state file + Result:=DoSavePackageCompiledState(APackage, + CompilerFilename,CompilerParams); + if Result<>mrOk then exit; + end; + finally + // clean up + PkgCompileTool.Free; - // clean up - PkgCompileTool.Free; - MainIDE.DoCheckFilesOnDisk; + if not (pcfAutomatic in Flags) then begin + // check for changed files on disk + MainIDE.DoCheckFilesOnDisk; + end; + end; Result:=mrOk; end;