lazarus/packager/packagedefs.pas
2012-03-30 15:57:23 +00:00

4660 lines
146 KiB
ObjectPascal

{
/***************************************************************************
packagedefs.pas
---------------
***************************************************************************/
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code 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. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
***************************************************************************
Author: Mattias Gaertner
What is a package:
A lazarus package is a collection of units and components, containing
information how they can be compiled and how they can be used by projects or
other packages or the IDE. In contrary to Delphi, packages are not limited
to libraries and they can be OS independent.
(Delphi: a package is a specially compiled library used by applications,
the IDE or both. Delphi packages require compiler magic, which fpc is not
capable of at the moment and of course this magic is not OS independent.)
}
unit PackageDefs;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, contnrs, typinfo, LCLProc, LCLType, LResources, Graphics,
Forms, FileProcs, FileUtil, AVL_Tree, LazConfigStorage, Laz2_XMLCfg,
BasicCodeTools, CodeToolsCfgScript, DefineTemplates, CodeToolManager,
CodeCache, CodeToolsStructs,
PropEdits, LazIDEIntf, MacroIntf, PackageIntf, IDEOptionsIntf,
EditDefineTree, CompilerOptions, CompOptsModes, IDEOptionDefs,
LazarusIDEStrConsts, IDEProcs, ComponentReg,
TransferMacros, FileReferenceList, PublishModule;
type
TLazPackage = class;
TPkgFile = class;
TBasePackageEditor = class;
TPkgDependency = class;
TIteratePackagesEvent =
procedure(APackage: TLazPackageID) of object;
TGetAllRequiredPackagesEvent =
procedure(FirstDependency: TPkgDependency; out List: TFPList) of object;
TGetDependencyOwnerDescription =
procedure(Dependency: TPkgDependency; out Description: string) of object;
TGetDependencyOwnerDirectory =
procedure(Dependency: TPkgDependency; out Directory: string) of object;
TGetWritablePkgOutputDirectory =
procedure(APackage: TLazPackage; var AnOutDirectory: string) of object;
{ TPkgComponent }
TPkgComponent = class(TRegisteredComponent)
private
FPkgFile: TPkgFile;
FIcon: TCustomBitmap;
FIconLoaded: boolean;
procedure SetPkgFile(const AValue: TPkgFile);
public
constructor Create(ThePkgFile: TPkgFile; TheComponentClass: TComponentClass;
const ThePageName: string);
destructor Destroy; override;
function GetUnitName: string; override;
function GetPriority: TComponentPriority; override;
procedure ConsistencyCheck; override;
function Icon: TCustomBitmap;
function GetIconCopy: TCustomBitmap;
function HasIcon: boolean;
function CanBeCreatedInDesigner: boolean; override;
public
property PkgFile: TPkgFile read FPkgFile write SetPkgFile;
end;
{ TPkgFile }
TPkgFileType = (
pftUnit, // file is pascal unit
pftVirtualUnit,// file is virtual pascal unit
pftMainUnit, // file is the auto created main pascal unit
pftLFM, // lazarus form text file
pftLRS, // lazarus resource file
pftInclude, // include file
pftIssues, // file is issues xml file
pftText, // file is text (e.g. copyright or install notes)
pftBinary // file is something else
);
TPkgFileTypes = set of TPkgFileType;
const
PkgFileUnitTypes = [pftUnit,pftVirtualUnit,pftMainUnit];
PkgFileRealUnitTypes = [pftUnit,pftMainUnit];
type
TPFComponentBaseClass = (
pfcbcNone, // unknown
pfcbcForm, // is TForm
pfcbcFrame, // is TFrame
pfcbcDataModule // is TDataModule
);
const
PFComponentBaseClassNames: array[TPFComponentBaseClass] of string = (
'None',
'Form',
'Frame',
'DataModule'
);
function StrToComponentBaseClass(const s: string): TPFComponentBaseClass;
function GetComponentBaseClass(aClass: TClass): TPFComponentBaseClass;
type
TPkgFileFlag = (
pffHasRegisterProc, // file is unit and has a 'register' procedure
pffAddToPkgUsesSection,// unit is added to uses section
pffReportedAsRemoved // file has been reported as removed
);
TPkgFileFlags = set of TPkgFileFlag;
{ TPkgFile }
TPkgFile = class(TLazPackageFile)
private
FAutoReferenceSourceDir: boolean;
FComponentPriority: TComponentPriority;
FComponents: TFPList; // list of TPkgComponent
FDirectory: string;
FFileType: TPkgFileType;
FFlags: TPkgFileFlags;
fFullFilename: string;
fFullFilenameStamp: integer;
FPackage: TLazPackage;
FResourceBaseClass: TPFComponentBaseClass;
FSourceDirectoryReferenced: boolean;
FSourceDirNeedReference: boolean;
FUnitName: string;
function GetAddToUsesPkgSection: boolean;
function GetComponents(Index: integer): TPkgComponent;
function GetHasRegisterProc: boolean;
procedure SetAddToUsesPkgSection(const AValue: boolean);
procedure SetAutoReferenceSourceDir(const AValue: boolean);
procedure SetFileType(const AValue: TPkgFileType);
procedure SetFlags(const AValue: TPkgFileFlags);
procedure SetHasRegisterProc(const AValue: boolean);
procedure UpdateUnitName;
function GetComponentList: TFPList;
protected
function GetIDEPackage: TIDEPackage; override;
procedure SetFilename(const AValue: string); override;
procedure SetRemoved(const AValue: boolean); override;
procedure SetDisableI18NForLFM(AValue: boolean); override;
public
constructor Create(ThePackage: TLazPackage);
destructor Destroy; override;
procedure Clear;
procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string;
FileVersion: integer; AdjustPathDelims: boolean);
procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string;
UsePathDelim: TPathDelimSwitch);
procedure ConsistencyCheck;
function ComponentCount: integer;
procedure AddPkgComponent(APkgComponent: TPkgComponent);
procedure RemovePkgComponent(APkgComponent: TPkgComponent);
function HasRegisteredPlugins: boolean;
function MakeSense: boolean;
procedure UpdateSourceDirectoryReference;
function GetFullFilename: string; override;
function GetShortFilename(UseUp: boolean): string; override;
function GetResolvedFilename: string; // GetFullFilename + ReadAllLinks
public
property AddToUsesPkgSection: boolean
read GetAddToUsesPkgSection write SetAddToUsesPkgSection;
property AutoReferenceSourceDir: boolean read FAutoReferenceSourceDir
write SetAutoReferenceSourceDir;
property ResourceBaseClass: TPFComponentBaseClass read FResourceBaseClass
write FResourceBaseClass;
property ComponentPriority: TComponentPriority read FComponentPriority
write FComponentPriority;
property Components[Index: integer]: TPkgComponent read GetComponents;// registered components
property Directory: string read FDirectory;
property FileType: TPkgFileType read FFileType write SetFileType;
property Flags: TPkgFileFlags read FFlags write SetFlags;
property HasRegisterProc: boolean
read GetHasRegisterProc write SetHasRegisterProc;
property LazPackage: TLazPackage read FPackage;
property SourceDirectoryReferenced: boolean read FSourceDirectoryReferenced;
property Unit_Name: string read FUnitName write FUnitName;
end;
{ TPkgUnitsTree - Tree of TPkgFile sorted for unitnames }
TPkgUnitsTree = class(TAVLTree)
private
FLazPackage: TLazPackage;
public
function FindNodeWithUnitName(const AUnitName: string): TAVLTreeNode;
function FindPkgFileWithUnitName(const AUnitName: string): TPkgFile;
constructor Create(ThePackage: TLazPackage);
property LazPackage: TLazPackage read FLazPackage write FLazPackage;
end;
{ TPkgDependency }
TPkgDependencyFlag = (
pdfMinVersion, // >= MinVersion
pdfMaxVersion // <= MaxVersion
);
TPkgDependencyFlags = set of TPkgDependencyFlag;
TPkgMarkerFlag = (
pmfVisited,
pmfMarked
);
TPkgMarkerFlags = set of TPkgMarkerFlag;
TLoadPackageResult = (
lprUndefined,
lprSuccess,
lprNotFound,
lprLoadError
);
TPkgDependencyList = (
pdlRequires,
pdlUsedBy
);
{ TPkgDependency }
TPkgDependency = class
private
FDefaultFilename: string;
FFlags: TPkgDependencyFlags;
FHoldPackage: boolean;
FLoadPackageResult: TLoadPackageResult;
FMarkerFlags: TPKgMarkerFlags;
FOwner: TObject;
FMaxVersion: TPkgVersion;
FMinVersion: TPkgVersion;
FPackageName: string;
FPreferDefaultFilename: boolean;
FRemoved: boolean;
FRequiredPackage: TLazPackage;
procedure SetFlags(const AValue: TPkgDependencyFlags);
procedure SetHoldPackage(const AValue: boolean);
procedure SetLoadPackageResult(const AValue: TLoadPackageResult);
procedure SetMaxVersion(const AValue: TPkgVersion);
procedure SetMinVersion(const AValue: TPkgVersion);
procedure SetPackageName(const AValue: string);
procedure SetRemoved(const AValue: boolean);
procedure SetRequiredPackage(const AValue: TLazPackage);
public
NextDependency, PrevDependency: array[TPkgDependencyList] of TPkgDependency;
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string;
FileVersion: integer);
procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string;
UsePathDelim: TPathDelimSwitch);
function MakeSense: boolean;
function IsCompatible(const Version: TPkgVersion): boolean;
function IsCompatible(const PkgName: string;
const Version: TPkgVersion): boolean;
function Compare(Dependency2: TPkgDependency): integer;
procedure Assign(Source: TPkgDependency);
procedure Assign(Source: TLazPackageID);
procedure ConsistencyCheck;
function IsCompatible(Pkg: TLazPackageID): boolean;
procedure MakeCompatible(const PkgName: string; const Version: TPkgVersion);
function AsString(WithOwner: boolean = false): string;
function NextUsedByDependency: TPkgDependency;
function PrevUsedByDependency: TPkgDependency;
function NextRequiresDependency: TPkgDependency;
function PrevRequiresDependency: TPkgDependency;
procedure AddToList(var FirstDependency: TPkgDependency;
ListType: TPkgDependencyList);
procedure AddToEndOfList(var LastDependency: TPkgDependency;
ListType: TPkgDependencyList);
procedure RemoveFromList(var FirstDependency: TPkgDependency;
ListType: TPkgDependencyList);
procedure MoveUpInList(var FirstDependency: TPkgDependency;
ListType: TPkgDependencyList);
procedure MoveDownInList(var FirstDependency: TPkgDependency;
ListType: TPkgDependencyList);
function MakeFilenameRelativeToOwner(const AFilename: string): string;
function FindDefaultFilename: string;
public
property PackageName: string read FPackageName write SetPackageName;
property Flags: TPkgDependencyFlags read FFlags write SetFlags;
property MinVersion: TPkgVersion read FMinVersion write SetMinVersion;
property MaxVersion: TPkgVersion read FMaxVersion write SetMaxVersion;
property Removed: boolean read FRemoved write SetRemoved;
property Owner: TObject read FOwner write FOwner;// package or project or IDE
property RequiredPackage: TLazPackage read FRequiredPackage write SetRequiredPackage;
property LoadPackageResult: TLoadPackageResult read FLoadPackageResult write SetLoadPackageResult;
property HoldPackage: boolean read FHoldPackage write SetHoldPackage;
property MarkerFlags: TPKgMarkerFlags read FMarkerFlags write FMarkerFlags;
property DefaultFilename: string read FDefaultFilename write FDefaultFilename;
property PreferDefaultFilename: boolean read FPreferDefaultFilename write FPreferDefaultFilename;
end;
PPkgDependency = ^TPkgDependency;
{ TPkgPair }
TPkgPair = class
public
Package1: TLazPackage;
Package2: TLazPackage;
constructor Create(Pkg1, Pkg2: TLazPackage);
function ComparePair(Pkg1, Pkg2: TLazPackage): integer;
function Compare(PkgPair: TPkgPair): integer;
function AsString: string;
end;
{ TPkgPairTree - Tree of TPkgPair }
TPkgPairTree = class(TAVLTree)
public
constructor Create;
destructor Destroy; override;
function FindPair(Pkg1, Pkg2: TLazPackage; IgnoreOrder: boolean): TPkgPair;
function AddPair(Pkg1, Pkg2: TLazPackage): TPkgPair;
function AddPairIfNotExists(Pkg1, Pkg2: TLazPackage): TPkgPair;
end;
{ TPkgCompilerOptions }
TPkgCompilerOptions = class(TBaseCompilerOptions)
private
FLazPackage: TLazPackage;
FSkipCompiler: Boolean;
protected
procedure SetLazPackage(const AValue: TLazPackage);
procedure SetCustomOptions(const AValue: string); override;
procedure SetIncludePaths(const AValue: string); override;
procedure SetLibraryPaths(const AValue: string); override;
procedure SetLinkerOptions(const AValue: string); override;
procedure SetObjectPath(const AValue: string); override;
procedure SetSrcPath(const AValue: string); override;
procedure SetUnitPaths(const AValue: string); override;
procedure SetUnitOutputDir(const AValue: string); override;
procedure SetConditionals(const AValue: string); override;
public
constructor Create(const AOwner: TObject); override;
// IDE options
class function GetGroupCaption: string; override;
class function GetInstance: TAbstractIDEOptions; override;
function IsActive: boolean; override;
procedure Clear; override;
procedure GetInheritedCompilerOptions(var OptionsList: TFPList); override;
function GetOwnerName: string; override;
procedure InvalidateOptions;
function GetDefaultMainSourceFileName: string; override;
function CreateTargetFilename(const {%H-}MainSourceFileName: string): string; override;
procedure LoadFromXMLConfig(AXMLConfig: TXMLConfig; const Path: string); override;
procedure SaveToXMLConfig(AXMLConfig: TXMLConfig; const Path: string); override;
procedure Assign(Source: TPersistent); override;
function CreateDiff(CompOpts: TBaseCompilerOptions;
Tool: TCompilerDiffTool = nil): boolean; override;
public
property LazPackage: TLazPackage read FLazPackage write SetLazPackage;
property SkipCompiler: Boolean read FSkipCompiler write FSkipCompiler;
end;
{ TPkgAdditionalCompilerOptions }
TPkgAdditionalCompilerOptions = class(TAdditionalCompilerOptions)
private
FLazPackage: TLazPackage;
procedure SetLazPackage(const AValue: TLazPackage);
protected
procedure SetCustomOptions(const AValue: string); override;
procedure SetIncludePath(const AValue: string); override;
procedure SetLibraryPath(const AValue: string); override;
procedure SetLinkerOptions(const AValue: string); override;
procedure SetObjectPath(const AValue: string); override;
procedure SetUnitPath(const AValue: string); override;
procedure SetSrcPath(const AValue: string); override;
public
constructor Create(ThePackage: TLazPackage);
procedure AssignOptions(Source: TObject); override;
function GetOwnerName: string; override;
function GetBaseCompilerOptions: TBaseCompilerOptions; override;
public
property LazPackage: TLazPackage read FLazPackage write SetLazPackage;
end;
{ TPublishPackageOptions }
TPublishPackageOptions = class(TPublishModuleOptions)
private
FLazPackage: TLazPackage;
protected
procedure DoOnModifyChange; override;
public
constructor Create(TheLazPackage: TLazPackage);
function GetDefaultDestinationDir: string; override;
property LazPackage: TLazPackage read FLazPackage;
end;
{ TLazPackageDefineTemplates }
TLazPkgDefineTemplatesFlag = (
pdtIDChanged,
pdtSourceDirsChanged,
pdtOutputDirChanged,
pdtCustomDefinesChanged
);
TLazPkgDefineTemplatesFlags = set of TLazPkgDefineTemplatesFlag;
TLazPackageDefineTemplates = class
private
FActive: boolean;
FSrcDirIfDef: TDefineTemplate;
FFlags: TLazPkgDefineTemplatesFlags;
fLastOutputDirSrcPathIDAsString: string;
fLastSourceDirectories: TStringList;
fLastSourceDirStamp: integer;
fLastSourceDirsIDAsString: string;
FLastCustomOptions: string;
fLastUnitPath: string;
FLazPackage: TLazPackage;
FMain: TDefineTemplate;
FOutputDir: TDefineTemplate;
FOutPutSrcPath: TDefineTemplate;
FSrcDirectories: TDefineTemplate;
FUpdateLock: integer;
procedure SetActive(const AValue: boolean);
procedure UpdateMain;
procedure UpdateSrcDirIfDef;
procedure UpdateOutputDirectory;
procedure UpdateSourceDirectories;
procedure UpdateDefinesForCustomDefines;
public
constructor Create(OwnerPackage: TLazPackage);
destructor Destroy; override;
procedure Clear;
procedure BeginUpdate;
procedure EndUpdate;
procedure PackageIDChanged;
procedure SourceDirectoriesChanged;// a source directory was added/deleted
procedure OutputDirectoryChanged;// the path or the defines of the output dir changed
procedure CustomDefinesChanged;// the defines of the source dirs changed
procedure AllChanged;
public
property LazPackage: TLazPackage read FLazPackage;
property Main: TDefineTemplate read FMain;
property SrcDirectories: TDefineTemplate read FSrcDirectories;
property OutputDir: TDefineTemplate read FOutputDir;
property OutPutSrcPath: TDefineTemplate read FOutPutSrcPath;
property CustomDefines: TDefineTemplate read FSrcDirIfDef;
property Active: boolean read FActive write SetActive;
end;
{ TLazPackage }
TLazPackageType = (
lptRunTime, // RunTime packages can't register anything in the IDE.
// They can be used by designtime packages.
lptDesignTime, // DesignTime packages can register anything in the IDE
// and should not be compiled into projects.
// The IDE calls the 'register' procedures of each unit.
lptRunAndDesignTime,// RunAndDesignTime packages can do anything.
lptRunTimeOnly // as lptRunTime, but they can not be used in the IDE
);
TLazPackageTypes = set of TLazPackageType;
TLazPackageFlag = (
lpfAutoIncrementVersionOnBuild, // increment version before
lpfModified, // package needs saving
lpfNeeded, // Set by PackageGraph, if package is in use
// (for example because it is Installed or an Installed
// package requires this package)
lpfVisited, // Used by the PackageGraph to avoid double checking
lpfDestroying, // set during destruction
lpfLoading, // set during loading
lpfSkipSaving, // Used by PkgBoss to skip saving
lpfCycle // Used by the PackageGraph to mark cycles
);
TLazPackageFlags = set of TLazPackageFlag;
TPackageUpdatePolicy = (
pupManually,
pupOnRebuildingAll,
pupAsNeeded
);
TPackageUpdatePolicies = set of TPackageUpdatePolicy;
const
pupAllAuto = [pupAsNeeded,pupOnRebuildingAll];
type
TPkgOutputDirWritable = (
podwUnknown,
podwWritable,
podwNotWritable
);
TPkgLastCompileStats = record
StateFileLoaded: boolean;
StateFileName: string; // the .compiled file
StateFileDate: longint;
CompilerFilename: string; // path to used compiler
CompilerFileDate: integer;
Params: string; // compiler parameters
Complete: boolean; // compilation was successful
MainPPUExists: boolean; // main ppu file was there after compile
ViaMakefile: boolean; // compiled via make
DirectoryWritable: TPkgOutputDirWritable;
end;
PPkgLastCompileStats = ^TPkgLastCompileStats;
TPkgOutputDir = (
podDefault,
podFallback // used when podDefault is not writable
);
TIterateComponentClassesEvent =
procedure(PkgComponent: TPkgComponent) of object;
TPkgChangeNameEvent = procedure(Pkg: TLazPackage;
const OldName: string) of object;
{ TLazPackage }
TLazPackage = class(TIDEPackage)
private
FAddToProjectUsesSection: boolean;
FAuthor: string;
FAutoCreated: boolean;
FAutoUpdate: TPackageUpdatePolicy;
FFPDocPackageName: string;
FOptionsBackup: TLazPackage;
FCompilerOptions: TPkgCompilerOptions;
FComponents: TFPList; // TFPList of TPkgComponent
FDefineTemplates: TLazPackageDefineTemplates;
FDescription: string;
FDirectory: string;
FDirectoryExpanded: string;
FDirectoryExpandedChangeStamp: integer;
FEnableI18N: boolean;
FEnableI18NForLFM: boolean;
FFileReadOnly: boolean;
FFiles: TFPList; // TFPList of TPkgFile
FFirstRemovedDependency: TPkgDependency;
FFirstRequiredDependency: TPkgDependency;
FFirstUsedByDependency: TPkgDependency;
FFlags: TLazPackageFlags;
FHasDirectory: boolean;
FHasStaticDirectory: boolean;
FHoldPackageCount: integer;
FIconFile: string;
FInstalled: TPackageInstallType;
FFPDocPaths: string;
FLicense: string;
FLPKSource: TCodeBuffer;
FLPKSourceChangeStep: integer;
FMacros: TTransferMacroList;
FMainUnit: TPkgFile;
FMissing: boolean;
FModifiedLock: integer;
FOutputStateFile: string;
FPackageEditor: TBasePackageEditor;
FPackageType: TLazPackageType;
FPOOutputDirectory: string;
FProvides: TStrings;
fPublishOptions: TPublishPackageOptions;
FRegistered: boolean;
FRemovedFiles: TFPList; // TFPList of TPkgFile
FSourceDirectories: TFileReferenceList;
FStorePathDelim: TPathDelimSwitch;
FTopologicalLevel: integer;
FTranslated: string;
FUpdateLock: integer;
FUsageOptions: TPkgAdditionalCompilerOptions;
FUserIgnoreChangeStamp: integer;
FUserReadOnly: boolean;
function GetAutoIncrementVersionOnBuild: boolean;
function GetComponentCount: integer;
function GetComponents(Index: integer): TPkgComponent;
function GetRemovedFiles(Index: integer): TPkgFile;
function GetFiles(Index: integer): TPkgFile;
procedure SetAddToProjectUsesSection(const AValue: boolean);
procedure SetAuthor(const AValue: string);
procedure SetAutoCreated(const AValue: boolean);
procedure SetAutoIncrementVersionOnBuild(const AValue: boolean);
procedure SetAutoUpdate(const AValue: TPackageUpdatePolicy);
procedure SetDescription(const AValue: string);
procedure SetEnableI18NForLFM(AValue: boolean);
procedure SetFileReadOnly(const AValue: boolean);
procedure SetFlags(const AValue: TLazPackageFlags);
procedure SetFPDocPackageName(AValue: string);
procedure SetIconFile(const AValue: string);
procedure SetInstalled(const AValue: TPackageInstallType);
procedure SetFPDocPaths(const AValue: string);
procedure SetLicense(const AValue: string);
procedure SetLPKSource(const AValue: TCodeBuffer);
procedure SetLPKSourceChangeStep(const AValue: integer);
procedure SetOutputStateFile(const AValue: string);
procedure SetProvides(const AValue: TStrings);
procedure SetPOOutputDirectory(const AValue: string);
procedure SetEnableI18N(const AValue: boolean);
procedure SetRegistered(const AValue: boolean);
procedure SetPackageEditor(const AValue: TBasePackageEditor);
procedure SetPackageType(const AValue: TLazPackageType);
procedure SetStorePathDelim(const AValue: TPathDelimSwitch);
procedure SetUserReadOnly(const AValue: boolean);
procedure OnMacroListSubstitution({%H-}TheMacro: TTransferMacro;
const MacroName: string; var s: string;
const Data: PtrInt; var Handled, {%H-}Abort: boolean; {%H-}Depth: integer);
procedure Clear;
procedure UpdateSourceDirectories;
procedure SourceDirectoriesChanged(Sender: TObject);
protected
function GetFileCount: integer; override;
function GetPkgFiles(Index: integer): TLazPackageFile; override;
function GetDirectoryExpanded: string; override;
function GetModified: boolean; override;
procedure SetFilename(const AValue: string); override;
procedure SetModified(const AValue: boolean); override;
procedure SetName(const AValue: string); override;
procedure VersionChanged(Sender: TObject); override;
function GetRemovedCount: integer; override;
function GetRemovedPkgFiles(Index: integer): TLazPackageFile; override;
procedure SetAutoInstall(AValue: TPackageInstallType); override;
public
procedure AssignOptions(Source: TPersistent); override;
constructor Create;
destructor Destroy; override;
// IDE options
class function GetGroupCaption: string; override;
class function GetInstance: TAbstractIDEOptions; override;
procedure BackupOptions;
procedure RestoreOptions;
// modified
procedure BeginUpdate;
procedure EndUpdate;
procedure LockModified;
procedure UnlockModified;
function ReadOnly: boolean; override;
// streaming
procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string);
procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string);
procedure SaveToString(out s: string);
// consistency
procedure CheckInnerDependencies;
function MakeSense: boolean;
procedure ConsistencyCheck;
// paths, define templates
function IsVirtual: boolean; override;
function HasDirectory: boolean;
function HasStaticDirectory: boolean;
function GetFullFilename(ResolveMacros: boolean): string;
function GetResolvedFilename(ResolveMacros: boolean): string; // GetFullFilename + ReadAllLinks
function GetSourceDirs(WithPkgDir, WithoutOutputDir: boolean): string;
procedure GetInheritedCompilerOptions(var OptionsList: TFPList);
function GetOutputDirectory(UseOverride: boolean = true): string; // this can change before building, when default dir is readonly
function HasSeparateOutputDirectory: boolean;
function GetStateFilename(UseOverride: boolean = true): string;
function GetCompileSourceFilename: string;// as GetSrcFilename without directory
function GetSrcFilename: string;
function GetSrcPPUFilename: string;
function GetCompilerFilename: string;
function GetPOOutDirectory: string;
function GetUnitPath(RelativeToBaseDir: boolean): string;
function GetIncludePath(RelativeToBaseDir: boolean): string;
function GetSrcPath(RelativeToBaseDir: boolean): string;
function GetFPDocPackageName: string;
function GetLastCompilerParams(o: TPkgOutputDir): string;
function NeedsDefineTemplates: boolean;
function SubstitutePkgMacros(const s: string;
PlatformIndependent: boolean): string;
procedure WriteInheritedUnparsedOptions;
// files
function IndexOfPkgFile(PkgFile: TPkgFile): integer;
function SearchShortFilename(const ShortFilename: string;
SearchFlags: TSearchIDEFileFlags): TPkgFile;
function SearchFilename(const AFilename: string;
SearchFlags: TSearchIDEFileFlags): TPkgFile;
procedure ShortenFilename(var ExpandedFilename: string; UseUp: boolean);
procedure LongenFilename(var AFilename: string);
function FindPkgFile(const AFilename: string;
IgnoreRemoved, FindVirtualFile: boolean): TPkgFile;
function FindUnitWithRegister(IgnorePkgFile: TPkgFile = nil): TPkgFile;
function FindUnit(const TheUnitName: string): TPkgFile;
function FindUnit(const TheUnitName: string; IgnoreRemoved: boolean): TPkgFile;
function FindUnit(const TheUnitName: string; IgnoreRemoved: boolean;
IgnorePkgFile: TPkgFile): TPkgFile;
function FindRemovedPkgFile(const AFilename: string): TPkgFile;
function AddFile(const NewFilename, NewUnitName: string;
NewFileType: TPkgFileType; NewFlags: TPkgFileFlags;
CompPriorityCat: TComponentPriorityCategory): TPkgFile;
function AddRemovedFile(const NewFilename, NewUnitName: string;
NewFileType: TPkgFileType; NewFlags: TPkgFileFlags;
CompPriorityCat: TComponentPriorityCategory): TPkgFile;
procedure RemoveFile(PkgFile: TPkgFile); // move file to removed file list
procedure UnremovePkgFile(PkgFile: TPkgFile); // move file back to file list
function RemoveNonExistingFiles: boolean; // true if something changed
function GetFileDialogInitialDir(const DefaultDirectory: string): string;
procedure MoveFile(CurIndex, NewIndex: integer);
procedure SortFiles;
function FixFilesCaseSensitivity: boolean;
function MainUnitHasPkgName: boolean;
// required dependencies (plus removed required dependencies)
function FindDependencyByName(const PkgName: string): TPkgDependency;
function RequiredDepByIndex(Index: integer): TPkgDependency;
function RemovedDepByIndex(Index: integer): TPkgDependency;
procedure AddRequiredDependency(Dependency: TPkgDependency);
procedure AddPackageDependency(const PkgName: string);
procedure RemoveRequiredDependency(Dependency: TPkgDependency);
procedure DeleteRequiredDependency(Dependency: TPkgDependency);
procedure DeleteRemovedDependency(Dependency: TPkgDependency);
procedure RemoveRemovedDependency(Dependency: TPkgDependency);
procedure MoveRequiredDependencyUp(Dependency: TPkgDependency);
procedure MoveRequiredDependencyDown(Dependency: TPkgDependency);
function CreateDependencyWithOwner(NewOwner: TObject;
WithMinVersion: boolean = false): TPkgDependency;
function Requires(APackage: TLazPackage): boolean;
procedure GetAllRequiredPackages(var List: TFPList; WithSelf: boolean);
// components
function IndexOfPkgComponent(PkgComponent: TPkgComponent): integer;
function AddComponent(PkgFile: TPkgFile; const Page: string;
TheComponentClass: TComponentClass): TPkgComponent;
procedure AddPkgComponent(APkgComponent: TPkgComponent);
procedure RemovePkgComponent(APkgComponent: TPkgComponent);
procedure IterateComponentClasses(Event: TIterateComponentClassesEvent;
WithUsedPackages: boolean);
procedure SetAllComponentPriorities(const p: TComponentPriority);
// used by dependencies
procedure AddUsedByDependency(Dependency: TPkgDependency);
procedure RemoveUsedByDependency(Dependency: TPkgDependency);
function UsedByDepByIndex(Index: integer): TPkgDependency;
function FindUsedByDepPrefer(Ignore: TPkgDependency): TPkgDependency;
// provides
function ProvidesPackage(const AName: string): boolean;
// ID
procedure ChangeID(const NewName: string; NewVersion: TPkgVersion);
public
LastCompile: array[TPkgOutputDir] of TPkgLastCompileStats;
function GetOutputDirType: TPkgOutputDir;
public
property AddToProjectUsesSection: boolean read FAddToProjectUsesSection
write SetAddToProjectUsesSection;
property Author: string read FAuthor write SetAuthor;
property AutoCreated: boolean read FAutoCreated write SetAutoCreated; // do not save
property AutoIncrementVersionOnBuild: boolean
read GetAutoIncrementVersionOnBuild
write SetAutoIncrementVersionOnBuild;
property AutoUpdate: TPackageUpdatePolicy read FAutoUpdate
write SetAutoUpdate;
property CompilerOptions: TPkgCompilerOptions read FCompilerOptions;
property ComponentCount: integer read GetComponentCount;
property Components[Index: integer]: TPkgComponent read GetComponents;
property DefineTemplates: TLazPackageDefineTemplates read FDefineTemplates
write FDefineTemplates;
property Description: string read FDescription write SetDescription;
property Directory: string read FDirectory; // the directory of the .lpk file with macros
property Editor: TBasePackageEditor read FPackageEditor
write SetPackageEditor;
property EnableI18N: Boolean read FEnableI18N write SetEnableI18N;
property EnableI18NForLFM: boolean read FEnableI18NForLFM write SetEnableI18NForLFM;
property FileReadOnly: boolean read FFileReadOnly write SetFileReadOnly;
property Files[Index: integer]: TPkgFile read GetFiles;
property FirstRemovedDependency: TPkgDependency
read FFirstRemovedDependency;
property FirstRequiredDependency: TPkgDependency
read FFirstRequiredDependency;
property FirstUsedByDependency: TPkgDependency read FFirstUsedByDependency;
property Flags: TLazPackageFlags read FFlags write SetFlags;
property HoldPackageCount: integer read FHoldPackageCount;
property IconFile: string read FIconFile write SetIconFile;
property Installed: TPackageInstallType read FInstalled write SetInstalled;
property FPDocPaths: string read FFPDocPaths write SetFPDocPaths;
property FPDocPackageName: string read FFPDocPackageName write SetFPDocPackageName;
property License: string read FLicense write SetLicense;
property LPKSource: TCodeBuffer read FLPKSource write SetLPKSource;// can be nil when file on disk was removed
property LPKSourceChangeStep: integer read FLPKSourceChangeStep write SetLPKSourceChangeStep;
property Macros: TTransferMacroList read FMacros;
property MainUnit: TPkgFile read FMainUnit;
property Missing: boolean read FMissing write FMissing;
property OptionsBackup: TLazPackage read FOptionsBackup;
property OutputStateFile: string read FOutputStateFile write SetOutputStateFile;
property PackageType: TLazPackageType read FPackageType
write SetPackageType;
property POOutputDirectory: string read FPOOutputDirectory
write SetPOOutputDirectory;
property Provides: TStrings read FProvides write SetProvides;
property PublishOptions: TPublishPackageOptions
read fPublishOptions write fPublishOptions;
property Registered: boolean read FRegistered write SetRegistered;
property RemovedFiles[Index: integer]: TPkgFile read GetRemovedFiles;
property SourceDirectories: TFileReferenceList read FSourceDirectories;
property StorePathDelim: TPathDelimSwitch read FStorePathDelim write SetStorePathDelim;
property TopologicalLevel: integer read FTopologicalLevel write FTopologicalLevel;
property Translated: string read FTranslated write FTranslated;
property UsageOptions: TPkgAdditionalCompilerOptions read FUsageOptions;
property UserReadOnly: boolean read FUserReadOnly write SetUserReadOnly;
property UserIgnoreChangeStamp: integer read FUserIgnoreChangeStamp
write FUserIgnoreChangeStamp;
end;
PLazPackage = ^TLazPackage;
{ TBasePackageEditor }
TBasePackageEditor = class(TForm)
protected
function GetLazPackage: TLazPackage; virtual;
procedure SetLazPackage(const AValue: TLazPackage); virtual; abstract;
public
procedure UpdateAll(Immediately: boolean); virtual; abstract;
property LazPackage: TLazPackage read GetLazPackage write SetLazPackage;
end;
const
LazPkgXMLFileVersion = 4;
PkgFileTypeIdents: array[TPkgFileType] of string = (
'Unit', 'Virtual Unit', 'Main Unit',
'LFM', 'LRS', 'Include', 'Issues', 'Text', 'Binary');
LazPackageTypeIdents: array[TLazPackageType] of string = (
'RunTime', 'DesignTime', 'RunAndDesignTime', 'RunTimeOnly');
AutoUpdateNames: array[TPackageUpdatePolicy] of string = (
'Manually', 'OnRebuildingAll', 'AsNeeded');
var
// All TPkgDependency are added to this AVL tree (sorted for names, not version!)
PackageDependencies: TAVLTree = nil; // tree of TPkgDependency
OnGetAllRequiredPackages: TGetAllRequiredPackagesEvent = nil;
OnGetDependencyOwnerDescription: TGetDependencyOwnerDescription = nil;
OnGetDependencyOwnerDirectory: TGetDependencyOwnerDirectory = nil;
OnPackageFileLoaded: TNotifyEvent = nil;
function CompareLazPackageID(Data1, Data2: Pointer): integer;
function CompareNameWithPackageID(Key, Data: Pointer): integer;
function ComparePkgIDMaskWithPackageID(Key, Data: Pointer): integer;
function CompareLazPackageIDNames(Data1, Data2: Pointer): integer;
function CompareNameWithPkgDependency(Key, Data: Pointer): integer;
function ComparePkgDependencyNames(Data1, Data2: Pointer): integer;
function CompareUnitsTree(UnitTree1, UnitTree2: TPkgUnitsTree): integer;
function ComparePackageWithUnitsTree(Package: TLazPackage;
UnitTree: TPkgUnitsTree): integer;
function ComparePkgFilesAlphabetically(PkgFile1, PkgFile2: TPkgFile): integer;
function GetUsageOptionsList(PackageList: TFPList): TFPList;
function PkgFileTypeIdentToType(const s: string): TPkgFileType;
function LazPackageTypeIdentToType(const s: string): TLazPackageType;
function GetPkgFileTypeLocalizedName(FileType: TPkgFileType): string;
function NameToAutoUpdatePolicy(const s: string): TPackageUpdatePolicy;
function FileNameToPkgFileType(const AFilename: string): TPkgFileType;
procedure SortDependencyListAlphabetically(Dependencies: TFPList);
procedure LoadPkgDependencyList(XMLConfig: TXMLConfig; const ThePath: string;
var First: TPkgDependency; ListType: TPkgDependencyList; Owner: TObject;
HoldPackages, SortList: boolean);
procedure SavePkgDependencyList(XMLConfig: TXMLConfig; const ThePath: string;
First: TPkgDependency; ListType: TPkgDependencyList;
UsePathDelim: TPathDelimSwitch);
procedure ListPkgIDToDependencyList(ListOfTLazPackageID: TObjectList;
var First: TPkgDependency; ListType: TPkgDependencyList; Owner: TObject;
HoldPackages: boolean);
procedure DeleteDependencyInList(ADependency: TPkgDependency;
var First: TPkgDependency; ListType: TPkgDependencyList);
procedure FreeDependencyList(var First: TPkgDependency;
ListType: TPkgDependencyList);
function DependencyListAsString(First: TPkgDependency;
ListType: TPkgDependencyList): string;
function FindDependencyByNameInList(First: TPkgDependency;
ListType: TPkgDependencyList; const Name: string): TPkgDependency;
function FindCompatibleDependencyInList(First: TPkgDependency;
ListType: TPkgDependencyList; ComparePackage: TLazPackageID): TPkgDependency;
function GetDependencyWithIndex(First: TPkgDependency;
ListType: TPkgDependencyList; Index: integer): TPkgDependency;
function IndexOfDependencyInList(First: TPkgDependency;
ListType: TPkgDependencyList; FindDependency: TPkgDependency): integer;
function GetFirstDependency(ListItem: TPkgDependency;
ListType: TPkgDependencyList): TPkgDependency;
function FindLowestPkgDependencyWithName(const PkgName: string): TPkgDependency;
function FindLowestPkgDependencyNodeWithName(const PkgName: string): TAVLTreeNode;
function FindNextPkgDependencyNodeWithSameName(Node: TAVLTreeNode): TAVLTreeNode;
function GetDependencyOwnerAsString(Dependency: TPkgDependency): string;
function GetDependencyOwnerDirectory(Dependency: TPkgDependency): string;
function PackageFileNameIsValid(const AFilename: string): boolean;
procedure PkgVersionLoadFromXMLConfig(Version: TPkgVersion;
XMLConfig: TXMLConfig; const Path: string; FileVersion: integer);
procedure PkgVersionSaveToXMLConfig(Version: TPkgVersion; XMLConfig: TXMLConfig;
const Path: string);
procedure PkgVersionLoadFromXMLConfig(Version: TPkgVersion;
XMLConfig: TXMLConfig);
function IsValidUnitName(AUnitName: String): Boolean; inline;
var
Package1: TLazPackage; // don't use it - only for options dialog
function dbgs(p: TPackageUpdatePolicy): string; overload;
function dbgs(p: TLazPackageType): string; overload;
function PackagePathToStr(PathList: TFPList): string;
implementation
function IsValidUnitName(AUnitName: String): Boolean;
begin
Result := IsDottedIdentifier(AUnitName);
end;
function PkgFileTypeIdentToType(const s: string): TPkgFileType;
begin
for Result:=Low(TPkgFileType) to High(TPkgFileType) do
if SysUtils.CompareText(s,PkgFileTypeIdents[Result])=0 then exit;
Result:=pftUnit;
end;
function LazPackageTypeIdentToType(const s: string): TLazPackageType;
begin
for Result:=Low(TLazPackageType) to High(TLazPackageType) do
if SysUtils.CompareText(s,LazPackageTypeIdents[Result])=0 then exit;
Result:=lptRunTime;
end;
function GetPkgFileTypeLocalizedName(FileType: TPkgFileType): string;
begin
case FileType of
pftUnit: Result:=lisPkgFileTypeUnit;
pftVirtualUnit: Result:=lisPkgFileTypeVirtualUnit;
pftMainUnit: Result:=lisPkgFileTypeMainUnit;
pftLFM: Result:=lisPkgFileTypeLFM;
pftLRS: Result:=lisPkgFileTypeLRS;
pftInclude: Result:=lisPkgFileTypeInclude;
pftIssues: Result:=lisPkgFileTypeIssues;
pftText: Result:=lisPkgFileTypeText;
pftBinary: Result:=lisPkgFileTypeBinary;
else
Result:='Unknown';
end;
end;
function NameToAutoUpdatePolicy(const s: string): TPackageUpdatePolicy;
begin
for Result:=Low(TPackageUpdatePolicy) to High(TPackageUpdatePolicy) do
if SysUtils.CompareText(AutoUpdateNames[Result],s)=0 then exit;
Result:=pupAsNeeded;
end;
function FileNameToPkgFileType(const AFilename: string): TPkgFileType;
begin
if CompareFileExt(AFilename,'.lfm',true)=0 then
Result:=pftLFM
else if CompareFileExt(AFilename,'.lrs',true)=0 then
Result:=pftLRS
else if CompareFileExt(AFilename,'.inc',true)=0 then
Result:=pftInclude
else if FilenameIsPascalUnit(AFilename) then
Result:=pftUnit
else if CompareFileExt(AFilename,'.xml',true)=0 then
Result:=pftIssues
else if FileIsText(AFilename) then
Result:=pftText
else
Result:=pftBinary;
end;
procedure LoadPkgDependencyList(XMLConfig: TXMLConfig; const ThePath: string;
var First: TPkgDependency; ListType: TPkgDependencyList; Owner: TObject;
HoldPackages, SortList: boolean);
var
i: Integer;
PkgDependency: TPkgDependency;
NewCount: Integer;
List: TFPList;
FileVersion: Integer;
Last: TPkgDependency;
begin
FileVersion:=XMLConfig.GetValue(ThePath+'Version',0);
NewCount:=XMLConfig.GetValue(ThePath+'Count',0);
List:=TFPList.Create;
for i:=0 to NewCount-1 do begin
PkgDependency:=TPkgDependency.Create;
PkgDependency.LoadFromXMLConfig(XMLConfig,ThePath+'Item'+IntToStr(i+1)+'/',
FileVersion);
PkgDependency.HoldPackage:=HoldPackages;
if PkgDependency.MakeSense then
List.Add(PkgDependency)
else
PkgDependency.Free;
end;
if SortList then
SortDependencyListAlphabetically(List);
Last:=First;
if Last<>nil then
while Last.NextDependency[ListType]<>nil do
Last:=Last.NextDependency[ListType];
for i:=0 to List.Count-1 do begin
PkgDependency:=TPkgDependency(List[i]);
PkgDependency.AddToEndOfList(Last,ListType);
if First=nil then
First:=Last;
PkgDependency.Owner:=Owner;
end;
List.Free;
end;
procedure SavePkgDependencyList(XMLConfig: TXMLConfig; const ThePath: string;
First: TPkgDependency; ListType: TPkgDependencyList;
UsePathDelim: TPathDelimSwitch);
var
i: Integer;
Dependency: TPkgDependency;
begin
i:=0;
Dependency:=First;
while Dependency<>nil do begin
inc(i);
Dependency.SaveToXMLConfig(XMLConfig,ThePath+'Item'+IntToStr(i)+'/',UsePathDelim);
Dependency:=Dependency.NextDependency[ListType];
end;
XMLConfig.SetDeleteValue(ThePath+'Count',i,0);
end;
procedure ListPkgIDToDependencyList(ListOfTLazPackageID: TObjectList;
var First: TPkgDependency; ListType: TPkgDependencyList; Owner: TObject;
HoldPackages: boolean);
var
NewDependency: TPkgDependency;
i: Integer;
PkgID: TLazPackageID;
begin
First:=nil;
for i:=ListOfTLazPackageID.Count-1 downto 0 do begin
PkgID:=TLazPackageID(ListOfTLazPackageID[i]);
NewDependency:=TPkgDependency.Create;
NewDependency.Assign(PkgID);
NewDependency.Owner:=Owner;
NewDependency.HoldPackage:=HoldPackages;
NewDependency.AddToList(First,ListType);
end;
end;
procedure DeleteDependencyInList(ADependency: TPkgDependency;
var First: TPkgDependency; ListType: TPkgDependencyList);
var
NextDependency, PrevDependency: TPkgDependency;
begin
NextDependency := ADependency.NextDependency[ListType];
PrevDependency := ADependency.PrevDependency[ListType];
if First = ADependency then First := NextDependency;
if Assigned(NextDependency) then
NextDependency.PrevDependency[ListType] := PrevDependency;
if Assigned(PrevDependency) then
PrevDependency.NextDependency[ListType] := NextDependency;
ADependency.Free;
end;
procedure FreeDependencyList(var First: TPkgDependency;
ListType: TPkgDependencyList);
var
NextDependency: TPkgDependency;
begin
while First<>nil do begin
NextDependency:=First.NextDependency[ListType];
First.Free;
First:=NextDependency;
end;
end;
function DependencyListAsString(First: TPkgDependency;
ListType: TPkgDependencyList): string;
begin
Result:='';
while First<>nil do begin
Result:=Result+First.AsString+LineEnding;
First:=First.NextDependency[ListType];
end;
end;
procedure SortDependencyListAlphabetically(Dependencies: TFPList);
var
Count: Integer;
i, j: Integer;
Dependency1: TPkgDependency;
Dependency2: TPkgDependency;
Sorted: Boolean;
begin
if (Dependencies=nil) or (Dependencies.Count<2) then exit;
// check if already sorted
Count:=Dependencies.Count;
Sorted:=true;
for i:=0 to Count-2 do begin
Dependency1:=TPkgDependency(Dependencies[i]);
Dependency2:=TPkgDependency(Dependencies[i+1]);
if Dependency1.Compare(Dependency2)>0 then begin
Sorted:=false;
break;
end;
end;
if Sorted then exit;
// bubble sort (slow, but dependency lists are normally sorted)
for i:=0 to Count-2 do begin
Dependency1:=TPkgDependency(Dependencies[i]);
for j:=i+1 to Count-1 do begin
Dependency2:=TPkgDependency(Dependencies[j]);
if Dependency1.Compare(Dependency2)>0 then begin
Dependencies.Exchange(i,j);
Dependency1:=TPkgDependency(Dependencies[i]);
end;
end;
end;
end;
function StrToComponentBaseClass(const s: string): TPFComponentBaseClass;
begin
for Result:=low(TPFComponentBaseClass) to high(TPFComponentBaseClass) do
if SysUtils.CompareText(PFComponentBaseClassNames[Result],s)=0 then exit;
Result:=pfcbcNone;
end;
function GetComponentBaseClass(aClass: TClass): TPFComponentBaseClass;
begin
Result:=pfcbcNone;
if aClass=nil then exit;
if aClass.InheritsFrom(TForm) then
Result:=pfcbcForm
else if aClass.InheritsFrom(TFrame) then
Result:=pfcbcFrame
else if aClass.InheritsFrom(TDataModule) then
Result:=pfcbcDataModule;
end;
function CompareLazPackageID(Data1, Data2: Pointer): integer;
var
Pkg1: TLazPackageID;
Pkg2: TLazPackageID;
begin
Pkg1:=TLazPackageID(Data1);
Pkg2:=TLazPackageID(Data2);
Result:=Pkg1.Compare(Pkg2);
end;
function CompareNameWithPackageID(Key, Data: Pointer): integer;
var
Name: String;
Pkg: TLazPackageID;
begin
if Key<>nil then begin
Name:=AnsiString(Key);
Pkg:=TLazPackageID(Data);
Result:=SysUtils.CompareText(Name,Pkg.Name);
end else
Result:=-1;
end;
function ComparePkgIDMaskWithPackageID(Key, Data: Pointer): integer;
var
Pkg1: TLazPackageID;
Pkg2: TLazPackageID;
begin
Pkg1:=TLazPackageID(Key);
Pkg2:=TLazPackageID(Data);
Result:=Pkg1.CompareMask(Pkg2);
end;
function CompareLazPackageIDNames(Data1, Data2: Pointer): integer;
var
Pkg1: TLazPackageID;
Pkg2: TLazPackageID;
begin
Pkg1:=TLazPackageID(Data1);
Pkg2:=TLazPackageID(Data2);
Result:=SysUtils.CompareText(Pkg1.Name,Pkg2.Name);
end;
function CompareNameWithPkgDependency(Key, Data: Pointer): integer;
var
PkgName: String;
Dependency: TPkgDependency;
begin
PkgName:=String(Key);
Dependency:=TPkgDependency(Data);
Result:=SysUtils.CompareText(PkgName,Dependency.PackageName);
end;
function ComparePkgDependencyNames(Data1, Data2: Pointer): integer;
var
Dependency1: TPkgDependency;
Dependency2: TPkgDependency;
begin
Dependency1:=TPkgDependency(Data1);
Dependency2:=TPkgDependency(Data2);
Result:=SysUtils.CompareText(Dependency1.PackageName,Dependency2.PackageName);
end;
function CompareUnitsTree(UnitTree1, UnitTree2: TPkgUnitsTree): integer;
begin
Result:=UnitTree1.LazPackage.Compare(UnitTree2.LazPackage);
end;
function ComparePackageWithUnitsTree(Package: TLazPackage;
UnitTree: TPkgUnitsTree): integer;
begin
Result:=Package.Compare(UnitTree.LazPackage);
end;
function ComparePkgFilesAlphabetically(PkgFile1, PkgFile2: TPkgFile): integer;
var
ShortFilename1: String;
ShortFilename2: String;
File1IsInMainDir: Boolean;
File2IsInMainDir: Boolean;
begin
ShortFilename1:=PkgFile1.GetShortFilename(true);
ShortFilename2:=PkgFile2.GetShortFilename(true);
// files in the main directory are higher
File1IsInMainDir:=ExtractFilePath(ShortFilename1)='';
File2IsInMainDir:=ExtractFilePath(ShortFilename2)='';
if File1IsInMainDir xor File2IsInMainDir then begin
if File1IsInMainDir then
Result:=-1
else
Result:=1;
exit;
end;
// compare short filenames without extension
Result:=CompareFilenames(ChangeFileExt(ShortFilename1,''),
ChangeFileExt(ShortFilename2,''));
if Result<>0 then exit;
// if one is a unit, then it is higher
if (PkgFile1.Unit_Name<>'') and (PkgFile2.Unit_Name='') then begin
Result:=-1;
exit;
end else if (PkgFile1.Unit_Name='') and (PkgFile2.Unit_Name<>'') then begin
Result:=1;
exit;
end;
// compare short filenames with extension
Result:=CompareFilenames(ShortFilename1,ShortFilename2);
if Result<>0 then exit;
// compare filenames
Result:=CompareFilenames(PkgFile1.FileName,PkgFile2.FileName);
end;
function GetUsageOptionsList(PackageList: TFPList): TFPList;
// returns a list of TPkgAdditionalCompilerOptions
// from the list of TLazPackage
var
Cnt: Integer;
i: Integer;
begin
if PackageList<>nil then begin
Result:=TFPList.Create;
Cnt:=PackageList.Count;
for i:=0 to Cnt-1 do begin
Result.Add(TLazPackage(PackageList[i]).UsageOptions);
end;
end else begin
Result:=nil;
end;
end;
function FindDependencyByNameInList(First: TPkgDependency;
ListType: TPkgDependencyList; const Name: string): TPkgDependency;
begin
Result:=First;
while Result<>nil do begin
if SysUtils.CompareText(Result.PackageName,Name)=0 then exit;
Result:=Result.NextDependency[ListType];
end;
end;
function FindCompatibleDependencyInList(First: TPkgDependency;
ListType: TPkgDependencyList; ComparePackage: TLazPackageID): TPkgDependency;
begin
Result:=First;
while Result<>nil do begin
if Result.IsCompatible(ComparePackage) then exit;
Result:=Result.NextDependency[ListType];
end;
end;
function GetDependencyWithIndex(First: TPkgDependency;
ListType: TPkgDependencyList; Index: integer): TPkgDependency;
begin
if Index<0 then RaiseException('GetDependencyWithIndex');
Result:=First;
while (Result<>nil) and (Index>0) do begin
Result:=Result.NextDependency[ListType];
dec(Index);
end;
end;
function FindLowestPkgDependencyNodeWithName(const PkgName: string
): TAVLTreeNode;
begin
Result:=nil;
if PackageDependencies=nil then exit;
Result:=PackageDependencies.FindLeftMostKey(PChar(PkgName),
@CompareNameWithPkgDependency);
end;
function FindNextPkgDependencyNodeWithSameName(
Node: TAVLTreeNode): TAVLTreeNode;
begin
Result:=nil;
if (Node=nil) or (PackageDependencies=nil) then exit;
Result:=PackageDependencies.FindSuccessor(Node);
if (Result<>nil)
and (SysUtils.CompareText(TPkgDependency(Node.Data).PackageName,
TPkgDependency(Result.Data).PackageName)<>0)
then
Result:=nil;
end;
function GetDependencyOwnerAsString(Dependency: TPkgDependency): string;
begin
Result := '';
OnGetDependencyOwnerDescription(Dependency,Result);
end;
function GetDependencyOwnerDirectory(Dependency: TPkgDependency): string;
begin
Result := '';
OnGetDependencyOwnerDirectory(Dependency,Result);
end;
function PackageFileNameIsValid(const AFilename: string): boolean;
var
PkgName: String;
begin
Result:=false;
if CompareFileExt(AFilename,'.lpk',false)<>0 then exit;
PkgName:=ExtractFileNameOnly(AFilename);
if (PkgName='') or (not IsValidUnitName(PkgName)) then exit;
Result:=true;
end;
procedure PkgVersionLoadFromXMLConfig(Version: TPkgVersion;
XMLConfig: TXMLConfig; const Path: string; FileVersion: integer);
var
NewMajor: Integer;
NewMinor: Integer;
NewRelease: Integer;
NewBuild: Integer;
begin
if FileVersion=1 then ;
NewMajor:=Version.VersionBound(XMLConfig.GetValue(Path+'Major',0));
NewMinor:=Version.VersionBound(XMLConfig.GetValue(Path+'Minor',0));
NewRelease:=Version.VersionBound(XMLConfig.GetValue(Path+'Release',0));
NewBuild:=Version.VersionBound(XMLConfig.GetValue(Path+'Build',0));
Version.SetValues(NewMajor,NewMinor,NewRelease,NewBuild,pvtBuild);
end;
procedure PkgVersionSaveToXMLConfig(Version: TPkgVersion; XMLConfig: TXMLConfig;
const Path: string);
begin
XMLConfig.SetDeleteValue(Path+'Major',Version.Major,0);
XMLConfig.SetDeleteValue(Path+'Minor',Version.Minor,0);
XMLConfig.SetDeleteValue(Path+'Release',Version.Release,0);
XMLConfig.SetDeleteValue(Path+'Build',Version.Build,0);
end;
procedure PkgVersionLoadFromXMLConfig(Version: TPkgVersion;
XMLConfig: TXMLConfig);
var
Path: String;
FileVersion: LongInt;
begin
Path:='Package/';
FileVersion:=XMLConfig.GetValue(Path+'Version',0);
PkgVersionLoadFromXMLConfig(Version,XMLConfig,Path+'Version/',FileVersion);
end;
function dbgs(p: TPackageUpdatePolicy): string;
begin
Result:=GetEnumName(TypeInfo(p),ord(p));
end;
function dbgs(p: TLazPackageType): string;
begin
Result:=LazPackageTypeIdents[p];
end;
function PackagePathToStr(PathList: TFPList): string;
var
i: Integer;
Item: TObject;
Dep: TPkgDependency;
begin
Result:='';
if PathList=nil then exit;
for i:=0 to PathList.Count-1 do begin
if i>0 then
Result:=Result+' -> ';
Item:=TObject(PathList[i]);
if Item is TPkgDependency then begin
Dep:=TPkgDependency(Item);
Result:=Result+GetDependencyOwnerAsString(Dep);
if i=PathList.Count-1 then
Result:=Result+' -> '+Dep.AsString;
end else if Item is TLazPackage then
Result:=Result+TLazPackage(Item).Name
else
Result:=Result+DbgSName(Item);
end;
end;
function IndexOfDependencyInList(First: TPkgDependency;
ListType: TPkgDependencyList; FindDependency: TPkgDependency): integer;
var
Dependency: TPkgDependency;
begin
Result:=-1;
Dependency:=First;
while Dependency<>nil do begin
inc(Result);
if Dependency=FindDependency then exit;
Dependency:=Dependency.NextDependency[ListType];
end;
Result:=-1;
end;
function GetFirstDependency(ListItem: TPkgDependency;
ListType: TPkgDependencyList): TPkgDependency;
begin
Result:=ListItem;
if Result=nil then exit;
while Result.PrevDependency[ListType]<>nil do
Result:=Result.PrevDependency[ListType];
end;
function FindLowestPkgDependencyWithName(const PkgName: string): TPkgDependency;
var
ANode: TAVLTreeNode;
begin
ANode:=FindLowestPkgDependencyNodeWithName(PkgName);
if ANode<>nil then
Result:=TPkgDependency(ANode.Data)
else
Result:=nil;
end;
{ TPkgFile }
procedure TPkgFile.SetFilename(const AValue: string);
var
NewFilename: String;
OldDirectory: String;
begin
NewFilename:=AValue;
DoDirSeparators(NewFilename);
if Filename=NewFilename then exit;
inherited SetFilename(NewFilename);
fFullFilenameStamp:=CTInvalidChangeStamp;
OldDirectory:=FDirectory;
FDirectory:=ExtractFilePath(Filename);
if OldDirectory<>FDirectory then begin
if FSourceDirNeedReference then begin
LazPackage.SourceDirectories.RemoveFilename(OldDirectory);
LazPackage.SourceDirectories.AddFilename(FDirectory);
end;
end;
UpdateUnitName;
end;
function TPkgFile.GetHasRegisterProc: boolean;
begin
Result:=pffHasRegisterProc in FFlags;
end;
procedure TPkgFile.SetAddToUsesPkgSection(const AValue: boolean);
begin
if AddToUsesPkgSection=AValue then exit;
if AValue then
Include(FFlags,pffAddToPkgUsesSection)
else
Exclude(FFlags,pffAddToPkgUsesSection);
end;
procedure TPkgFile.SetAutoReferenceSourceDir(const AValue: boolean);
begin
if FAutoReferenceSourceDir=AValue then exit;
FAutoReferenceSourceDir:=AValue;
if FSourceDirNeedReference then
UpdateSourceDirectoryReference;
end;
procedure TPkgFile.SetRemoved(const AValue: boolean);
begin
if Removed=AValue then exit;
inherited SetRemoved(AValue);
FSourceDirNeedReference:=(FileType in PkgFileRealUnitTypes) and not Removed;
UpdateSourceDirectoryReference;
end;
procedure TPkgFile.SetDisableI18NForLFM(AValue: boolean);
begin
if DisableI18NForLFM=AValue then exit;
inherited SetDisableI18NForLFM(AValue);
LazPackage.Modified:=true;
end;
function TPkgFile.GetComponents(Index: integer): TPkgComponent;
begin
Result:=TPkgComponent(FComponents[Index]);
end;
function TPkgFile.GetAddToUsesPkgSection: boolean;
begin
Result:=pffAddToPkgUsesSection in FFlags;
end;
procedure TPkgFile.SetFileType(const AValue: TPkgFileType);
begin
if FFileType=AValue then exit;
if (LazPackage<>nil) and (LazPackage.MainUnit=Self) then
LazPackage.FMainUnit:=nil;
FFileType:=AValue;
FSourceDirNeedReference:=(FFileType in PkgFileRealUnitTypes) and not Removed;
UpdateSourceDirectoryReference;
if (FFileType=pftMainUnit) and (LazPackage<>nil)
and (LazPackage.MainUnit<>Self) then begin
if LazPackage.MainUnit<>nil then
LazPackage.MainUnit.FileType:=pftUnit;
LazPackage.FMainUnit:=Self;
end;
end;
procedure TPkgFile.SetFlags(const AValue: TPkgFileFlags);
begin
if FFlags=AValue then exit;
FFlags:=AValue;
end;
procedure TPkgFile.SetHasRegisterProc(const AValue: boolean);
begin
if HasRegisterProc=AValue then exit;
if AValue then
Include(FFlags,pffHasRegisterProc)
else
Exclude(FFlags,pffHasRegisterProc);
end;
procedure TPkgFile.UpdateUnitName;
var
NewUnitName: String;
begin
if FilenameIsPascalUnit(Filename) then begin
NewUnitName:=ExtractFileNameOnly(Filename);
if SysUtils.CompareText(NewUnitName,FUnitName)<>0 then
FUnitName:=NewUnitName;
end else
FUnitName:='';
end;
function TPkgFile.GetComponentList: TFPList;
begin
if FComponents=nil then FComponents:=TFPList.Create;
Result:=FComponents;
end;
function TPkgFile.GetIDEPackage: TIDEPackage;
begin
Result:=FPackage;
end;
function TPkgFile.HasRegisteredPlugins: boolean;
begin
Result:=ComponentCount>0;
end;
function TPkgFile.MakeSense: boolean;
begin
Result:=Filename<>'';
end;
procedure TPkgFile.UpdateSourceDirectoryReference;
begin
if (not AutoReferenceSourceDir) or (FPackage=nil) then exit;
if FSourceDirNeedReference then begin
if not SourceDirectoryReferenced then begin
LazPackage.SourceDirectories.AddFilename(FDirectory);
FSourceDirectoryReferenced:=true;
end;
end else begin
if SourceDirectoryReferenced then begin
LazPackage.SourceDirectories.RemoveFilename(FDirectory);
FSourceDirectoryReferenced:=false;
end;
end;
end;
function TPkgFile.GetFullFilename: string;
begin
if fFullFilenameStamp<>CompilerParseStamp then begin
fFullFilename:=Filename;
fFullFilenameStamp:=CompilerParseStamp;
if LazPackage<>nil then begin
LazPackage.SubstitutePkgMacros(fFullFilename,false);
fFullFilename:=TrimFilename(fFullFilename);
LazPackage.LongenFilename(fFullFilename);
end
else begin
IDEMacros.SubstituteMacros(fFullFilename);
fFullFilename:=TrimAndExpandFilename(fFullFilename);
end;
end;
Result:=fFullFilename;
end;
constructor TPkgFile.Create(ThePackage: TLazPackage);
begin
inherited Create;
Clear;
FPackage:=ThePackage;
FComponentPriority:=ComponentPriorityNormal;
end;
destructor TPkgFile.Destroy;
begin
Clear;
inherited Destroy;
end;
procedure TPkgFile.Clear;
begin
AutoReferenceSourceDir:=false;
inherited SetRemoved(false);
inherited SetFilename('');
FDirectory:='';
FFlags:=[];
FFileType:=pftUnit;
FSourceDirectoryReferenced:=false;
FSourceDirNeedReference:=true;
FreeThenNil(FComponents);
if (LazPackage<>nil) and (LazPackage.MainUnit=Self) then
LazPackage.FMainUnit:=nil;
end;
procedure TPkgFile.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string;
FileVersion: integer; AdjustPathDelims: boolean);
var
AFilename: String;
CaseInsensitiveUnitName: String;
begin
if FileVersion=1 then ;
Clear;
AFilename:=SwitchPathDelims(XMLConfig.GetValue(Path+'Filename/Value',''),
AdjustPathDelims);
FPackage.LongenFilename(AFilename);
Filename:=AFilename;
FileType:=PkgFileTypeIdentToType(XMLConfig.GetValue(Path+'Type/Value',''));
HasRegisterProc:=XMLConfig.GetValue(Path+'HasRegisterProc/Value',false);
AddToUsesPkgSection:=XMLConfig.GetValue(Path+'AddToUsesPkgSection/Value',
FileType in PkgFileUnitTypes);
DisableI18NForLFM:=XMLConfig.GetValue(Path+'DisableI18NForLFM/Value',false);
fUnitName:=XMLConfig.GetValue(Path+'UnitName/Value','');
if FileType in PkgFileUnitTypes then begin
// make sure the unitname makes sense
CaseInsensitiveUnitName:=ExtractFileNameOnly(Filename);
if SysUtils.CompareText(fUnitName,CaseInsensitiveUnitName)<>0 then
fUnitName:=CaseInsensitiveUnitName;
end;
FResourceBaseClass:=StrToComponentBaseClass(
XMLConfig.GetValue(Path+'ResourceBaseClass/Value',''));
end;
procedure TPkgFile.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string;
UsePathDelim: TPathDelimSwitch);
var
TmpFilename: String;
begin
TmpFilename:=Filename;
FPackage.ShortenFilename(TmpFilename,true);
XMLConfig.SetDeleteValue(Path+'Filename/Value',
SwitchPathDelims(TmpFilename,UsePathDelim),'');
XMLConfig.SetDeleteValue(Path+'HasRegisterProc/Value',HasRegisterProc,
false);
XMLConfig.SetDeleteValue(Path+'AddToUsesPkgSection/Value',AddToUsesPkgSection,
FileType in PkgFileUnitTypes);
XMLConfig.SetDeleteValue(Path+'DisableI18NForLFM/Value',DisableI18NForLFM,false);
XMLConfig.SetDeleteValue(Path+'Type/Value',PkgFileTypeIdents[FileType],
PkgFileTypeIdents[pftUnit]);
XMLConfig.SetDeleteValue(Path+'UnitName/Value',FUnitName,'');
XMLConfig.SetDeleteValue(Path+'ResourceBaseClass/Value',
PFComponentBaseClassNames[FResourceBaseClass],
PFComponentBaseClassNames[pfcbcNone]);
end;
procedure TPkgFile.ConsistencyCheck;
begin
if FPackage=nil then
RaiseGDBException('TPkgFile.ConsistencyCheck FPackage=nil');
if Filename='' then
RaiseGDBException('TPkgFile.ConsistencyCheck FFilename=""');
end;
function TPkgFile.GetShortFilename(UseUp: boolean): string;
begin
Result:=GetFullFilename;
LazPackage.ShortenFilename(Result,UseUp);
end;
function TPkgFile.ComponentCount: integer;
begin
if FComponents<>nil then
Result:=FComponents.Count
else
Result:=0;
end;
procedure TPkgFile.AddPkgComponent(APkgComponent: TPkgComponent);
begin
if FComponents=nil then FComponents:=TFPList.Create;
FComponents.Add(APkgComponent);
if LazPackage<>nil then
LazPackage.AddPkgComponent(APkgComponent);
end;
procedure TPkgFile.RemovePkgComponent(APkgComponent: TPkgComponent);
begin
if FComponents<>nil then
FComponents.Remove(APkgComponent);
if LazPackage<>nil then
LazPackage.RemovePkgComponent(APkgComponent);
end;
function TPkgFile.GetResolvedFilename: string;
begin
Result:=ReadAllLinks(GetFullFilename,false);
if Result='' then Result:=GetFullFilename;
end;
{ TPkgDependency }
procedure TPkgDependency.SetFlags(const AValue: TPkgDependencyFlags);
begin
if FFlags=AValue then exit;
FFlags:=AValue;
end;
procedure TPkgDependency.SetHoldPackage(const AValue: boolean);
begin
if FHoldPackage=AValue then exit;
FHoldPackage:=AValue;
if RequiredPackage<>nil then begin
if FHoldPackage then
inc(RequiredPackage.FHoldPackageCount)
else
dec(RequiredPackage.FHoldPackageCount);
end;
end;
procedure TPkgDependency.SetLoadPackageResult(const AValue: TLoadPackageResult);
begin
if FLoadPackageResult=AValue then exit;
FLoadPackageResult:=AValue;
end;
procedure TPkgDependency.SetMaxVersion(const AValue: TPkgVersion);
begin
if FMaxVersion=AValue then exit;
FMaxVersion:=AValue;
end;
procedure TPkgDependency.SetMinVersion(const AValue: TPkgVersion);
begin
if FMinVersion=AValue then exit;
FMinVersion:=AValue;
end;
procedure TPkgDependency.SetPackageName(const AValue: string);
begin
if FPackageName=AValue then exit;
if (PackageDependencies<>nil) and (FPackageName<>'') then
AVLRemovePointer(PackageDependencies,Self);
FPackageName:=AValue;
if (PackageDependencies<>nil) and (FPackageName<>'') then
PackageDependencies.Add(Self);
FDefaultFilename:='';
end;
procedure TPkgDependency.SetRemoved(const AValue: boolean);
begin
if FRemoved=AValue then exit;
FRemoved:=AValue;
end;
procedure TPkgDependency.SetRequiredPackage(const AValue: TLazPackage);
begin
if FRequiredPackage=AValue then exit;
if FRequiredPackage<>nil then
FRequiredPackage.RemoveUsedByDependency(Self);
fLoadPackageResult:=lprUndefined;
FRequiredPackage:=AValue;
if FRequiredPackage<>nil then
FRequiredPackage.AddUsedByDependency(Self);
end;
constructor TPkgDependency.Create;
begin
MinVersion:=TPkgVersion.Create;
MaxVersion:=TPkgVersion.Create;
Clear;
end;
destructor TPkgDependency.Destroy;
begin
RequiredPackage:=nil;
PackageName:='';
FreeAndNil(fMinVersion);
FreeAndNil(fMaxVersion);
inherited Destroy;
end;
procedure TPkgDependency.Clear;
begin
RequiredPackage:=nil;
PackageName:='';
FRemoved:=false;
FFlags:=[];
FMaxVersion.Clear;
FMinVersion.Clear;
FDefaultFilename:='';
FPreferDefaultFilename:=false;
end;
procedure TPkgDependency.LoadFromXMLConfig(XMLConfig: TXMLConfig;
const Path: string; FileVersion: integer);
function LoadFilename(const SubPath: string): string;
var
BaseDir: String;
begin
Result:=SetDirSeparators(XMLConfig.GetValue(Path+SubPath,''));
if (Result<>'') and (Owner<>nil)
and (not FilenameIsAbsolute(Result)) then begin
BaseDir:=GetDependencyOwnerDirectory(Self);
if BaseDir<>'' then
Result:=TrimFilename(AppendPathDelim(BaseDir)+Result);
end;
end;
begin
if FileVersion=1 then ;
Clear;
PackageName:=XMLConfig.GetValue(Path+'PackageName/Value','');
PkgVersionLoadFromXMLConfig(MaxVersion,XMLConfig,Path+'MaxVersion/',FileVersion);
PkgVersionLoadFromXMLConfig(MinVersion,XMLConfig,Path+'MinVersion/',FileVersion);
if XMLConfig.GetValue(Path+'MaxVersion/Valid',false) then
Include(FFlags,pdfMaxVersion);
if XMLConfig.GetValue(Path+'MinVersion/Valid',false) then
Include(FFlags,pdfMinVersion);
FDefaultFilename:=LoadFilename('DefaultFilename/Value');
PreferDefaultFilename:=XMLConfig.GetValue(Path+'DefaultFilename/Prefer',false);
end;
procedure TPkgDependency.SaveToXMLConfig(XMLConfig: TXMLConfig;
const Path: string; UsePathDelim: TPathDelimSwitch);
procedure SaveFilename(const aPath: string; AFilename: string);
var
BaseDir: String;
begin
if (AFilename<>'')
and (Owner<>nil) then begin
BaseDir:=GetDependencyOwnerDirectory(Self);
if BaseDir<>'' then
AFilename:=CreateRelativePath(AFilename,BaseDir);
end;
XMLConfig.SetDeleteValue(Path+aPath,SwitchPathDelims(AFilename,UsePathDelim),'');
end;
begin
XMLConfig.SetDeleteValue(Path+'PackageName/Value',PackageName,'');
PkgVersionSaveToXMLConfig(MaxVersion,XMLConfig,Path+'MaxVersion/');
PkgVersionSaveToXMLConfig(MinVersion,XMLConfig,Path+'MinVersion/');
XMLConfig.SetDeleteValue(Path+'MaxVersion/Valid',pdfMaxVersion in FFlags,false);
XMLConfig.SetDeleteValue(Path+'MinVersion/Valid',pdfMinVersion in FFlags,false);
SaveFilename('DefaultFilename/Value',FDefaultFilename);
XMLConfig.SetDeleteValue(Path+'DefaultFilename/Prefer',PreferDefaultFilename,false);
end;
function TPkgDependency.MakeSense: boolean;
begin
Result:=IsValidUnitName(PackageName);
if Result
and (pdfMinVersion in FFlags) and (pdfMaxVersion in FFlags)
and (MinVersion.Compare(MaxVersion)>0) then
Result:=false;
end;
function TPkgDependency.IsCompatible(const Version: TPkgVersion): boolean;
begin
if ((pdfMinVersion in FFlags) and (MinVersion.Compare(Version)>0))
or ((pdfMaxVersion in FFlags) and (MaxVersion.Compare(Version)<0)) then
Result:=false
else
Result:=true;
end;
function TPkgDependency.IsCompatible(const PkgName: string;
const Version: TPkgVersion): boolean;
begin
Result:=(SysUtils.CompareText(PkgName,PackageName)=0) and IsCompatible(Version);
end;
function TPkgDependency.Compare(Dependency2: TPkgDependency): integer;
begin
Result:=SysUtils.CompareText(PackageName,Dependency2.PackageName);
if Result<>0 then exit;
Result:=MinVersion.Compare(Dependency2.MinVersion);
if Result<>0 then exit;
Result:=CompareBoolean(pdfMinVersion in Flags,
pdfMinVersion in Dependency2.Flags);
if Result<>0 then exit;
Result:=MaxVersion.Compare(Dependency2.MaxVersion);
if Result<>0 then exit;
Result:=CompareBoolean(pdfMaxVersion in Flags,
pdfMaxVersion in Dependency2.Flags);
end;
procedure TPkgDependency.Assign(Source: TPkgDependency);
begin
PackageName:=Source.PackageName;
Flags:=Source.Flags;
MinVersion.Assign(Source.MinVersion);
MaxVersion.Assign(Source.MaxVersion);
end;
procedure TPkgDependency.Assign(Source: TLazPackageID);
begin
PackageName:=Source.Name;
Flags:=[pdfMinVersion];
MinVersion.Assign(Source.Version);
end;
procedure TPkgDependency.ConsistencyCheck;
begin
end;
function TPkgDependency.IsCompatible(Pkg: TLazPackageID): boolean;
begin
Result:=IsCompatible(Pkg.Name,Pkg.Version);
end;
procedure TPkgDependency.MakeCompatible(const PkgName: string;
const Version: TPkgVersion);
begin
PackageName:=PkgName;
if MinVersion.Compare(Version)>0 then MinVersion.Assign(Version);
if MaxVersion.Compare(Version)<0 then MaxVersion.Assign(Version);
end;
function TPkgDependency.AsString(WithOwner: boolean): string;
begin
if Self=nil then
exit('(nil)');
Result:=FPackageName;
if pdfMinVersion in FFlags then
Result:=Result+' (>='+MinVersion.AsString+')';
if pdfMaxVersion in FFlags then
Result:=Result+' (<='+MaxVersion.AsString+')';
if WithOwner and (Owner<>nil) then
Result:=GetDependencyOwnerAsString(Self)+' uses '+Result;
end;
function TPkgDependency.NextUsedByDependency: TPkgDependency;
begin
Result:=NextDependency[pdlUsedBy];
end;
function TPkgDependency.PrevUsedByDependency: TPkgDependency;
begin
Result:=PrevDependency[pdlUsedBy];
end;
function TPkgDependency.NextRequiresDependency: TPkgDependency;
begin
Result:=NextDependency[pdlRequires];
end;
function TPkgDependency.PrevRequiresDependency: TPkgDependency;
begin
Result:=PrevDependency[pdlRequires];
end;
procedure TPkgDependency.AddToList(var FirstDependency: TPkgDependency;
ListType: TPkgDependencyList);
begin
NextDependency[ListType]:=FirstDependency;
FirstDependency:=Self;
PrevDependency[ListType]:=nil;
if NextDependency[ListType]<>nil then
NextDependency[ListType].PrevDependency[ListType]:=Self;
end;
procedure TPkgDependency.AddToEndOfList(var LastDependency: TPkgDependency;
ListType: TPkgDependencyList);
begin
PrevDependency[ListType]:=LastDependency;
LastDependency:=Self;
NextDependency[ListType]:=nil;
if PrevDependency[ListType]<>nil then
PrevDependency[ListType].NextDependency[ListType]:=Self;
end;
procedure TPkgDependency.RemoveFromList(var FirstDependency: TPkgDependency;
ListType: TPkgDependencyList);
begin
if FirstDependency=Self then FirstDependency:=NextDependency[ListType];
if NextDependency[ListType]<>nil then
NextDependency[ListType].PrevDependency[ListType]:=PrevDependency[ListType];
if PrevDependency[ListType]<>nil then
PrevDependency[ListType].NextDependency[ListType]:=NextDependency[ListType];
NextDependency[ListType]:=nil;
PrevDependency[ListType]:=nil;
end;
procedure TPkgDependency.MoveUpInList(var FirstDependency: TPkgDependency;
ListType: TPkgDependencyList);
var
OldPrev: TPkgDependency;
begin
if (FirstDependency=Self) or (PrevDependency[ListType]=nil) then exit;
OldPrev:=PrevDependency[ListType];
if OldPrev.PrevDependency[ListType]<>nil then
OldPrev.PrevDependency[ListType].NextDependency[ListType]:=Self;
if NextDependency[ListType]<>nil then
NextDependency[ListType].PrevDependency[ListType]:=OldPrev;
OldPrev.NextDependency[ListType]:=NextDependency[ListType];
PrevDependency[ListType]:=OldPrev.PrevDependency[ListType];
NextDependency[ListType]:=OldPrev;
OldPrev.PrevDependency[ListType]:=Self;
if FirstDependency=OldPrev then FirstDependency:=Self;
end;
procedure TPkgDependency.MoveDownInList(var FirstDependency: TPkgDependency;
ListType: TPkgDependencyList);
var
OldNext: TPkgDependency;
begin
if (NextDependency[ListType]=nil) then exit;
OldNext:=NextDependency[ListType];
if OldNext.NextDependency[ListType]<>nil then
OldNext.NextDependency[ListType].PrevDependency[ListType]:=Self;
if PrevDependency[ListType]<>nil then
PrevDependency[ListType].NextDependency[ListType]:=OldNext;
OldNext.PrevDependency[ListType]:=PrevDependency[ListType];
NextDependency[ListType]:=OldNext.NextDependency[ListType];
PrevDependency[ListType]:=OldNext;
OldNext.NextDependency[ListType]:=Self;
if FirstDependency=Self then FirstDependency:=OldNext;
end;
function TPkgDependency.MakeFilenameRelativeToOwner(const AFilename: string
): string;
var
BaseDir: String;
begin
Result:=AFilename;
if (Result<>'')
and (Owner<>nil) then begin
BaseDir:=GetDependencyOwnerDirectory(Self);
if BaseDir<>'' then
Result:=CreateRelativePath(Result,BaseDir);
end;
end;
function TPkgDependency.FindDefaultFilename: string;
var
AFilename: String;
CurDir: String;
begin
Result:='';
AFilename:=TrimFilename(DefaultFilename);
if (CompareFileExt(AFilename,'lpk')<>0)
or (SysUtils.CompareText(ExtractFileNameOnly(AFilename),PackageName)<>0)
then
exit;
if not FilenameIsAbsolute(AFilename) then begin
CurDir:=GetDependencyOwnerDirectory(Self);
if (CurDir<>'') then
AFilename:=AppendPathDelim(CurDir)+AFilename;
end;
if not FilenameIsAbsolute(AFilename) then exit;
AFilename:=FindDiskFileCaseInsensitive(AFilename);
if not FileExistsCached(AFilename) then exit;
Result:=AFilename;
end;
{ TLazPackage }
procedure TLazPackage.OnMacroListSubstitution(TheMacro: TTransferMacro;
const MacroName: string; var s: string; const Data: PtrInt;
var Handled, Abort: boolean; Depth: integer);
var
Values: TCTCfgScriptVariables;
Macro: PCTCfgScriptVariable;
var
NewValue: String;
begin
if Data=CompilerOptionMacroPlatformIndependent then
begin
NewValue:=GetMakefileMacroValue(MacroName);
if NewValue<>'' then begin
s:=NewValue;
Handled:=true;
exit;
end;
end;
// check build macros
if (MacroName<>'') and IsValidIdent(MacroName) then
begin
Values:=GetBuildMacroValues(CompilerOptions,true);
if Values<>nil then begin
Macro:=Values.GetVariable(PChar(MacroName));
if Macro<>nil then
begin
s:=GetCTCSVariableAsString(Macro);
//if MacroName='MyPackageOptions' then
// debugln(['TLazPackage.OnMacroListSubstitution Pkg=',Name,' Macro=',MacroName,' Value="',s,'"']);
Handled:=true;
exit;
end;
end;
end;
// check local macros
if SysUtils.CompareText(MacroName,'PkgOutDir')=0 then begin
Handled:=true;
if Data=CompilerOptionMacroNormal then
s:=CompilerOptions.ParsedOpts.GetParsedValue(pcosOutputDir)
else
s:=CompilerOptions.ParsedOpts.GetParsedPIValue(pcosOutputDir);
exit;
end
else if SysUtils.CompareText(MacroName,'PkgDir')=0 then begin
Handled:=true;
s:=FDirectory;
exit;
end
else if SysUtils.CompareText(MacroName,'PkgName')=0 then begin
Handled:=true;
s:=Name;
exit;
end;
// check global macros
GlobalMacroList.ExecuteMacro(MacroName,s,Data,Handled,Abort,Depth);
end;
procedure TLazPackage.SetUserReadOnly(const AValue: boolean);
begin
if FUserReadOnly=AValue then exit;
FUserReadOnly:=AValue;
end;
function TLazPackage.SubstitutePkgMacros(const s: string;
PlatformIndependent: boolean): string;
begin
Result:=s;
if PlatformIndependent then
FMacros.SubstituteStr(Result,CompilerOptionMacroPlatformIndependent)
else
FMacros.SubstituteStr(Result,CompilerOptionMacroNormal);
end;
procedure TLazPackage.WriteInheritedUnparsedOptions;
var
OptionsList: TFPList;
AddOptions: TAdditionalCompilerOptions;
i: Integer;
begin
OptionsList:=nil;
CompilerOptions.GetInheritedCompilerOptions(OptionsList);
if OptionsList<>nil then begin
for i:=0 to OptionsList.Count-1 do begin
AddOptions:=TAdditionalCompilerOptions(OptionsList[i]);
if (not (AddOptions is TAdditionalCompilerOptions)) then continue;
DebugLn('TLazPackage.WriteInheritedUnparsedOptions ',
(AddOptions.Owner as TLazPackage).IDAsString,
' UnitPath="',AddOptions.GetOption(icoUnitPath),'"');
end;
OptionsList.Free;
end;
end;
function TLazPackage.GetAutoIncrementVersionOnBuild: boolean;
begin
Result:=lpfAutoIncrementVersionOnBuild in FFlags;
end;
function TLazPackage.GetComponentCount: integer;
begin
Result:=FComponents.Count;
end;
function TLazPackage.GetComponents(Index: integer): TPkgComponent;
begin
Result:=TPkgComponent(FComponents[Index]);
end;
function TLazPackage.GetDirectoryExpanded: string;
begin
if (FDirectoryExpandedChangeStamp<>CompilerParseStamp) then begin
FDirectoryExpanded:=FDirectory;
// use default macros (not package macros)
if IDEMacros<>nil then
IDEMacros.SubstituteMacros(FDirectoryExpanded);
FDirectoryExpanded:=AppendPathDelim(TrimFilename(FDirectoryExpanded));
FDirectoryExpandedChangeStamp:=CompilerParseStamp;
end;
Result:=FDirectoryExpanded;
end;
function TLazPackage.GetRemovedCount: integer;
begin
Result:=FRemovedFiles.Count;
end;
function TLazPackage.GetRemovedPkgFiles(Index: integer): TLazPackageFile;
begin
Result:=GetRemovedFiles(Index);
end;
procedure TLazPackage.AssignOptions(Source: TPersistent);
var
aSource: TLazPackage;
begin
inherited AssignOptions(Source);
if Source is TLazPackage then
begin
aSource:=TLazPackage(Source);
UserReadOnly:=aSource.UserReadOnly;
Translated:=aSource.Translated;
StorePathDelim:=aSource.StorePathDelim;
// ToDo: PublishOptions.AssignOptions(aSource.PublishOptions);
Provides.Assign(aSource.Provides);
POOutputDirectory:=aSource.POOutputDirectory;
PackageType:=aSource.PackageType;
OutputStateFile:=aSource.OutputStateFile;
License:=aSource.License;
FPDocPaths:=aSource.FPDocPaths;
FPDocPackageName:=aSource.FPDocPackageName;
IconFile:=aSource.IconFile;
UsageOptions.AssignOptions(aSource.UsageOptions);
EnableI18N:=aSource.EnableI18N;
EnableI18NForLFM:=aSource.EnableI18NForLFM;
Description:=aSource.Description;
AutoUpdate:=aSource.AutoUpdate;
AutoIncrementVersionOnBuild:=aSource.AutoIncrementVersionOnBuild;
Author:=aSource.Author;
AddToProjectUsesSection:=aSource.AddToProjectUsesSection;
end;
end;
function TLazPackage.GetRemovedFiles(Index: integer): TPkgFile;
begin
Result:=TPkgFile(FRemovedFiles[Index]);
end;
function TLazPackage.GetFileCount: integer;
begin
Result:=FFiles.Count;
end;
function TLazPackage.GetPkgFiles(Index: integer): TLazPackageFile;
begin
Result:=GetFiles(Index);
end;
function TLazPackage.GetFiles(Index: integer): TPkgFile;
begin
Result:=TPkgFile(FFiles[Index]);
end;
function TLazPackage.GetModified: boolean;
begin
Result:=(lpfModified in FFlags) or CompilerOptions.Modified;
end;
procedure TLazPackage.SetAddToProjectUsesSection(const AValue: boolean);
begin
if FAddToProjectUsesSection=AValue then exit;
FAddToProjectUsesSection:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetAuthor(const AValue: string);
begin
if FAuthor=AValue then exit;
FAuthor:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetAutoCreated(const AValue: boolean);
begin
if FAutoCreated=AValue then exit;
FAutoCreated:=AValue;
if AutoCreated then UserReadOnly:=true;
end;
procedure TLazPackage.SetAutoIncrementVersionOnBuild(const AValue: boolean);
begin
if AutoIncrementVersionOnBuild=AValue then exit;
if AValue then
Include(FFlags,lpfAutoIncrementVersionOnBuild)
else
Exclude(FFlags,lpfAutoIncrementVersionOnBuild);
Modified:=true;
end;
procedure TLazPackage.SetAutoInstall(AValue: TPackageInstallType);
begin
if FAutoInstall=AValue then exit;
FAutoInstall:=AValue;
if AutoCreated and (FAutoInstall<>pitStatic) then
DumpStack;
end;
procedure TLazPackage.SetAutoUpdate(const AValue: TPackageUpdatePolicy);
begin
if AValue=AutoUpdate then exit;
FAutoUpdate:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetDescription(const AValue: string);
begin
if FDescription=AValue then exit;
FDescription:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetEnableI18NForLFM(AValue: boolean);
begin
if FEnableI18NForLFM=AValue then Exit;
FEnableI18NForLFM:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetFileReadOnly(const AValue: boolean);
begin
if FFileReadOnly=AValue then exit;
FFileReadOnly:=AValue;
end;
procedure TLazPackage.SetFilename(const AValue: string);
var
NewFilename: String;
begin
NewFilename:=AValue;
DoDirSeparators(NewFilename);
if FFilename=NewFilename then exit;
FFilename:=NewFilename;
if (FFilename<>'') and (FFilename[length(FFilename)]=PathDelim) then
FDirectory:=FFilename
else
FDirectory:=ExtractFilePath(FFilename);
FDirectoryExpandedChangeStamp:=CTInvalidChangeStamp;
FHasDirectory:=(FDirectory<>'') and (FDirectory[length(FDirectory)]=PathDelim);
FHasStaticDirectory:=FHasDirectory and FilenameIsAbsolute(FDirectory);
FUsageOptions.BaseDirectory:=FDirectory;
FCompilerOptions.BaseDirectory:=FDirectory;
Modified:=true;
end;
procedure TLazPackage.SetFlags(const AValue: TLazPackageFlags);
var
ChangedFlags: TLazPackageFlags;
begin
if FFlags=AValue then exit;
ChangedFlags:=FFlags+AValue-(FFlags*AValue);
FFlags:=AValue;
if ChangedFlags*[lpfAutoIncrementVersionOnBuild]<>[] then
Modified:=true;
end;
procedure TLazPackage.SetFPDocPackageName(AValue: string);
begin
if FFPDocPackageName=AValue then Exit;
FFPDocPackageName:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetIconFile(const AValue: string);
begin
if FIconFile=AValue then exit;
FIconFile:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetInstalled(const AValue: TPackageInstallType);
begin
if FInstalled=AValue then exit;
FInstalled:=AValue;
end;
procedure TLazPackage.SetFPDocPaths(const AValue: string);
var
NewValue: String;
begin
NewValue:=TrimSearchPath(AValue,'');
if FFPDocPaths=NewValue then exit;
FFPDocPaths:=NewValue;
Modified:=true;
end;
procedure TLazPackage.SetLicense(const AValue: string);
begin
if FLicense=AValue then exit;
FLicense:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetLPKSource(const AValue: TCodeBuffer);
begin
if FLPKSource=AValue then exit;
FLPKSource:=AValue;
if FLPKSource<>nil then
FLPKSourceChangeStep:=FLPKSource.ChangeStep;
// do not change Filename here.
// See TPkgManager.DoSavePackage and TPkgManager.DoOpenPackageFile
// the LPKSource is the codebuffer last used during load/save, so it is not valid
// for packages that were not yet loaded/saved or during renaming/loading/saving.
end;
procedure TLazPackage.SetLPKSourceChangeStep(const AValue: integer);
begin
if FLPKSourceChangeStep=AValue then exit;
FLPKSourceChangeStep:=AValue;
end;
procedure TLazPackage.SetOutputStateFile(const AValue: string);
var
NewStateFile: String;
begin
NewStateFile:=TrimFilename(AValue);
if FOutputStateFile=NewStateFile then exit;
FOutputStateFile:=NewStateFile;
end;
procedure TLazPackage.SetProvides(const AValue: TStrings);
begin
if (AValue=FProvides) or (FProvides.Equals(AValue)) then exit;
FProvides.Assign(AValue);
Modified:=true;
end;
procedure TLazPackage.SetPOOutputDirectory(const AValue: string);
var
NewValue: String;
begin
NewValue:=TrimFilename(AValue);
if FPOOutputDirectory=NewValue then exit;
FPOOutputDirectory:=NewValue;
Modified:=true;
end;
procedure TLazPackage.SetEnableI18N(const AValue: boolean);
begin
if FEnableI18N=AValue then exit;
FEnableI18N:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetRegistered(const AValue: boolean);
begin
if FRegistered=AValue then exit;
FRegistered:=AValue;
end;
procedure TLazPackage.SetModified(const AValue: boolean);
var
OldModified: Boolean;
begin
OldModified:=Modified;
if AValue and (FModifiedLock>0) then exit;
if AValue then begin
Include(FFlags,lpfModified);
if FChangeStamp<High(FChangeStamp) then
inc(FChangeStamp)
else
FChangeStamp:=low(FChangeStamp);
end else
Exclude(FFlags,lpfModified);
Exclude(FFlags,lpfSkipSaving);
if not AValue then
begin
PublishOptions.Modified:=false;
CompilerOptions.Modified:=false;
end;
if (OldModified<>Modified) and (Editor<>nil) then
Editor.UpdateAll(false);
end;
procedure TLazPackage.SetName(const AValue: string);
begin
if FName=AValue then exit;
inherited SetName(AValue);
FDefineTemplates.PackageIDChanged;
Modified:=true;
end;
procedure TLazPackage.SetPackageEditor(const AValue: TBasePackageEditor);
begin
if FPackageEditor=AValue then exit;
FPackageEditor:=AValue;
end;
procedure TLazPackage.SetPackageType(const AValue: TLazPackageType);
begin
if FPackageType=AValue then exit;
FPackageType:=AValue;
Modified:=true;
end;
procedure TLazPackage.SetStorePathDelim(const AValue: TPathDelimSwitch);
begin
if FStorePathDelim=AValue then exit;
FStorePathDelim:=AValue;
end;
constructor TLazPackage.Create;
begin
inherited Create;
FComponents:=TFPList.Create;
FSourceDirectories:=TFileReferenceList.Create;
FSourceDirectories.OnChanged:=@SourceDirectoriesChanged;
FFiles:=TFPList.Create;
FRemovedFiles:=TFPList.Create;
FMacros:=TTransferMacroList.Create;
FMacros.OnSubstitution:=@OnMacroListSubstitution;
FCompilerOptions:=TPkgCompilerOptions.Create(Self);
FLazCompilerOptions:=FCompilerOptions;
FCompilerOptions.ParsedOpts.InvalidateParseOnChange:=true;
FCompilerOptions.ParsedOpts.OnLocalSubstitute:=@SubstitutePkgMacros;
FCompilerOptions.DefaultMakeOptionsFlags:=[ccloNoLinkerOpts];
FUsageOptions:=TPkgAdditionalCompilerOptions.Create(Self);
FUsageOptions.ParsedOpts.OnLocalSubstitute:=@SubstitutePkgMacros;
FDefineTemplates:=TLazPackageDefineTemplates.Create(Self);
fPublishOptions:=TPublishPackageOptions.Create(Self);
FProvides:=TStringList.Create;
Clear;
FUsageOptions.ParsedOpts.InvalidateParseOnChange:=true;
end;
destructor TLazPackage.Destroy;
begin
Include(FFlags,lpfDestroying);
Clear;
FreeAndNil(FOptionsBackup);
FreeAndNil(fPublishOptions);
FreeAndNil(FProvides);
FreeAndNil(FDefineTemplates);
FreeAndNil(FRemovedFiles);
FreeAndNil(FFiles);
FreeAndNil(FComponents);
FreeAndNil(FCompilerOptions);
FreeAndNil(FUsageOptions);
FreeAndNil(FMacros);
FreeAndNil(FSourceDirectories);
inherited Destroy;
end;
class function TLazPackage.GetGroupCaption: string;
begin
Result := lisPckOptsPackageOptions;
end;
class function TLazPackage.GetInstance: TAbstractIDEOptions;
begin
Result := Package1;
end;
procedure TLazPackage.BackupOptions;
begin
if FOptionsBackup=nil then
FOptionsBackup:=TLazPackage.Create;
FOptionsBackup.AssignOptions(Self);
FOptionsBackup.FFlags:=FOptionsBackup.FFlags-[lpfModified]+[lpfModified]*FFlags;
FOptionsBackup.CompilerOptions.Modified:=CompilerOptions.Modified;
end;
procedure TLazPackage.RestoreOptions;
begin
if FOptionsBackup=nil then exit;
AssignOptions(FOptionsBackup);
FFlags:=FFlags-[lpfModified]+[lpfModified]*FOptionsBackup.FFlags;
CompilerOptions.Modified:=FOptionsBackup.CompilerOptions.Modified;
end;
procedure TLazPackage.BeginUpdate;
begin
inc(FUpdateLock);
FDefineTemplates.BeginUpdate;
FSourceDirectories.BeginUpdate;
end;
procedure TLazPackage.EndUpdate;
begin
if FUpdateLock=0 then RaiseException('TLazPackage.EndUpdate');
dec(FUpdateLock);
FDefineTemplates.EndUpdate;
FSourceDirectories.EndUpdate;
end;
procedure TLazPackage.Clear;
var
i: Integer;
begin
// break used-by dependencies
while FFirstUsedByDependency<>nil do
FFirstUsedByDependency.RequiredPackage:=nil;
// break and free removed dependencies
while FFirstRemovedDependency<>nil do
DeleteRemovedDependency(FFirstRemovedDependency);
// break and free required dependencies
while FFirstRequiredDependency<>nil do
DeleteRequiredDependency(FFirstRequiredDependency);
if not (lpfDestroying in FFlags) then begin
FAddToProjectUsesSection:=false;
FAuthor:='';
FAutoInstall:=pitNope;
FComponents.Clear;
FCompilerOptions.Clear;
FDescription:='';
FDirectory:='';
FDirectoryExpandedChangeStamp:=CTInvalidChangeStamp;
FEnableI18N:=false;
FEnableI18NForLFM:=false;
FPOOutputDirectory:='';
FHasDirectory:=false;
FHasStaticDirectory:=false;
FVersion.Clear;
FFilename:='';
FIconFile:='';
FInstalled:=pitNope;
FName:='';
FPackageType:=lptRunAndDesignTime;
FRegistered:=false;
FFPDocPaths:='';
FFPDocPackageName:='';
ClearCustomOptions;
end;
for i:=FComponents.Count-1 downto 0 do Components[i].Free;
for i:=FRemovedFiles.Count-1 downto 0 do RemovedFiles[i].Free;
FRemovedFiles.Clear;
for i:=FFiles.Count-1 downto 0 do Files[i].Free;
FFiles.Clear;
FUsageOptions.Clear;
fPublishOptions.Clear;
FProvides.Clear;
UpdateSourceDirectories;
// set some nice start values
if not (lpfDestroying in FFlags) then begin
FFlags:=[lpfAutoIncrementVersionOnBuild];
FAutoUpdate:=pupAsNeeded;
fCompilerOptions.UnitOutputDirectory:=
'lib'+PathDelim+'$(TargetCPU)-$(TargetOS)'+PathDelim;
FUsageOptions.UnitPath:='$(PkgOutDir)';
end else begin
FFlags:=[lpfDestroying];
end;
FStorePathDelim:=pdsNone;
end;
//function DbgS(PkgFileType: TPkgFileType): string;
//begin
// WriteStr(Result, PkgFileType);
//end;
procedure TLazPackage.UpdateSourceDirectories;
var
Cnt: Integer;
i: Integer;
PkgFile: TPkgFile;
begin
Cnt:=FFiles.Count;
for i:=0 to Cnt-1 do begin
PkgFile:=Files[i];
PkgFile.FSourceDirectoryReferenced:=false;
end;
fSourceDirectories.Clear;
for i:=0 to Cnt-1 do begin
PkgFile:=Files[i];
PkgFile.AutoReferenceSourceDir:=true;
PkgFile.UpdateSourceDirectoryReference;
//debugln('TLazPackage.UpdateSourceDirectories A ',PkgFile.Filename,' ',
// ' ',DbgS(PkgFile.FileType),' ',PkgFile.Removed,
// ' HasPkg=',dbgs(PkgFile.LazPackage=Self),
// ' Need=',PkgFile.FSourceDirNeedReference,
// ' Is=',PkgFile.FSourceDirectoryReferenced);
end;
//debugln('TLazPackage.UpdateSourceDirectories B ',IDAsString,' ',FFiles.Count,' "',fSourceDirectories.CreateSearchPathFromAllFiles,'"');
end;
procedure TLazPackage.VersionChanged(Sender: TObject);
begin
inherited VersionChanged(Sender);
FDefineTemplates.PackageIDChanged;
Modified:=true;
end;
procedure TLazPackage.SourceDirectoriesChanged(Sender: TObject);
begin
FDefineTemplates.SourceDirectoriesChanged;
end;
procedure TLazPackage.LockModified;
begin
inc(FModifiedLock);
end;
procedure TLazPackage.UnlockModified;
begin
if FModifiedLock<=0 then
RaiseException('TLazPackage.UnlockModified');
dec(FModifiedLock);
end;
function TLazPackage.ReadOnly: boolean;
begin
Result:=UserReadOnly or FileReadOnly;
end;
procedure TLazPackage.LoadFromXMLConfig(XMLConfig: TXMLConfig;
const Path: string);
var
FileVersion: integer;
OldFilename: String;
PathDelimChanged: boolean;
Config: TXMLOptionsStorage;
procedure LoadFiles(const ThePath: string; List: TFPList);
var
i: Integer;
NewCount: Integer;
PkgFile: TPkgFile;
begin
NewCount:=XMLConfig.GetValue(ThePath+'Count',0);
for i:=0 to NewCount-1 do begin
PkgFile:=TPkgFile.Create(Self);
PkgFile.LoadFromXMLConfig(XMLConfig,ThePath+'Item'+IntToStr(i+1)+'/',
FileVersion,PathDelimChanged);
if PkgFile.MakeSense then
List.Add(PkgFile)
else
PkgFile.Free;
end;
end;
procedure LoadFlags(const ThePath: string);
begin
if XMLConfig.GetValue(ThePath+'AutoIncrementVersionOnBuild/Value',true) then
Include(FFlags,lpfAutoIncrementVersionOnBuild)
else
Exclude(FFlags,lpfAutoIncrementVersionOnBuild);
end;
begin
Flags:=Flags+[lpfLoading];
FileVersion:=XMLConfig.GetValue(Path+'Version',0);
OldFilename:=Filename;
BeginUpdate;
Clear;
Filename:=OldFilename;
LockModified;
StorePathDelim:=CheckPathDelim(XMLConfig.GetValue(Path+'PathDelim/Value','/'),PathDelimChanged);
Name:=XMLConfig.GetValue(Path+'Name/Value','');
FPackageType:=LazPackageTypeIdentToType(XMLConfig.GetValue(Path+'Type/Value',
LazPackageTypeIdents[lptRunTime]));
FAddToProjectUsesSection:=XMLConfig.GetValue(Path+'AddToProjectUsesSection/Value',
FileVersion<4); // since version 4 the default is false
FAuthor:=XMLConfig.GetValue(Path+'Author/Value','');
FAutoUpdate:=NameToAutoUpdatePolicy(
XMLConfig.GetValue(Path+'AutoUpdate/Value',''));
FDescription:=XMLConfig.GetValue(Path+'Description/Value','');
FLicense:=XMLConfig.GetValue(Path+'License/Value','');
PkgVersionLoadFromXMLConfig(FVersion,XMLConfig,Path+'Version/',FileVersion);
FIconFile:=SwitchPathDelims(XMLConfig.GetValue(Path+'IconFile/Value',''),
PathDelimChanged);
OutputStateFile:=SwitchPathDelims(
XMLConfig.GetValue(Path+'OutputStateFile/Value',''),
PathDelimChanged);
FFPDocPaths:=SwitchPathDelims(XMLConfig.GetValue(Path+'LazDoc/Paths',''),
PathDelimChanged);
FFPDocPackageName:=XMLConfig.GetValue(Path+'LazDoc/PackageName','');
// i18n
if FileVersion<3 then begin
FPOOutputDirectory := SwitchPathDelims(
xmlconfig.GetValue(Path+'RST/OutDir', ''),PathDelimChanged);
EnableI18N := FPOOutputDirectory <> '';
end else begin
EnableI18N := xmlconfig.GetValue(Path+'i18n/EnableI18N/Value', False);
FPOOutputDirectory := SwitchPathDelims(
xmlconfig.GetValue(Path+'i18n/OutDir/Value', ''),PathDelimChanged);
end;
EnableI18NForLFM:=xmlconfig.GetValue(Path+'i18n/EnableI18NForLFM/Value', false);
LoadFiles(Path+'Files/',FFiles);
UpdateSourceDirectories;
LoadFlags(Path);
LoadPkgDependencyList(XMLConfig,Path+'RequiredPkgs/',
FFirstRequiredDependency,pdlRequires,Self,false,false);
if FileVersion<2 then
FCompilerOptions.LoadFromXMLConfig(XMLConfig,'CompilerOptions/')
else
FCompilerOptions.LoadFromXMLConfig(XMLConfig,Path+'CompilerOptions/');
FUsageOptions.LoadFromXMLConfig(XMLConfig,Path+'UsageOptions/',
PathDelimChanged);
fPublishOptions.LoadFromXMLConfig(XMLConfig,Path+'PublishOptions/',
PathDelimChanged);
LoadStringList(XMLConfig,FProvides,Path+'Provides/');
Config:=TXMLOptionsStorage.Create(XMLConfig);
try
TConfigMemStorage(CustomOptions).LoadFromConfig(Config,Path+'CustomOptions/');
finally
Config.Free;
end;
EndUpdate;
Modified:=false;
UnlockModified;
Flags:=Flags-[lpfLoading];
end;
procedure TLazPackage.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string);
var
UsePathDelim: TPathDelimSwitch;
Config: TXMLOptionsStorage;
function f(const AFilename: string): string;
begin
Result:=SwitchPathDelims(AFilename,UsePathDelim);
end;
procedure SaveFiles(const ThePath: string; List: TFPList);
var
i: Integer;
PkgFile: TPkgFile;
begin
XMLConfig.SetDeleteValue(ThePath+'Count',List.Count,0);
for i:=0 to List.Count-1 do begin
PkgFile:=TPkgFile(List[i]);
PkgFile.SaveToXMLConfig(XMLConfig,ThePath+'Item'+IntToStr(i+1)+'/',UsePathDelim);
end;
end;
procedure SaveFlags(const ThePath: string);
begin
XMLConfig.SetDeleteValue(ThePath+'AutoIncrementVersionOnBuild/Value',
AutoIncrementVersionOnBuild,true);
end;
begin
UsePathDelim:=StorePathDelim;
XMLConfig.SetValue(Path+'Version',LazPkgXMLFileVersion);
XMLConfig.SetDeleteValue(Path+'PathDelim/Value',PathDelimSwitchToDelim[UsePathDelim],'/');
XMLConfig.SetDeleteValue(Path+'Name/Value',FName,'');
XMLConfig.SetDeleteValue(Path+'AddToProjectUsesSection/Value',
FAddToProjectUsesSection,false);
XMLConfig.SetDeleteValue(Path+'Author/Value',FAuthor,'');
XMLConfig.SetDeleteValue(Path+'AutoUpdate/Value',AutoUpdateNames[FAutoUpdate],
AutoUpdateNames[pupAsNeeded]);
FCompilerOptions.SaveToXMLConfig(XMLConfig,Path+'CompilerOptions/');
XMLConfig.SetDeleteValue(Path+'Description/Value',FDescription,'');
XMLConfig.SetDeleteValue(Path+'License/Value',FLicense,'');
PkgVersionSaveToXMLConfig(FVersion,XMLConfig,Path+'Version/');
SaveFiles(Path+'Files/',FFiles);
SaveFlags(Path);
XMLConfig.SetDeleteValue(Path+'IconFile/Value',f(FIconFile),'');
XMLConfig.SetDeleteValue(Path+'Name/Value',FName,'');
XMLConfig.SetDeleteValue(Path+'OutputStateFile/Value',f(OutputStateFile),'');
XMLConfig.SetDeleteValue(Path+'LazDoc/Paths',f(FFPDocPaths),'');
XMLConfig.SetDeleteValue(Path+'LazDoc/PackageName',FFPDocPackageName,'');
XMLConfig.SetDeleteValue(Path+'i18n/EnableI18N/Value', EnableI18N, false);
XMLConfig.SetDeleteValue(Path+'i18n/OutDir/Value',f(FPOOutputDirectory), '');
XMLConfig.SetDeleteValue(Path+'i18n/EnableI18NForLFM/Value', EnableI18NForLFM, false);
XMLConfig.SetDeleteValue(Path+'Type/Value',LazPackageTypeIdents[FPackageType],
LazPackageTypeIdents[lptRunTime]);
SavePkgDependencyList(XMLConfig,Path+'RequiredPkgs/',
FFirstRequiredDependency,pdlRequires,UsePathDelim);
FUsageOptions.SaveToXMLConfig(XMLConfig,Path+'UsageOptions/',UsePathDelim);
fPublishOptions.SaveToXMLConfig(XMLConfig,Path+'PublishOptions/',UsePathDelim);
SaveStringList(XMLConfig,FProvides,Path+'Provides/');
Config:=TXMLOptionsStorage.Create(XMLConfig);
try
TConfigMemStorage(CustomOptions).SaveToConfig(Config,Path+'CustomOptions/');
finally
Config.Free;
end;
Modified:=false;
end;
procedure TLazPackage.SaveToString(out s: string);
var
XMLConfig: TXMLConfig;
ms: TMemoryStream;
begin
s:='';
XMLConfig:=TXMLConfig.Create(nil);
ms:=TMemoryStream.Create;
try
XMLConfig.Clear;
SaveToXMLConfig(XMLConfig,'Package/');
XMLConfig.WriteToStream(ms);
ms.Position:=0;
SetLength(s,ms.Size);
if s<>'' then
ms.Read(s[1],length(s));
finally
XMLConfig.Free;
ms.Free;
end;
end;
function TLazPackage.IsVirtual: boolean;
begin
Result:=not FilenameIsAbsolute(Filename);
end;
function TLazPackage.HasDirectory: boolean;
begin
Result:=FHasDirectory;
end;
function TLazPackage.HasStaticDirectory: boolean;
begin
Result:=FHasStaticDirectory;
end;
function TLazPackage.GetFullFilename(ResolveMacros: boolean): string;
begin
Result:=FFilename;
if ResolveMacros then
GlobalMacroList.SubstituteStr(Result);
end;
procedure TLazPackage.CheckInnerDependencies;
begin
// ToDo: make some checks like deactivating double requirements
end;
function TLazPackage.MakeSense: boolean;
begin
Result:=false;
if (Name='') or (not IsValidUnitName(Name)) then exit;
Result:=true;
end;
procedure TLazPackage.ShortenFilename(var ExpandedFilename: string; UseUp: boolean);
var
PkgDir: String;
CurPath: String;
begin
if (not HasDirectory) then exit;
PkgDir:=DirectoryExpanded;
if HasStaticDirectory and UseUp then
ExpandedFilename:=CreateRelativePath(ExpandedFilename,PkgDir)
else begin
CurPath:=copy(ExtractFilePath(ExpandedFilename),1,length(PkgDir));
if CompareFilenames(PkgDir,CurPath)=0 then begin
ExpandedFilename:=copy(ExpandedFilename,length(CurPath)+1,
length(ExpandedFilename)-length(CurPath));
end;
end;
end;
procedure TLazPackage.LongenFilename(var AFilename: string);
begin
if not HasDirectory then exit;
if not FilenameIsAbsolute(AFilename) then
AFilename:=TrimFilename(DirectoryExpanded+AFilename);
end;
function TLazPackage.GetResolvedFilename(ResolveMacros: boolean): string;
var
s: String;
begin
Result:=GetFullFilename(ResolveMacros);
s:=ReadAllLinks(Result,false);
if s<>'' then Result:=s;
end;
function TLazPackage.GetSourceDirs(WithPkgDir, WithoutOutputDir: boolean): string;
begin
Result:=SourceDirectories.CreateSearchPathFromAllFiles;
if WithPkgDir then
Result:=MergeSearchPaths(Result,Directory);
if WithoutOutputDir then
Result:=RemoveSearchPaths(Result,GetOutputDirectory);
end;
procedure TLazPackage.IterateComponentClasses(
Event: TIterateComponentClassesEvent;
WithUsedPackages: boolean);
var
Cnt: Integer;
i: Integer;
Dependency: TPkgDependency;
begin
// iterate through components in this package
Cnt:=ComponentCount;
for i:=0 to Cnt-1 do Event(Components[i]);
// iterate through all used/required packages
if WithUsedPackages then begin
Dependency:=FirstRequiredDependency;
while Dependency<>nil do begin
if Dependency.RequiredPackage<>nil then
Dependency.RequiredPackage.IterateComponentClasses(Event,false);
Dependency:=Dependency.NextRequiresDependency;
end;
end;
end;
procedure TLazPackage.SetAllComponentPriorities(const p: TComponentPriority);
var
i: Integer;
begin
//debugln(['TLazPackage.SetAllComponentPriorities ',Name,' ',dbgs(p), ' FileCount=',FileCount]);
for i:=0 to FileCount-1 do
Files[i].ComponentPriority:=p;
end;
procedure TLazPackage.ConsistencyCheck;
begin
CheckList(FRemovedFiles,true,true,true);
CheckList(FFiles,true,true,true);
CheckList(FComponents,true,true,true);
end;
function TLazPackage.IndexOfPkgComponent(PkgComponent: TPkgComponent): integer;
begin
Result:=FComponents.IndexOf(PkgComponent);
end;
function TLazPackage.FindPkgFile(const AFilename: string; IgnoreRemoved,
FindVirtualFile: boolean): TPkgFile;
var
TheFilename: String;
Cnt: Integer;
i: Integer;
begin
Result:=nil;
TheFilename:=AFilename;
Cnt:=FileCount;
for i:=0 to Cnt-1 do begin
Result:=Files[i];
if (not FindVirtualFile) and (not FilenameIsAbsolute(Result.Filename)) then
continue;
if (CompareFilenames(Result.Filename,TheFilename)=0)
or (CompareFilenames(Result.GetFullFilename,TheFilename)=0) then
exit;
end;
if not IgnoreRemoved then begin
Cnt:=RemovedFilesCount;
for i:=0 to Cnt-1 do begin
Result:=RemovedFiles[i];
if (not FindVirtualFile) and (not FilenameIsAbsolute(Result.Filename)) then
continue;
if (CompareFilenames(Result.Filename,TheFilename)=0)
or (CompareFilenames(Result.GetFullFilename,TheFilename)=0) then
exit;
end;
end;
Result:=nil;
end;
function TLazPackage.FindUnitWithRegister(IgnorePkgFile: TPkgFile): TPkgFile;
var
Cnt: LongInt;
i: Integer;
begin
Cnt:=FileCount;
for i:=0 to Cnt-1 do begin
Result:=Files[i];
if IgnorePkgFile=Result then continue;
if not (Result.FileType in PkgFileRealUnitTypes) then continue;
if Result.HasRegisterProc then exit;
end;
Result:=nil;
end;
function TLazPackage.FindUnit(const TheUnitName: string): TPkgFile;
begin
Result:=FindUnit(TheUnitName,true);
end;
function TLazPackage.FindUnit(const TheUnitName: string;
IgnoreRemoved: boolean): TPkgFile;
begin
Result:=FindUnit(TheUnitName,IgnoreRemoved,nil);
end;
function TLazPackage.FindUnit(const TheUnitName: string;
IgnoreRemoved: boolean; IgnorePkgFile: TPkgFile): TPkgFile;
var
Cnt: Integer;
i: Integer;
begin
if TheUnitName='' then exit(nil);
Cnt:=FileCount;
for i:=0 to Cnt-1 do begin
Result:=Files[i];
if IgnorePkgFile=Result then continue;
if SysUtils.CompareText(Result.Unit_Name,TheUnitName)=0 then exit;
end;
if not IgnoreRemoved then begin
Cnt:=RemovedFilesCount;
for i:=0 to Cnt-1 do begin
Result:=RemovedFiles[i];
if IgnorePkgFile=Result then continue;
if SysUtils.CompareText(Result.Unit_Name,TheUnitName)=0 then exit;
end;
end;
Result:=nil;
end;
function TLazPackage.FindRemovedPkgFile(const AFilename: string): TPkgFile;
var
Cnt: Integer;
i: Integer;
begin
Cnt:=RemovedFilesCount;
for i:=0 to Cnt-1 do begin
Result:=RemovedFiles[i];
if CompareFilenames(Result.Filename,AFilename)=0 then exit;
end;
Result:=nil;
end;
function TLazPackage.FindDependencyByName(const PkgName: string
): TPkgDependency;
begin
Result:=FindDependencyByNameInList(FFirstRequiredDependency,pdlRequires,
PkgName);
end;
function TLazPackage.RequiredDepByIndex(Index: integer): TPkgDependency;
begin
Result:=GetDependencyWithIndex(FFirstRequiredDependency,pdlRequires,Index);
end;
function TLazPackage.RemovedDepByIndex(Index: integer): TPkgDependency;
begin
Result:=GetDependencyWithIndex(FFirstRemovedDependency,pdlRequires,Index);
end;
function TLazPackage.UsedByDepByIndex(Index: integer): TPkgDependency;
begin
Result:=GetDependencyWithIndex(FFirstUsedByDependency,pdlUsedBy,Index);
end;
function TLazPackage.FindUsedByDepPrefer(Ignore: TPkgDependency
): TPkgDependency;
begin
Result:=FFirstUsedByDependency;
while (Result<>nil) do begin
if Result.PreferDefaultFilename
and (Result<>Ignore) then
exit;
Result:=Result.NextUsedByDependency;
end;
end;
function TLazPackage.ProvidesPackage(const AName: string): boolean;
var
i: Integer;
begin
if AName='' then exit(false);
for i:=0 to Provides.Count-1 do
if SysUtils.CompareText(Provides[i],AName)=0 then begin
//DebugLn(['TLazPackage.ProvidesPackage AName=',AName,' Provides[i]="',Provides[i],'"']);
exit(true);
end;
Result:=false;
end;
function TLazPackage.AddFile(const NewFilename, NewUnitName: string;
NewFileType: TPkgFileType; NewFlags: TPkgFileFlags;
CompPriorityCat: TComponentPriorityCategory): TPkgFile;
var
NewComponentPriority: TComponentPriority;
begin
Result:=FindRemovedPkgFile(NewFilename);
if Result=nil then begin
Result:=TPkgFile.Create(Self);
end else begin
Result.AutoReferenceSourceDir:=false;
FRemovedFiles.Remove(Result);
Result.Removed:=false;
end;
with Result do begin
Filename:=NewFilename;
//debugln(['TLazPackage.AddFile Is=',Filename,' Should=',NewFilename]);
Unit_Name:=NewUnitName;
FileType:=NewFileType;
Flags:=NewFlags;
NewComponentPriority:=ComponentPriorityNormal;
NewComponentPriority.Category:=CompPriorityCat;
ComponentPriority:=NewComponentPriority;
Removed:=false;
AutoReferenceSourceDir:=true;
end;
FFiles.Add(Result);
//debugln(['TLazPackage.AddFile Is=',Result.Filename,' Should=',NewFilename]);
Modified:=true;
end;
function TLazPackage.AddRemovedFile(const NewFilename, NewUnitName: string;
NewFileType: TPkgFileType; NewFlags: TPkgFileFlags;
CompPriorityCat: TComponentPriorityCategory): TPkgFile;
var
NewComponentPriority: TComponentPriority;
begin
Result:=FindRemovedPkgFile(NewFilename);
if Result=nil then begin
Result:=TPkgFile.Create(Self);
end;
with Result do begin
AutoReferenceSourceDir:=false;
Filename:=NewFilename;
Unit_Name:=NewUnitName;
FileType:=NewFileType;
Flags:=NewFlags;
NewComponentPriority:=ComponentPriorityNormal;
NewComponentPriority.Category:=CompPriorityCat;
ComponentPriority:=NewComponentPriority;
Removed:=false;
AutoReferenceSourceDir:=true;
end;
FRemovedFiles.Add(Result);
end;
procedure TLazPackage.RemoveFile(PkgFile: TPkgFile);
begin
FFiles.Remove(PkgFile);
FRemovedFiles.Add(PkgFile);
PkgFile.Removed:=true;
Modified:=true;
end;
procedure TLazPackage.UnremovePkgFile(PkgFile: TPkgFile);
begin
FFiles.Add(PkgFile);
FRemovedFiles.Remove(PkgFile);
PkgFile.Removed:=false;
end;
function TLazPackage.RemoveNonExistingFiles: boolean;
var
i: Integer;
AFilename: String;
begin
Result:=false;
i:=FileCount-1;
while i>=0 do begin
if i>=FileCount then continue;
AFilename:=Files[i].GetResolvedFilename;
if (AFilename='') or (not FileExistsCached(AFilename)) then
begin
RemoveFile(Files[i]);
Result:=true;
end;
dec(i);
end;
end;
function TLazPackage.GetFileDialogInitialDir(const DefaultDirectory: string
): string;
begin
Result:=AppendPathDelim(TrimFilename(DefaultDirectory));
if (SourceDirectories.GetFileReference(Result)=nil)
and DirPathExists(Directory) then
Result:=Directory;
end;
procedure TLazPackage.MoveFile(CurIndex, NewIndex: integer);
begin
if CurIndex=NewIndex then exit;
FFiles.Move(CurIndex,NewIndex);
Modified:=true;
end;
procedure TLazPackage.SortFiles;
var
NewList: TFPList;
Cnt: Integer;
i: Integer;
begin
if FileCount=0 then exit;
NewList:=TFPList.Create;
try
Cnt:=FileCount;
for i:=0 to Cnt-1 do NewList.Add(FFiles[i]);
NewList.Sort(TListSortCompare(@ComparePkgFilesAlphabetically));
i:=Cnt-1;
while (i>=0) and (NewList[i]=FFiles[i]) do dec(i);
if i<0 then exit;
FFiles.Clear;
for i:= 0 to Cnt-1 do FFiles.Add(NewList[i]);
Modified:=true;
finally
NewList.Free;
end;
end;
function TLazPackage.FixFilesCaseSensitivity: boolean;
var
SrcDirs: TStringList;
function IndexOfFileInStringList(List: TStringList;
const Filename: string; OnlyExact: boolean): integer;
begin
// first search for exact match
Result:=List.Count-1;
while (Result>=0) do begin
if (Filename=List[Result]) then exit;
dec(Result);
end;
if OnlyExact then exit;
// then search for case insensitive match
Result:=List.Count-1;
while (Result>=0) and (SysUtils.CompareText(Filename,List[Result])<>0) do
dec(Result);
end;
function AddDirectoryListing(const ADirectory: string): TStringList;
var
SrcDirID: Integer;
FileInfo: TSearchRec;
begin
if SrcDirs=nil then
SrcDirs:=TStringList.Create;
// search directory listing
SrcDirID:=IndexOfFileInStringList(SrcDirs,ADirectory,true);
if SrcDirID>=0 then begin
Result:=TStringList(SrcDirs.Objects[SrcDirID]);
exit;
end;
// create new directory listing
Result:=TStringList.Create;
if FindFirstUTF8(AppendPathDelim(ADirectory)+GetAllFilesMask,
faAnyFile,FileInfo)=0
then begin
repeat
// check if special file
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
then continue;
Result.Add(FileInfo.Name);
//debugln('AddDirectoryListing ',FileInfo.Name);
until FindNextUTF8(FileInfo)<>0;
end;
FindCloseUTF8(FileInfo);
SrcDirs.AddObject(ADirectory,Result);
end;
var
Cnt: Integer;
i: Integer;
CurFile: TPkgFile;
CurShortFilename: String;
DirListID: LongInt;
DirListing: TStringList;
NewShortFilename: string;
NewFilename: String;
CurDir: String;
AFilename: String;
begin
Result:=false;
Cnt:=FileCount;
SrcDirs:=nil;
try
for i:=0 to Cnt-1 do begin
CurFile:=Files[i];
//debugln('TLazPackage.FixFilesCaseSensitivity A ',dbgs(i),' CurFile.Filename=',CurFile.Filename);
AFilename:=CurFile.GetFullFilename;
CurShortFilename:=ExtractFilename(AFilename);
CurDir:=ExtractFilePath(AFilename);
DirListing:=AddDirectoryListing(CurDir);
DirListID:=IndexOfFileInStringList(DirListing,CurShortFilename,false);
//debugln('TLazPackage.FixFilesCaseSensitivity B ',dbgs(i),' CurShortFilename=',CurShortFilename,' DirListID=',dbgs(DirListID));
if DirListID<0 then continue;
NewShortFilename:=DirListing[DirListID];
//debugln('TLazPackage.FixFilesCaseSensitivity New ',dbgs(i),' NewShortFilename=',NewShortFilename);
if CurShortFilename<>NewShortFilename then begin
// case changes
NewFilename:=
AppendPathDelim(ExtractFilePath(CurFile.Filename))+NewShortFilename;
//debugln('TLazPackage.FixFilesCaseSensitivity New ',dbgs(i),' NewFilename=',NewFilename);
CurFile.Filename:=NewFilename;
Result:=true;
end;
end;
finally
if SrcDirs<>nil then begin
for i:=0 to SrcDirs.Count-1 do
SrcDirs.Objects[i].Free;
SrcDirs.Free;
end;
end;
end;
function TLazPackage.MainUnitHasPkgName: boolean;
begin
Result:=(MainUnit=nil) or (SysUtils.CompareText(MainUnit.Unit_Name,Name)=0);
end;
procedure TLazPackage.RemoveRemovedDependency(Dependency: TPkgDependency);
begin
Dependency.RemoveFromList(FFirstRemovedDependency,pdlRequires);
Dependency.Removed:=false;
end;
procedure TLazPackage.AddRequiredDependency(Dependency: TPkgDependency);
begin
Dependency.AddToList(FFirstRequiredDependency,pdlRequires);
Dependency.Owner:=Self;
Modified:=true;
end;
procedure TLazPackage.AddPackageDependency(const PkgName: string);
var
Dependency: TPkgDependency;
begin
if FindDependencyByName(PkgName)<>nil then exit;
Dependency:=TPkgDependency.Create;
Dependency.PackageName:=PkgName;
AddRequiredDependency(Dependency);
end;
procedure TLazPackage.RemoveRequiredDependency(Dependency: TPkgDependency);
begin
Dependency.RemoveFromList(FFirstRequiredDependency,pdlRequires);
Dependency.RequiredPackage:=nil;
Dependency.AddToList(FFirstRemovedDependency,pdlRequires);
Dependency.Removed:=true;
Modified:=true;
end;
procedure TLazPackage.DeleteRequiredDependency(Dependency: TPkgDependency);
begin
Dependency.RequiredPackage:=nil;
Dependency.RemoveFromList(FFirstRequiredDependency,pdlRequires);
Dependency.Free;
end;
procedure TLazPackage.DeleteRemovedDependency(Dependency: TPkgDependency);
begin
Dependency.RequiredPackage:=nil;
Dependency.RemoveFromList(FFirstRemovedDependency,pdlRequires);
Dependency.Free;
end;
procedure TLazPackage.MoveRequiredDependencyUp(Dependency: TPkgDependency);
begin
Dependency.MoveUpInList(FFirstRequiredDependency,pdlRequires);
end;
procedure TLazPackage.MoveRequiredDependencyDown(Dependency: TPkgDependency);
begin
Dependency.MoveDownInList(FFirstRequiredDependency,pdlRequires);
end;
function TLazPackage.CreateDependencyWithOwner(NewOwner: TObject;
WithMinVersion: boolean): TPkgDependency;
begin
Result:=TPkgDependency.Create;
with Result do begin
Owner:=NewOwner;
PackageName:=Self.Name;
if WithMinVersion then begin
MinVersion.Assign(Version);
Flags:=[pdfMinVersion];
end;
end;
end;
function TLazPackage.AddComponent(PkgFile: TPkgFile; const Page: string;
TheComponentClass: TComponentClass): TPkgComponent;
begin
Result:=TPkgComponent.Create(PkgFile,TheComponentClass,Page);
end;
procedure TLazPackage.AddPkgComponent(APkgComponent: TPkgComponent);
begin
FComponents.Add(APkgComponent);
end;
procedure TLazPackage.RemovePkgComponent(APkgComponent: TPkgComponent);
begin
FComponents.Remove(APkgComponent);
end;
function TLazPackage.Requires(APackage: TLazPackage): boolean;
begin
Result:=FindCompatibleDependencyInList(FFirstRequiredDependency,pdlRequires,
APackage)<>nil;
end;
procedure TLazPackage.AddUsedByDependency(Dependency: TPkgDependency);
begin
Dependency.AddToList(FFirstUsedByDependency,pdlUsedBy);
if Dependency.HoldPackage then
inc(FHoldPackageCount);
end;
procedure TLazPackage.RemoveUsedByDependency(Dependency: TPkgDependency);
begin
Dependency.RemoveFromList(FFirstUsedByDependency,pdlUsedBy);
if Dependency.HoldPackage then
dec(FHoldPackageCount);
end;
procedure TLazPackage.ChangeID(const NewName: string; NewVersion: TPkgVersion);
begin
Version.Assign(NewVersion);
Name:=NewName;
end;
function TLazPackage.GetFPDocPackageName: string;
begin
if FPDocPackageName<>'' then
Result:=FPDocPackageName
else
Result:=Name;
end;
function TLazPackage.GetOutputDirType: TPkgOutputDir;
begin
if (CompilerOptions<>nil)
and (CompilerOptions.ParsedOpts<>nil)
and (CompilerOptions.ParsedOpts.OutputDirectoryOverride<>'') then
Result:=podFallback
else
Result:=podDefault;
end;
procedure TLazPackage.GetAllRequiredPackages(var List: TFPList;
WithSelf: boolean);
begin
if Assigned(OnGetAllRequiredPackages) then
OnGetAllRequiredPackages(FirstRequiredDependency,List);
if WithSelf then begin
if List=nil then List:=TFPList.Create;
if List.IndexOf(Self)<0 then;
List.Insert(0,Self);
end else if List<>nil then begin
List.Remove(Self);
if List.Count=0 then FreeAndNil(List);
end;
end;
procedure TLazPackage.GetInheritedCompilerOptions(var OptionsList: TFPList);
var
PkgList: TFPList; // list of TLazPackage
begin
PkgList:=nil;
GetAllRequiredPackages(PkgList,false);
OptionsList:=GetUsageOptionsList(PkgList);
PkgList.Free;
end;
function TLazPackage.GetCompileSourceFilename: string;
begin
if MainUnit<>nil then
Result:=ExtractFilename(MainUnit.GetFullFilename)
else
Result:=ChangeFileExt(ExtractFilename(Filename),'.pas');
end;
function TLazPackage.GetOutputDirectory(UseOverride: boolean = true): string;
begin
if HasDirectory then begin
Result:=CompilerOptions.ParsedOpts.GetParsedValue(pcosOutputDir,UseOverride);
end else
Result:='';
end;
function TLazPackage.HasSeparateOutputDirectory: boolean;
var
VisitedPackages: TStringToStringTree;
OutputDir: String;
function CheckDependency(ADependency: TPkgDependency): boolean;
var
aPkg: TLazPackage;
Dir: String;
SrcPaths: String;
begin
Result:=false;
while ADependency<>nil do begin
if ADependency.RequiredPackage<>nil then begin
aPkg:=ADependency.RequiredPackage;
if not VisitedPackages.Contains(aPkg.Name) then begin
VisitedPackages[aPkg.Name]:='1';
// check recursively
if not CheckDependency(aPkg.FirstRequiredDependency) then exit;
// check if required package has the same output directory
Dir:=aPkg.GetOutputDirectory;
if CompareFilenames(Dir,OutputDir)=0 then exit;
// check if output directory is a sour directory of a required package
SrcPaths:=aPkg.SourceDirectories.CreateSearchPathFromAllFiles;
if (SrcPaths<>'')
and (FindPathInSearchPath(PChar(OutputDir),length(OutputDir),
PChar(SrcPaths),length(SrcPaths))<>nil)
then exit;
end;
end;
ADependency:=ADependency.NextRequiresDependency;
end;
Result:=true;
end;
var
SrcPaths: String;
begin
Result:=false;
if CompilerOptions.UnitOutputDirectory='' then exit;
OutputDir:=CompilerOptions.ParsedOpts.GetParsedValue(pcosOutputDir,false);
if OutputDir='' then exit;
SrcPaths:=SourceDirectories.CreateSearchPathFromAllFiles;
if SrcPaths='' then exit(true);
if FindPathInSearchPath(PChar(OutputDir),length(OutputDir),PChar(SrcPaths),length(SrcPaths))<>nil
then exit;
// check used packages
VisitedPackages:=TStringToStringTree.Create(false);
try
if not CheckDependency(FirstRequiredDependency) then exit;
finally
VisitedPackages.Free;
end;
Result:=true;
end;
function TLazPackage.GetStateFilename(UseOverride: boolean): string;
begin
Result:=AppendPathDelim(GetOutputDirectory(UseOverride))+Name+'.compiled';
end;
function TLazPackage.GetSrcFilename: string;
begin
if MainUnit<>nil then
Result:=MainUnit.GetFullFilename
else
Result:=FDirectory+GetCompileSourceFilename;
end;
function TLazPackage.GetSrcPPUFilename: string;
begin
Result:=AppendPathDelim(GetOutputDirectory)
+ChangeFileExt(GetCompileSourceFilename,'.ppu');
end;
function TLazPackage.GetCompilerFilename: string;
begin
Result:=CompilerOptions.ParsedOpts.GetParsedValue(pcosCompilerPath);
end;
function TLazPackage.GetPOOutDirectory: string;
begin
Result:=TrimFilename(SubstitutePkgMacros(fPOOutputDirectory,false));
LongenFilename(Result);
IDEMacros.SubstituteMacros(Result);
Result:=TrimFilename(Result);
end;
function TLazPackage.GetUnitPath(RelativeToBaseDir: boolean): string;
begin
Result:=CompilerOptions.GetUnitPath(RelativeToBaseDir);
end;
function TLazPackage.GetIncludePath(RelativeToBaseDir: boolean): string;
begin
Result:=CompilerOptions.GetIncludePath(RelativeToBaseDir);
end;
function TLazPackage.GetSrcPath(RelativeToBaseDir: boolean): string;
begin
Result:=CompilerOptions.GetSrcPath(RelativeToBaseDir);
end;
function TLazPackage.GetLastCompilerParams(o: TPkgOutputDir): string;
begin
Result:=LastCompile[o].Params;
if LastCompile[o].ViaMakefile then begin
Result:=StringReplace(Result,'%(CPU_TARGET)','$(TargetCPU)',[rfReplaceAll]);
Result:=StringReplace(Result,'%(OS_TARGET)','$(TargetOS)',[rfReplaceAll]);
Result:=StringReplace(Result,'%(LCL_PLATFORM)','$(LCLWidgetType)',[rfReplaceAll]);
Result:=SubstitutePkgMacros(Result,false);
end;
end;
function TLazPackage.NeedsDefineTemplates: boolean;
begin
if IsVirtual or AutoCreated or (lpfDestroying in Flags) or (Name='') then
Result:=false
else
Result:=true;
end;
function TLazPackage.IndexOfPkgFile(PkgFile: TPkgFile): integer;
begin
Result := FileCount - 1;
if Result < 0 then
Exit;
while (Files[Result] <> PkgFile) do
begin
dec(Result);
if Result < 0 then
Exit;
end;
end;
function TLazPackage.SearchShortFilename(const ShortFilename: string;
SearchFlags: TSearchIDEFileFlags): TPkgFile;
var
SearchedFilename: String;
i: Integer;
function FilenameFits(TheFilename: string): boolean;
begin
if siffIgnoreExtension in SearchFlags then
TheFileName:=ExtractFileNameWithoutExt(TheFileName);
//debugln('TLazPackage.SearchFile A ',SearchedFilename,' ',TheFilename);
if siffCaseSensitive in SearchFlags then
Result:=SearchedFilename=TheFilename
else
Result:=SysUtils.CompareText(SearchedFilename,TheFilename)=0;
end;
begin
SearchedFilename:=ShortFilename;
if siffIgnoreExtension in SearchFlags then
SearchedFilename:=ExtractFileNameWithoutExt(SearchedFilename);
// search in files
for i:=0 to FileCount-1 do begin
Result:=Files[i];
if FilenameFits(Result.GetShortFilename(true)) then exit;
end;
Result:=nil;
end;
function TLazPackage.SearchFilename(const AFilename: string;
SearchFlags: TSearchIDEFileFlags): TPkgFile;
var
SearchedFilename: String;
i: Integer;
function FilenameFits(TheFilename: string): boolean;
begin
if siffIgnoreExtension in SearchFlags then
TheFileName:=ExtractFileNameWithoutExt(TheFileName);
//debugln('TLazPackage.SearchFile A ',SearchedFilename,' ',TheFilename);
if siffCaseSensitive in SearchFlags then
Result:=SearchedFilename=TheFilename
else
Result:=SysUtils.CompareText(SearchedFilename,TheFilename)=0;
end;
begin
SearchedFilename:=AFilename;
if siffIgnoreExtension in SearchFlags then
SearchedFilename:=ExtractFileNameWithoutExt(SearchedFilename);
// search in files
for i:=0 to FileCount-1 do begin
Result:=Files[i];
if FilenameFits(Result.GetFullFilename) then exit;
end;
Result:=nil;
end;
{ TPkgComponent }
procedure TPkgComponent.SetPkgFile(const AValue: TPkgFile);
begin
if FPkgFile=AValue then exit;
if (FPkgFile<>nil) then PkgFile.RemovePkgComponent(Self);
FPkgFile:=AValue;
if (FPkgFile<>nil) then PkgFile.AddPkgComponent(Self);
end;
constructor TPkgComponent.Create(ThePkgFile: TPkgFile;
TheComponentClass: TComponentClass; const ThePageName: string);
begin
inherited Create(TheComponentClass,ThePageName);
PkgFile:=ThePkgFile;
end;
destructor TPkgComponent.Destroy;
begin
PkgFile:=nil;
if fIconLoaded then begin
FIcon.Free;
FIcon:=nil;
fIconLoaded:=false;
end;
inherited Destroy;
end;
function TPkgComponent.GetUnitName: string;
var
TIUnitName: String;
begin
Result:=PkgFile.Unit_Name;
// compare with RTTI unit name
if ComponentClass<>nil then begin
TIUnitName:=GetClassUnitName(ComponentClass);
if SysUtils.CompareText(TIUnitName,Result)<>0 then
Result:=TIUnitName;
end;
end;
function TPkgComponent.GetPriority: TComponentPriority;
begin
Result:=PkgFile.ComponentPriority;
end;
procedure TPkgComponent.ConsistencyCheck;
begin
inherited ConsistencyCheck;
if FPkgFile=nil then
RaiseGDBException('TIDEComponent.ConsistencyCheck FPkgFile=nil');
if FPkgFile.LazPackage=nil then
RaiseGDBException('TIDEComponent.ConsistencyCheck FPkgFile.LazPackage=nil');
if FPkgFile.LazPackage.IndexOfPkgComponent(Self)<0 then
RaiseGDBException('TIDEComponent.ConsistencyCheck FPkgFile.LazPackage.IndexOfPkgComponent(Self)<0');
if PkgFile.FComponents=nil then
RaiseGDBException('TIDEComponent.ConsistencyCheck PkgFile.FComponents=nil');
if PkgFile.FComponents.IndexOf(Self)<0 then
RaiseGDBException('TIDEComponent.ConsistencyCheck PkgFile.FComponents.IndexOf(Self)<0');
end;
function TPkgComponent.Icon: TCustomBitmap;
begin
if not fIconLoaded
then begin
fIcon:=GetIconCopy;
fIconLoaded:=true;
end;
Result:=FIcon;
end;
function TPkgComponent.GetIconCopy: TCustomBitMap;
var
ResHandle: TLResource;
ResName: String;
begin
Result := nil;
ResName := ComponentClass.ClassName;
// prevent raising exception and speedup a bit search/load
ResHandle := LazarusResources.Find(ResName);
if ResHandle <> nil then
Result := CreateBitmapFromLazarusResource(ResHandle)
else
if FindResource(HInstance, PChar(ResName), PChar(RT_BITMAP)) <> 0 then
begin
Result := TBitmap.Create;
Result.LoadFromResourceName(HInstance, ResName);
Result.Transparent := True;
end;
if Result = nil then
Result := CreateBitmapFromLazarusResource('default');
end;
function TPkgComponent.HasIcon: boolean;
begin
Result:=Page.PageName<>'';
end;
function TPkgComponent.CanBeCreatedInDesigner: boolean;
begin
Result:=(not PkgFile.Removed);
end;
{ TPkgCompilerOptions }
procedure TPkgCompilerOptions.LoadFromXMLConfig(AXMLConfig: TXMLConfig;
const Path: string);
begin
inherited LoadFromXMLConfig(AXMLConfig,Path);
FSkipCompiler := AXMLConfig.GetValue(Path+'SkipCompiler/Value', False);
end;
procedure TPkgCompilerOptions.SaveToXMLConfig(AXMLConfig: TXMLConfig; const Path: string);
begin
inherited SaveToXMLConfig(AXMLConfig,Path);
AXMLConfig.SetDeleteValue(Path+'SkipCompiler/Value', FSkipCompiler, False);
end;
procedure TPkgCompilerOptions.SetLazPackage(const AValue: TLazPackage);
begin
if FLazPackage=AValue then exit;
FLazPackage:=AValue;
end;
procedure TPkgCompilerOptions.SetCustomOptions(const AValue: string);
begin
if CustomOptions=AValue then exit;
InvalidateOptions;
inherited SetCustomOptions(AValue);
if LazPackage<>nil then
LazPackage.DefineTemplates.CustomDefinesChanged;
end;
procedure TPkgCompilerOptions.SetIncludePaths(const AValue: string);
begin
if IncludePath=AValue then exit;
InvalidateOptions;
inherited SetIncludePaths(AValue);
end;
procedure TPkgCompilerOptions.SetLibraryPaths(const AValue: string);
begin
if Libraries=AValue then exit;
InvalidateOptions;
inherited SetLibraryPaths(AValue);
end;
procedure TPkgCompilerOptions.SetLinkerOptions(const AValue: string);
begin
if LinkerOptions=AValue then exit;
InvalidateOptions;
inherited SetLinkerOptions(AValue);
end;
procedure TPkgCompilerOptions.SetObjectPath(const AValue: string);
begin
if ObjectPath=AValue then exit;
InvalidateOptions;
inherited SetObjectPath(AValue);
end;
procedure TPkgCompilerOptions.SetSrcPath(const AValue: string);
begin
if SrcPath=AValue then exit;
InvalidateOptions;
inherited SetSrcPath(AValue);
end;
procedure TPkgCompilerOptions.SetUnitPaths(const AValue: string);
begin
if OtherUnitFiles=AValue then exit;
InvalidateOptions;
inherited SetUnitPaths(AValue);
end;
procedure TPkgCompilerOptions.SetUnitOutputDir(const AValue: string);
begin
if UnitOutputDirectory=AValue then exit;
InvalidateOptions;
inherited SetUnitOutputDir(AValue);
if LazPackage<>nil then
LazPackage.DefineTemplates.OutputDirectoryChanged;
end;
procedure TPkgCompilerOptions.SetConditionals(const AValue: string);
var
NewValue: String;
begin
NewValue:=Trim(AValue);
if Conditionals=NewValue then exit;
InvalidateOptions;
inherited SetConditionals(NewValue);
end;
constructor TPkgCompilerOptions.Create(const AOwner: TObject);
begin
inherited Create(AOwner);
if AOwner<>nil then
FLazPackage := AOwner as TLazPackage;
end;
class function TPkgCompilerOptions.GetGroupCaption: string;
begin
Result := dlgCompilerOptions;
end;
class function TPkgCompilerOptions.GetInstance: TAbstractIDEOptions;
begin
Result := Package1.CompilerOptions;
end;
function TPkgCompilerOptions.IsActive: boolean;
begin
Result:=(LazPackage<>nil) and (LazPackage.CompilerOptions=Self);
end;
procedure TPkgCompilerOptions.Clear;
begin
inherited Clear;
FSkipCompiler:=false;
end;
procedure TPkgCompilerOptions.GetInheritedCompilerOptions(
var OptionsList: TFPList);
begin
if LazPackage<>nil then
LazPackage.GetInheritedCompilerOptions(OptionsList);
end;
function TPkgCompilerOptions.GetOwnerName: string;
begin
if LazPackage<>nil then
Result:=LazPackage.IDAsString;
end;
procedure TPkgCompilerOptions.InvalidateOptions;
begin
if (LazPackage=nil) then exit;
if LazPackage.UsageOptions=nil then RaiseException('');
if LazPackage.UsageOptions.ParsedOpts=nil then RaiseException('');
LazPackage.UsageOptions.ParsedOpts.InvalidateAll;
end;
function TPkgCompilerOptions.GetDefaultMainSourceFileName: string;
begin
if LazPackage<>nil then
Result:=LazPackage.GetCompileSourceFilename
else
Result:='';
if Result='' then
Result:=inherited GetDefaultMainSourceFileName;
end;
function TPkgCompilerOptions.CreateTargetFilename(
const MainSourceFileName: string): string;
begin
Result:='';
end;
procedure TPkgCompilerOptions.Assign(Source: TPersistent);
begin
inherited Assign(Source);
if Source is TPkgCompilerOptions
then begin
FSkipCompiler := TPkgCompilerOptions(Source).FSkipCompiler;
end
else begin
FSkipCompiler := False;
end;
end;
function TPkgCompilerOptions.CreateDiff(CompOpts: TBaseCompilerOptions;
Tool: TCompilerDiffTool): boolean;
begin
if (CompOpts is TPkgCompilerOptions) then begin
Result:=Tool.AddDiff('SkipCompiler',FSkipCompiler,
TPkgCompilerOptions(CompOpts).FSkipCompiler);
end else begin
Result:=true;
if Tool<>nil then Tool.Differ:=true;
end;
Result:=Result or inherited CreateDiff(CompOpts, Tool);
end;
{ TPkgAdditionalCompilerOptions }
procedure TPkgAdditionalCompilerOptions.SetLazPackage(const AValue: TLazPackage);
begin
if FLazPackage=AValue then exit;
FLazPackage:=AValue;
end;
procedure TPkgAdditionalCompilerOptions.SetCustomOptions(const AValue: string);
begin
if AValue=CustomOptions then exit;
inherited SetCustomOptions(AValue);
LazPackage.Modified:=true;
end;
procedure TPkgAdditionalCompilerOptions.SetIncludePath(const AValue: string);
begin
if AValue=IncludePath then exit;
inherited SetIncludePath(AValue);
LazPackage.Modified:=true;
end;
procedure TPkgAdditionalCompilerOptions.SetLibraryPath(const AValue: string);
begin
if AValue=LibraryPath then exit;
inherited SetLibraryPath(AValue);
LazPackage.Modified:=true;
end;
procedure TPkgAdditionalCompilerOptions.SetLinkerOptions(const AValue: string);
begin
if AValue=LinkerOptions then exit;
inherited SetLinkerOptions(AValue);
LazPackage.Modified:=true;
end;
procedure TPkgAdditionalCompilerOptions.SetObjectPath(const AValue: string);
begin
if AValue=ObjectPath then exit;
inherited SetObjectPath(AValue);
LazPackage.Modified:=true;
end;
procedure TPkgAdditionalCompilerOptions.SetUnitPath(const AValue: string);
begin
if AValue=UnitPath then exit;
inherited SetUnitPath(AValue);
LazPackage.Modified:=true;
end;
procedure TPkgAdditionalCompilerOptions.SetSrcPath(const AValue: string);
begin
if AValue=SrcPath then exit;
inherited SetSrcPath(AValue);
LazPackage.Modified:=true;
end;
constructor TPkgAdditionalCompilerOptions.Create(ThePackage: TLazPackage);
begin
inherited Create(ThePackage);
FLazPackage:=ThePackage;
end;
procedure TPkgAdditionalCompilerOptions.AssignOptions(Source: TObject);
begin
inherited AssignOptions(Source);
if Source is TPkgAdditionalCompilerOptions then begin
//Src:=TPkgAdditionalCompilerOptions(Source);
// nothing to do
end;
end;
function TPkgAdditionalCompilerOptions.GetOwnerName: string;
begin
Result:=LazPackage.IDAsString;
end;
function TPkgAdditionalCompilerOptions.
GetBaseCompilerOptions: TBaseCompilerOptions;
begin
Result:=LazPackage.CompilerOptions;
end;
{ TLazPackageDefineTemplates }
constructor TLazPackageDefineTemplates.Create(OwnerPackage: TLazPackage);
begin
FLazPackage:=OwnerPackage;
fLastSourceDirStamp:=CTInvalidChangeStamp;
end;
destructor TLazPackageDefineTemplates.Destroy;
begin
Clear;
fLastSourceDirectories.Free;
inherited Destroy;
end;
procedure TLazPackageDefineTemplates.Clear;
begin
if FMain<>nil then begin
if (CodeToolBoss<>nil) then
CodeToolBoss.DefineTree.RemoveDefineTemplate(FMain);
FMain:=nil;
FSrcDirIfDef:=nil;
FSrcDirectories:=nil;
FOutputDir:=nil;
FOutPutSrcPath:=nil;
fLastOutputDirSrcPathIDAsString:='';
FLastCustomOptions:='';
fLastUnitPath:='';
fLastSourceDirsIDAsString:='';
if fLastSourceDirectories<>nil then
fLastSourceDirectories.Clear;
FFlags:=FFlags+[pdtIDChanged,pdtOutputDirChanged,pdtSourceDirsChanged,
pdtCustomDefinesChanged];
end;
end;
procedure TLazPackageDefineTemplates.BeginUpdate;
begin
inc(FUpdateLock);
end;
procedure TLazPackageDefineTemplates.EndUpdate;
begin
if FUpdateLock=0 then RaiseException('TLazPackageDefineTemplates.EndUpdate');
dec(FUpdateLock);
if FUpdateLock=0 then begin
if pdtIDChanged in FFlags then PackageIDChanged;
if pdtSourceDirsChanged in FFlags then SourceDirectoriesChanged;
if pdtOutputDirChanged in FFlags then OutputDirectoryChanged;
if pdtCustomDefinesChanged in FFlags then CustomDefinesChanged;
end;
end;
procedure TLazPackageDefineTemplates.PackageIDChanged;
begin
if FUpdateLock>0 then begin
Include(FFlags,pdtIDChanged);
exit;
end;
Exclude(FFlags,pdtIDChanged);
UpdateMain;
UpdateOutputDirectory;
UpdateSourceDirectories;
UpdateDefinesForCustomDefines;
end;
procedure TLazPackageDefineTemplates.SourceDirectoriesChanged;
begin
if FUpdateLock>0 then begin
Include(FFlags,pdtSourceDirsChanged);
exit;
end;
Exclude(FFlags,pdtSourceDirsChanged);
UpdateSourceDirectories;
CodeToolBoss.DefineTree.ClearCache;
end;
procedure TLazPackageDefineTemplates.OutputDirectoryChanged;
begin
if FUpdateLock>0 then begin
Include(FFlags,pdtOutputDirChanged);
exit;
end;
Exclude(FFlags,pdtOutputDirChanged);
UpdateOutputDirectory;
CodeToolBoss.DefineTree.ClearCache;
end;
procedure TLazPackageDefineTemplates.CustomDefinesChanged;
begin
if FUpdateLock>0 then begin
Include(FFlags,pdtCustomDefinesChanged);
exit;
end;
Exclude(FFlags,pdtCustomDefinesChanged);
UpdateDefinesForCustomDefines;
CodeToolBoss.DefineTree.ClearCache;
end;
procedure TLazPackageDefineTemplates.AllChanged;
begin
PackageIDChanged;
UpdateSrcDirIfDef;// always create the SrcDirIfDef for IDE add-ons
SourceDirectoriesChanged;
OutputDirectoryChanged;
CustomDefinesChanged;
end;
procedure TLazPackageDefineTemplates.UpdateMain;
begin
if (not LazPackage.NeedsDefineTemplates) or (not Active) then exit;
// update the package block define template (the container for all other
// define templates of the package)
if FMain=nil then begin
FMain:=CreatePackageTemplateWithID(LazPackage.IDAsWord);
FMain.SetDefineOwner(LazPackage,false);
FMain.SetFlags([dtfAutoGenerated],[],false);
end else
FMain.Name:=LazPackage.IDAsWord;
// ClearCache is here unnessary, because it is only a block
end;
procedure TLazPackageDefineTemplates.UpdateSrcDirIfDef;
var
NewVariable: String;
Changed: Boolean;
UnitPathDefTempl: TDefineTemplate;
IncPathDefTempl: TDefineTemplate;
begin
// create custom options
// The custom options are enclosed by an IFDEF #PkgSrcMark<PckId> template.
// Each source directory defines this variable, so that the settings can be
// activated for each source directory by a simple DEFINE.
if (FMain=nil) then UpdateMain;
if FMain=nil then exit;
if FSrcDirectories=nil then begin
FSrcDirectories:=TDefineTemplate.Create('Source Directories',
'Source Directories','','',
da_Block);
FMain.AddChild(FSrcDirectories);
end;
if FSrcDirIfDef=nil then begin
FSrcDirIfDef:=TDefineTemplate.Create('Source Directory Additions',
'Additional defines for package source directories',
'#PkgSrcMark'+LazPackage.IDAsWord,'',
da_IfDef);
FMain.AddChild(FSrcDirIfDef);
// create unit path template for this directory
UnitPathDefTempl:=TDefineTemplate.Create('UnitPath', lisPkgDefsUnitPath,
'#UnitPath','$(#UnitPath);$PkgUnitPath('+LazPackage.IDAsString+')',
da_Define);
FSrcDirIfDef.AddChild(UnitPathDefTempl);
// create include path template for this directory
IncPathDefTempl:=TDefineTemplate.Create('IncPath','Include Path',
'#IncPath','$(#IncPath);$PkgIncPath('+LazPackage.IDAsString+')',
da_Define);
FSrcDirIfDef.AddChild(IncPathDefTempl);
Changed:=true;
end else begin
NewVariable:='#PkgSrcMark'+LazPackage.IDAsWord;
if NewVariable<>FSrcDirIfDef.Variable then begin
FSrcDirIfDef.Variable:=NewVariable;
// unit path
UnitPathDefTempl:=FSrcDirIfDef.FindChildByName('UnitPath');
if UnitPathDefTempl<>nil then
UnitPathDefTempl.Value:='$(#UnitPath);$PkgUnitPath('+LazPackage.IDAsString+')';
// include path
IncPathDefTempl:=FSrcDirIfDef.FindChildByName('IncPath');
if IncPathDefTempl<>nil then
IncPathDefTempl.Value:='$(#IncPath);$PkgIncPath('+LazPackage.IDAsString+')';
Changed:=true;
end;
end;
if Changed then
CodeToolBoss.DefineTree.ClearCache;
end;
procedure TLazPackageDefineTemplates.SetActive(const AValue: boolean);
begin
if FActive=AValue then exit;
FActive:=AValue;
if not FActive then Clear else AllChanged;
end;
procedure TLazPackageDefineTemplates.UpdateOutputDirectory;
begin
if FMain=nil then UpdateMain;
if FMain=nil then exit;
if FOutputDir=nil then begin
FOutputDir:=TDefineTemplate.Create(PkgOutputDirDefTemplName,
lisPkgDefsOutputDirectory, '', LazPackage.GetOutputDirectory, da_Directory
);
FOutputDir.SetDefineOwner(LazPackage,false);
FOutputDir.SetFlags([dtfAutoGenerated],[],false);
DisableDefaultsInDirectories(FOutputDir,false);
FMain.AddChild(FOutputDir);
end else begin
FOutputDir.Value:=LazPackage.GetOutputDirectory;
end;
if (FOutPutSrcPath=nil)
or (fLastOutputDirSrcPathIDAsString<>LazPackage.IDAsString) then begin
fLastOutputDirSrcPathIDAsString:=LazPackage.IDAsString;
FOutputSrcPath:=TDefineTemplate.Create('CompiledSrcPath',
lisPkgDefsCompiledSrcPathAddition, CompiledSrcPathMacroName,
'$PkgSrcPath('+fLastOutputDirSrcPathIDAsString+');'
+'$('+CompiledSrcPathMacroName+')',
da_Define);
FOutputSrcPath.SetDefineOwner(LazPackage,false);
FOutputSrcPath.SetFlags([dtfAutoGenerated],[],false);
CodeToolBoss.DefineTree.ReplaceChild(FOutputDir,FOutputSrcPath,
FOutputSrcPath.Name);
end;
end;
procedure TLazPackageDefineTemplates.UpdateSourceDirectories;
var
i: Integer;
SrcDirDefTempl: TDefineTemplate;
IDHasChanged: Boolean;
SrcDirMarkDefTempl: TDefineTemplate;
CurUnitPath: String;
SrcDirs: String;
begin
if (not LazPackage.NeedsDefineTemplates) or (not Active) then exit;
// quick check if something has changed
IDHasChanged:=fLastSourceDirsIDAsString<>LazPackage.IDAsString;
CurUnitPath:=LazPackage.CompilerOptions.ParsedOpts.GetParsedValue(pcosUnitPath);
SrcDirs:=LazPackage.SourceDirectories.CreateSearchPathFromAllFiles;
CurUnitPath:=TrimSearchPath(SrcDirs+';'+CurUnitPath+';.',
LazPackage.CompilerOptions.BaseDirectory,true);
if (fLastSourceDirectories<>nil)
and (fLastSourceDirStamp=LazPackage.SourceDirectories.TimeStamp)
and (not IDHasChanged)
and (CurUnitPath=fLastUnitPath) then
exit;
//debugln(['TLazPackageDefineTemplates.UpdateSourceDirectories ',LazPackage.Name,' CurUnitPath=',CurUnitPath]);
fLastSourceDirStamp:=LazPackage.SourceDirectories.TimeStamp;
fLastSourceDirsIDAsString:=LazPackage.IDAsString;
fLastUnitPath:=CurUnitPath;
// clear old define templates
if fLastSourceDirectories<>nil then begin
for i:=0 to fLastSourceDirectories.Count-1 do begin
SrcDirDefTempl:=TDefineTemplate(fLastSourceDirectories.Objects[i]);
SrcDirDefTempl.Unbind;
SrcDirDefTempl.Free;
end;
fLastSourceDirectories.Clear;
end else
fLastSourceDirectories:=TStringList.Create;
// build source directory define templates
FreeAndNil(fLastSourceDirectories);
fLastSourceDirectories:=SearchPathToList(CurUnitPath);
if (fLastSourceDirectories.Count>0)
and ((FSrcDirIfDef=nil) or IDHasChanged) then
UpdateSrcDirIfDef;
for i:=0 to fLastSourceDirectories.Count-1 do begin
// create directory template
SrcDirDefTempl:=TDefineTemplate.Create('Source Directory '+IntToStr(i+1),
fLastSourceDirectories[i],'',fLastSourceDirectories[i],da_Directory);
DisableDefaultsInDirectories(SrcDirDefTempl,false);
fLastSourceDirectories.Objects[i]:=SrcDirDefTempl;
// add package source directory marker
SrcDirMarkDefTempl:=TDefineTemplate.Create('PkgSrcDirMark',
lisPkgDefsSrcDirMark,'#PkgSrcMark'+LazPackage.IDAsWord,'',da_Define);
SrcDirDefTempl.AddChild(SrcDirMarkDefTempl);
SrcDirDefTempl.SetDefineOwner(LazPackage,false);
SrcDirDefTempl.SetFlags([dtfAutoGenerated],[],false);
// add directory
FSrcDirectories.AddChild(SrcDirDefTempl);
end;
CodeToolBoss.DefineTree.ClearCache;
end;
procedure TLazPackageDefineTemplates.UpdateDefinesForCustomDefines;
var
OptionsDefTempl: TDefineTemplate;
NewCustomOptions: String;
begin
if (not LazPackage.NeedsDefineTemplates) or (not Active) then exit;
// check if something has changed
NewCustomOptions:=LazPackage.CompilerOptions.GetOptionsForCTDefines;
if FLastCustomOptions=NewCustomOptions then exit;
FLastCustomOptions:=NewCustomOptions;
OptionsDefTempl:=CodeToolBoss.DefinePool.CreateFPCCommandLineDefines(
'Custom Options',FLastCustomOptions,false,LazPackage);
if OptionsDefTempl=nil then begin
// no custom options -> delete old template
if FSrcDirIfDef<>nil then begin
if FSrcDirIfDef.DeleteChild('Custom Options') then
CodeToolBoss.DefineTree.ClearCache;
end;
end else begin
UpdateSrcDirIfDef;
FSrcDirIfDef.ReplaceChild(OptionsDefTempl);
CodeToolBoss.DefineTree.ClearCache;
end;
end;
{ TBasePackageEditor }
function TBasePackageEditor.GetLazPackage: TLazPackage;
begin
Result:=nil;
end;
{ TPublishPackageOptions }
procedure TPublishPackageOptions.DoOnModifyChange;
begin
if Modified then LazPackage.Modified:=true;
end;
constructor TPublishPackageOptions.Create(TheLazPackage: TLazPackage);
begin
FLazPackage:=TheLazPackage;
inherited Create(FLazPackage);
end;
function TPublishPackageOptions.GetDefaultDestinationDir: string;
begin
Result:='$(TestDir)/publishedpackage/';
end;
{ TPkgPairTree }
function ComparePkgPairs(Pair1, Pair2: Pointer): integer;
begin
Result:=TPkgPair(Pair1).Compare(TPkgPair(Pair2));
end;
constructor TPkgPairTree.Create;
begin
inherited Create(@ComparePkgPairs);
end;
destructor TPkgPairTree.Destroy;
begin
FreeAndClear;
inherited Destroy;
end;
function TPkgPairTree.FindPair(Pkg1, Pkg2: TLazPackage; IgnoreOrder: boolean
): TPkgPair;
var
Comp: integer;
ANode: TAVLTreeNode;
begin
ANode:=Root;
while (ANode<>nil) do begin
Result:=TPkgPair(ANode.Data);
Comp:=-Result.ComparePair(Pkg1,Pkg2);
if Comp=0 then exit;
if Comp<0 then begin
ANode:=ANode.Left
end else begin
ANode:=ANode.Right
end;
end;
if IgnoreOrder and (Pkg1<>Pkg2) then
Result:=FindPair(Pkg2,Pkg1,false)
else
Result:=nil;
end;
function TPkgPairTree.AddPair(Pkg1, Pkg2: TLazPackage): TPkgPair;
begin
Result:=TPkgPair.Create(Pkg1,Pkg2);
Add(Result);
end;
function TPkgPairTree.AddPairIfNotExists(Pkg1, Pkg2: TLazPackage): TPkgPair;
begin
Result:=FindPair(Pkg1,Pkg2,true);
if Result=nil then
Result:=AddPair(Pkg1,Pkg2);
end;
{ TPkgPair }
constructor TPkgPair.Create(Pkg1, Pkg2: TLazPackage);
begin
Package1:=Pkg1;
Package2:=Pkg2;
end;
function TPkgPair.ComparePair(Pkg1, Pkg2: TLazPackage): integer;
begin
Result:=Package1.Compare(Pkg1);
if Result=0 then
Result:=Package2.Compare(Pkg2);
end;
function TPkgPair.Compare(PkgPair: TPkgPair): integer;
begin
Result:=ComparePair(PkgPair.Package1,PkgPair.Package2);
end;
function TPkgPair.AsString: string;
begin
Result:=Package1.IDAsString+' - '+Package2.IDAsString;
end;
{ TPkgUnitsTree }
function TPkgUnitsTree.FindNodeWithUnitName(const AUnitName: string
): TAVLTreeNode;
var
Comp: integer;
PkgFile: TPkgFile;
begin
Result:=Root;
while (Result<>nil) do begin
PkgFile:=TPkgFile(Result.Data);
Comp:=SysUtils.CompareText(AUnitName,PkgFile.Unit_Name);
if Comp=0 then exit;
if Comp<0 then begin
Result:=Result.Left
end else begin
Result:=Result.Right
end;
end;
end;
function TPkgUnitsTree.FindPkgFileWithUnitName(const AUnitName: string
): TPkgFile;
var
ANode: TAVLTreeNode;
begin
ANode:=FindNodeWithUnitName(AUnitName);
if ANode=nil then
Result:=nil
else
Result:=TPkgFile(ANode.Data);
end;
function ComparePkgFilesUnitname(PkgFile1, PkgFile2: Pointer): integer;
begin
Result := SysUtils.CompareText(
TPkgFile(PkgFile1).Unit_Name,
TPkgFile(PkgFile2).Unit_Name);
end;
constructor TPkgUnitsTree.Create(ThePackage: TLazPackage);
begin
fLazPackage:=ThePackage;
inherited Create(@ComparePkgFilesUnitname);
end;
initialization
RegisterIDEOptionsGroup(GroupPackage, TLazPackage);
RegisterIDEOptionsGroup(GroupPkgCompiler, TPkgCompilerOptions);
PackageDependencies:=TAVLTree.Create(@ComparePkgDependencyNames);
finalization
FreeThenNil(PackageDependencies);
end.