1 {
2  /***************************************************************************
3                             packagedefs.pas
4                             ---------------
5 
6 
7  ***************************************************************************/
8 
9  ***************************************************************************
10  *                                                                         *
11  *   This source is free software; you can redistribute it and/or modify   *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  *   This code is distributed in the hope that it will be useful, but      *
17  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
19  *   General Public License for more details.                              *
20  *                                                                         *
21  *   A copy of the GNU General Public License is available on the World    *
22  *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
23  *   obtain it by writing to the Free Software Foundation,                 *
24  *   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA.   *
25  *                                                                         *
26  ***************************************************************************
27 
28   Author: Mattias Gaertner
29 
30   Abstract:
31     Classes for packages and dependencies.
32 }
33 unit PackageDefs;
34 
35 {$mode objfpc}{$H+}
36 
37 interface
38 
39 uses
40   // FCL
41   Classes, SysUtils, contnrs, typinfo, Laz_AVL_Tree,
42   // LCL
43   Forms, ImgList,
44   // Codetools
45   LazConfigStorage, DefineTemplates, CodeToolManager,
46   CodeCache, CodeToolsCfgScript, CodeToolsStructs,
47   // LazUtils
48   FileUtil, LazFileUtils, LazUtilities, LazFileCache, LazUTF8, FileReferenceList,
49   LazTracer, LazLoggerBase, UITypes, Laz2_XMLCfg, AvgLvlTree,
50   // BuildIntf
51   MacroIntf, MacroDefIntf, IDEOptionsIntf, PublishModuleIntf,
52   PackageDependencyIntf, PackageIntf, FppkgIntf,
53   // IDEIntf
54   LazIDEIntf, IDEOptEditorIntf, IDEDialogs, ComponentReg, IDEImagesIntf,
55   // IDE
56   EditDefineTree, CompilerOptions, CompOptsModes, IDEOptionDefs, ProjPackCommon,
57   LazarusIDEStrConsts, IDEProcs, TransferMacros, FppkgHelper;
58 
59 type
60   TLazPackage = class;
61   TPkgFile = class;
62   TBasePackageEditor = class;
63   TPkgDependency = class;
64 
65   TPackageUpdatePolicy = (
66     pupManually,
67     pupOnRebuildingAll,
68     pupAsNeeded
69     );
70   TPackageUpdatePolicies = set of TPackageUpdatePolicy;
71 
72   TGetAllRequiredPackagesEvent =
73     procedure(APackage: TLazPackage; // if not nil then ignore FirstDependency and do not add APackage to Result
74               FirstDependency: TPkgDependency;
75               out List, FPMakeList: TFPList;
76               Flags: TPkgIntfRequiredFlags = [];
77               MinPolicy: TPackageUpdatePolicy = low(TPackageUpdatePolicy)) of object;
78   TGetDependencyOwnerDescription =
79     procedure(Dependency: TPkgDependency; out Description: string) of object;
80   TGetDependencyOwnerDirectory =
81     procedure(Dependency: TPkgDependency; out Directory: string) of object;
82   TGetWritablePkgOutputDirectory =
83     procedure(APackage: TLazPackage; var AnOutDirectory: string) of object;
84 
85 
86   { TPkgComponent }
87 
88   TPkgComponent = class(TRegisteredComponent)
89   private
90     FPkgFile: TPkgFile;
91     procedure SetPkgFile(const AValue: TPkgFile);
92   public
93     constructor Create(ThePkgFile: TPkgFile; TheComponentClass: TComponentClass;
94                        const ThePageName: string);
95     destructor Destroy; override;
GetUnitNamenull96     function GetUnitName: string; override;
GetPrioritynull97     function GetPriority: TComponentPriority; override;
98     procedure ConsistencyCheck; override;
ImageIndexnull99     function ImageIndex: TImageIndex;
Imagesnull100     class function Images: TCustomImageList;
HasIconnull101     function HasIcon: boolean;
CanBeCreatedInDesignernull102     function CanBeCreatedInDesigner: boolean; override;
103   public
104     property PkgFile: TPkgFile read FPkgFile write SetPkgFile;
105   end;
106 
107   { TPkgFile }
108 
109 type
110   TPFComponentBaseClass = (
111     pfcbcNone,      // unknown
112     pfcbcForm,      // is TForm
113     pfcbcFrame,     // is TFrame
114     pfcbcDataModule,// is TDataModule
115     pfcbcCustomForm // is TCustomForm (not TForm)
116     );
117 
118 const
119   PFComponentBaseClassNames: array[TPFComponentBaseClass] of string = (
120     'None',
121     'Form',
122     'Frame',
123     'DataModule',
124     'CustomForm'
125     );
126 
StrToComponentBaseClassnull127 function StrToComponentBaseClass(const s: string): TPFComponentBaseClass;
GetComponentBaseClassnull128 function GetComponentBaseClass(aClass: TClass): TPFComponentBaseClass;
129 
130 type
131   TPkgFileFlag = (
132     pffHasRegisterProc,  // file is unit and has a 'register' procedure
133     pffAddToPkgUsesSection,// unit is added to uses section
134     pffReportedAsRemoved // file has been reported as removed
135     );
136   TPkgFileFlags = set of TPkgFileFlag;
137 
138   { TPkgFile }
139 
140   TPkgFile = class(TLazPackageFile)
141   private
142     FAutoReferenceSourceDir: boolean;
143     FComponentPriority: TComponentPriority;
144     FComponents: TFPList; // list of TPkgComponent
145     FDirectory: string;
146     FFlags: TPkgFileFlags;
147     fFilename: string;
148     fFullFilename: string;
149     fFullFilenameStamp: integer;
150     FPackage: TLazPackage;
151     FResourceBaseClass: TPFComponentBaseClass;
152     FSourceDirectoryReferenced: boolean;
153     FSourceDirNeedReference: boolean;
GetAddToUsesPkgSectionnull154     function GetAddToUsesPkgSection: boolean;
GetComponentsnull155     function GetComponents(Index: integer): TPkgComponent;
GetHasRegisterProcnull156     function GetHasRegisterProc: boolean;
157     procedure SetAddToUsesPkgSection(const AValue: boolean);
158     procedure SetAutoReferenceSourceDir(const AValue: boolean);
159     procedure SetFlags(const AValue: TPkgFileFlags);
160     procedure SetHasRegisterProc(const AValue: boolean);
161     procedure UpdateUnitName;
GetComponentListnull162     function GetComponentList: TFPList;
163   protected
GetInUsesnull164     function GetInUses: boolean; override;
165     procedure SetInUses(AValue: boolean); override;
GetIDEPackagenull166     function GetIDEPackage: TIDEPackage; override;
GetFilenamenull167     function GetFilename: string; override;
168     procedure SetFilename(const AValue: string); override;
169     procedure SetRemoved(const AValue: boolean); override;
170     procedure SetDisableI18NForLFM(AValue: boolean); override;
171     procedure SetFileType(const AValue: TPkgFileType); override;
172     procedure SetUnitName(const AValue: string); override;
173   public
174     constructor Create(ThePackage: TLazPackage);
175     destructor Destroy; override;
176     procedure Clear;
177     procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string;
178       FileVersion: integer; AdjustPathDelims: boolean);
179     procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string;
180       UsePathDelim: TPathDelimSwitch);
181     procedure ConsistencyCheck;
ComponentCountnull182     function ComponentCount: integer;
183     procedure AddPkgComponent(APkgComponent: TPkgComponent);
184     procedure RemovePkgComponent(APkgComponent: TPkgComponent);
HasRegisteredPluginsnull185     function HasRegisteredPlugins: boolean;
MakeSensenull186     function MakeSense: boolean;
187     procedure UpdateSourceDirectoryReference;
GetFullFilenamenull188     function GetFullFilename: string; override;
GetShortFilenamenull189     function GetShortFilename(UseUp: boolean): string; override;
GetResolvedFilenamenull190     function GetResolvedFilename: string; // GetFullFilename + resolve symlinks
GetFileOwnernull191     function GetFileOwner: TObject; override;
GetFileOwnerNamenull192     function GetFileOwnerName: string; override;
193   public
194     property AddToUsesPkgSection: boolean
195                        read GetAddToUsesPkgSection write SetAddToUsesPkgSection;
196     property AutoReferenceSourceDir: boolean read FAutoReferenceSourceDir
197                                              write SetAutoReferenceSourceDir;
198     property ResourceBaseClass: TPFComponentBaseClass read FResourceBaseClass
199                                                       write FResourceBaseClass;
200     property ComponentPriority: TComponentPriority read FComponentPriority
201                                                    write FComponentPriority;
202     property Components[Index: integer]: TPkgComponent read GetComponents;// registered components
203     property Directory: string read FDirectory;
204     property Flags: TPkgFileFlags read FFlags write SetFlags;
205     property HasRegisterProc: boolean read GetHasRegisterProc write SetHasRegisterProc;
206     property LazPackage: TLazPackage read FPackage;
207     property SourceDirectoryReferenced: boolean read FSourceDirectoryReferenced;
208   end;
209 
210 
211   { TPkgUnitsTree - Tree of TPkgFile sorted for unitnames }
212 
213   TPkgUnitsTree = class(TAVLTree)
214   private
215     FLazPackage: TLazPackage;
216   public
FindNodeWithUnitNamenull217     function FindNodeWithUnitName(const AUnitName: string): TAVLTreeNode;
FindPkgFileWithUnitNamenull218     function FindPkgFileWithUnitName(const AUnitName: string): TPkgFile;
219     constructor Create(ThePackage: TLazPackage);
220     property LazPackage: TLazPackage read FLazPackage write FLazPackage;
221   end;
222 
223 
224   { TPkgDependency }
225 
226   TPkgMarkerFlag = (
227     pmfVisited,
228     pmfMarked
229     );
230   TPkgMarkerFlags = set of TPkgMarkerFlag;
231 
232   TPkgDependencyDirection = (
233     pddRequires,
234     pddUsedBy
235     );
236 
237   { TPkgDependency }
238 
239   TPkgDependency = class(TPkgDependencyID)
240   private
241     FDefaultFilename: string;
242     FHoldPackage: boolean;
243     FMarkerFlags: TPKgMarkerFlags;
244     FOwner: TObject;
245     FPreferDefaultFilename: boolean;
GetRequiredPackagenull246     function GetRequiredPackage: TLazPackage;
247     procedure SetHoldPackage(const AValue: boolean);
248     procedure SetRequiredPackage(AValue: TLazPackage);
249   protected
250     procedure SetPackageName(const AValue: string); override;
251   public
252     NextDependency, PrevDependency: array[TPkgDependencyDirection] of TPkgDependency;
253     constructor Create;
254     destructor Destroy; override;
255     procedure Clear; override;
256     procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string;
257                                 FileVersion: integer);
258     procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string;
259       UsePathDelim: TPathDelimSwitch);
260 
Comparenull261     function Compare(Dependency2: TPkgDependency): integer;
262     procedure Assign(Source: TPkgDependency);
263     procedure Assign(Source: TLazPackageID);
264     procedure ConsistencyCheck;
IsCompatiblenull265     function IsCompatible(Pkg: TLazPackageID): boolean; overload;
266     procedure MakeCompatible(const PkgName: string; const Version: TPkgVersion);
AsStringnull267     function AsString(WithOwner, WithDefaults: boolean): string; overload;
268     // API for iterating dependencies.
NextUsedByDependencynull269     function NextUsedByDependency: TPkgDependency; override;
PrevUsedByDependencynull270     function PrevUsedByDependency: TPkgDependency; override;
NextRequiresDependencynull271     function NextRequiresDependency: TPkgDependency; override;
PrevRequiresDependencynull272     function PrevRequiresDependency: TPkgDependency; override;
273     // API for adding / removing dependencies, defined in base class.
274     procedure AddUsedByDep(var FirstDependency: TPkgDependencyBase); override;
275     procedure RemoveUsedByDep(var FirstDependency: TPkgDependencyBase); override;
276     procedure AddRequiresDep(var FirstDependency: TPkgDependencyBase); override;
277     procedure RemoveRequiresDep(var FirstDependency: TPkgDependencyBase); override;
278     // API using ListType.
279     procedure AddToList(var FirstDependency: TPkgDependency;
280                         ListType: TPkgDependencyDirection);
281     procedure AddToEndOfList(var LastDependency: TPkgDependency;
282                              ListType: TPkgDependencyDirection);
283     procedure RemoveFromList(var FirstDependency: TPkgDependency;
284                              ListType: TPkgDependencyDirection);
MoveUpInListnull285     function MoveUpInList(var FirstDependency: TPkgDependency;
286                           ListType: TPkgDependencyDirection): Boolean;
MoveDownInListnull287     function MoveDownInList(var FirstDependency: TPkgDependency;
288       ListType: TPkgDependencyDirection): Boolean;
MakeFilenameRelativeToOwnernull289     function MakeFilenameRelativeToOwner(const AFilename: string): string;
FindDefaultFilenamenull290     function FindDefaultFilename: string;
291   public
292     property Owner: TObject read FOwner write FOwner;// package or project or IDE
293     property HoldPackage: boolean read FHoldPackage write SetHoldPackage;
294     property MarkerFlags: TPKgMarkerFlags read FMarkerFlags write FMarkerFlags;
295     property DefaultFilename: string read FDefaultFilename write FDefaultFilename;
296     property PreferDefaultFilename: boolean read FPreferDefaultFilename write FPreferDefaultFilename;
297     property RequiredPackage: TLazPackage read GetRequiredPackage write SetRequiredPackage;
298   end;
299   PPkgDependency = ^TPkgDependency;
300 
301 
302   { TPkgPair }
303 
304   TPkgPair = class
305   public
306     Package1: TLazPackage;
307     Package2: TLazPackage;
308     constructor Create(Pkg1, Pkg2: TLazPackage);
ComparePairnull309     function ComparePair(Pkg1, Pkg2: TLazPackage): integer;
Comparenull310     function Compare(PkgPair: TPkgPair): integer;
AsStringnull311     function AsString: string;
312   end;
313 
314 
315   { TPkgPairTree - Tree of TPkgPair }
316 
317   TPkgPairTree = class(TAVLTree)
318   public
319     constructor Create;
320     destructor Destroy; override;
FindPairnull321     function FindPair(Pkg1, Pkg2: TLazPackage; IgnoreOrder: boolean): TPkgPair;
AddPairnull322     function AddPair(Pkg1, Pkg2: TLazPackage): TPkgPair;
AddPairIfNotExistsnull323     function AddPairIfNotExists(Pkg1, Pkg2: TLazPackage): TPkgPair;
324   end;
325 
326 
327   { TPkgCompilerOptions }
328 
329   TPkgCompilerOptions = class(TBaseCompilerOptions)
330   private
331     FLazPackage: TLazPackage;
332     FSkipCompiler: Boolean;
333     procedure InvalidateOptions;
334   protected
335     procedure SetLazPackage(const AValue: TLazPackage);
336     procedure SetCustomOptions(const AValue: string); override;
337     procedure SetIncludePaths(const AValue: string); override;
338     procedure SetLibraryPaths(const AValue: string); override;
339     procedure SetLinkerOptions(const AValue: string); override;
340     procedure SetObjectPath(const AValue: string); override;
341     procedure SetSrcPath(const AValue: string); override;
342     procedure SetUnitPaths(const AValue: string); override;
343     procedure SetUnitOutputDir(const AValue: string); override;
344     procedure SetConditionals(AValue: string); override;
345   public
346     constructor Create(const AOwner: TObject); override;
347     // IDE options
GetGroupCaptionnull348     class function GetGroupCaption: string; override;
GetInstancenull349     class function GetInstance: TAbstractIDEOptions; override;
IsActivenull350     function IsActive: boolean; override;
351     procedure Clear; override;
352     procedure GetInheritedCompilerOptions(var OptionsList: TFPList); override;
GetOwnerNamenull353     function GetOwnerName: string; override;
GetDefaultMainSourceFileNamenull354     function GetDefaultMainSourceFileName: string; override;
CreateTargetFilenamenull355     function CreateTargetFilename: string; override;
HasCompilerCommandnull356     function HasCompilerCommand: boolean; override;
357 
358     procedure LoadFromXMLConfig(AXMLConfig: TXMLConfig; const Path: string); override;
359     procedure SaveToXMLConfig(AXMLConfig: TXMLConfig; const Path: string); override;
360     procedure Assign(Source: TPersistent); override;
CreateDiffnull361     function CreateDiff(CompOpts: TBaseCompilerOptions;
362                         Tool: TCompilerDiffTool = nil): boolean; override;
363   public
364     property LazPackage: TLazPackage read FLazPackage write SetLazPackage;
365     property SkipCompiler: Boolean read FSkipCompiler write FSkipCompiler;
366   end;
367 
368 
369   { TPkgAdditionalCompilerOptions }
370 
371   TPkgAdditionalCompilerOptions = class(TAdditionalCompilerOptions)
372   private
373     FLazPackage: TLazPackage;
374     procedure SetLazPackage(const AValue: TLazPackage);
375   protected
376     procedure SetCustomOptions(const AValue: string); override;
377     procedure SetIncludePath(const AValue: string); override;
378     procedure SetLibraryPath(const AValue: string); override;
379     procedure SetLinkerOptions(const AValue: string); override;
380     procedure SetObjectPath(const AValue: string); override;
381     procedure SetUnitPath(const AValue: string); override;
382     procedure SetSrcPath(const AValue: string); override;
383   public
384     constructor Create(ThePackage: TLazPackage);
385     procedure AssignOptions(Source: TObject); override;
GetOwnerNamenull386     function GetOwnerName: string; override;
GetBaseCompilerOptionsnull387     function GetBaseCompilerOptions: TBaseCompilerOptions; override;
388   public
389     property LazPackage: TLazPackage read FLazPackage write SetLazPackage;
390   end;
391 
392   { TPublishPackageOptions }
393 
394   TPublishPackageOptions = class(TPublishModuleOptions)
395   protected
396     procedure DoOnModifyChange; override;
397   public
GetDefaultDestinationDirnull398     function GetDefaultDestinationDir: string; override;
399   end;
400 
401 
402   { TLazPackageDefineTemplates }
403 
404   TLazPackageDefineTemplates = class(TProjPackDefineTemplates)
405   private
406   protected
407     procedure UpdateMain; override;
UpdateSrcDirIfDefnull408     function UpdateSrcDirIfDef: Boolean; override;
409     procedure UpdateSourceDirectories; override;
410     procedure UpdateOutputDirectory; override;
411     procedure UpdateDefinesForCustomDefines; override;
412     procedure ClearFlags; override;
413   public
414     constructor Create(AOwner: IProjPack);
415     destructor Destroy; override;
416     procedure AllChanged(AActivating: boolean); override;
417   end;
418 
419 
420   { TLazPackage }
421 
422   TLazPackageFlag = (
423     lpfAutoIncrementVersionOnBuild, // increment version before
424     lpfModified,       // package needs saving
425     lpfNeeded,         // Set by PackageGraph, if package is in use
426                        //   (for example because it is Installed or an Installed
427                        //    package requires this package)
428     lpfVisited,        // Used by the PackageGraph to avoid double checking
429     lpfDestroying,     // set during destruction
430     lpfLoading,        // set during loading
431     lpfSkipSaving,     // Used by PkgBoss to skip saving
432     lpfCycle,          // Used by the PackageGraph to mark cycles
433     lpfNeedGroupCompile,// set during group compile, dependent packages need compile too
434     lpfCompatibilityMode// use legacy file format to maximize compatibility with old Lazarus versions
435     );
436   TLazPackageFlags = set of TLazPackageFlag;
437 
438 const
439   pupAllAuto = [pupAsNeeded,pupOnRebuildingAll];
440 
441 type
442   TPkgOutputDirWritable = (
443     podwUnknown,
444     podwWritable,
445     podwNotWritable
446     );
447   TPkgLastCompileStats = record
448     StateFileLoaded: boolean;
449     StateFileName: string; // the .compiled file
450     StateFileDate: longint;
451     CompilerFilename: string; // path to used compiler
452     CompilerFileDate: integer;
453     Params: string;        // compiler parameters
454     Complete: boolean;     // compilation was successful
455     MainPPUExists: boolean; // main ppu file was there after compile
456     ViaMakefile: boolean;  // compiled via make
457     DirectoryWritable: TPkgOutputDirWritable;
458   end;
459   PPkgLastCompileStats = ^TPkgLastCompileStats;
460   TPkgOutputDir = (
461     podDefault,
462     podFallback // used when podDefault is not writable
463     );
464 
465   TIterateComponentClassesEvent = procedure(PkgComponent: TPkgComponent) of object;
466   TPkgChangeNameEvent = procedure(Pkg: TLazPackage; const OldName: string) of object;
467 
468   { TPackageIDEOptions }
469 
470   TPackageIDEOptions = class(TAbstractPackageIDEOptions)
471   private
472     FPackage: TLazPackage;
473   protected
GetPackagenull474     function GetPackage: TIDEPackage; override;
475   public
476     constructor Create(APackage: TLazPackage);
477     destructor Destroy; override;
GetInstancenull478     class function GetInstance: TAbstractIDEOptions; override;
GetGroupCaptionnull479     class function GetGroupCaption: string; override;
480     property Package: TLazPackage read FPackage;
481   end;
482 
483 
484   { TLazPackage }
485 
486   TLazPackage = class(TIDEPackage, IProjPack)
487   private
488     FAddToProjectUsesSection: boolean;
489     FAuthor: string;
490     FAutoUpdate: TPackageUpdatePolicy;
491     FFPDocPackageName: string;
492     FOnModifySilently: TNotifyEvent;
493     FOptionsBackup: TLazPackage;
494     FComponents: TFPList; // TFPList of TPkgComponent
495     FDefineTemplates: TLazPackageDefineTemplates;
496     FDescription: string;
497     FDirectory: string;
498     FDirectoryExpanded: string;
499     FDirectoryExpandedChangeStamp: integer;
500     FEnableI18N: boolean;
501     FEnableI18NForLFM: boolean;
502     FFileReadOnly: boolean;
503     FFiles: TFPList; // TFPList of TPkgFile
504     FFirstRemovedDependency: TPkgDependency;
505     FFirstRequiredDependency: TPkgDependency;
506     FFirstUsedByDependency: TPkgDependency;
507     FFlags: TLazPackageFlags;
508     FHasDirectory: boolean;
509     FHasStaticDirectory: boolean;
510     FHoldPackageCount: integer;
511     FIconFile: string;
512     FInstalled: TPackageInstallType;
513     FFPDocPaths: string;
514     FLicense: string;
515     FLPKSource: TCodeBuffer;
516     FLPKSourceChangeStep: integer;
517     FMacros: TTransferMacroList;
518     FMainUnit: TPkgFile;
519     FMissing: boolean;
520     FModifiedLock: integer;
521     FOutputStateFile: string;
522     FPackageEditor: TBasePackageEditor;
523     FPOOutputDirectory: string;
524     FProvides: TStrings;
525     fPublishOptions: TPublishPackageOptions;
526     FRegistered: boolean;
527     FRemovedFiles: TFPList; // TFPList of TPkgFile
528     FSourceDirectories: TFileReferenceList;
529     FStorePathDelim: TPathDelimSwitch;
530     FTopologicalLevel: integer;
531     FTranslated: string;
532     FUpdateLock: integer;
533     FUsageOptions: TPkgAdditionalCompilerOptions;
534     FUserIgnoreChangeStamp: integer;
535     FUserReadOnly: boolean;
GetAutoIncrementVersionOnBuildnull536     function GetAutoIncrementVersionOnBuild: boolean;
GetCompilerOptionsnull537     function GetCompilerOptions: TPkgCompilerOptions;
GetBaseCompilerOptionsnull538     function GetBaseCompilerOptions: TBaseCompilerOptions;
GetComponentCountnull539     function GetComponentCount: integer;
GetComponentsnull540     function GetComponents(Index: integer): TPkgComponent;
GetRemovedFilesnull541     function GetRemovedFiles(Index: integer): TPkgFile;
GetFilesnull542     function GetFiles(Index: integer): TPkgFile;
GetIDEOptionsnull543     function GetIDEOptions: TPackageIDEOptions;
GetSourceDirectoriesnull544     function GetSourceDirectories: TFileReferenceList;
GetUseLegacyListsnull545     function GetUseLegacyLists: Boolean;
546     procedure SetAddToProjectUsesSection(const AValue: boolean);
547     procedure SetAuthor(const AValue: string);
548     procedure SetAutoIncrementVersionOnBuild(const AValue: boolean);
549     procedure SetAutoUpdate(const AValue: TPackageUpdatePolicy);
550     procedure SetDescription(const AValue: string);
551     procedure SetEnableI18NForLFM(AValue: boolean);
552     procedure SetFileReadOnly(const AValue: boolean);
553     procedure SetFlags(const AValue: TLazPackageFlags);
554     procedure SetFPDocPackageName(AValue: string);
555     procedure SetIconFile(const AValue: string);
556     procedure SetInstalled(const AValue: TPackageInstallType);
557     procedure SetFPDocPaths(const AValue: string);
558     procedure SetLicense(const AValue: string);
559     procedure SetLPKSource(const AValue: TCodeBuffer);
560     procedure SetOutputStateFile(const AValue: string);
561     procedure SetProvides(const AValue: TStrings);
562     procedure SetPOOutputDirectory(const AValue: string);
563     procedure SetEnableI18N(const AValue: boolean);
564     procedure SetRegistered(const AValue: boolean);
565     procedure SetPackageEditor(const AValue: TBasePackageEditor);
566     procedure SetPackageType(const AValue: TLazPackageType);
567     procedure SetStorePathDelim(const AValue: TPathDelimSwitch);
568     procedure SetUseLegacyLists(const AUseLegacyLists: Boolean);
569     procedure SetUserReadOnly(const AValue: boolean);
570     procedure OnMacroListSubstitution({%H-}TheMacro: TTransferMacro;
571       const MacroName: string; var s: string;
572       const Data: PtrInt; var Handled, {%H-}Abort: boolean; {%H-}Depth: integer);
573     procedure Clear;
574     procedure UpdateSourceDirectories;
575     procedure SourceDirectoriesChanged(Sender: TObject);
576   protected
GetDirectorynull577     function GetDirectory: string; override;
GetDefineTemplatesnull578     function GetDefineTemplates: TProjPackDefineTemplates;
GetFileCountnull579     function GetFileCount: integer; override;
GetPkgFilesnull580     function GetPkgFiles(Index: integer): TLazPackageFile; override;
GetDirectoryExpandednull581     function GetDirectoryExpanded: string; override;
GetModifiednull582     function GetModified: boolean; override;
583     procedure SetFilename(const AValue: string); override;
584     procedure SetModified(const AValue: boolean); override;
585     procedure SetName(const NewName: TComponentName); override;
586     procedure VersionChanged(Sender: TObject); override;
GetRemovedCountnull587     function GetRemovedCount: integer; override;
GetRemovedPkgFilesnull588     function GetRemovedPkgFiles(Index: integer): TLazPackageFile; override;
589     procedure SetAutoInstall(AValue: TPackageInstallType); override;
590   public
591     constructor Create; override;
592     constructor CreateAndClear;
593     destructor Destroy; override;
594     procedure AssignOptions(Source: TPersistent); override;
595     // IDE options
596     procedure BackupOptions;
597     procedure RestoreOptions;
598     // modified
599     procedure BeginUpdate;
600     procedure EndUpdate;
601     procedure LockModified;
602     procedure UnlockModified;
ReadOnlynull603     function ReadOnly: boolean; override;
604     procedure ModifySilently; // Set Modified but do not trigger update of editors.
605     // streaming
606     procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string);
607     procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string);
608     procedure SaveToString(out s: string);
609     // consistency
610     procedure CheckInnerDependencies;
IsMakingSensenull611     function IsMakingSense: boolean;
612     procedure ConsistencyCheck;
613     // paths, define templates
ExtendUnitSearchPathnull614     function ExtendUnitSearchPath(NewUnitPaths: string): boolean;
ExtendIncSearchPathnull615     function ExtendIncSearchPath(NewIncPaths: string): boolean;
IsVirtualnull616     function IsVirtual: boolean; override;
HasDirectorynull617     function HasDirectory: boolean; override;
HasStaticDirectorynull618     function HasStaticDirectory: boolean;
GetFullFilenamenull619     function GetFullFilename(ResolveMacros: boolean): string;
GetResolvedFilenamenull620     function GetResolvedFilename(ResolveMacros: boolean): string; // GetFullFilename + resolve symlinks
GetSourceDirsnull621     function GetSourceDirs(WithPkgDir, WithoutOutputDir: boolean): string;
622     procedure GetInheritedCompilerOptions(var OptionsList: TFPList);
GetOutputDirectorynull623     function GetOutputDirectory(UseOverride: boolean = true): string; // this can change before building, when default dir is readonly
HasSeparateOutputDirectorynull624     function HasSeparateOutputDirectory: boolean;
GetStateFilenamenull625     function GetStateFilename(UseOverride: boolean = true): string;
GetCompileSourceFilenamenull626     function GetCompileSourceFilename: string;// as GetSrcFilename without directory
GetSrcFilenamenull627     function GetSrcFilename: string;
GetSrcPPUFilenamenull628     function GetSrcPPUFilename: string;
GetCompilerFilenamenull629     function GetCompilerFilename: string;
GetPOOutDirectorynull630     function GetPOOutDirectory: string;
GetUnitPathnull631     function GetUnitPath(RelativeToBaseDir: boolean): string;
GetIncludePathnull632     function GetIncludePath(RelativeToBaseDir: boolean): string;
GetSrcPathnull633     function GetSrcPath(RelativeToBaseDir: boolean): string;
GetFPDocPackageNamenull634     function GetFPDocPackageName: string;
GetLastCompilerParamsnull635     function GetLastCompilerParams(o: TPkgOutputDir): string;
NeedsDefineTemplatesnull636     function NeedsDefineTemplates: boolean;
SubstitutePkgMacrosnull637     function SubstitutePkgMacros(const s: string; PlatformIndependent: boolean): string;
638     procedure WriteInheritedUnparsedOptions;
GetActiveBuildMethodnull639     function GetActiveBuildMethod: TBuildMethod;
640     // files
IndexOfPkgFilenull641     function IndexOfPkgFile(PkgFile: TPkgFile): integer;
SearchShortFilenamenull642     function SearchShortFilename(const ShortFilename: string;
643                             SearchFlags: TSearchIDEFileFlags): TPkgFile;
SearchFilenamenull644     function SearchFilename(const AFilename: string;
645                             SearchFlags: TSearchIDEFileFlags): TPkgFile;
646     procedure ShortenFilename(var ExpandedFilename: string; UseUp: boolean);
647     procedure LongenFilename(var AFilename: string);
FindPkgFilenull648     function FindPkgFile(const AFilename: string;
649                          IgnoreRemoved, FindVirtualFile: boolean): TPkgFile;
FindUnitWithRegisternull650     function FindUnitWithRegister(IgnorePkgFile: TPkgFile = nil): TPkgFile;
FindUnitnull651     function FindUnit(const TheUnitName: string): TPkgFile;
FindUnitnull652     function FindUnit(const TheUnitName: string; IgnoreRemoved: boolean): TPkgFile;
FindUnitnull653     function FindUnit(const TheUnitName: string; IgnoreRemoved: boolean;
654                       IgnorePkgFile: TPkgFile): TPkgFile;
FindUsedUnitnull655     function FindUsedUnit(TheUnitName: string; IgnorePkgFile: TPkgFile = nil): TPkgFile;
FindRemovedPkgFilenull656     function FindRemovedPkgFile(const AFilename: string): TPkgFile;
AddFilenull657     function AddFile(const NewFilename, NewUnitName: string;
658                      NewFileType: TPkgFileType; NewFlags: TPkgFileFlags;
659                      CompPriorityCat: TComponentPriorityCategory): TPkgFile;
AddFileByNamenull660     function AddFileByName(aFilename: string;
661                            var NewUnitPaths, NewIncPaths: String): Boolean;
AddRemovedFilenull662     function AddRemovedFile(const NewFilename, NewUnitName: string;
663                      NewFileType: TPkgFileType; NewFlags: TPkgFileFlags;
664                      CompPriorityCat: TComponentPriorityCategory): TPkgFile;
665     procedure DeleteFile(PkgFile: TPkgFile); // free TPkgFile
666     procedure RemoveFileSilently(PkgFile: TPkgFile);
667     procedure RemoveFile(PkgFile: TPkgFile); // move file to removed file list
668     procedure UnremovePkgFile(PkgFile: TPkgFile); // move file back to file list
669     // True if something changed. Param is ignored here, just to match with interface.
RemoveNonExistingFilesnull670     function RemoveNonExistingFiles({%H-}RemoveFromUsesSection: boolean = true): boolean;
GetFileDialogInitialDirnull671     function GetFileDialogInitialDir(const DefaultDirectory: string): string;
672     procedure MoveFile(CurIndex, NewIndex: integer);
673     procedure SortFiles;
FixFilesCaseSensitivitynull674     function FixFilesCaseSensitivity: boolean;
MainUnitHasPkgNamenull675     function MainUnitHasPkgName: boolean;
676     // required dependencies (plus removed required dependencies)
FindDependencyByNamenull677     function FindDependencyByName(const PackageName: string): TPkgDependency;
FindRemovedDependencyByNamenull678     function FindRemovedDependencyByName(const PkgName: string): TPkgDependency;
RequiredDepByIndexnull679     function RequiredDepByIndex(Index: integer): TPkgDependency;
RemovedDepByIndexnull680     function RemovedDepByIndex(Index: integer): TPkgDependency;
681     procedure AddRequiredDependency(Dependency: TPkgDependency);
682     procedure AddPackageDependency(const PackageName: string);
683     procedure RemoveRequiredDepSilently(Dependency: TPkgDependency);
684     procedure RemoveRequiredDependency(Dependency: TPkgDependency);
685     procedure DeleteRequiredDependency(Dependency: TPkgDependency);
686     procedure DeleteRemovedDependency(Dependency: TPkgDependency);
687     procedure RemoveRemovedDependency(Dependency: TPkgDependency);
MoveRequiredDependencyUpnull688     function MoveRequiredDependencyUp(Dependency: TPkgDependency): Boolean;
MoveRequiredDependencyDownnull689     function MoveRequiredDependencyDown(Dependency: TPkgDependency): Boolean;
CreateDependencyWithOwnernull690     function CreateDependencyWithOwner(NewOwner: TObject;
691                                WithMinVersion: boolean = false): TPkgDependency;
Requiresnull692     function Requires(APackage: TLazPackage): boolean;
693     procedure GetAllRequiredPackages(var List, FPMakeList: TFPList; WithSelf: boolean;
694       aFlags: TPkgIntfRequiredFlags = [];
695       MinPolicy: TPackageUpdatePolicy = low(TPackageUpdatePolicy));
696     // components
IndexOfPkgComponentnull697     function IndexOfPkgComponent(PkgComponent: TPkgComponent): integer;
AddComponentnull698     function AddComponent(PkgFile: TPkgFile; const Page: string;
699                           TheComponentClass: TComponentClass): TPkgComponent;
700     procedure AddPkgComponent(APkgComponent: TPkgComponent);
701     procedure RemovePkgComponent(APkgComponent: TPkgComponent);
702     procedure IterateComponentClasses(Event: TIterateComponentClassesEvent;
703                                       WithUsedPackages: boolean);
704     procedure SetAllComponentPriorities(const p: TComponentPriority);
705     // used by dependencies
706     procedure AddUsedByDependency(Dependency: TPkgDependencyBase); override;
707     procedure RemoveUsedByDependency(Dependency: TPkgDependencyBase); override;
UsedByDepByIndexnull708     function UsedByDepByIndex(Index: integer): TPkgDependency;
FindUsedByDepPrefernull709     function FindUsedByDepPrefer(Ignore: TPkgDependency): TPkgDependency;
710     // provides
ProvidesPackagenull711     function ProvidesPackage(const AName: string): boolean;
712     // ID
713     procedure ChangeID(const NewName: string; NewVersion: TPkgVersion);
714   public
715     LastCompile: array[TPkgOutputDir] of TPkgLastCompileStats;
GetOutputDirTypenull716     function GetOutputDirType: TPkgOutputDir;
717   public
718     property AddToProjectUsesSection: boolean read FAddToProjectUsesSection
719                                               write SetAddToProjectUsesSection;
720     property Author: string read FAuthor write SetAuthor;
721     property AutoIncrementVersionOnBuild: boolean read GetAutoIncrementVersionOnBuild
722                                                  write SetAutoIncrementVersionOnBuild;
723     property AutoUpdate: TPackageUpdatePolicy read FAutoUpdate write SetAutoUpdate;
724     property CompilerOptions: TPkgCompilerOptions read GetCompilerOptions;
725     property ComponentCount: integer read GetComponentCount;
726     property Components[Index: integer]: TPkgComponent read GetComponents;
727     property DefineTemplates: TLazPackageDefineTemplates read FDefineTemplates
728                                                          write FDefineTemplates;
729     property Description: string read FDescription write SetDescription;
730     property Editor: TBasePackageEditor read FPackageEditor write SetPackageEditor;
731     property EnableI18N: Boolean read FEnableI18N write SetEnableI18N;
732     property EnableI18NForLFM: boolean read FEnableI18NForLFM write SetEnableI18NForLFM;
733     property FileReadOnly: boolean read FFileReadOnly write SetFileReadOnly;
734     property Files[Index: integer]: TPkgFile read GetFiles;
735     property FirstRemovedDependency: TPkgDependency read FFirstRemovedDependency;
736     property FirstRequiredDependency: TPkgDependency read FFirstRequiredDependency;
737     property FirstUsedByDependency: TPkgDependency read FFirstUsedByDependency;
738     property Flags: TLazPackageFlags read FFlags write SetFlags;
739     property HoldPackageCount: integer read FHoldPackageCount;
740     property IconFile: string read FIconFile write SetIconFile;
741     property IDEOptions: TPackageIDEOptions read GetIDEOptions;
742     property Installed: TPackageInstallType read FInstalled write SetInstalled;
743     property FPDocPaths: string read FFPDocPaths write SetFPDocPaths;
744     property FPDocPackageName: string read FFPDocPackageName write SetFPDocPackageName;
745     property License: string read FLicense write SetLicense;
746     // see Missing, can be nil when file on disk was removed or point to a different codebuffer during rename
747     property LPKSource: TCodeBuffer read FLPKSource write SetLPKSource;
748     property LPKSourceChangeStep: integer read FLPKSourceChangeStep write FLPKSourceChangeStep;
749     property Macros: TTransferMacroList read FMacros;
750     property MainUnit: TPkgFile read FMainUnit;
751     property Missing: boolean read FMissing write FMissing; // lpk is missing, Note: virtual packages can have Missing=false
752     property OptionsBackup: TLazPackage read FOptionsBackup;
753     property OutputStateFile: string read FOutputStateFile write SetOutputStateFile;
754     property PackageType: TLazPackageType read FPackageType write SetPackageType;
755     property POOutputDirectory: string read FPOOutputDirectory write SetPOOutputDirectory;
756     property Provides: TStrings read FProvides write SetProvides;
757     property PublishOptions: TPublishPackageOptions read fPublishOptions write fPublishOptions;
758     property Registered: boolean read FRegistered write SetRegistered;
759     property RemovedFiles[Index: integer]: TPkgFile read GetRemovedFiles;
760     property SourceDirectories: TFileReferenceList read GetSourceDirectories;
761     property StorePathDelim: TPathDelimSwitch read FStorePathDelim write SetStorePathDelim;
762     property TopologicalLevel: integer read FTopologicalLevel write FTopologicalLevel;
763     property Translated: string read FTranslated write FTranslated;
764     property UsageOptions: TPkgAdditionalCompilerOptions read FUsageOptions;
765     property UseLegacyLists: Boolean read GetUseLegacyLists write SetUseLegacyLists;
766     property UserReadOnly: boolean read FUserReadOnly write SetUserReadOnly;
767     property UserIgnoreChangeStamp: integer read FUserIgnoreChangeStamp
768                                             write FUserIgnoreChangeStamp;
769     property OnModifySilently: TNotifyEvent read FOnModifySilently write FOnModifySilently;
770   end;
771 
772   PLazPackage = ^TLazPackage;
773 
774 
775   { TBasePackageEditor }
776 
777   TBasePackageEditor = class(TForm)
778   protected
GetLazPackagenull779     function GetLazPackage: TLazPackage; virtual;
780     procedure SetLazPackage(const AValue: TLazPackage); virtual; abstract;
781   public
CanCloseEditornull782     function CanCloseEditor: TModalResult; virtual; abstract;
783     procedure UpdateAll(Immediately: boolean = false); virtual; abstract;
784     property LazPackage: TLazPackage read GetLazPackage write SetLazPackage;
785   end;
786 
787 const
788   LazPkgXMLFileVersion = 5;
789 
790   AutoUpdateNames: array[TPackageUpdatePolicy] of string = (
791     'Manually', 'OnRebuildingAll', 'AsNeeded');
792 
793 var
794   // All TPkgDependency are added to this AVL tree (sorted for names, not version!)
795   PackageDependencies: TAVLTree = nil; // tree of TPkgDependency
796 
797   OnGetAllRequiredPackages: TGetAllRequiredPackagesEvent = nil;
798   OnGetDependencyOwnerDescription: TGetDependencyOwnerDescription = nil;
799   OnGetDependencyOwnerDirectory: TGetDependencyOwnerDirectory = nil;
800   OnPackageFileLoaded: TNotifyEvent = nil;
801 
CompareLazPackageIDnull802 function CompareLazPackageID(Data1, Data2: Pointer): integer;
CompareNameWithPackageIDnull803 function CompareNameWithPackageID(Key, Data: Pointer): integer;
ComparePkgIDMaskWithPackageIDnull804 function ComparePkgIDMaskWithPackageID(Key, Data: Pointer): integer;
CompareLazPackageIDNamesnull805 function CompareLazPackageIDNames(Data1, Data2: Pointer): integer;
CompareLazPackageTopologicallyAndNamenull806 function CompareLazPackageTopologicallyAndName(Data1, Data2: Pointer): integer;
CompareNameWithPkgDependencynull807 function CompareNameWithPkgDependency(Key, Data: Pointer): integer;
ComparePkgDependencyNamesnull808 function ComparePkgDependencyNames(Data1, Data2: Pointer): integer;
CompareUnitsTreenull809 function CompareUnitsTree(UnitTree1, UnitTree2: TPkgUnitsTree): integer;
ComparePackageWithUnitsTreenull810 function ComparePackageWithUnitsTree(Package: TLazPackage;
811                                      UnitTree: TPkgUnitsTree): integer;
ComparePkgFilesAlphabeticallynull812 function ComparePkgFilesAlphabetically(PkgFile1, PkgFile2: TPkgFile): integer;
813 
GetUsageOptionsListnull814 function GetUsageOptionsList(PackageList: TFPList): TFPList;
815 
GetPkgFileTypeLocalizedNamenull816 function GetPkgFileTypeLocalizedName(FileType: TPkgFileType): string;
NameToAutoUpdatePolicynull817 function NameToAutoUpdatePolicy(const s: string): TPackageUpdatePolicy;
FileNameToPkgFileTypenull818 function FileNameToPkgFileType(AFilename: string): TPkgFileType;
819 
820 procedure SortDependencyListAlphabetically(Dependencies: TFPList);
821 procedure LoadPkgDependencyList(XMLConfig: TXMLConfig; const ThePath: string;
822   var First: TPkgDependency; ListType: TPkgDependencyDirection; Owner: TObject;
823   HoldPackages, SortList: boolean);
824 procedure SavePkgDependencyList(XMLConfig: TXMLConfig; const ThePath: string;
825   First: TPkgDependency; ListType: TPkgDependencyDirection;
826   UsePathDelim: TPathDelimSwitch;LegacyLists:Boolean);
827 procedure ListPkgIDToDependencyList(ListOfTLazPackageID: TObjectList;
828   var First: TPkgDependency; ListType: TPkgDependencyDirection; Owner: TObject;
829   HoldPackages: boolean);
830 procedure DeleteDependencyInList(ADependency: TPkgDependency;
831   var First: TPkgDependency; ListType: TPkgDependencyDirection);
832 procedure FreeDependencyList(var First: TPkgDependency;
833   ListType: TPkgDependencyDirection);
DependencyListAsStringnull834 function DependencyListAsString(First: TPkgDependency;
835   ListType: TPkgDependencyDirection): string;
836 
FindDependencyByNameInListnull837 function FindDependencyByNameInList(First: TPkgDependency;
838   ListType: TPkgDependencyDirection; const Name: string): TPkgDependency;
FindCompatibleDependencyInListnull839 function FindCompatibleDependencyInList(First: TPkgDependency;
840   ListType: TPkgDependencyDirection; ComparePackage: TLazPackageID): TPkgDependency;
GetDependencyWithIndexnull841 function GetDependencyWithIndex(First: TPkgDependency;
842   ListType: TPkgDependencyDirection; Index: integer): TPkgDependency;
IndexOfDependencyInListnull843 function IndexOfDependencyInList(First: TPkgDependency;
844   ListType: TPkgDependencyDirection; FindDependency: TPkgDependency): integer;
GetFirstDependencynull845 function GetFirstDependency(ListItem: TPkgDependency;
846   ListType: TPkgDependencyDirection): TPkgDependency;
847 
FindLowestPkgDependencyWithNamenull848 function FindLowestPkgDependencyWithName(const PkgName: string): TPkgDependency;
FindLowestPkgDependencyNodeWithNamenull849 function FindLowestPkgDependencyNodeWithName(const PkgName: string): TAVLTreeNode;
FindNextPkgDependencyNodeWithSameNamenull850 function FindNextPkgDependencyNodeWithSameName(Node: TAVLTreeNode): TAVLTreeNode;
851 
GetDependencyOwnerAsStringnull852 function GetDependencyOwnerAsString(Dependency: TPkgDependency): string;
GetDependencyOwnerDirectorynull853 function GetDependencyOwnerDirectory(Dependency: TPkgDependency): string;
854 
855 procedure PkgVersionLoadFromXMLConfig(Version: TPkgVersion;
856   XMLConfig: TXMLConfig; const Path: string; FileVersion: integer);
857 procedure PkgVersionSaveToXMLConfig(Version: TPkgVersion; XMLConfig: TXMLConfig;
858   const Path: string);
859 procedure PkgVersionLoadFromXMLConfig(Version: TPkgVersion;
860   XMLConfig: TXMLConfig);
861 
862 var
863   Package1: TLazPackage; // don't use it - only for options dialog
864 
865 function dbgs(p: TPackageUpdatePolicy): string; overload;
866 function dbgs(p: TLazPackageType): string; overload;
867 function PackagePathToStr(PathList: TFPList): string;
868 
869 
870 implementation
871 
872 function GetPkgFileTypeLocalizedName(FileType: TPkgFileType): string;
873 begin
874   case FileType of
875   pftUnit: Result:=lisUnit;
876   pftVirtualUnit: Result:=lisPkgFileTypeVirtualUnit;
877   pftMainUnit: Result:=lisPkgFileTypeMainUnit;
878   pftLFM: Result:=lisPkgFileTypeLFM;
879   pftLRS: Result:=lisPkgFileTypeLRS;
880   pftInclude: Result:=lisPkgFileTypeInclude;
881   pftIssues: Result:=lisPkgFileTypeIssues;
882   pftText: Result:=lisPkgFileTypeText;
883   pftBinary: Result:=lisPkgFileTypeBinary;
884   else
885     Result:='Unknown';
886   end;
887 end;
888 
889 function NameToAutoUpdatePolicy(const s: string): TPackageUpdatePolicy;
890 begin
891   for Result:=Low(TPackageUpdatePolicy) to High(TPackageUpdatePolicy) do
892     if SysUtils.CompareText(AutoUpdateNames[Result],s)=0 then exit;
893   Result:=pupAsNeeded;
894 end;
895 
896 function FileNameToPkgFileType(AFilename: string): TPkgFileType;
897 var
898   Code: TCodeBuffer;
899   SrcType: String;
900   HasName: Boolean;
901 begin
902   HasName:=ExtractFileNameOnly(AFilename)<>'';
903   if HasName then begin
904     if FilenameExtIs(AFilename,'lfm',true) then
905       exit(pftLFM)
906     else if FilenameExtIs(AFilename,'lrs',true) then
907       exit(pftLRS)
908     else if FilenameExtIs(AFilename,'inc') then
909       exit(pftInclude)
910     else if FilenameExtIs(AFilename,'xml') then
911       exit(pftIssues)
912     else if FilenameHasPascalExt(AFilename) then begin
913       Result:=pftUnit;
914       AFilename:=CleanAndExpandFilename(AFilename);
915       Code:=CodeToolBoss.LoadFile(aFilename,true,false);
916       if Code<>nil then begin
917         SrcType:=CodeToolBoss.GetSourceType(Code,false);
918         if CompareText(SrcType,'unit')<>0 then
919           Result:=pftInclude;
920       end;
921       exit;
922     end;
923   end;
924   if FileIsText(AFilename) then
925     Result:=pftText
926   else
927     Result:=pftBinary;
928 end;
929 
930 procedure LoadPkgDependencyList(XMLConfig: TXMLConfig; const ThePath: string;
931   var First: TPkgDependency; ListType: TPkgDependencyDirection; Owner: TObject;
932   HoldPackages, SortList: boolean);
933 var
934   i: Integer;
935   PkgDependency: TPkgDependency;
936   NewCount: Integer;
937   List: TFPList;
938   FileVersion: Integer;
939   Last: TPkgDependency;
940   LegacyList: Boolean;
941   SubPath: string;
942 begin
943   FileVersion:=XMLConfig.GetValue(ThePath+'Version',0);
944   LegacyList:=XMLConfig.IsLegacyList(ThePath);
945   NewCount:=XMLConfig.GetListItemCount(ThePath, 'Item', LegacyList);
946   List:=TFPList.Create;
947   for i:=0 to NewCount-1 do begin
948     PkgDependency:=TPkgDependency.Create;
949     SubPath:=ThePath+XMLConfig.GetListItemXPath('Item', i, LegacyList, True)+'/';
950     PkgDependency.LoadFromXMLConfig(XMLConfig,SubPath,FileVersion);
951     PkgDependency.HoldPackage:=HoldPackages;
952     // IsMakingSense checks if the package-name is a valid identifier. This is
953     // not applicable to FPMake-packages.
954     if (PkgDependency.DependencyType=pdtFPMake) or PkgDependency.IsMakingSense then
955       List.Add(PkgDependency)
956     else
957       PkgDependency.Free;
958   end;
959   if SortList then
960     SortDependencyListAlphabetically(List);
961   Last:=First;
962   if Last<>nil then
963     while Last.NextDependency[ListType]<>nil do
964       Last:=Last.NextDependency[ListType];
965   for i:=0 to List.Count-1 do begin
966     PkgDependency:=TPkgDependency(List[i]);
967     PkgDependency.AddToEndOfList(Last,ListType);
968     if First=nil then
969       First:=Last;
970     PkgDependency.Owner:=Owner;
971   end;
972   List.Free;
973 end;
974 
975 procedure SavePkgDependencyList(XMLConfig: TXMLConfig; const ThePath: string;
976   First: TPkgDependency; ListType: TPkgDependencyDirection;
977   UsePathDelim: TPathDelimSwitch; LegacyLists: Boolean);
978 var
979   i: Integer;
980   Dependency: TPkgDependency;
981   SubPath: string;
982 begin
983   i:=0;
984   Dependency:=First;
985   while Dependency<>nil do begin
986     SubPath:=ThePath+XMLConfig.GetListItemXPath('Item', i, LegacyLists, True)+'/';
987     Dependency.SaveToXMLConfig(XMLConfig,SubPath,UsePathDelim);
988     Dependency:=Dependency.NextDependency[ListType];
989     inc(i);
990   end;
991   XMLConfig.SetListItemCount(ThePath, i, LegacyLists);
992 end;
993 
994 procedure ListPkgIDToDependencyList(ListOfTLazPackageID: TObjectList;
995   var First: TPkgDependency; ListType: TPkgDependencyDirection; Owner: TObject;
996   HoldPackages: boolean);
997 var
998   NewDependency: TPkgDependency;
999   i: Integer;
1000   PkgID: TLazPackageID;
1001 begin
1002   First:=nil;
1003   for i:=ListOfTLazPackageID.Count-1 downto 0 do begin
1004     PkgID:=TLazPackageID(ListOfTLazPackageID[i]);
1005     NewDependency:=TPkgDependency.Create;
1006     NewDependency.Assign(PkgID);
1007     NewDependency.Owner:=Owner;
1008     NewDependency.HoldPackage:=HoldPackages;
1009     NewDependency.AddToList(First,ListType);
1010   end;
1011 end;
1012 
1013 procedure DeleteDependencyInList(ADependency: TPkgDependency;
1014   var First: TPkgDependency; ListType: TPkgDependencyDirection);
1015 var
1016   NextDependency, PrevDependency: TPkgDependency;
1017 begin
1018   NextDependency := ADependency.NextDependency[ListType];
1019   PrevDependency := ADependency.PrevDependency[ListType];
1020   if First = ADependency then First := NextDependency;
1021   if Assigned(NextDependency) then
1022     NextDependency.PrevDependency[ListType] := PrevDependency;
1023   if Assigned(PrevDependency) then
1024     PrevDependency.NextDependency[ListType] := NextDependency;
1025   ADependency.Free;
1026 end;
1027 
1028 procedure FreeDependencyList(var First: TPkgDependency;
1029   ListType: TPkgDependencyDirection);
1030 var
1031   NextDependency: TPkgDependency;
1032 begin
1033   while First<>nil do begin
1034     NextDependency:=First.NextDependency[ListType];
1035     First.Free;
1036     First:=NextDependency;
1037   end;
1038 end;
1039 
1040 function DependencyListAsString(First: TPkgDependency;
1041   ListType: TPkgDependencyDirection): string;
1042 begin
1043   Result:='';
1044   while First<>nil do begin
1045     Result:=Result+First.AsString+LineEnding;
1046     First:=First.NextDependency[ListType];
1047   end;
1048 end;
1049 
1050 procedure SortDependencyListAlphabetically(Dependencies: TFPList);
1051 var
1052   Count: Integer;
1053   i, j: Integer;
1054   Dependency1: TPkgDependency;
1055   Dependency2: TPkgDependency;
1056   Sorted: Boolean;
1057 begin
1058   if (Dependencies=nil) or (Dependencies.Count<2) then exit;
1059   // check if already sorted
1060   Count:=Dependencies.Count;
1061   Sorted:=true;
1062   for i:=0 to Count-2 do begin
1063     Dependency1:=TPkgDependency(Dependencies[i]);
1064     Dependency2:=TPkgDependency(Dependencies[i+1]);
1065     if Dependency1.Compare(Dependency2)>0 then begin
1066       Sorted:=false;
1067       break;
1068     end;
1069   end;
1070   if Sorted then exit;
1071   // bubble sort (slow, but dependency lists are normally sorted)
1072   for i:=0 to Count-2 do begin
1073     Dependency1:=TPkgDependency(Dependencies[i]);
1074     for j:=i+1 to Count-1 do begin
1075       Dependency2:=TPkgDependency(Dependencies[j]);
1076       if Dependency1.Compare(Dependency2)>0 then begin
1077         Dependencies.Exchange(i,j);
1078         Dependency1:=TPkgDependency(Dependencies[i]);
1079       end;
1080     end;
1081   end;
1082 end;
1083 
1084 function StrToComponentBaseClass(const s: string): TPFComponentBaseClass;
1085 begin
1086   for Result:=low(TPFComponentBaseClass) to high(TPFComponentBaseClass) do
1087     if SysUtils.CompareText(PFComponentBaseClassNames[Result],s)=0 then exit;
1088   Result:=pfcbcNone;
1089 end;
1090 
1091 function GetComponentBaseClass(aClass: TClass): TPFComponentBaseClass;
1092 begin
1093   Result:=pfcbcNone;
1094   if aClass=nil then exit;
1095   if aClass.InheritsFrom(TForm) then
1096     Result:=pfcbcForm
1097   else if aClass.InheritsFrom(TFrame) then
1098     Result:=pfcbcFrame
1099   else if aClass.InheritsFrom(TDataModule) then
1100     Result:=pfcbcDataModule
1101   else if aClass.InheritsFrom(TCustomForm) then
1102     Result:=pfcbcCustomForm;
1103 end;
1104 
1105 function CompareLazPackageID(Data1, Data2: Pointer): integer;
1106 var
1107   Pkg1: TLazPackageID absolute Data1;
1108   Pkg2: TLazPackageID absolute Data2;
1109 begin
1110   Result:=Pkg1.Compare(Pkg2);
1111 end;
1112 
1113 function CompareNameWithPackageID(Key, Data: Pointer): integer;
1114 var
1115   Name: String;
1116   Pkg: TLazPackageID;
1117 begin
1118   if Key<>nil then begin
1119     Name:=AnsiString(Key);
1120     Pkg:=TLazPackageID(Data);
1121     Result:=SysUtils.CompareText(Name,Pkg.Name);
1122   end else
1123     Result:=-1;
1124 end;
1125 
1126 function ComparePkgIDMaskWithPackageID(Key, Data: Pointer): integer;
1127 var
1128   Pkg1: TLazPackageID absolute Key;
1129   Pkg2: TLazPackageID absolute Data;
1130 begin
1131   Result:=Pkg1.CompareMask(Pkg2);
1132 end;
1133 
1134 function CompareLazPackageIDNames(Data1, Data2: Pointer): integer;
1135 var
1136   Pkg1: TLazPackageID absolute Data1;
1137   Pkg2: TLazPackageID absolute Data2;
1138 begin
1139   Result:=SysUtils.CompareText(Pkg1.Name,Pkg2.Name);
1140 end;
1141 
1142 function CompareLazPackageTopologicallyAndName(Data1, Data2: Pointer): integer;
1143 var
1144   Pkg1: TLazPackage absolute Data1;
1145   Pkg2: TLazPackage absolute Data2;
1146 begin
1147   Result:=Pkg1.TopologicalLevel-Pkg2.TopologicalLevel;
1148   if Result<>0 then exit;
1149   Result:=SysUtils.CompareText(Pkg1.Name,Pkg2.Name);
1150 end;
1151 
1152 function CompareNameWithPkgDependency(Key, Data: Pointer): integer;
1153 var
1154   PkgName: String;
1155   Dependency: TPkgDependency absolute Data;
1156 begin
1157   PkgName:=String(Key);
1158   Result:=SysUtils.CompareText(PkgName,Dependency.PackageName);
1159 end;
1160 
1161 function ComparePkgDependencyNames(Data1, Data2: Pointer): integer;
1162 var
1163   Dependency1: TPkgDependency absolute Data1;
1164   Dependency2: TPkgDependency absolute Data2;
1165 begin
1166   Result:=SysUtils.CompareText(Dependency1.PackageName,Dependency2.PackageName);
1167 end;
1168 
1169 function CompareUnitsTree(UnitTree1, UnitTree2: TPkgUnitsTree): integer;
1170 begin
1171   Result:=UnitTree1.LazPackage.Compare(UnitTree2.LazPackage);
1172 end;
1173 
1174 function ComparePackageWithUnitsTree(Package: TLazPackage;
1175                                      UnitTree: TPkgUnitsTree): integer;
1176 begin
1177   Result:=Package.Compare(UnitTree.LazPackage);
1178 end;
1179 
1180 function ComparePkgFilesAlphabetically(PkgFile1, PkgFile2: TPkgFile): integer;
1181 var
1182   ShortFilename1: String;
1183   ShortFilename2: String;
1184   File1IsInMainDir: Boolean;
1185   File2IsInMainDir: Boolean;
1186 begin
1187   ShortFilename1:=PkgFile1.GetShortFilename(true);
1188   ShortFilename2:=PkgFile2.GetShortFilename(true);
1189   // files in the main directory are higher
1190   File1IsInMainDir:=ExtractFilePath(ShortFilename1)='';
1191   File2IsInMainDir:=ExtractFilePath(ShortFilename2)='';
1192   if File1IsInMainDir xor File2IsInMainDir then begin
1193     if File1IsInMainDir then
1194       Result:=-1
1195     else
1196       Result:=1;
1197     exit;
1198   end;
1199   // compare short filenames without extension
1200   Result:=CompareFilenames(ChangeFileExt(ShortFilename1,''),
1201                            ChangeFileExt(ShortFilename2,''));
1202   if Result<>0 then exit;
1203   // if one is a unit, then it is higher
1204   if (PkgFile1.Unit_Name<>'') and (PkgFile2.Unit_Name='') then begin
1205     Result:=-1;
1206     exit;
1207   end else if (PkgFile1.Unit_Name='') and (PkgFile2.Unit_Name<>'') then begin
1208     Result:=1;
1209     exit;
1210   end;
1211   // compare short filenames with extension
1212   Result:=CompareFilenames(ShortFilename1,ShortFilename2);
1213   if Result<>0 then exit;
1214   // compare filenames
1215   Result:=CompareFilenames(PkgFile1.FileName,PkgFile2.FileName);
1216 end;
1217 
1218 function GetUsageOptionsList(PackageList: TFPList): TFPList;
1219 // returns a list of TPkgAdditionalCompilerOptions
1220 // from the list of TLazPackage
1221 var
1222   Cnt: Integer;
1223   i: Integer;
1224 begin
1225   if PackageList<>nil then begin
1226     Result:=TFPList.Create;
1227     Cnt:=PackageList.Count;
1228     for i:=0 to Cnt-1 do begin
1229       Result.Add(TLazPackage(PackageList[i]).UsageOptions);
1230     end;
1231   end else begin
1232     Result:=nil;
1233   end;
1234 end;
1235 
1236 function FindDependencyByNameInList(First: TPkgDependency;
1237   ListType: TPkgDependencyDirection; const Name: string): TPkgDependency;
1238 begin
1239   Result:=First;
1240   while Result<>nil do begin
1241     if SysUtils.CompareText(Result.PackageName,Name)=0 then exit;
1242     Result:=Result.NextDependency[ListType];
1243   end;
1244 end;
1245 
1246 function FindCompatibleDependencyInList(First: TPkgDependency;
1247   ListType: TPkgDependencyDirection; ComparePackage: TLazPackageID): TPkgDependency;
1248 begin
1249   Result:=First;
1250   while Result<>nil do begin
1251     if Result.IsCompatible(ComparePackage) then exit;
1252     Result:=Result.NextDependency[ListType];
1253   end;
1254 end;
1255 
1256 function GetDependencyWithIndex(First: TPkgDependency;
1257   ListType: TPkgDependencyDirection; Index: integer): TPkgDependency;
1258 begin
1259   if Index<0 then RaiseGDBException('GetDependencyWithIndex');
1260   Result:=First;
1261   while (Result<>nil) and (Index>0) do begin
1262     Result:=Result.NextDependency[ListType];
1263     dec(Index);
1264   end;
1265 end;
1266 
1267 function FindLowestPkgDependencyNodeWithName(const PkgName: string): TAVLTreeNode;
1268 begin
1269   Result:=nil;
1270   if PackageDependencies=nil then exit;
1271   Result:=PackageDependencies.FindLeftMostKey(PChar(PkgName),
1272                                               @CompareNameWithPkgDependency);
1273 end;
1274 
1275 function FindNextPkgDependencyNodeWithSameName(
1276   Node: TAVLTreeNode): TAVLTreeNode;
1277 begin
1278   Result:=nil;
1279   if (Node=nil) or (PackageDependencies=nil) then exit;
1280   Result:=PackageDependencies.FindSuccessor(Node);
1281   if (Result<>nil)
1282   and (SysUtils.CompareText(TPkgDependency(Node.Data).PackageName,
1283                    TPkgDependency(Result.Data).PackageName)<>0)
1284   then
1285     Result:=nil;
1286 end;
1287 
1288 function GetDependencyOwnerAsString(Dependency: TPkgDependency): string;
1289 begin
1290   Result := '';
1291   OnGetDependencyOwnerDescription(Dependency,Result);
1292 end;
1293 
1294 function GetDependencyOwnerDirectory(Dependency: TPkgDependency): string;
1295 begin
1296   Result := '';
1297   OnGetDependencyOwnerDirectory(Dependency,Result);
1298 end;
1299 
1300 procedure PkgVersionLoadFromXMLConfig(Version: TPkgVersion;
1301   XMLConfig: TXMLConfig; const Path: string; FileVersion: integer);
1302 var
1303   NewMajor: Integer;
1304   NewMinor: Integer;
1305   NewRelease: Integer;
1306   NewBuild: Integer;
1307 begin
1308   if FileVersion=1 then ;
1309   NewMajor:=Version.VersionBound(XMLConfig.GetValue(Path+'Major',0));
1310   NewMinor:=Version.VersionBound(XMLConfig.GetValue(Path+'Minor',0));
1311   NewRelease:=Version.VersionBound(XMLConfig.GetValue(Path+'Release',0));
1312   NewBuild:=Version.VersionBound(XMLConfig.GetValue(Path+'Build',0));
1313   Version.SetValues(NewMajor,NewMinor,NewRelease,NewBuild,pvtBuild);
1314 end;
1315 
1316 procedure PkgVersionSaveToXMLConfig(Version: TPkgVersion; XMLConfig: TXMLConfig;
1317   const Path: string);
1318 begin
1319   XMLConfig.SetDeleteValue(Path+'Major',Version.Major,0);
1320   XMLConfig.SetDeleteValue(Path+'Minor',Version.Minor,0);
1321   XMLConfig.SetDeleteValue(Path+'Release',Version.Release,0);
1322   XMLConfig.SetDeleteValue(Path+'Build',Version.Build,0);
1323 end;
1324 
1325 procedure PkgVersionLoadFromXMLConfig(Version: TPkgVersion;
1326   XMLConfig: TXMLConfig);
1327 var
1328   Path: String;
1329   FileVersion: LongInt;
1330 begin
1331   Path:='Package/';
1332   FileVersion:=XMLConfig.GetValue(Path+'Version',0);
1333   PkgVersionLoadFromXMLConfig(Version,XMLConfig,Path+'Version/',FileVersion);
1334 end;
1335 
1336 function dbgs(p: TPackageUpdatePolicy): string;
1337 begin
1338   Result:=GetEnumName(TypeInfo(p),ord(p));
1339 end;
1340 
1341 function dbgs(p: TLazPackageType): string;
1342 begin
1343   Result:=LazPackageTypeIdents[p];
1344 end;
1345 
1346 function PackagePathToStr(PathList: TFPList): string;
1347 var
1348   i: Integer;
1349   Item: TObject;
1350   Dep: TPkgDependency;
1351 begin
1352   Result:='';
1353   if PathList=nil then exit;
1354   for i:=0 to PathList.Count-1 do begin
1355     if i>0 then
1356       Result:=Result+' -> ';
1357     Item:=TObject(PathList[i]);
1358     if Item is TPkgDependency then begin
1359       Dep:=TPkgDependency(Item);
1360       Result:=Result+GetDependencyOwnerAsString(Dep);
1361       if i=PathList.Count-1 then
1362         Result:=Result+' -> '+Dep.AsString;
1363     end else if Item is TLazPackage then
1364       Result:=Result+TLazPackage(Item).Name
1365     else
1366       Result:=Result+DbgSName(Item);
1367   end;
1368 end;
1369 
1370 function IndexOfDependencyInList(First: TPkgDependency;
1371   ListType: TPkgDependencyDirection; FindDependency: TPkgDependency): integer;
1372 var
1373   Dependency: TPkgDependency;
1374 begin
1375   Result:=-1;
1376   Dependency:=First;
1377   while Dependency<>nil do begin
1378     inc(Result);
1379     if Dependency=FindDependency then exit;
1380     Dependency:=Dependency.NextDependency[ListType];
1381   end;
1382   Result:=-1;
1383 end;
1384 
1385 function GetFirstDependency(ListItem: TPkgDependency;
1386   ListType: TPkgDependencyDirection): TPkgDependency;
1387 begin
1388   Result:=ListItem;
1389   if Result=nil then exit;
1390   while Result.PrevDependency[ListType]<>nil do
1391     Result:=Result.PrevDependency[ListType];
1392 end;
1393 
1394 function FindLowestPkgDependencyWithName(const PkgName: string): TPkgDependency;
1395 var
1396   ANode: TAVLTreeNode;
1397 begin
1398   ANode:=FindLowestPkgDependencyNodeWithName(PkgName);
1399   if ANode<>nil then
1400     Result:=TPkgDependency(ANode.Data)
1401   else
1402     Result:=nil;
1403 end;
1404 
1405 { TPkgFile }
1406 
1407 procedure TPkgFile.SetFilename(const AValue: string);
1408 var
1409   NewFilename: String;
1410   OldDirectory: String;
1411 begin
1412   NewFilename:=AValue;
1413   ForcePathDelims(NewFilename);
1414   if Filename=NewFilename then exit;
1415   fFilename:=NewFilename;
1416   fFullFilenameStamp:=LUInvalidChangeStamp;
1417   OldDirectory:=FDirectory;
1418   FDirectory:=ExtractFilePath(Filename);
1419   if OldDirectory<>FDirectory then begin
1420     if FSourceDirNeedReference then begin
1421       LazPackage.SourceDirectories.RemoveFilename(OldDirectory);
1422       LazPackage.SourceDirectories.AddFilename(FDirectory);
1423     end;
1424   end;
1425   UpdateUnitName;
1426 end;
1427 
GetHasRegisterProcnull1428 function TPkgFile.GetHasRegisterProc: boolean;
1429 begin
1430   Result:=pffHasRegisterProc in FFlags;
1431 end;
1432 
1433 procedure TPkgFile.SetAddToUsesPkgSection(const AValue: boolean);
1434 begin
1435   if AddToUsesPkgSection=AValue then exit;
1436   if AValue then
1437     Include(FFlags,pffAddToPkgUsesSection)
1438   else
1439     Exclude(FFlags,pffAddToPkgUsesSection);
1440 end;
1441 
1442 procedure TPkgFile.SetAutoReferenceSourceDir(const AValue: boolean);
1443 begin
1444   if FAutoReferenceSourceDir=AValue then exit;
1445   FAutoReferenceSourceDir:=AValue;
1446   if FSourceDirNeedReference then
1447     UpdateSourceDirectoryReference;
1448 end;
1449 
1450 procedure TPkgFile.SetRemoved(const AValue: boolean);
1451 begin
1452   if Removed=AValue then exit;
1453   inherited SetRemoved(AValue);
1454   FSourceDirNeedReference:=(FileType in PkgFileRealUnitTypes) and not Removed;
1455   UpdateSourceDirectoryReference;
1456 end;
1457 
1458 procedure TPkgFile.SetDisableI18NForLFM(AValue: boolean);
1459 begin
1460   if DisableI18NForLFM=AValue then exit;
1461   inherited SetDisableI18NForLFM(AValue);
1462   LazPackage.Modified:=true;
1463 end;
1464 
GetComponentsnull1465 function TPkgFile.GetComponents(Index: integer): TPkgComponent;
1466 begin
1467   Result:=TPkgComponent(FComponents[Index]);
1468 end;
1469 
GetAddToUsesPkgSectionnull1470 function TPkgFile.GetAddToUsesPkgSection: boolean;
1471 begin
1472   Result:=pffAddToPkgUsesSection in FFlags;
1473 end;
1474 
1475 procedure TPkgFile.SetFileType(const AValue: TPkgFileType);
1476 begin
1477   if FileType=AValue then exit;
1478   if (LazPackage<>nil) and (LazPackage.MainUnit=Self) then
1479     LazPackage.FMainUnit:=nil;
1480   inherited SetFileType(AValue);
1481   FSourceDirNeedReference:=(FileType in PkgFileRealUnitTypes) and not Removed;
1482   UpdateSourceDirectoryReference;
1483   if (FileType=pftMainUnit) and (LazPackage<>nil)
1484   and (LazPackage.MainUnit<>Self) then begin
1485     if LazPackage.MainUnit<>nil then
1486       LazPackage.MainUnit.FileType:=pftUnit;
1487     LazPackage.FMainUnit:=Self;
1488   end;
1489 end;
1490 
1491 procedure TPkgFile.SetFlags(const AValue: TPkgFileFlags);
1492 begin
1493   if FFlags=AValue then exit;
1494   FFlags:=AValue;
1495 end;
1496 
1497 procedure TPkgFile.SetHasRegisterProc(const AValue: boolean);
1498 begin
1499   if HasRegisterProc=AValue then exit;
1500   if AValue then
1501     Include(FFlags,pffHasRegisterProc)
1502   else
1503     Exclude(FFlags,pffHasRegisterProc);
1504 end;
1505 
1506 procedure TPkgFile.SetUnitName(const AValue: string);
1507 begin
1508   if FUnitName=AValue then Exit;
1509   FUnitName:=AValue;
1510 end;
1511 
1512 procedure TPkgFile.UpdateUnitName;
1513 var
1514   NewUnitName: String;
1515 begin
1516   if FilenameHasPascalExt(Filename) then begin
1517     NewUnitName:=ExtractFileNameOnly(Filename);
1518     if SysUtils.CompareText(NewUnitName,FUnitName)<>0 then
1519       FUnitName:=NewUnitName;
1520   end else
1521     FUnitName:='';
1522 end;
1523 
GetComponentListnull1524 function TPkgFile.GetComponentList: TFPList;
1525 begin
1526   if FComponents=nil then FComponents:=TFPList.Create;
1527   Result:=FComponents;
1528 end;
1529 
GetInUsesnull1530 function TPkgFile.GetInUses: boolean;
1531 begin
1532   Result:=pffAddToPkgUsesSection in FFlags;
1533 end;
1534 
1535 procedure TPkgFile.SetInUses(AValue: boolean);
1536 begin
1537   if InUses=AValue then exit;
1538   if AValue then
1539     Include(FFlags,pffAddToPkgUsesSection)
1540   else
1541     Exclude(FFlags,pffAddToPkgUsesSection);
1542 end;
1543 
GetIDEPackagenull1544 function TPkgFile.GetIDEPackage: TIDEPackage;
1545 begin
1546   Result:=FPackage;
1547 end;
1548 
GetFilenamenull1549 function TPkgFile.GetFilename: string;
1550 begin
1551   Result:=fFilename;
1552 end;
1553 
HasRegisteredPluginsnull1554 function TPkgFile.HasRegisteredPlugins: boolean;
1555 begin
1556   Result:=ComponentCount>0;
1557 end;
1558 
MakeSensenull1559 function TPkgFile.MakeSense: boolean;
1560 begin
1561   Result:=Filename<>'';
1562 end;
1563 
1564 procedure TPkgFile.UpdateSourceDirectoryReference;
1565 begin
1566   if (not AutoReferenceSourceDir) or (FPackage=nil) then exit;
1567   if FSourceDirNeedReference then begin
1568     if not SourceDirectoryReferenced then begin
1569       LazPackage.SourceDirectories.AddFilename(FDirectory);
1570       FSourceDirectoryReferenced:=true;
1571     end;
1572   end else begin
1573     if SourceDirectoryReferenced then begin
1574       LazPackage.SourceDirectories.RemoveFilename(FDirectory);
1575       FSourceDirectoryReferenced:=false;
1576     end;
1577   end;
1578 end;
1579 
GetFullFilenamenull1580 function TPkgFile.GetFullFilename: string;
1581 begin
1582   if fFullFilenameStamp<>CompilerParseStamp then begin
1583     fFullFilename:=Filename;
1584     fFullFilenameStamp:=CompilerParseStamp;
1585     if LazPackage<>nil then begin
1586       LazPackage.SubstitutePkgMacros(fFullFilename,false);
1587       fFullFilename:=TrimFilename(fFullFilename);
1588       LazPackage.LongenFilename(fFullFilename);
1589     end
1590     else begin
1591       IDEMacros.SubstituteMacros(fFullFilename);
1592       fFullFilename:=TrimAndExpandFilename(fFullFilename);
1593     end;
1594   end;
1595   Result:=fFullFilename;
1596 end;
1597 
1598 constructor TPkgFile.Create(ThePackage: TLazPackage);
1599 begin
1600   inherited Create;
1601   Clear;
1602   FPackage:=ThePackage;
1603   FComponentPriority:=ComponentPriorityNormal;
1604 end;
1605 
1606 destructor TPkgFile.Destroy;
1607 begin
1608   FreeThenNil(FComponents);
1609   if (LazPackage<>nil) then begin
1610     if (LazPackage.MainUnit=Self) then
1611       LazPackage.FMainUnit:=nil;
1612     if (not (lpfDestroying in LazPackage.Flags)) then begin
1613       if Removed then
1614         LazPackage.FRemovedFiles.Remove(Self)
1615       else
1616         LazPackage.FFiles.Remove(Self);
1617     end;
1618   end;
1619   inherited Destroy;
1620 end;
1621 
1622 procedure TPkgFile.Clear;
1623 begin
1624   AutoReferenceSourceDir:=false;
1625   if (LazPackage=nil) or (not (lpfDestroying in LazPackage.Flags)) then begin
1626     inherited SetRemoved(false);
1627     fFilename:='';
1628     FDirectory:='';
1629     FFlags:=[];
1630     inherited SetFileType(pftUnit);
1631     FSourceDirectoryReferenced:=false;
1632     FSourceDirNeedReference:=true;
1633   end;
1634   FreeThenNil(FComponents);
1635   if (LazPackage<>nil) and (LazPackage.MainUnit=Self) then
1636     LazPackage.FMainUnit:=nil;
1637 end;
1638 
1639 procedure TPkgFile.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string;
1640   FileVersion: integer; AdjustPathDelims: boolean);
1641 var
1642   AFilename: String;
1643   CaseInsensitiveUnitName: String;
1644   Config: TXMLOptionsStorage;
1645 begin
1646   if FileVersion=1 then ;
1647   Clear;
1648   AFilename:=SwitchPathDelims(XMLConfig.GetValue(Path+'Filename/Value',''),
1649                               AdjustPathDelims);
1650   FPackage.LongenFilename(AFilename);
1651   Filename:=AFilename;
1652   FileType:=PkgFileTypeIdentToType(XMLConfig.GetValue(Path+'Type/Value',''));
1653   HasRegisterProc:=XMLConfig.GetValue(Path+'HasRegisterProc/Value',false);
1654   AddToUsesPkgSection:=XMLConfig.GetValue(Path+'AddToUsesPkgSection/Value',
1655                                           FileType in PkgFileUnitTypes);
1656   DisableI18NForLFM:=XMLConfig.GetValue(Path+'DisableI18NForLFM/Value',false);
1657   fUnitName:=XMLConfig.GetValue(Path+'UnitName/Value','');
1658   if FileType in PkgFileUnitTypes then begin
1659     // make sure the unitname makes sense
1660     CaseInsensitiveUnitName:=ExtractFileNameOnly(Filename);
1661     if SysUtils.CompareText(fUnitName,CaseInsensitiveUnitName)<>0 then
1662       fUnitName:=CaseInsensitiveUnitName;
1663   end;
1664   FResourceBaseClass:=StrToComponentBaseClass(
1665                          XMLConfig.GetValue(Path+'ResourceBaseClass/Value',''));
1666 
1667   Config:=TXMLOptionsStorage.Create(XMLConfig);
1668   try
1669     TConfigMemStorage(CustomOptions).LoadFromConfig(Config,Path+'CustomOptions/');
1670   finally
1671     Config.Free;
1672   end;
1673 end;
1674 
1675 procedure TPkgFile.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string;
1676   UsePathDelim: TPathDelimSwitch);
1677 var
1678   TmpFilename: String;
1679   Config: TXMLOptionsStorage;
1680 begin
1681   TmpFilename:=Filename;
1682   FPackage.ShortenFilename(TmpFilename,true);
1683   XMLConfig.SetDeleteValue(Path+'Filename/Value',
1684                            SwitchPathDelims(TmpFilename,UsePathDelim),'');
1685   XMLConfig.SetDeleteValue(Path+'Type/Value',PkgFileTypeIdents[FileType],
1686                            PkgFileTypeIdents[pftUnit]);
1687   XMLConfig.SetDeleteValue(Path+'HasRegisterProc/Value',HasRegisterProc,
1688                            false);
1689   XMLConfig.SetDeleteValue(Path+'AddToUsesPkgSection/Value',AddToUsesPkgSection,
1690                            FileType in PkgFileUnitTypes);
1691   XMLConfig.SetDeleteValue(Path+'DisableI18NForLFM/Value',DisableI18NForLFM,false);
1692   XMLConfig.SetDeleteValue(Path+'UnitName/Value',FUnitName,'');
1693   XMLConfig.SetDeleteValue(Path+'ResourceBaseClass/Value',
1694                            PFComponentBaseClassNames[FResourceBaseClass],
1695                            PFComponentBaseClassNames[pfcbcNone]);
1696 
1697   Config:=TXMLOptionsStorage.Create(XMLConfig);
1698   try
1699     TConfigMemStorage(CustomOptions).SaveToConfig(Config,Path+'CustomOptions/');
1700   finally
1701     Config.Free;
1702   end;
1703 end;
1704 
1705 procedure TPkgFile.ConsistencyCheck;
1706 begin
1707   if FPackage=nil then
1708     RaiseGDBException('TPkgFile.ConsistencyCheck FPackage=nil');
1709   if Filename='' then
1710     RaiseGDBException('TPkgFile.ConsistencyCheck FFilename=""');
1711 end;
1712 
GetShortFilenamenull1713 function TPkgFile.GetShortFilename(UseUp: boolean): string;
1714 begin
1715   Result:=GetFullFilename;
1716   LazPackage.ShortenFilename(Result,UseUp);
1717 end;
1718 
ComponentCountnull1719 function TPkgFile.ComponentCount: integer;
1720 begin
1721   if FComponents<>nil then
1722     Result:=FComponents.Count
1723   else
1724     Result:=0;
1725 end;
1726 
1727 procedure TPkgFile.AddPkgComponent(APkgComponent: TPkgComponent);
1728 begin
1729   if FComponents=nil then FComponents:=TFPList.Create;
1730   FComponents.Add(APkgComponent);
1731   if LazPackage<>nil then
1732     LazPackage.AddPkgComponent(APkgComponent);
1733 end;
1734 
1735 procedure TPkgFile.RemovePkgComponent(APkgComponent: TPkgComponent);
1736 begin
1737   if FComponents<>nil then
1738     FComponents.Remove(APkgComponent);
1739   if LazPackage<>nil then
1740     LazPackage.RemovePkgComponent(APkgComponent);
1741 end;
1742 
GetResolvedFilenamenull1743 function TPkgFile.GetResolvedFilename: string;
1744 begin
1745   Result:=GetPhysicalFilenameCached(GetFullFilename,false);
1746 end;
1747 
GetFileOwnernull1748 function TPkgFile.GetFileOwner: TObject;
1749 begin
1750   Result:=LazPackage;
1751 end;
1752 
GetFileOwnerNamenull1753 function TPkgFile.GetFileOwnerName: string;
1754 begin
1755   if LazPackage<>nil then
1756     Result:=LazPackage.Name
1757   else
1758     Result:='';
1759 end;
1760 
1761 { TPkgDependency }
1762 
1763 procedure TPkgDependency.SetHoldPackage(const AValue: boolean);
1764 begin
1765   if FHoldPackage=AValue then exit;
1766   FHoldPackage:=AValue;
1767   if RequiredPackage<>nil then begin
1768     if FHoldPackage then
1769       inc(RequiredPackage.FHoldPackageCount)
1770     else
1771       dec(RequiredPackage.FHoldPackageCount);
1772   end;
1773 end;
1774 
GetRequiredPackagenull1775 function TPkgDependency.GetRequiredPackage: TLazPackage;
1776 begin
1777   Result := TLazPackage(FRequiredPackage);
1778 end;
1779 
1780 procedure TPkgDependency.SetRequiredPackage(AValue: TLazPackage);
1781 begin
1782   Assert((DependencyType=pdtLazarus) or not assigned(AValue), 'Not possible to set a reference to a LazPackage into an FPMake-dependency');
1783   RequiredIDEPackage := AValue;
1784 end;
1785 
1786 procedure TPkgDependency.SetPackageName(const AValue: string);
1787 begin
1788   if FPackageName=AValue then exit;
1789   if (PackageDependencies<>nil) and (FPackageName<>'') then
1790     AVLRemovePointer(PackageDependencies,Self);
1791   FPackageName:=AValue;
1792   if (PackageDependencies<>nil) and (FPackageName<>'') then
1793     PackageDependencies.Add(Self);
1794   FDefaultFilename:='';
1795 end;
1796 
1797 constructor TPkgDependency.Create;
1798 begin
1799   inherited Create;
1800 end;
1801 
1802 destructor TPkgDependency.Destroy;
1803 begin
1804   inherited Destroy;
1805 end;
1806 
1807 procedure TPkgDependency.Clear;
1808 begin
1809   inherited Clear;
1810   FDefaultFilename:='';
1811   FPreferDefaultFilename:=false;
1812 end;
1813 
1814 procedure TPkgDependency.LoadFromXMLConfig(XMLConfig: TXMLConfig;
1815   const Path: string; FileVersion: integer);
1816 
1817   function LoadFilename(const SubPath: string): string;
1818   var
1819     BaseDir: String;
1820   begin
1821     Result:=GetForcedPathDelims(XMLConfig.GetValue(Path+SubPath,''));
1822     if (Result<>'') and (Owner<>nil)
1823     and (not FilenameIsAbsolute(Result)) then begin
1824       BaseDir:=GetDependencyOwnerDirectory(Self);
1825       if BaseDir<>'' then
1826         Result:=TrimFilename(AppendPathDelim(BaseDir)+Result);
1827     end;
1828   end;
1829 
1830 begin
1831   if FileVersion=1 then ;
1832   Clear;
1833   PackageName:=XMLConfig.GetValue(Path+'PackageName/Value','');
1834   if SameText(XMLConfig.GetValue(Path+'DependencyType/Value',''), PkgDependencyTypeNames[pdtFPMake]) then
1835     DependencyType:=pdtFPMake
1836   else
1837     DependencyType:=pdtLazarus;
1838   PkgVersionLoadFromXMLConfig(MaxVersion,XMLConfig,Path+'MaxVersion/',FileVersion);
1839   PkgVersionLoadFromXMLConfig(MinVersion,XMLConfig,Path+'MinVersion/',FileVersion);
1840   if XMLConfig.GetValue(Path+'MaxVersion/Valid',false) then
1841     Include(FFlags,pdfMaxVersion);
1842   if XMLConfig.GetValue(Path+'MinVersion/Valid',false) then
1843     Include(FFlags,pdfMinVersion);
1844   FDefaultFilename:=LoadFilename('DefaultFilename/Value');
1845   PreferDefaultFilename:=XMLConfig.GetValue(Path+'DefaultFilename/Prefer',false);
1846 end;
1847 
1848 procedure TPkgDependency.SaveToXMLConfig(XMLConfig: TXMLConfig;
1849   const Path: string; UsePathDelim: TPathDelimSwitch);
1850 
1851   procedure SaveFilename(const aPath: string; AFilename: string);
1852   var
1853     BaseDir: String;
1854   begin
1855     if (AFilename<>'')
1856     and (Owner<>nil) then begin
1857       BaseDir:=GetDependencyOwnerDirectory(Self);
1858       if BaseDir<>'' then
1859         AFilename:=CreateRelativePath(AFilename,BaseDir);
1860     end;
1861     XMLConfig.SetDeleteValue(Path+aPath,SwitchPathDelims(AFilename,UsePathDelim),'');
1862   end;
1863 
1864 begin
1865   XMLConfig.SetDeleteValue(Path+'PackageName/Value',PackageName,'');
1866   PkgVersionSaveToXMLConfig(MaxVersion,XMLConfig,Path+'MaxVersion/');
1867   PkgVersionSaveToXMLConfig(MinVersion,XMLConfig,Path+'MinVersion/');
1868   XMLConfig.SetDeleteValue(Path+'MaxVersion/Valid',pdfMaxVersion in FFlags,false);
1869   XMLConfig.SetDeleteValue(Path+'MinVersion/Valid',pdfMinVersion in FFlags,false);
1870   SaveFilename('DefaultFilename/Value',FDefaultFilename);
1871   XMLConfig.SetDeleteValue(Path+'DefaultFilename/Prefer',PreferDefaultFilename,false);
1872   XMLConfig.SetDeleteValue(Path+'DependencyType/Value',PkgDependencyTypeNames[DependencyType],PkgDependencyTypeNames[pdtLazarus]);
1873 end;
1874 
Comparenull1875 function TPkgDependency.Compare(Dependency2: TPkgDependency): integer;
1876 begin
1877   Result:=SysUtils.CompareText(PackageName,Dependency2.PackageName);
1878   if Result<>0 then exit;
1879   Result:=MinVersion.Compare(Dependency2.MinVersion);
1880   if Result<>0 then exit;
1881   Result:=CompareBoolean(pdfMinVersion in Flags,
1882                          pdfMinVersion in Dependency2.Flags);
1883   if Result<>0 then exit;
1884   Result:=MaxVersion.Compare(Dependency2.MaxVersion);
1885   if Result<>0 then exit;
1886   Result:=CompareBoolean(pdfMaxVersion in Flags,
1887                          pdfMaxVersion in Dependency2.Flags);
1888 end;
1889 
1890 procedure TPkgDependency.Assign(Source: TPkgDependency);
1891 begin
1892   PackageName:=Source.PackageName;
1893   Flags:=Source.Flags;
1894   MinVersion.Assign(Source.MinVersion);
1895   MaxVersion.Assign(Source.MaxVersion);
1896 end;
1897 
1898 procedure TPkgDependency.Assign(Source: TLazPackageID);
1899 begin
1900   PackageName:=Source.Name;
1901   Flags:=[pdfMinVersion];
1902   MinVersion.Assign(Source.Version);
1903 end;
1904 
1905 procedure TPkgDependency.ConsistencyCheck;
1906 begin
1907 
1908 end;
1909 
IsCompatiblenull1910 function TPkgDependency.IsCompatible(Pkg: TLazPackageID): boolean;
1911 begin
1912   Result:=IsCompatible(Pkg.Name,Pkg.Version);
1913 end;
1914 
1915 procedure TPkgDependency.MakeCompatible(const PkgName: string;
1916   const Version: TPkgVersion);
1917 begin
1918   PackageName:=PkgName;
1919   if MinVersion.Compare(Version)>0 then MinVersion.Assign(Version);
1920   if MaxVersion.Compare(Version)<0 then MaxVersion.Assign(Version);
1921 end;
1922 
AsStringnull1923 function TPkgDependency.AsString(WithOwner, WithDefaults: boolean): string;
1924 var
1925   FN: String;
1926 begin
1927   Result:=inherited AsString;
1928   if WithOwner and (Owner<>nil) then
1929     Result:=GetDependencyOwnerAsString(Self)+' uses '+Result;
1930   if WithDefaults then
1931   begin
1932     if DefaultFilename<>'' then
1933     begin
1934       FN:=MakeFilenameRelativeToOwner(DefaultFilename);
1935       if PreferDefaultFilename then
1936         Result:=Format(lisCEIn, [Result,FN]) // like 'in' keyword in uses section
1937       else
1938         Result:=Format(lisPckEditDefault, [Result,FN]);
1939     end;
1940     if DependencyType=pdtFPMake then
1941       Result:=Result+' '+lisPckEditFPMakePackage;
1942   end;
1943 end;
1944 
NextUsedByDependencynull1945 function TPkgDependency.NextUsedByDependency: TPkgDependency;
1946 begin
1947   Result:=NextDependency[pddUsedBy];
1948 end;
1949 
PrevUsedByDependencynull1950 function TPkgDependency.PrevUsedByDependency: TPkgDependency;
1951 begin
1952   Result:=PrevDependency[pddUsedBy];
1953 end;
1954 
NextRequiresDependencynull1955 function TPkgDependency.NextRequiresDependency: TPkgDependency;
1956 begin
1957   Result:=NextDependency[pddRequires];
1958 end;
1959 
PrevRequiresDependencynull1960 function TPkgDependency.PrevRequiresDependency: TPkgDependency;
1961 begin
1962   Result:=PrevDependency[pddRequires];
1963 end;
1964 
1965 procedure TPkgDependency.AddUsedByDep(var FirstDependency: TPkgDependencyBase);
1966 begin
1967   AddToList(TPkgDependency(FirstDependency), pddUsedBy);
1968 end;
1969 
1970 procedure TPkgDependency.RemoveUsedByDep(var FirstDependency: TPkgDependencyBase);
1971 begin
1972   RemoveFromList(TPkgDependency(FirstDependency), pddUsedBy);
1973 end;
1974 
1975 procedure TPkgDependency.AddRequiresDep(var FirstDependency: TPkgDependencyBase);
1976 begin
1977   AddToList(TPkgDependency(FirstDependency), pddRequires);
1978 end;
1979 
1980 procedure TPkgDependency.RemoveRequiresDep(var FirstDependency: TPkgDependencyBase);
1981 begin
1982   RemoveFromList(TPkgDependency(FirstDependency), pddRequires);
1983 end;
1984 
1985 procedure TPkgDependency.AddToList(var FirstDependency: TPkgDependency;
1986   ListType: TPkgDependencyDirection);
1987 begin
1988   NextDependency[ListType]:=FirstDependency;
1989   FirstDependency:=Self;
1990   PrevDependency[ListType]:=nil;
1991   if NextDependency[ListType]<>nil then
1992     NextDependency[ListType].PrevDependency[ListType]:=Self;
1993 end;
1994 
1995 procedure TPkgDependency.AddToEndOfList(var LastDependency: TPkgDependency;
1996   ListType: TPkgDependencyDirection);
1997 begin
1998   PrevDependency[ListType]:=LastDependency;
1999   LastDependency:=Self;
2000   NextDependency[ListType]:=nil;
2001   if PrevDependency[ListType]<>nil then
2002     PrevDependency[ListType].NextDependency[ListType]:=Self;
2003 end;
2004 
2005 procedure TPkgDependency.RemoveFromList(var FirstDependency: TPkgDependency;
2006   ListType: TPkgDependencyDirection);
2007 begin
2008   if FirstDependency=Self then FirstDependency:=NextDependency[ListType];
2009   if NextDependency[ListType]<>nil then
2010     NextDependency[ListType].PrevDependency[ListType]:=PrevDependency[ListType];
2011   if PrevDependency[ListType]<>nil then
2012     PrevDependency[ListType].NextDependency[ListType]:=NextDependency[ListType];
2013   NextDependency[ListType]:=nil;
2014   PrevDependency[ListType]:=nil;
2015 end;
2016 
MoveUpInListnull2017 function TPkgDependency.MoveUpInList(var FirstDependency: TPkgDependency;
2018   ListType: TPkgDependencyDirection): Boolean;
2019 var
2020   OldPrev: TPkgDependency;
2021 begin
2022   if (FirstDependency=Self) or (PrevDependency[ListType]=nil) then exit(False);
2023   OldPrev:=PrevDependency[ListType];
2024   if OldPrev.PrevDependency[ListType]<>nil then
2025     OldPrev.PrevDependency[ListType].NextDependency[ListType]:=Self;
2026   if NextDependency[ListType]<>nil then
2027     NextDependency[ListType].PrevDependency[ListType]:=OldPrev;
2028   OldPrev.NextDependency[ListType]:=NextDependency[ListType];
2029   PrevDependency[ListType]:=OldPrev.PrevDependency[ListType];
2030   NextDependency[ListType]:=OldPrev;
2031   OldPrev.PrevDependency[ListType]:=Self;
2032   if FirstDependency=OldPrev then FirstDependency:=Self;
2033   Result:=True;
2034 end;
2035 
MoveDownInListnull2036 function TPkgDependency.MoveDownInList(var FirstDependency: TPkgDependency;
2037   ListType: TPkgDependencyDirection): Boolean;
2038 var
2039   OldNext: TPkgDependency;
2040 begin
2041   if (NextDependency[ListType]=nil) then exit(False);
2042   OldNext:=NextDependency[ListType];
2043   if OldNext.NextDependency[ListType]<>nil then
2044     OldNext.NextDependency[ListType].PrevDependency[ListType]:=Self;
2045   if PrevDependency[ListType]<>nil then
2046     PrevDependency[ListType].NextDependency[ListType]:=OldNext;
2047   OldNext.PrevDependency[ListType]:=PrevDependency[ListType];
2048   NextDependency[ListType]:=OldNext.NextDependency[ListType];
2049   PrevDependency[ListType]:=OldNext;
2050   OldNext.NextDependency[ListType]:=Self;
2051   if FirstDependency=Self then FirstDependency:=OldNext;
2052   Result:=True;
2053 end;
2054 
MakeFilenameRelativeToOwnernull2055 function TPkgDependency.MakeFilenameRelativeToOwner(const AFilename: string): string;
2056 var
2057   BaseDir: String;
2058 begin
2059   Result:=AFilename;
2060   if (Result<>'')
2061   and (Owner<>nil) then begin
2062     BaseDir:=GetDependencyOwnerDirectory(Self);
2063     if BaseDir<>'' then
2064       Result:=CreateRelativePath(Result,BaseDir);
2065   end;
2066 end;
2067 
FindDefaultFilenamenull2068 function TPkgDependency.FindDefaultFilename: string;
2069 var
2070   AFilename: String;
2071   CurDir: String;
2072 begin
2073   Result:='';
2074   AFilename:=TrimFilename(DefaultFilename);
2075   if not FilenameExtIs(AFilename,'lpk',true)
2076   or (CompareText(ExtractFileNameOnly(AFilename),PackageName)<>0) then
2077     exit;
2078   if not FilenameIsAbsolute(AFilename) then begin
2079     CurDir:=GetDependencyOwnerDirectory(Self);
2080     if (CurDir<>'') then
2081       AFilename:=AppendPathDelim(CurDir)+AFilename;
2082   end;
2083   if not FilenameIsAbsolute(AFilename) then exit;
2084   AFilename:=CodeToolBoss.DirectoryCachePool.FindDiskFilename(AFilename);
2085   if not FileExistsCached(AFilename) then exit;
2086   Result:=AFilename;
2087 end;
2088 
2089 { TPackageIDEOptions }
2090 
GetPackagenull2091 function TPackageIDEOptions.GetPackage: TIDEPackage;
2092 begin
2093   Result := FPackage;
2094 end;
2095 
2096 constructor TPackageIDEOptions.Create(APackage: TLazPackage);
2097 begin
2098   inherited Create;
2099   FPackage := APackage;
2100 end;
2101 
2102 destructor TPackageIDEOptions.Destroy;
2103 begin
2104   inherited Destroy;
2105 end;
2106 
2107 class function TPackageIDEOptions.GetInstance: TAbstractIDEOptions;
2108 begin
2109   if Package1<>nil then
2110     Result := Package1.IDEOptions
2111   else
2112     Result := nil;
2113 end;
2114 
2115 class function TPackageIDEOptions.GetGroupCaption: string;
2116 begin
2117   Result := lisPckOptsPackageOptions;
2118 end;
2119 
2120 { TLazPackage }
2121 
2122 procedure TLazPackage.OnMacroListSubstitution(TheMacro: TTransferMacro;
2123   const MacroName: string; var s: string; const Data: PtrInt;
2124   var Handled, Abort: boolean; Depth: integer);
2125 var
2126   Values: TCTCfgScriptVariables;
2127   Macro: PCTCfgScriptVariable;
2128 var
2129   NewValue: String;
2130 begin
2131   if Data=CompilerOptionMacroPlatformIndependent then
2132   begin
2133     NewValue:=GetMakefileMacroValue(MacroName);
2134     if NewValue<>'' then begin
2135       s:=NewValue;
2136       Handled:=true;
2137       exit;
2138     end;
2139   end;
2140 
2141   // check build macros
2142   if IsValidIdent(MacroName) then
2143   begin
2144     Values:=GetBuildMacroValues(CompilerOptions,true);
2145     if Values<>nil then begin
2146       Macro:=Values.GetVariable(PChar(MacroName));
2147       if Macro<>nil then
2148       begin
2149         s:=GetCTCSVariableAsString(Macro);
2150         //if MacroName='MyPackageOptions' then
2151         //  debugln(['TLazPackage.OnMacroListSubstitution Pkg=',Name,' Macro=',MacroName,' Value="',s,'"']);
2152         Handled:=true;
2153         exit;
2154       end;
2155     end;
2156   end;
2157 
2158   if s = '' then
2159   begin
2160   // check local macros
2161     if SysUtils.CompareText(MacroName,'PkgOutDir')=0 then begin
2162       Handled:=true;
2163       if Data=CompilerOptionMacroNormal then
2164         s:=GetOutputDirectory()
2165       else
2166         s:=CompilerOptions.ParsedOpts.GetParsedPIValue(pcosOutputDir);
2167       exit;
2168     end
2169     else if SysUtils.CompareText(MacroName,'PkgDir')=0 then begin
2170       Handled:=true;
2171       s:=FDirectory;
2172       exit;
2173     end
2174     else if SysUtils.CompareText(MacroName,'PkgName')=0 then begin
2175       Handled:=true;
2176       s:=Name;
2177       exit;
2178     end
2179     else if SysUtils.CompareText(MacroName,'PkgIncPath')=0 then begin
2180       Handled:=true;
2181       s:=GetIncludePath(false);
2182       exit;
2183     end
2184     else if SysUtils.CompareText(MacroName,'PkgSrcPath')=0 then begin
2185       Handled:=true;
2186       s:=SourceDirectories.CreateSearchPathFromAllFiles;
2187       exit;
2188     end
2189     else if SysUtils.CompareText(MacroName,'PkgUnitPath')=0 then begin
2190       Handled:=true;
2191       s:=GetUnitPath(false);
2192       exit;
2193     end;
2194   end;
2195 
2196   // check global macros
2197   GlobalMacroList.ExecuteMacro(MacroName,s,Data,Handled,Abort,Depth);
2198 end;
2199 
2200 procedure TLazPackage.SetUserReadOnly(const AValue: boolean);
2201 begin
2202   if FUserReadOnly=AValue then exit;
2203   FUserReadOnly:=AValue;
2204 end;
2205 
SubstitutePkgMacrosnull2206 function TLazPackage.SubstitutePkgMacros(const s: string;
2207   PlatformIndependent: boolean): string;
2208 begin
2209   Result:=s;
2210   if PlatformIndependent then
2211     FMacros.SubstituteStr(Result,CompilerOptionMacroPlatformIndependent)
2212   else
2213     FMacros.SubstituteStr(Result,CompilerOptionMacroNormal);
2214 end;
2215 
2216 procedure TLazPackage.WriteInheritedUnparsedOptions;
2217 var
2218   OptionsList: TFPList;
2219   AddOptions: TAdditionalCompilerOptions;
2220   i: Integer;
2221 begin
2222   OptionsList:=nil;
2223   CompilerOptions.GetInheritedCompilerOptions(OptionsList);
2224   if OptionsList<>nil then begin
2225     for i:=0 to OptionsList.Count-1 do begin
2226       AddOptions:=TAdditionalCompilerOptions(OptionsList[i]);
2227       if (not (AddOptions is TAdditionalCompilerOptions)) then continue;
2228       DebugLn('TLazPackage.WriteInheritedUnparsedOptions ',
2229         (AddOptions.Owner as TLazPackage).IDAsString,
2230         ' UnitPath="',AddOptions.GetOption(icoUnitPath),'"');
2231     end;
2232     OptionsList.Free;
2233   end;
2234 end;
2235 
GetActiveBuildMethodnull2236 function TLazPackage.GetActiveBuildMethod: TBuildMethod;
2237 begin
2238   Result:=BuildMethod;
2239   if Result=bmBoth then begin
2240     if Assigned(FppkgInterface) and FppkgInterface.UseFPMakeWhenPossible then
2241       Result:=bmFPMake
2242     else
2243       Result:=bmLazarus;
2244   end;
2245 end;
2246 
GetAutoIncrementVersionOnBuildnull2247 function TLazPackage.GetAutoIncrementVersionOnBuild: boolean;
2248 begin
2249   Result:=lpfAutoIncrementVersionOnBuild in FFlags;
2250 end;
2251 
GetCompilerOptionsnull2252 function TLazPackage.GetCompilerOptions: TPkgCompilerOptions;
2253 begin
2254   Result := TPkgCompilerOptions(FLazCompilerOptions);
2255 end;
2256 
GetBaseCompilerOptionsnull2257 function TLazPackage.GetBaseCompilerOptions: TBaseCompilerOptions;
2258 // This satisfies the IProjPack interface requirement.
2259 begin
2260   Result := TBaseCompilerOptions(FLazCompilerOptions);
2261 end;
2262 
GetComponentCountnull2263 function TLazPackage.GetComponentCount: integer;
2264 begin
2265   Result:=FComponents.Count;
2266 end;
2267 
GetComponentsnull2268 function TLazPackage.GetComponents(Index: integer): TPkgComponent;
2269 begin
2270   Result:=TPkgComponent(FComponents[Index]);
2271 end;
2272 
GetDirectoryExpandednull2273 function TLazPackage.GetDirectoryExpanded: string;
2274 begin
2275   if (FDirectoryExpandedChangeStamp<>CompilerParseStamp) then begin
2276     FDirectoryExpanded:=FDirectory;
2277     // use default macros (not package macros)
2278     if IDEMacros<>nil then
2279       IDEMacros.SubstituteMacros(FDirectoryExpanded);
2280     FDirectoryExpanded:=AppendPathDelim(TrimFilename(FDirectoryExpanded));
2281     FDirectoryExpandedChangeStamp:=CompilerParseStamp;
2282   end;
2283   Result:=FDirectoryExpanded;
2284 end;
2285 
GetRemovedCountnull2286 function TLazPackage.GetRemovedCount: integer;
2287 begin
2288   Result:=FRemovedFiles.Count;
2289 end;
2290 
GetRemovedPkgFilesnull2291 function TLazPackage.GetRemovedPkgFiles(Index: integer): TLazPackageFile;
2292 begin
2293   Result:=GetRemovedFiles(Index);
2294 end;
2295 
2296 procedure TLazPackage.AssignOptions(Source: TPersistent);
2297 var
2298   aSource: TLazPackage;
2299 begin
2300   inherited AssignOptions(Source);
2301   if Source is TLazPackage then
2302   begin
2303     aSource:=TLazPackage(Source);
2304     UserReadOnly:=aSource.UserReadOnly;
2305     Translated:=aSource.Translated;
2306     StorePathDelim:=aSource.StorePathDelim;
2307     // ToDo: PublishOptions.AssignOptions(aSource.PublishOptions);
2308     Provides.Assign(aSource.Provides);
2309     POOutputDirectory:=aSource.POOutputDirectory;
2310     PackageType:=aSource.PackageType;
2311     OutputStateFile:=aSource.OutputStateFile;
2312     License:=aSource.License;
2313     FPDocPaths:=aSource.FPDocPaths;
2314     FPDocPackageName:=aSource.FPDocPackageName;
2315     IconFile:=aSource.IconFile;
2316     UsageOptions.AssignOptions(aSource.UsageOptions);
2317     EnableI18N:=aSource.EnableI18N;
2318     EnableI18NForLFM:=aSource.EnableI18NForLFM;
2319     Description:=aSource.Description;
2320     AutoUpdate:=aSource.AutoUpdate;
2321     AutoIncrementVersionOnBuild:=aSource.AutoIncrementVersionOnBuild;
2322     Author:=aSource.Author;
2323     AddToProjectUsesSection:=aSource.AddToProjectUsesSection;
2324   end;
2325 end;
2326 
GetRemovedFilesnull2327 function TLazPackage.GetRemovedFiles(Index: integer): TPkgFile;
2328 begin
2329   If (Index >= 0) And (Index < FRemovedFiles.Count) Then
2330     Result:=TPkgFile(FRemovedFiles[Index])
2331   Else
2332     Result := NIL;
2333 end;
2334 
GetDefineTemplatesnull2335 function TLazPackage.GetDefineTemplates: TProjPackDefineTemplates;
2336 begin
2337   Result:=FDefineTemplates;
2338 end;
2339 
GetFileCountnull2340 function TLazPackage.GetFileCount: integer;
2341 begin
2342   Result:=FFiles.Count;
2343 end;
2344 
GetPkgFilesnull2345 function TLazPackage.GetPkgFiles(Index: integer): TLazPackageFile;
2346 begin
2347   Result:=GetFiles(Index);
2348 end;
2349 
GetFilesnull2350 function TLazPackage.GetFiles(Index: integer): TPkgFile;
2351 begin
2352   Result:=TPkgFile(FFiles[Index]);
2353 end;
2354 
GetIDEOptionsnull2355 function TLazPackage.GetIDEOptions: TPackageIDEOptions;
2356 begin
2357   Result := TPackageIDEOptions(FIDEOptions);
2358 end;
2359 
GetSourceDirectoriesnull2360 function TLazPackage.GetSourceDirectories: TFileReferenceList;
2361 begin
2362   Result:=FSourceDirectories;
2363 end;
2364 
GetModifiednull2365 function TLazPackage.GetModified: boolean;
2366 begin
2367   Result:=(lpfModified in FFlags) or CompilerOptions.Modified;
2368 end;
2369 
2370 procedure TLazPackage.SetAddToProjectUsesSection(const AValue: boolean);
2371 begin
2372   if FAddToProjectUsesSection=AValue then exit;
2373   FAddToProjectUsesSection:=AValue;
2374   Modified:=true;
2375 end;
2376 
2377 procedure TLazPackage.SetAuthor(const AValue: string);
2378 begin
2379   if FAuthor=AValue then exit;
2380   FAuthor:=AValue;
2381   Modified:=true;
2382 end;
2383 
2384 procedure TLazPackage.SetAutoIncrementVersionOnBuild(const AValue: boolean);
2385 begin
2386   if AutoIncrementVersionOnBuild=AValue then exit;
2387   if AValue then
2388     Include(FFlags,lpfAutoIncrementVersionOnBuild)
2389   else
2390     Exclude(FFlags,lpfAutoIncrementVersionOnBuild);
2391   Modified:=true;
2392 end;
2393 
2394 procedure TLazPackage.SetAutoInstall(AValue: TPackageInstallType);
2395 begin
2396   if FAutoInstall=AValue then exit;
2397   FAutoInstall:=AValue;
2398 end;
2399 
2400 procedure TLazPackage.SetAutoUpdate(const AValue: TPackageUpdatePolicy);
2401 begin
2402   if AValue=AutoUpdate then exit;
2403   FAutoUpdate:=AValue;
2404   Modified:=true;
2405 end;
2406 
2407 procedure TLazPackage.SetDescription(const AValue: string);
2408 begin
2409   if FDescription=AValue then exit;
2410   FDescription:=AValue;
2411   Modified:=true;
2412 end;
2413 
2414 procedure TLazPackage.SetEnableI18NForLFM(AValue: boolean);
2415 begin
2416   if FEnableI18NForLFM=AValue then Exit;
2417   FEnableI18NForLFM:=AValue;
2418   Modified:=true;
2419 end;
2420 
2421 procedure TLazPackage.SetFileReadOnly(const AValue: boolean);
2422 begin
2423   if FFileReadOnly=AValue then exit;
2424   FFileReadOnly:=AValue;
2425 end;
2426 
2427 procedure TLazPackage.SetFilename(const AValue: string);
2428 var
2429   NewFilename: String;
2430 begin
2431   NewFilename:=AValue;
2432   ForcePathDelims(NewFilename);
2433   if FFilename=NewFilename then exit;
2434   FFilename:=NewFilename;
2435   if (FFilename<>'') and (FFilename[length(FFilename)]=PathDelim) then
2436     FDirectory:=FFilename
2437   else
2438     FDirectory:=ExtractFilePath(FFilename);
2439   FDirectoryExpandedChangeStamp:=LUInvalidChangeStamp;
2440   FHasDirectory:=(FDirectory<>'') and (FDirectory[length(FDirectory)]=PathDelim);
2441   FHasStaticDirectory:=FHasDirectory and FilenameIsAbsolute(FDirectory);
2442   FUsageOptions.BaseDirectory:=FDirectory;
2443   CompilerOptions.BaseDirectory:=FDirectory;
2444   Modified:=true;
2445 end;
2446 
2447 procedure TLazPackage.SetFlags(const AValue: TLazPackageFlags);
2448 var
2449   ChangedFlags: TLazPackageFlags;
2450 begin
2451   if FFlags=AValue then exit;
2452   ChangedFlags:=(FFlags-AValue)+(AValue-FFlags);
2453   FFlags:=AValue;
2454   if ChangedFlags*[lpfAutoIncrementVersionOnBuild,lpfCompatibilityMode]<>[] then
2455     Modified:=true;
2456 end;
2457 
2458 procedure TLazPackage.SetFPDocPackageName(AValue: string);
2459 begin
2460   if FFPDocPackageName=AValue then Exit;
2461   FFPDocPackageName:=AValue;
2462   Modified:=true;
2463 end;
2464 
2465 procedure TLazPackage.SetIconFile(const AValue: string);
2466 begin
2467   if FIconFile=AValue then exit;
2468   FIconFile:=AValue;
2469   Modified:=true;
2470 end;
2471 
2472 procedure TLazPackage.SetInstalled(const AValue: TPackageInstallType);
2473 begin
2474   if FInstalled=AValue then exit;
2475   FInstalled:=AValue;
2476 end;
2477 
2478 procedure TLazPackage.SetFPDocPaths(const AValue: string);
2479 var
2480   NewValue: String;
2481 begin
2482   NewValue:=TrimSearchPath(AValue,'');
2483   if FFPDocPaths=NewValue then exit;
2484   FFPDocPaths:=NewValue;
2485   Modified:=true;
2486 end;
2487 
2488 procedure TLazPackage.SetLicense(const AValue: string);
2489 begin
2490   if FLicense=AValue then exit;
2491   FLicense:=AValue;
2492   Modified:=true;
2493 end;
2494 
2495 procedure TLazPackage.SetLPKSource(const AValue: TCodeBuffer);
2496 begin
2497   if FLPKSource=AValue then exit;
2498   FLPKSource:=AValue;
2499   if LPKSource<>nil then
2500     FLPKSourceChangeStep:=LPKSource.ChangeStep;
2501   // do not change Filename here.
2502   // See TPkgManager.DoSavePackage and TPkgManager.DoOpenPackageFile
2503   // the LPKSource is the codebuffer last used during load/save, so it is not valid
2504   // for packages that were not yet loaded/saved or during renaming/loading/saving.
2505 end;
2506 
2507 procedure TLazPackage.SetOutputStateFile(const AValue: string);
2508 var
2509   NewStateFile: String;
2510 begin
2511   NewStateFile:=TrimFilename(AValue);
2512   if FOutputStateFile=NewStateFile then exit;
2513   FOutputStateFile:=NewStateFile;
2514 end;
2515 
2516 procedure TLazPackage.SetProvides(const AValue: TStrings);
2517 begin
2518   if (AValue=FProvides) or (FProvides.Equals(AValue)) then exit;
2519   FProvides.Assign(AValue);
2520   Modified:=true;
2521 end;
2522 
2523 procedure TLazPackage.SetPOOutputDirectory(const AValue: string);
2524 var
2525   NewValue: String;
2526 begin
2527   NewValue:=TrimFilename(AValue);
2528   if FPOOutputDirectory=NewValue then exit;
2529   FPOOutputDirectory:=NewValue;
2530   Modified:=true;
2531 end;
2532 
2533 procedure TLazPackage.SetEnableI18N(const AValue: boolean);
2534 begin
2535   if FEnableI18N=AValue then exit;
2536   FEnableI18N:=AValue;
2537   Modified:=true;
2538 end;
2539 
2540 procedure TLazPackage.SetRegistered(const AValue: boolean);
2541 begin
2542   if FRegistered=AValue then exit;
2543   FRegistered:=AValue;
2544 end;
2545 
2546 procedure TLazPackage.ModifySilently;
2547 begin
2548   if FModifiedLock>0 then exit;
2549   Include(FFlags,lpfModified);
2550   Exclude(FFlags,lpfSkipSaving);
2551   if FChangeStamp<High(FChangeStamp) then
2552     inc(FChangeStamp)
2553   else
2554     FChangeStamp:=low(FChangeStamp);
2555   if Assigned(FOnModifySilently) then
2556     FOnModifySilently(Self);
2557 end;
2558 
2559 procedure TLazPackage.SetModified(const AValue: boolean);
2560 begin
2561   if AValue then begin
2562     if FModifiedLock>0 then exit;
2563     ModifySilently;
2564   end
2565   else begin
2566     FFlags:=FFlags-[lpfModified,lpfSkipSaving];
2567     PublishOptions.Modified:=false;
2568     CompilerOptions.Modified:=false;
2569   end;
2570   if Modified and (Editor<>nil) then
2571     Editor.UpdateAll(false);
2572 end;
2573 
2574 procedure TLazPackage.SetName(const NewName: TComponentName);
2575 begin
2576   if Name=NewName then exit;
2577   inherited SetName(NewName);
2578   FDefineTemplates.IDChanged;
2579   Modified:=true;
2580 end;
2581 
2582 procedure TLazPackage.SetPackageEditor(const AValue: TBasePackageEditor);
2583 begin
2584   if FPackageEditor=AValue then exit;
2585   FPackageEditor:=AValue;
2586 end;
2587 
2588 procedure TLazPackage.SetPackageType(const AValue: TLazPackageType);
2589 begin
2590   if FPackageType=AValue then exit;
2591   FPackageType:=AValue;
2592   Modified:=true;
2593 end;
2594 
2595 procedure TLazPackage.SetStorePathDelim(const AValue: TPathDelimSwitch);
2596 begin
2597   if FStorePathDelim=AValue then exit;
2598   FStorePathDelim:=AValue;
2599 end;
2600 
2601 procedure TLazPackage.SetUseLegacyLists(const AUseLegacyLists: Boolean);
2602 begin
2603   if AUseLegacyLists=UseLegacyLists then exit;
2604   if AUseLegacyLists then
2605     Include(FFlags, lpfCompatibilityMode)
2606   else
2607     Exclude(FFlags, lpfCompatibilityMode);
2608   Modified:=true;
2609 end;
2610 
2611 constructor TLazPackage.Create;
2612 begin
2613   inherited Create;
2614   FComponents:=TFPList.Create;
2615   FSourceDirectories:=TFileReferenceList.Create;
2616   FSourceDirectories.OnChanged:=@SourceDirectoriesChanged;
2617   FFiles:=TFPList.Create;
2618   FRemovedFiles:=TFPList.Create;
2619   FMacros:=TTransferMacroList.Create;
2620   FMacros.OnSubstitution:=@OnMacroListSubstitution;
2621   FIDEOptions:=TPackageIDEOptions.Create(Self);
2622   FLazCompilerOptions:=TPkgCompilerOptions.Create(Self);
2623   CompilerOptions.ParsedOpts.InvalidateParseOnChange:=true;
2624   CompilerOptions.ParsedOpts.OnLocalSubstitute:=@SubstitutePkgMacros;
2625   CompilerOptions.DefaultMakeOptionsFlags:=[ccloNoLinkerOpts];
2626   FUsageOptions:=TPkgAdditionalCompilerOptions.Create(Self);
2627   FUsageOptions.ParsedOpts.OnLocalSubstitute:=@SubstitutePkgMacros;
2628   FDefineTemplates:=TLazPackageDefineTemplates.Create(Self);
2629   fPublishOptions:=TPublishPackageOptions.Create(Self);
2630   FProvides:=TStringList.Create;
2631   FUsageOptions.ParsedOpts.InvalidateParseOnChange:=true;
2632 end;
2633 
2634 constructor TLazPackage.CreateAndClear;
2635 begin
2636   Create;
2637   Clear;
2638 end;
2639 
2640 destructor TLazPackage.Destroy;
2641 begin
2642   Include(FFlags,lpfDestroying);
2643   Clear;
2644   FreeAndNil(FOptionsBackup);
2645   FreeAndNil(fPublishOptions);
2646   FreeAndNil(FProvides);
2647   FreeAndNil(FDefineTemplates);
2648   FreeAndNil(FRemovedFiles);
2649   FreeAndNil(FFiles);
2650   FreeAndNil(FComponents);
2651   FreeAndNil(FLazCompilerOptions);
2652   FreeAndNil(FIDEOptions);
2653   FreeAndNil(FUsageOptions);
2654   FreeAndNil(FMacros);
2655   FreeAndNil(FSourceDirectories);
2656   inherited Destroy;
2657 end;
2658 
2659 procedure TLazPackage.BackupOptions;
2660 begin
2661   if FOptionsBackup=nil then
2662     FOptionsBackup:=TLazPackage.Create;
2663   FOptionsBackup.AssignOptions(Self);
2664   FOptionsBackup.FFlags:=FOptionsBackup.FFlags-[lpfModified]+[lpfModified]*FFlags;
2665   FOptionsBackup.CompilerOptions.Modified:=CompilerOptions.Modified;
2666 end;
2667 
2668 procedure TLazPackage.RestoreOptions;
2669 begin
2670   if FOptionsBackup=nil then exit;
2671   AssignOptions(FOptionsBackup);
2672   FFlags:=FFlags-[lpfModified]+[lpfModified]*FOptionsBackup.FFlags;
2673   CompilerOptions.Modified:=FOptionsBackup.CompilerOptions.Modified;
2674 end;
2675 
2676 procedure TLazPackage.BeginUpdate;
2677 begin
2678   inc(FUpdateLock);
2679   FDefineTemplates.BeginUpdate;
2680   FSourceDirectories.BeginUpdate;
2681 end;
2682 
2683 procedure TLazPackage.EndUpdate;
2684 begin
2685   if FUpdateLock=0 then RaiseGDBException('TLazPackage.EndUpdate');
2686   dec(FUpdateLock);
2687   FDefineTemplates.EndUpdate;
2688   FSourceDirectories.EndUpdate;
2689 end;
2690 
2691 procedure TLazPackage.Clear;
2692 var
2693   i: Integer;
2694 begin
2695   // break used-by dependencies
2696   while FFirstUsedByDependency<>nil do
2697     FFirstUsedByDependency.RequiredPackage:=nil;
2698   // break and free removed dependencies
2699   while FFirstRemovedDependency<>nil do
2700     DeleteRemovedDependency(FFirstRemovedDependency);
2701   // break and free required dependencies
2702   while FFirstRequiredDependency<>nil do
2703     DeleteRequiredDependency(FFirstRequiredDependency);
2704   if not (lpfDestroying in FFlags) then begin
2705     FAddToProjectUsesSection:=false;
2706     FAuthor:='';
2707     FAutoInstall:=pitNope;
2708     FComponents.Clear;
2709     CompilerOptions.Clear;
2710     FDescription:='';
2711     FDirectory:='';
2712     FDirectoryExpandedChangeStamp:=LUInvalidChangeStamp;
2713     FEnableI18N:=false;
2714     FEnableI18NForLFM:=false;
2715     FPOOutputDirectory:='';
2716     FHasDirectory:=false;
2717     FHasStaticDirectory:=false;
2718     FVersion.Clear;
2719     FFilename:='';
2720     FIconFile:='';
2721     FInstalled:=pitNope;
2722     Name:='';
2723     FPackageType:=lptRunAndDesignTime;
2724     FRegistered:=false;
2725     FFPDocPaths:='';
2726     FFPDocPackageName:='';
2727     ClearCustomOptions;
2728   end;
2729   for i:=FComponents.Count-1 downto 0 do Components[i].Free;
2730   for i:=FRemovedFiles.Count-1 downto 0 do RemovedFiles[i].Free;
2731   FRemovedFiles.Clear;
2732   for i:=FFiles.Count-1 downto 0 do Files[i].Free;
2733   FFiles.Clear;
2734   FUsageOptions.Clear;
2735   fPublishOptions.Clear;
2736   FProvides.Clear;
2737   UpdateSourceDirectories;
2738   // set some nice start values
2739   if not (lpfDestroying in FFlags) then begin
2740     FFlags:=[lpfAutoIncrementVersionOnBuild];
2741     FAutoUpdate:=pupAsNeeded;
2742     FLazCompilerOptions.UnitOutputDirectory:=
2743                            'lib'+PathDelim+'$(TargetCPU)-$(TargetOS)'+PathDelim;
2744     FUsageOptions.UnitPath:='$(PkgOutDir)';
2745   end else begin
2746     FFlags:=[lpfDestroying];
2747   end;
2748   FStorePathDelim:=pdsNone;
2749 end;
2750 
2751 //function DbgS(PkgFileType: TPkgFileType): string;
2752 //begin
2753 //  WriteStr(Result, PkgFileType);
2754 //end;
2755 
2756 procedure TLazPackage.UpdateSourceDirectories;
2757 var
2758   Cnt: Integer;
2759   i: Integer;
2760   PkgFile: TPkgFile;
2761 begin
2762   Cnt:=FFiles.Count;
2763   for i:=0 to Cnt-1 do begin
2764     PkgFile:=Files[i];
2765     PkgFile.FSourceDirectoryReferenced:=false;
2766   end;
2767   fSourceDirectories.Clear;
2768   for i:=0 to Cnt-1 do begin
2769     PkgFile:=Files[i];
2770     PkgFile.AutoReferenceSourceDir:=true;
2771     PkgFile.UpdateSourceDirectoryReference;
2772     //debugln('TLazPackage.UpdateSourceDirectories A ',PkgFile.Filename,' ',
2773     //  ' ',DbgS(PkgFile.FileType),' ',PkgFile.Removed,
2774     //  ' HasPkg=',dbgs(PkgFile.LazPackage=Self),
2775     //  ' Need=',PkgFile.FSourceDirNeedReference,
2776     //  ' Is=',PkgFile.FSourceDirectoryReferenced);
2777   end;
2778   //debugln('TLazPackage.UpdateSourceDirectories B ',IDAsString,' ',FFiles.Count,' "',fSourceDirectories.CreateSearchPathFromAllFiles,'"');
2779 end;
2780 
2781 procedure TLazPackage.VersionChanged(Sender: TObject);
2782 begin
2783   inherited VersionChanged(Sender);
2784   FDefineTemplates.IDChanged;
2785   Modified:=true;
2786 end;
2787 
2788 procedure TLazPackage.SourceDirectoriesChanged(Sender: TObject);
2789 begin
2790   FDefineTemplates.SourceDirectoriesChanged;
2791 end;
2792 
GetDirectorynull2793 function TLazPackage.GetDirectory: string;
2794 begin
2795   Result:=FDirectory;
2796 end;
2797 
2798 procedure TLazPackage.LockModified;
2799 begin
2800   inc(FModifiedLock);
2801 end;
2802 
2803 procedure TLazPackage.UnlockModified;
2804 begin
2805   if FModifiedLock<=0 then
2806     RaiseGDBException('TLazPackage.UnlockModified');
2807   dec(FModifiedLock);
2808 end;
2809 
ReadOnlynull2810 function TLazPackage.ReadOnly: boolean;
2811 begin
2812   Result:=UserReadOnly or FileReadOnly;
2813 end;
2814 
2815 procedure TLazPackage.LoadFromXMLConfig(XMLConfig: TXMLConfig;
2816   const Path: string);
2817 var
2818   FileVersion: integer;
2819   OldFilename: String;
2820   PathDelimChanged: boolean;
2821   Config: TXMLOptionsStorage;
2822 
2823   procedure LoadFiles(const ThePath: string; List: TFPList);
2824   var
2825     i: Integer;
2826     NewCount: Integer;
2827     PkgFile: TPkgFile;
2828     LegacyList: Boolean;
2829     SubPath: string;
2830   begin
2831     LegacyList := (FileVersion<=4) or XMLConfig.IsLegacyList(ThePath);
2832     NewCount:=XMLConfig.GetListItemCount(ThePath, 'Item', LegacyList);
2833     for i:=0 to NewCount-1 do begin
2834       PkgFile:=TPkgFile.Create(Self);
2835       SubPath := ThePath+XMLConfig.GetListItemXPath('Item', i, LegacyList, True)+'/';
2836       PkgFile.LoadFromXMLConfig(XMLConfig,SubPath,FileVersion,PathDelimChanged);
2837       if PkgFile.MakeSense then
2838         List.Add(PkgFile)
2839       else
2840         PkgFile.Free;
2841     end;
2842   end;
2843 
2844   procedure LoadFlags(const ThePath: string);
2845   begin
2846     if XMLConfig.GetValue(ThePath+'AutoIncrementVersionOnBuild/Value',true) then
2847       Include(FFlags,lpfAutoIncrementVersionOnBuild)
2848     else
2849       Exclude(FFlags,lpfAutoIncrementVersionOnBuild);
2850     if FileVersion<=4 then begin
2851       // set CompatibilityMode flag for legacy projects (this flag was added in FileVersion=5 that changed
2852       // item format so that LPK cannot be opened in legacy Lazarus unless lpfCompatibilityMode is set)
2853       Include(FFlags,lpfCompatibilityMode);
2854     end else
2855     begin
2856       if XMLConfig.GetValue(ThePath+'CompatibilityMode/Value',false) then
2857         Include(FFlags,lpfCompatibilityMode)
2858       else
2859         Exclude(FFlags,lpfCompatibilityMode);
2860     end;
2861   end;
2862 
2863 begin
2864   Flags:=Flags+[lpfLoading];
2865   FileVersion:=XMLConfig.GetValue(Path+'Version',0);
2866   OldFilename:=Filename;
2867   BeginUpdate;
2868   Clear;
2869   Filename:=OldFilename;
2870   LockModified;
2871   LoadFlags(Path);
2872   StorePathDelim:=CheckPathDelim(XMLConfig.GetValue(Path+'PathDelim/Value','/'),PathDelimChanged);
2873   Name:=XMLConfig.GetValue(Path+'Name/Value','');
2874   FPackageType:=LazPackageTypeIdentToType(XMLConfig.GetValue(Path+'Type/Value',
2875                                           LazPackageTypeIdents[lptRunTime]));
2876   FBuildMethod:=StringToBuildMethod(XMLConfig.GetValue(Path+'BuildMethod/Value',
2877                                     SBuildMethod[bmLazarus]));
2878   FAddToProjectUsesSection:=XMLConfig.GetValue(Path+'AddToProjectUsesSection/Value',
2879     FileVersion<4); // since version 4 the default is false
2880   FAuthor:=XMLConfig.GetValue(Path+'Author/Value','');
2881   FAutoUpdate:=NameToAutoUpdatePolicy(
2882                                 XMLConfig.GetValue(Path+'AutoUpdate/Value',''));
2883   if FileVersion<2 then
2884     CompilerOptions.LoadFromXMLConfig(XMLConfig,'CompilerOptions/')
2885   else
2886     CompilerOptions.LoadFromXMLConfig(XMLConfig,Path+'CompilerOptions/');
2887   FDescription:=XMLConfig.GetValue(Path+'Description/Value','');
2888   FLicense:=XMLConfig.GetValue(Path+'License/Value','');
2889   PkgVersionLoadFromXMLConfig(FVersion,XMLConfig,Path+'Version/',FileVersion);
2890   FIconFile:=SwitchPathDelims(XMLConfig.GetValue(Path+'IconFile/Value',''),
2891                               PathDelimChanged);
2892   OutputStateFile:=SwitchPathDelims(
2893                             XMLConfig.GetValue(Path+'OutputStateFile/Value',''),
2894                             PathDelimChanged);
2895   FFPDocPaths:=SwitchPathDelims(XMLConfig.GetValue(Path+'LazDoc/Paths',''),
2896                             PathDelimChanged);
2897   FFPDocPackageName:=XMLConfig.GetValue(Path+'LazDoc/PackageName','');
2898   // i18n
2899   if FileVersion<3 then begin
2900     FPOOutputDirectory := SwitchPathDelims(
2901               xmlconfig.GetValue(Path+'RST/OutDir', ''),PathDelimChanged);
2902     EnableI18N := FPOOutputDirectory <> '';
2903   end else begin
2904     EnableI18N := xmlconfig.GetValue(Path+'i18n/EnableI18N/Value', False);
2905     FPOOutputDirectory := SwitchPathDelims(
2906              xmlconfig.GetValue(Path+'i18n/OutDir/Value', ''),PathDelimChanged);
2907   end;
2908   EnableI18NForLFM:=xmlconfig.GetValue(Path+'i18n/EnableI18NForLFM/Value', false);
2909 
2910   LoadFiles(Path+'Files/',FFiles);
2911   UpdateSourceDirectories;
2912   LoadPkgDependencyList(XMLConfig,Path+'RequiredPkgs/',
2913                         FFirstRequiredDependency,pddRequires,Self,false,false);
2914   FUsageOptions.LoadFromXMLConfig(XMLConfig,Path+'UsageOptions/',
2915                                   PathDelimChanged);
2916   fPublishOptions.LoadFromXMLConfig(XMLConfig,Path+'PublishOptions/',
2917                                     PathDelimChanged);
2918   LoadStringList(XMLConfig,FProvides,Path+'Provides/');
2919   Config:=TXMLOptionsStorage.Create(XMLConfig);
2920   try
2921     TConfigMemStorage(CustomOptions).LoadFromConfig(Config,Path+'CustomOptions/');
2922   finally
2923     Config.Free;
2924   end;
2925 
2926   EndUpdate;
2927   Modified:=false;
2928   UnlockModified;
2929   Flags:=Flags-[lpfLoading];
2930 end;
2931 
2932 procedure TLazPackage.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string);
2933 var
2934   UsePathDelim: TPathDelimSwitch;
2935   Config: TXMLOptionsStorage;
2936 
2937   function f(const AFilename: string): string;
2938   begin
2939     Result:=SwitchPathDelims(AFilename,UsePathDelim);
2940   end;
2941 
2942   procedure SaveFiles(const ThePath: string; List: TFPList);
2943   var
2944     i: Integer;
2945     PkgFile: TPkgFile;
2946     SubPath: string;
2947   begin
2948     XMLConfig.SetListItemCount(ThePath, List.Count, UseLegacyLists);
2949     for i:=0 to List.Count-1 do begin
2950       PkgFile:=TPkgFile(List[i]);
2951       SubPath := ThePath+XMLConfig.GetListItemXPath('Item', i, UseLegacyLists, True)+'/';
2952       PkgFile.SaveToXMLConfig(XMLConfig,SubPath,UsePathDelim);
2953     end;
2954   end;
2955 
2956   procedure SaveFlags(const ThePath: string);
2957   begin
2958     XMLConfig.SetDeleteValue(ThePath+'AutoIncrementVersionOnBuild/Value',
2959       AutoIncrementVersionOnBuild,true);
2960     XMLConfig.SetDeleteValue(ThePath+'CompatibilityMode/Value',
2961       UseLegacyLists,false);
2962   end;
2963 
2964 begin
2965   UsePathDelim:=StorePathDelim;
2966   XMLConfig.SetValue(Path+'Version',LazPkgXMLFileVersion);
2967   XMLConfig.SetDeleteValue(Path+'PathDelim/Value',PathDelimSwitchToDelim[UsePathDelim],'/');
2968   XMLConfig.SetDeleteValue(Path+'Name/Value',Name,'');
2969   XMLConfig.SetDeleteValue(Path+'Type/Value',LazPackageTypeIdents[FPackageType],
2970                            LazPackageTypeIdents[lptRunTime]);
2971   XMLConfig.SetDeleteValue(Path+'BuildMethod/Value',SBuildMethod[FBuildMethod],
2972                            SBuildMethod[bmLazarus]);
2973   XMLConfig.SetDeleteValue(Path+'AddToProjectUsesSection/Value',
2974                            FAddToProjectUsesSection,false);
2975   XMLConfig.SetDeleteValue(Path+'Author/Value',FAuthor,'');
2976   XMLConfig.SetDeleteValue(Path+'AutoUpdate/Value',AutoUpdateNames[FAutoUpdate],
2977                            AutoUpdateNames[pupAsNeeded]);
2978   CompilerOptions.SaveToXMLConfig(XMLConfig,Path+'CompilerOptions/');
2979   XMLConfig.SetDeleteValue(Path+'Description/Value',FDescription,'');
2980   XMLConfig.SetDeleteValue(Path+'License/Value',FLicense,'');
2981   PkgVersionSaveToXMLConfig(FVersion,XMLConfig,Path+'Version/');
2982   SaveFiles(Path+'Files/',FFiles);
2983   SaveFlags(Path);
2984   XMLConfig.SetDeleteValue(Path+'IconFile/Value',f(FIconFile),'');
2985   XMLConfig.SetDeleteValue(Path+'OutputStateFile/Value',f(OutputStateFile),'');
2986   XMLConfig.SetDeleteValue(Path+'LazDoc/Paths',f(FFPDocPaths),'');
2987   XMLConfig.SetDeleteValue(Path+'LazDoc/PackageName',FFPDocPackageName,'');
2988 
2989   XMLConfig.SetDeleteValue(Path+'i18n/EnableI18N/Value', EnableI18N, false);
2990   XMLConfig.SetDeleteValue(Path+'i18n/OutDir/Value',f(FPOOutputDirectory), '');
2991   XMLConfig.SetDeleteValue(Path+'i18n/EnableI18NForLFM/Value', EnableI18NForLFM, false);
2992 
2993   SavePkgDependencyList(XMLConfig,Path+'RequiredPkgs/',
2994                         FFirstRequiredDependency,pddRequires,UsePathDelim,UseLegacyLists);
2995   FUsageOptions.SaveToXMLConfig(XMLConfig,Path+'UsageOptions/',UsePathDelim);
2996   fPublishOptions.SaveToXMLConfig(XMLConfig,Path+'PublishOptions/',UsePathDelim);
2997   SaveStringList(XMLConfig,FProvides,Path+'Provides/');
2998   Config:=TXMLOptionsStorage.Create(XMLConfig);
2999   try
3000     TConfigMemStorage(CustomOptions).SaveToConfig(Config,Path+'CustomOptions/');
3001   finally
3002     Config.Free;
3003   end;
3004   Modified:=false;
3005 end;
3006 
3007 procedure TLazPackage.SaveToString(out s: string);
3008 var
3009   XMLConfig: TXMLConfig;
3010   ms: TMemoryStream;
3011 begin
3012   s:='';
3013   XMLConfig:=TXMLConfig.Create(nil);
3014   ms:=TMemoryStream.Create;
3015   try
3016     XMLConfig.Clear;
3017     SaveToXMLConfig(XMLConfig,'Package/');
3018     XMLConfig.WriteToStream(ms);
3019     ms.Position:=0;
3020     SetLength(s,ms.Size);
3021     if s<>'' then
3022       ms.Read(s[1],length(s));
3023   finally
3024     XMLConfig.Free;
3025     ms.Free;
3026   end;
3027 end;
3028 
IsVirtualnull3029 function TLazPackage.IsVirtual: boolean;
3030 begin
3031   Result:=not FilenameIsAbsolute(Filename);
3032 end;
3033 
HasDirectorynull3034 function TLazPackage.HasDirectory: boolean;
3035 begin
3036   Result:=FHasDirectory;
3037 end;
3038 
HasStaticDirectorynull3039 function TLazPackage.HasStaticDirectory: boolean;
3040 begin
3041   Result:=FHasStaticDirectory;
3042 end;
3043 
GetFullFilenamenull3044 function TLazPackage.GetFullFilename(ResolveMacros: boolean): string;
3045 begin
3046   Result:=FFilename;
3047   if ResolveMacros then
3048     GlobalMacroList.SubstituteStr(Result);
3049 end;
3050 
3051 procedure TLazPackage.CheckInnerDependencies;
3052 begin
3053   // ToDo: make some checks like deactivating double requirements
3054 end;
3055 
IsMakingSensenull3056 function TLazPackage.IsMakingSense: boolean;
3057 begin
3058   Result:=IsValidPkgName(Name);
3059 end;
3060 
3061 procedure TLazPackage.ShortenFilename(var ExpandedFilename: string; UseUp: boolean);
3062 var
3063   PkgDir: String;
3064   CurPath: String;
3065 begin
3066   if (not HasDirectory) then exit;
3067   PkgDir:=DirectoryExpanded;
3068   if HasStaticDirectory and UseUp then
3069     ExpandedFilename:=CreateRelativePath(ExpandedFilename,PkgDir)
3070   else begin
3071     CurPath:=copy(ExtractFilePath(ExpandedFilename),1,length(PkgDir));
3072     if CompareFilenames(PkgDir,CurPath)=0 then begin
3073       ExpandedFilename:=copy(ExpandedFilename,length(CurPath)+1,
3074                              length(ExpandedFilename)-length(CurPath));
3075     end;
3076   end;
3077 end;
3078 
3079 procedure TLazPackage.LongenFilename(var AFilename: string);
3080 begin
3081   if not HasDirectory then exit;
3082   if not FilenameIsAbsolute(AFilename) then
3083     AFilename:=TrimFilename(DirectoryExpanded+AFilename);
3084 end;
3085 
GetResolvedFilenamenull3086 function TLazPackage.GetResolvedFilename(ResolveMacros: boolean): string;
3087 begin
3088   Result:=GetPhysicalFilenameCached(GetFullFilename(ResolveMacros),false);
3089 end;
3090 
GetSourceDirsnull3091 function TLazPackage.GetSourceDirs(WithPkgDir, WithoutOutputDir: boolean): string;
3092 begin
3093   Result:=SourceDirectories.CreateSearchPathFromAllFiles;
3094   if WithPkgDir then
3095     Result:=MergeSearchPaths(Result,Directory);
3096   if WithoutOutputDir then
3097     Result:=RemoveSearchPaths(Result,GetOutputDirectory);
3098 end;
3099 
3100 procedure TLazPackage.IterateComponentClasses(Event: TIterateComponentClassesEvent;
3101   WithUsedPackages: boolean);
3102 var
3103   Cnt: Integer;
3104   i: Integer;
3105   Dependency: TPkgDependency;
3106 begin
3107   // iterate through components in this package
3108   Cnt:=ComponentCount;
3109   for i:=0 to Cnt-1 do Event(Components[i]);
3110   // iterate through all used/required packages
3111   if WithUsedPackages then begin
3112     Dependency:=FirstRequiredDependency;
3113     while Dependency<>nil do begin
3114       if Dependency.RequiredPackage<>nil then
3115         Dependency.RequiredPackage.IterateComponentClasses(Event,false);
3116       Dependency:=Dependency.NextRequiresDependency;
3117     end;
3118   end;
3119 end;
3120 
3121 procedure TLazPackage.SetAllComponentPriorities(const p: TComponentPriority);
3122 var
3123   i: Integer;
3124 begin
3125   //debugln(['TLazPackage.SetAllComponentPriorities ',Name,' ',dbgs(p), ' FileCount=',FileCount]);
3126   for i:=0 to FileCount-1 do
3127     Files[i].ComponentPriority:=p;
3128 end;
3129 
3130 procedure TLazPackage.ConsistencyCheck;
3131 begin
3132   CheckList(FRemovedFiles,true,true,true);
3133   CheckList(FFiles,true,true,true);
3134   CheckList(FComponents,true,true,true);
3135 end;
3136 
ExtendUnitSearchPathnull3137 function TLazPackage.ExtendUnitSearchPath(NewUnitPaths: string): boolean;
3138 var
3139   CurUnitPaths: String;
3140   r: TModalResult;
3141 begin
3142   Result:=True;
3143   CurUnitPaths:=CompilerOptions.ParsedOpts.GetParsedValue(pcosUnitPath);
3144   NewUnitPaths:=RemoveSearchPaths(NewUnitPaths,CurUnitPaths);
3145   if NewUnitPaths='' then Exit;
3146   NewUnitPaths:=CreateRelativeSearchPath(NewUnitPaths,Directory);
3147   if NewUnitPaths='.' then Exit;
3148   r:=IDEMessageDialog(lisExtendUnitPath,
3149         Format(lisExtendUnitSearchPathOfPackageWith, [Name, #13, NewUnitPaths]),
3150         mtConfirmation, [mbYes, mbNo, mbCancel]);
3151   case r of
3152     mrYes: CompilerOptions.MergeToUnitPaths(NewUnitPaths);
3153     mrNo: ;
3154   else exit(false);
3155   end;
3156 end;
3157 
ExtendIncSearchPathnull3158 function TLazPackage.ExtendIncSearchPath(NewIncPaths: string): boolean;
3159 var
3160   CurIncPaths: String;
3161   r: TModalResult;
3162 begin
3163   Result:=True;
3164   CurIncPaths:=CompilerOptions.ParsedOpts.GetParsedValue(pcosIncludePath);
3165   NewIncPaths:=RemoveSearchPaths(NewIncPaths,CurIncPaths);
3166   if NewIncPaths='' then Exit;
3167   NewIncPaths:=CreateRelativeSearchPath(NewIncPaths,Directory);
3168   if NewIncPaths='.' then Exit;
3169   r:=IDEMessageDialog(lisExtendIncludePath,
3170       Format(lisExtendIncludeFileSearchPathOfPackageWith, [Name, #13, NewIncPaths]),
3171       mtConfirmation, [mbYes, mbNo, mbCancel]);
3172   case r of
3173   mrYes: CompilerOptions.MergeToIncludePaths(NewIncPaths);
3174   mrNo: ;
3175   else exit(false);
3176   end;
3177 end;
3178 
IndexOfPkgComponentnull3179 function TLazPackage.IndexOfPkgComponent(PkgComponent: TPkgComponent): integer;
3180 begin
3181   Result:=FComponents.IndexOf(PkgComponent);
3182 end;
3183 
FindPkgFilenull3184 function TLazPackage.FindPkgFile(const AFilename: string; IgnoreRemoved,
3185   FindVirtualFile: boolean): TPkgFile;
3186 var
3187   TheFilename: String;
3188   Cnt: Integer;
3189   i: Integer;
3190 begin
3191   Result:=nil;
3192 
3193   TheFilename:=AFilename;
3194 
3195   Cnt:=FileCount;
3196   for i:=0 to Cnt-1 do begin
3197     Result:=Files[i];
3198     if (not FindVirtualFile) and (not FilenameIsAbsolute(Result.Filename)) then
3199       continue;
3200     if (CompareFilenames(Result.Filename,TheFilename)=0)
3201     or (CompareFilenames(Result.GetFullFilename,TheFilename)=0) then
3202       exit;
3203   end;
3204   if not IgnoreRemoved then begin
3205     Cnt:=RemovedFilesCount;
3206     for i:=0 to Cnt-1 do begin
3207       Result:=RemovedFiles[i];
3208       if (not FindVirtualFile) and (not FilenameIsAbsolute(Result.Filename)) then
3209         continue;
3210       if (CompareFilenames(Result.Filename,TheFilename)=0)
3211       or (CompareFilenames(Result.GetFullFilename,TheFilename)=0) then
3212         exit;
3213     end;
3214   end;
3215   Result:=nil;
3216 end;
3217 
FindUnitWithRegisternull3218 function TLazPackage.FindUnitWithRegister(IgnorePkgFile: TPkgFile): TPkgFile;
3219 var
3220   Cnt: LongInt;
3221   i: Integer;
3222 begin
3223   Cnt:=FileCount;
3224   for i:=0 to Cnt-1 do begin
3225     Result:=Files[i];
3226     if IgnorePkgFile=Result then continue;
3227     if not (Result.FileType in PkgFileRealUnitTypes) then continue;
3228     if Result.HasRegisterProc then exit;
3229   end;
3230   Result:=nil;
3231 end;
3232 
FindUnitnull3233 function TLazPackage.FindUnit(const TheUnitName: string): TPkgFile;
3234 begin
3235   Result:=FindUnit(TheUnitName,true);
3236 end;
3237 
FindUnitnull3238 function TLazPackage.FindUnit(const TheUnitName: string;
3239   IgnoreRemoved: boolean): TPkgFile;
3240 begin
3241   Result:=FindUnit(TheUnitName,IgnoreRemoved,nil);
3242 end;
3243 
FindUnitnull3244 function TLazPackage.FindUnit(const TheUnitName: string;
3245   IgnoreRemoved: boolean; IgnorePkgFile: TPkgFile): TPkgFile;
3246 var
3247   Cnt: Integer;
3248   i: Integer;
3249 begin
3250   if TheUnitName='' then exit(nil);
3251   Cnt:=FileCount;
3252   for i:=0 to Cnt-1 do begin
3253     Result:=Files[i];
3254     if IgnorePkgFile=Result then continue;
3255     if SysUtils.CompareText(Result.Unit_Name,TheUnitName)=0 then exit;
3256   end;
3257   if not IgnoreRemoved then begin
3258     Cnt:=RemovedFilesCount;
3259     for i:=0 to Cnt-1 do begin
3260       Result:=RemovedFiles[i];
3261       if IgnorePkgFile=Result then continue;
3262       if SysUtils.CompareText(Result.Unit_Name,TheUnitName)=0 then exit;
3263     end;
3264   end;
3265   Result:=nil;
3266 end;
3267 
FindUsedUnitnull3268 function TLazPackage.FindUsedUnit(TheUnitName: string; IgnorePkgFile: TPkgFile
3269   ): TPkgFile;
3270 var
3271   i: Integer;
3272 begin
3273   for i:=0 to FileCount-1 do begin
3274     Result:=Files[i];
3275     if IgnorePkgFile=Result then continue;
3276     if not Result.AddToUsesPkgSection then continue;
3277     if not (Result.FileType in PkgFileRealUnitTypes) then continue;
3278     if SysUtils.CompareText(Result.Unit_Name,TheUnitName)=0 then exit;
3279   end;
3280   Result:=nil;
3281 end;
3282 
FindRemovedPkgFilenull3283 function TLazPackage.FindRemovedPkgFile(const AFilename: string): TPkgFile;
3284 var
3285   Cnt: Integer;
3286   i: Integer;
3287 begin
3288   Cnt:=RemovedFilesCount;
3289   for i:=0 to Cnt-1 do begin
3290     Result:=RemovedFiles[i];
3291     if CompareFilenames(Result.Filename,AFilename)=0 then exit;
3292   end;
3293   Result:=nil;
3294 end;
3295 
FindDependencyByNamenull3296 function TLazPackage.FindDependencyByName(const PackageName: string): TPkgDependency;
3297 begin
3298   Result:=FindDependencyByNameInList(FFirstRequiredDependency,pddRequires,PackageName);
3299 end;
3300 
FindRemovedDependencyByNamenull3301 function TLazPackage.FindRemovedDependencyByName(const PkgName: string): TPkgDependency;
3302 begin
3303   Result:=FindDependencyByNameInList(FFirstRemovedDependency,pddRequires,PkgName);
3304 end;
3305 
RequiredDepByIndexnull3306 function TLazPackage.RequiredDepByIndex(Index: integer): TPkgDependency;
3307 begin
3308   Result:=GetDependencyWithIndex(FFirstRequiredDependency,pddRequires,Index);
3309 end;
3310 
RemovedDepByIndexnull3311 function TLazPackage.RemovedDepByIndex(Index: integer): TPkgDependency;
3312 begin
3313   Result:=GetDependencyWithIndex(FFirstRemovedDependency,pddRequires,Index);
3314 end;
3315 
UsedByDepByIndexnull3316 function TLazPackage.UsedByDepByIndex(Index: integer): TPkgDependency;
3317 begin
3318   Result:=GetDependencyWithIndex(FFirstUsedByDependency,pddUsedBy,Index);
3319 end;
3320 
FindUsedByDepPrefernull3321 function TLazPackage.FindUsedByDepPrefer(Ignore: TPkgDependency): TPkgDependency;
3322 begin
3323   Result:=FFirstUsedByDependency;
3324   while (Result<>nil) do begin
3325     if Result.PreferDefaultFilename
3326     and (Result<>Ignore) then
3327       exit;
3328     Result:=Result.NextUsedByDependency;
3329   end;
3330 end;
3331 
ProvidesPackagenull3332 function TLazPackage.ProvidesPackage(const AName: string): boolean;
3333 var
3334   i: Integer;
3335 begin
3336   if AName='' then exit(false);
3337   for i:=0 to Provides.Count-1 do
3338     if SysUtils.CompareText(Provides[i],AName)=0 then begin
3339       //DebugLn(['TLazPackage.ProvidesPackage AName=',AName,' Provides[i]="',Provides[i],'"']);
3340       exit(true);
3341     end;
3342   Result:=false;
3343 end;
3344 
AddFilenull3345 function TLazPackage.AddFile(const NewFilename, NewUnitName: string;
3346   NewFileType: TPkgFileType; NewFlags: TPkgFileFlags;
3347   CompPriorityCat: TComponentPriorityCategory): TPkgFile;
3348 var
3349   NewComponentPriority: TComponentPriority;
3350 begin
3351   Result:=FindRemovedPkgFile(NewFilename);
3352   if Result=nil then begin
3353     Result:=TPkgFile.Create(Self);
3354   end else begin
3355     Result.AutoReferenceSourceDir:=false;
3356     FRemovedFiles.Remove(Result);
3357     Result.Removed:=false;
3358   end;
3359   with Result do begin
3360     Filename:=NewFilename;
3361     //debugln(['TLazPackage.AddFile Is=',Filename,' Should=',NewFilename]);
3362     Unit_Name:=NewUnitName;
3363     FileType:=NewFileType;
3364     Flags:=NewFlags;
3365     NewComponentPriority:=ComponentPriorityNormal;
3366     NewComponentPriority.Category:=CompPriorityCat;
3367     ComponentPriority:=NewComponentPriority;
3368     Removed:=false;
3369     AutoReferenceSourceDir:=true;
3370   end;
3371   FFiles.Add(Result);
3372   //debugln(['TLazPackage.AddFile Is=',Result.Filename,' Should=',NewFilename]);
3373   Modified:=true;
3374 end;
3375 
AddFileByNamenull3376 function TLazPackage.AddFileByName(aFilename: string;
3377   var NewUnitPaths, NewIncPaths: String): Boolean;
3378 var
3379   NewFileType: TPkgFileType;
3380   NewUnitName: String;
3381   NewFlags: TPkgFileFlags;
3382   Code: TCodeBuffer;
3383   CurDir: String;
3384 begin
3385   Result := True;
3386   aFilename:=CleanAndExpandFilename(aFileName);
3387   if not FileExistsUTF8(aFilename) then Exit(False);
3388   if DirPathExists(aFilename) then Exit(False);
3389   if FindPkgFile(aFilename,true,false)<>nil then Exit(False);
3390   NewFileType:=FileNameToPkgFileType(aFilename);
3391   NewFlags:=[];
3392   NewUnitName:='';
3393   if (NewFileType=pftUnit) then begin
3394     Code:=CodeToolBoss.LoadFile(aFilename,true,false);
3395     NewUnitName:=CodeToolBoss.GetSourceName(Code,false);
3396     Assert(NewUnitName<>'', 'TLazPackage.AddFileByName: NewUnitName is empty.');
3397     //if NewUnitName='' then NewUnitName:=ExtractFileNameOnly(aFilename);
3398     if FindUsedUnit(NewUnitName)=nil then
3399       Include(NewFlags,pffAddToPkgUsesSection);
3400     if CodeToolBoss.HasInterfaceRegisterProc(Code) then
3401       Include(NewFlags,pffHasRegisterProc);
3402   end;
3403   AddFile(aFilename,NewUnitName,NewFileType,NewFlags,cpNormal);
3404   CurDir:=ChompPathDelim(ExtractFilePath(aFilename));
3405   if NewFileType=pftUnit then
3406     NewUnitPaths:=MergeSearchPaths(NewUnitPaths,CurDir)
3407   else
3408     NewIncPaths:=MergeSearchPaths(NewIncPaths,CurDir);
3409 end;
3410 
AddRemovedFilenull3411 function TLazPackage.AddRemovedFile(const NewFilename, NewUnitName: string;
3412   NewFileType: TPkgFileType; NewFlags: TPkgFileFlags;
3413   CompPriorityCat: TComponentPriorityCategory): TPkgFile;
3414 var
3415   NewComponentPriority: TComponentPriority;
3416 begin
3417   Result:=FindRemovedPkgFile(NewFilename);
3418   if Result=nil then begin
3419     Result:=TPkgFile.Create(Self);
3420   end;
3421   with Result do begin
3422     AutoReferenceSourceDir:=false;
3423     Filename:=NewFilename;
3424     Unit_Name:=NewUnitName;
3425     FileType:=NewFileType;
3426     Flags:=NewFlags;
3427     NewComponentPriority:=ComponentPriorityNormal;
3428     NewComponentPriority.Category:=CompPriorityCat;
3429     ComponentPriority:=NewComponentPriority;
3430     Removed:=false;
3431     AutoReferenceSourceDir:=true;
3432   end;
3433   FRemovedFiles.Add(Result);
3434 end;
3435 
3436 procedure TLazPackage.DeleteFile(PkgFile: TPkgFile);
3437 begin
3438   PkgFile.Free;
3439   Modified:=true
3440 end;
3441 
3442 procedure TLazPackage.RemoveFileSilently(PkgFile: TPkgFile);
3443 // Remove a file without setting the Modified flag. Caller must take care of it.
3444 begin
3445   FFiles.Remove(PkgFile);
3446   FRemovedFiles.Add(PkgFile);
3447   PkgFile.Removed:=true;
3448 end;
3449 
3450 procedure TLazPackage.RemoveFile(PkgFile: TPkgFile);
3451 begin
3452   RemoveFileSilently(PkgFile);
3453   Modified:=true;
3454 end;
3455 
3456 procedure TLazPackage.UnremovePkgFile(PkgFile: TPkgFile);
3457 begin
3458   FFiles.Add(PkgFile);
3459   FRemovedFiles.Remove(PkgFile);
3460   PkgFile.Removed:=false;
3461 end;
3462 
RemoveNonExistingFilesnull3463 function TLazPackage.RemoveNonExistingFiles(RemoveFromUsesSection: boolean): boolean;
3464 // Param is ignored here, it is just to match with interface.
3465 var
3466   i: Integer;
3467   AFilename: String;
3468 begin
3469   Result:=false;
3470   i:=FileCount-1;
3471   while i>=0 do begin
3472     if i>=FileCount then continue;
3473     AFilename:=Files[i].GetResolvedFilename;
3474     if (AFilename='') or (not FileExistsCached(AFilename)) then
3475     begin
3476       RemoveFile(Files[i]);
3477       Result:=true;
3478     end;
3479     dec(i);
3480   end;
3481 end;
3482 
GetFileDialogInitialDirnull3483 function TLazPackage.GetFileDialogInitialDir(const DefaultDirectory: string): string;
3484 begin
3485   Result:=AppendPathDelim(TrimFilename(DefaultDirectory));
3486   if (SourceDirectories.GetFileReference(Result)=nil)
3487   and DirPathExists(Directory) then
3488     Result:=Directory;
3489 end;
3490 
3491 procedure TLazPackage.MoveFile(CurIndex, NewIndex: integer);
3492 begin
3493   if CurIndex=NewIndex then exit;
3494   FFiles.Move(CurIndex,NewIndex);
3495   Include(FFlags,lpfModified);
3496   if FChangeStamp<High(FChangeStamp) then
3497     inc(FChangeStamp)
3498   else
3499     FChangeStamp:=low(FChangeStamp);
3500 end;
3501 
3502 procedure TLazPackage.SortFiles;
3503 var
3504   NewList: TFPList;
3505   Cnt: Integer;
3506   i: Integer;
3507 begin
3508   if FileCount=0 then exit;
3509   NewList:=TFPList.Create;
3510   try
3511     Cnt:=FileCount;
3512     for i:=0 to Cnt-1 do NewList.Add(FFiles[i]);
3513     NewList.Sort(TListSortCompare(@ComparePkgFilesAlphabetically));
3514     i:=Cnt-1;
3515     while (i>=0) and (NewList[i]=FFiles[i]) do dec(i);
3516     if i<0 then exit;
3517     FFiles.Clear;
3518     for i:= 0 to Cnt-1 do FFiles.Add(NewList[i]);
3519     Modified:=true;
3520   finally
3521     NewList.Free;
3522   end;
3523 end;
3524 
FixFilesCaseSensitivitynull3525 function TLazPackage.FixFilesCaseSensitivity: boolean;
3526 var
3527   SrcDirs: TStringList;
3528 
3529   function IndexOfFileInStringList(List: TStringList;
3530     const Filename: string; OnlyExact: boolean): integer;
3531   begin
3532     // first search for exact match
3533     Result:=List.Count-1;
3534     while (Result>=0) do begin
3535       if (Filename=List[Result]) then exit;
3536       dec(Result);
3537     end;
3538     if OnlyExact then exit;
3539     // then search for case insensitive match
3540     Result:=List.Count-1;
3541     while (Result>=0) and (SysUtils.CompareText(Filename,List[Result])<>0) do
3542       dec(Result);
3543   end;
3544 
3545   function AddDirectoryListing(const ADirectory: string): TStringList;
3546   var
3547     SrcDirID: Integer;
3548     FileInfo: TSearchRec;
3549   begin
3550     if SrcDirs=nil then
3551       SrcDirs:=TStringList.Create;
3552     // search directory listing
3553     SrcDirID:=IndexOfFileInStringList(SrcDirs,ADirectory,true);
3554     if SrcDirID>=0 then begin
3555       Result:=TStringList(SrcDirs.Objects[SrcDirID]);
3556       exit;
3557     end;
3558     // create new directory listing
3559     Result:=TStringList.Create;
3560     if FindFirstUTF8(AppendPathDelim(ADirectory)+GetAllFilesMask,
3561                           faAnyFile,FileInfo)=0
3562     then begin
3563       repeat
3564         // check if special file
3565         if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
3566         then continue;
3567         Result.Add(FileInfo.Name);
3568         //debugln('AddDirectoryListing ',FileInfo.Name);
3569       until FindNextUTF8(FileInfo)<>0;
3570     end;
3571     FindCloseUTF8(FileInfo);
3572     SrcDirs.AddObject(ADirectory,Result);
3573   end;
3574 
3575 var
3576   Cnt: Integer;
3577   i: Integer;
3578   CurFile: TPkgFile;
3579   CurShortFilename: String;
3580   DirListID: LongInt;
3581   DirListing: TStringList;
3582   NewShortFilename: string;
3583   NewFilename: String;
3584   CurDir: String;
3585   AFilename: String;
3586 begin
3587   Result:=false;
3588   Cnt:=FileCount;
3589   SrcDirs:=nil;
3590   try
3591     for i:=0 to Cnt-1 do begin
3592       CurFile:=Files[i];
3593       //debugln('TLazPackage.FixFilesCaseSensitivity A ',dbgs(i),' CurFile.Filename=',CurFile.Filename);
3594       AFilename:=CurFile.GetFullFilename;
3595       CurShortFilename:=ExtractFilename(AFilename);
3596       CurDir:=ExtractFilePath(AFilename);
3597       DirListing:=AddDirectoryListing(CurDir);
3598       DirListID:=IndexOfFileInStringList(DirListing,CurShortFilename,false);
3599       //debugln('TLazPackage.FixFilesCaseSensitivity B ',dbgs(i),' CurShortFilename=',CurShortFilename,' DirListID=',dbgs(DirListID));
3600       if DirListID<0 then continue;
3601       NewShortFilename:=DirListing[DirListID];
3602       //debugln('TLazPackage.FixFilesCaseSensitivity New ',dbgs(i),' NewShortFilename=',NewShortFilename);
3603       if CurShortFilename<>NewShortFilename then begin
3604         // case changes
3605         NewFilename:=AppendPathDelim(ExtractFilePath(CurFile.Filename))+NewShortFilename;
3606         //debugln('TLazPackage.FixFilesCaseSensitivity New ',dbgs(i),' NewFilename=',NewFilename);
3607         CurFile.Filename:=NewFilename;
3608         Result:=true;
3609       end;
3610     end;
3611     if Result then
3612       Modified:=true;
3613   finally
3614     if SrcDirs<>nil then begin
3615       for i:=0 to SrcDirs.Count-1 do
3616         SrcDirs.Objects[i].Free;
3617       SrcDirs.Free;
3618     end;
3619   end;
3620 end;
3621 
MainUnitHasPkgNamenull3622 function TLazPackage.MainUnitHasPkgName: boolean;
3623 begin
3624   Result:=(MainUnit=nil) or (SysUtils.CompareText(MainUnit.Unit_Name,Name)=0);
3625 end;
3626 
3627 procedure TLazPackage.RemoveRemovedDependency(Dependency: TPkgDependency);
3628 begin
3629   Dependency.RemoveFromList(FFirstRemovedDependency,pddRequires);
3630   Dependency.Removed:=false;
3631 end;
3632 
3633 procedure TLazPackage.AddRequiredDependency(Dependency: TPkgDependency);
3634 begin
3635   Dependency.AddToList(FFirstRequiredDependency,pddRequires);
3636   Dependency.Owner:=Self;
3637   Modified:=true;
3638 end;
3639 
3640 procedure TLazPackage.AddPackageDependency(const PackageName: string);
3641 var
3642   Dependency: TPkgDependency;
3643 begin
3644   if FindDependencyByName(PackageName)<>nil then exit;
3645   Dependency:=TPkgDependency.Create;
3646   Dependency.PackageName:=PackageName;
3647   AddRequiredDependency(Dependency);
3648 end;
3649 
3650 procedure TLazPackage.RemoveRequiredDepSilently(Dependency: TPkgDependency);
3651 // Remove a dependency without setting the Modified flag. Caller must take care of it.
3652 begin
3653   Dependency.RemoveFromList(FFirstRequiredDependency,pddRequires);
3654   Dependency.RequiredPackage:=nil;
3655   Dependency.AddToList(FFirstRemovedDependency,pddRequires);
3656   Dependency.Removed:=true;
3657 end;
3658 
3659 procedure TLazPackage.RemoveRequiredDependency(Dependency: TPkgDependency);
3660 begin
3661   RemoveRequiredDepSilently(Dependency);
3662   Modified:=true;
3663 end;
3664 
3665 procedure TLazPackage.DeleteRequiredDependency(Dependency: TPkgDependency);
3666 begin
3667   Dependency.RequiredPackage:=nil;
3668   Dependency.RemoveFromList(FFirstRequiredDependency,pddRequires);
3669   Dependency.Free;
3670 end;
3671 
3672 procedure TLazPackage.DeleteRemovedDependency(Dependency: TPkgDependency);
3673 begin
3674   Dependency.RequiredPackage:=nil;
3675   Dependency.RemoveFromList(FFirstRemovedDependency,pddRequires);
3676   Dependency.Free;
3677 end;
3678 
MoveRequiredDependencyUpnull3679 function TLazPackage.MoveRequiredDependencyUp(Dependency: TPkgDependency): Boolean;
3680 begin
3681   Result := Dependency.MoveUpInList(FFirstRequiredDependency,pddRequires);
3682 end;
3683 
MoveRequiredDependencyDownnull3684 function TLazPackage.MoveRequiredDependencyDown(Dependency: TPkgDependency): Boolean;
3685 begin
3686   Result := Dependency.MoveDownInList(FFirstRequiredDependency,pddRequires);
3687 end;
3688 
CreateDependencyWithOwnernull3689 function TLazPackage.CreateDependencyWithOwner(NewOwner: TObject;
3690   WithMinVersion: boolean): TPkgDependency;
3691 begin
3692   Result:=TPkgDependency.Create;
3693   with Result do begin
3694     Owner:=NewOwner;
3695     PackageName:=Self.Name;
3696     if WithMinVersion then begin
3697       MinVersion.Assign(Version);
3698       Flags:=[pdfMinVersion];
3699     end;
3700   end;
3701 end;
3702 
AddComponentnull3703 function TLazPackage.AddComponent(PkgFile: TPkgFile; const Page: string;
3704   TheComponentClass: TComponentClass): TPkgComponent;
3705 begin
3706   Result:=TPkgComponent.Create(PkgFile,TheComponentClass,Page);
3707 end;
3708 
3709 procedure TLazPackage.AddPkgComponent(APkgComponent: TPkgComponent);
3710 begin
3711   FComponents.Add(APkgComponent);
3712 end;
3713 
3714 procedure TLazPackage.RemovePkgComponent(APkgComponent: TPkgComponent);
3715 begin
3716   FComponents.Remove(APkgComponent);
3717 end;
3718 
Requiresnull3719 function TLazPackage.Requires(APackage: TLazPackage): boolean;
3720 begin
3721   Result:=FindCompatibleDependencyInList(FFirstRequiredDependency,pddRequires,
3722                   APackage)<>nil;
3723 end;
3724 
3725 procedure TLazPackage.AddUsedByDependency(Dependency: TPkgDependencyBase);
3726 begin
3727   Dependency.AddUsedByDep(TPkgDependencyBase(FFirstUsedByDependency));
3728   if TPkgDependency(Dependency).HoldPackage then
3729     inc(FHoldPackageCount);
3730 end;
3731 
3732 procedure TLazPackage.RemoveUsedByDependency(Dependency: TPkgDependencyBase);
3733 begin
3734   Dependency.RemoveUsedByDep(TPkgDependencyBase(FFirstUsedByDependency));
3735   if TPkgDependency(Dependency).HoldPackage then
3736     dec(FHoldPackageCount);
3737 end;
3738 
3739 procedure TLazPackage.ChangeID(const NewName: string; NewVersion: TPkgVersion);
3740 begin
3741   Version.Assign(NewVersion);
3742   Name:=NewName;
3743 end;
3744 
GetFPDocPackageNamenull3745 function TLazPackage.GetFPDocPackageName: string;
3746 begin
3747   if FPDocPackageName<>'' then
3748     Result:=FPDocPackageName
3749   else
3750     Result:=Name;
3751 end;
3752 
GetOutputDirTypenull3753 function TLazPackage.GetOutputDirType: TPkgOutputDir;
3754 begin
3755   if (CompilerOptions<>nil)
3756   and (CompilerOptions.ParsedOpts<>nil)
3757   and (CompilerOptions.ParsedOpts.OutputDirectoryOverride<>'') then
3758     Result:=podFallback
3759   else
3760     Result:=podDefault;
3761 end;
3762 
3763 procedure TLazPackage.GetAllRequiredPackages(var List, FPMakeList: TFPList;
3764   WithSelf: boolean; aFlags: TPkgIntfRequiredFlags;
3765   MinPolicy: TPackageUpdatePolicy);
3766 begin
3767   if Assigned(OnGetAllRequiredPackages) then
3768     OnGetAllRequiredPackages(Self,FirstRequiredDependency,List,FPMakeList,aFlags,MinPolicy);
3769   if WithSelf then begin
3770     if List=nil then List:=TFPList.Create;
3771     if List.IndexOf(Self)<0 then
3772       List.Insert(0,Self);
3773   end else if List<>nil then begin
3774     List.Remove(Self);
3775     if List.Count=0 then FreeAndNil(List);
3776   end;
3777 end;
3778 
3779 procedure TLazPackage.GetInheritedCompilerOptions(var OptionsList: TFPList);
3780 var
3781   PkgList: TFPList; // list of TLazPackage
3782   FPMakeList: TFPList;
3783 begin
3784   PkgList:=nil;
3785   FPMakeList:=nil;
3786   GetAllRequiredPackages(PkgList,FPMakeList,false,[pirCompileOrder]);
3787   OptionsList:=GetUsageOptionsList(PkgList);
3788   PkgList.Free;
3789   FPMakeList.Free;
3790 end;
3791 
GetCompileSourceFilenamenull3792 function TLazPackage.GetCompileSourceFilename: string;
3793 begin
3794   if MainUnit<>nil then
3795     Result:=ExtractFilename(MainUnit.GetFullFilename)
3796   else
3797     Result:=ChangeFileExt(ExtractFilename(Filename),'.pas');
3798 end;
3799 
GetOutputDirectorynull3800 function TLazPackage.GetOutputDirectory(UseOverride: boolean = true): string;
3801 begin
3802   if HasDirectory then begin
3803     if GetActiveBuildMethod = bmFPMake then begin
3804       Result :=TFppkgHelper.Instance.GetPackageUnitPath(name);
3805     end else begin
3806       Result:=CompilerOptions.ParsedOpts.GetParsedValue(pcosOutputDir,UseOverride);
3807     end;
3808   end else
3809     Result:='';
3810 end;
3811 
HasSeparateOutputDirectorynull3812 function TLazPackage.HasSeparateOutputDirectory: boolean;
3813 var
3814   VisitedPackages: TStringToStringTree;
3815   OutputDir: String;
3816 
3817   function CheckDependency(ADependency: TPkgDependency): boolean;
3818   var
3819     aPkg: TLazPackage;
3820     Dir: String;
3821     SrcPaths: String;
3822   begin
3823     Result:=false;
3824     while ADependency<>nil do begin
3825       if ADependency.RequiredPackage<>nil then begin
3826         aPkg:=ADependency.RequiredPackage;
3827         if not VisitedPackages.Contains(aPkg.Name) then begin
3828           VisitedPackages[aPkg.Name]:='1';
3829           // check recursively
3830           if not CheckDependency(aPkg.FirstRequiredDependency) then exit;
3831           // check if required package has the same output directory
3832           Dir:=aPkg.GetOutputDirectory;
3833           if CompareFilenames(Dir,OutputDir)=0 then exit;
3834           // check if output directory is a sour directory of a required package
3835           SrcPaths:=aPkg.SourceDirectories.CreateSearchPathFromAllFiles;
3836           if (SrcPaths<>'')
3837           and (FindPathInSearchPath(PChar(OutputDir),length(OutputDir),
3838                                     PChar(SrcPaths),length(SrcPaths))<>nil)
3839           then exit;
3840         end;
3841       end;
3842       ADependency:=ADependency.NextRequiresDependency;
3843     end;
3844     Result:=true;
3845   end;
3846 
3847 var
3848   SrcPaths: String;
3849 begin
3850   Result:=false;
3851   if CompilerOptions.UnitOutputDirectory='' then exit;
3852   OutputDir:=CompilerOptions.ParsedOpts.GetParsedValue(pcosOutputDir,false);
3853   if OutputDir='' then exit;
3854   SrcPaths:=SourceDirectories.CreateSearchPathFromAllFiles;
3855   if SrcPaths='' then exit(true);
3856   if FindPathInSearchPath(PChar(OutputDir),length(OutputDir),PChar(SrcPaths),length(SrcPaths))<>nil
3857   then exit;
3858   // check used packages
3859   VisitedPackages:=TStringToStringTree.Create(false);
3860   try
3861     if not CheckDependency(FirstRequiredDependency) then exit;
3862   finally
3863     VisitedPackages.Free;
3864   end;
3865   Result:=true;
3866 end;
3867 
GetStateFilenamenull3868 function TLazPackage.GetStateFilename(UseOverride: boolean): string;
3869 begin
3870   Result:=AppendPathDelim(GetOutputDirectory(UseOverride))+Name+'.compiled';
3871 end;
3872 
GetSrcFilenamenull3873 function TLazPackage.GetSrcFilename: string;
3874 begin
3875   if MainUnit<>nil then
3876     Result:=MainUnit.GetFullFilename
3877   else
3878     Result:=FDirectory+GetCompileSourceFilename;
3879 end;
3880 
GetSrcPPUFilenamenull3881 function TLazPackage.GetSrcPPUFilename: string;
3882 begin
3883   Result:=AppendPathDelim(GetOutputDirectory)
3884           +ChangeFileExt(GetCompileSourceFilename,'.ppu');
3885 end;
3886 
GetCompilerFilenamenull3887 function TLazPackage.GetCompilerFilename: string;
3888 begin
3889   Result:=CompilerOptions.ParsedOpts.GetParsedValue(pcosCompilerPath);
3890 end;
3891 
GetPOOutDirectorynull3892 function TLazPackage.GetPOOutDirectory: string;
3893 begin
3894   Result:=TrimFilename(SubstitutePkgMacros(fPOOutputDirectory,false));
3895   LongenFilename(Result);
3896   IDEMacros.SubstituteMacros(Result);
3897   Result:=TrimFilename(Result);
3898 end;
3899 
GetUnitPathnull3900 function TLazPackage.GetUnitPath(RelativeToBaseDir: boolean): string;
3901 begin
3902   Result:=CompilerOptions.GetUnitPath(RelativeToBaseDir);
3903 end;
3904 
GetUseLegacyListsnull3905 function TLazPackage.GetUseLegacyLists: Boolean;
3906 begin
3907   Result:=lpfCompatibilityMode in Flags;
3908 end;
3909 
GetIncludePathnull3910 function TLazPackage.GetIncludePath(RelativeToBaseDir: boolean): string;
3911 begin
3912   Result:=CompilerOptions.GetIncludePath(RelativeToBaseDir);
3913 end;
3914 
GetSrcPathnull3915 function TLazPackage.GetSrcPath(RelativeToBaseDir: boolean): string;
3916 begin
3917   Result:=CompilerOptions.GetSrcPath(RelativeToBaseDir);
3918 end;
3919 
GetLastCompilerParamsnull3920 function TLazPackage.GetLastCompilerParams(o: TPkgOutputDir): string;
3921 begin
3922   Result:=LastCompile[o].Params;
3923   if LastCompile[o].ViaMakefile then begin
3924     Result:=StringReplace(Result,'$(CPU_TARGET)','$(TargetCPU)',[rfReplaceAll]);
3925     Result:=StringReplace(Result,'$(OS_TARGET)','$(TargetOS)',[rfReplaceAll]);
3926     Result:=StringReplace(Result,'$(LCL_PLATFORM)','$(LCLWidgetType)',[rfReplaceAll]);
3927     Result:=SubstitutePkgMacros(Result,false);
3928   end;
3929 end;
3930 
NeedsDefineTemplatesnull3931 function TLazPackage.NeedsDefineTemplates: boolean;
3932 begin
3933   if IsVirtual or (lpfDestroying in Flags) or (Name='') then
3934     Result:=false
3935   else
3936     Result:=true;
3937 end;
3938 
IndexOfPkgFilenull3939 function TLazPackage.IndexOfPkgFile(PkgFile: TPkgFile): integer;
3940 begin
3941   Result := FileCount - 1;
3942   if Result < 0 then
3943     Exit;
3944   while (Files[Result] <> PkgFile) do
3945   begin
3946     dec(Result);
3947     if Result < 0 then
3948       Exit;
3949   end;
3950 end;
3951 
SearchShortFilenamenull3952 function TLazPackage.SearchShortFilename(const ShortFilename: string;
3953   SearchFlags: TSearchIDEFileFlags): TPkgFile;
3954 var
3955   SearchedFilename: String;
3956   i: Integer;
3957 
3958   function FilenameFits(TheFilename: string): boolean;
3959   begin
3960     if siffIgnoreExtension in SearchFlags then
3961       TheFileName:=ExtractFileNameWithoutExt(TheFileName);
3962     //debugln('TLazPackage.SearchFile A ',SearchedFilename,' ',TheFilename);
3963     if siffCaseSensitive in SearchFlags then
3964       Result:=SearchedFilename=TheFilename
3965     else
3966       Result:=SysUtils.CompareText(SearchedFilename,TheFilename)=0;
3967   end;
3968 
3969 begin
3970   SearchedFilename:=ShortFilename;
3971   if siffIgnoreExtension in SearchFlags then
3972     SearchedFilename:=ExtractFileNameWithoutExt(SearchedFilename);
3973 
3974   // search in files
3975   for i:=0 to FileCount-1 do begin
3976     Result:=Files[i];
3977     if FilenameFits(Result.GetShortFilename(true)) then exit;
3978   end;
3979   Result:=nil;
3980 end;
3981 
SearchFilenamenull3982 function TLazPackage.SearchFilename(const AFilename: string;
3983   SearchFlags: TSearchIDEFileFlags): TPkgFile;
3984 var
3985   SearchedFilename: String;
3986   i: Integer;
3987 
3988   function FilenameFits(TheFilename: string): boolean;
3989   begin
3990     if siffIgnoreExtension in SearchFlags then
3991       TheFileName:=ExtractFileNameWithoutExt(TheFileName);
3992     //debugln('TLazPackage.SearchFile A ',SearchedFilename,' ',TheFilename);
3993     if siffCaseSensitive in SearchFlags then
3994       Result:=SearchedFilename=TheFilename
3995     else
3996       Result:=SysUtils.CompareText(SearchedFilename,TheFilename)=0;
3997   end;
3998 
3999 begin
4000   SearchedFilename:=AFilename;
4001   if siffIgnoreExtension in SearchFlags then
4002     SearchedFilename:=ExtractFileNameWithoutExt(SearchedFilename);
4003 
4004   // search in files
4005   for i:=0 to FileCount-1 do begin
4006     Result:=Files[i];
4007     if FilenameFits(Result.GetFullFilename) then exit;
4008   end;
4009   Result:=nil;
4010 end;
4011 
4012 { TPkgComponent }
4013 
4014 procedure TPkgComponent.SetPkgFile(const AValue: TPkgFile);
4015 begin
4016   if FPkgFile=AValue then exit;
4017   if (FPkgFile<>nil) then PkgFile.RemovePkgComponent(Self);
4018   FPkgFile:=AValue;
4019   if (FPkgFile<>nil) then PkgFile.AddPkgComponent(Self);
4020 end;
4021 
4022 constructor TPkgComponent.Create(ThePkgFile: TPkgFile;
4023   TheComponentClass: TComponentClass; const ThePageName: string);
4024 begin
4025   inherited Create(TheComponentClass,ThePageName);
4026   PkgFile:=ThePkgFile;
4027 end;
4028 
4029 destructor TPkgComponent.Destroy;
4030 begin
4031   PkgFile:=nil;
4032   inherited Destroy;
4033 end;
4034 
GetUnitNamenull4035 function TPkgComponent.GetUnitName: string;
4036 var
4037   TIUnitName: String;
4038 begin
4039   Result:=PkgFile.Unit_Name;
4040   // compare with RTTI unit name
4041   if ComponentClass<>nil then begin
4042     TIUnitName:=ComponentClass.UnitName;
4043     if SysUtils.CompareText(TIUnitName,Result)<>0 then
4044       Result:=TIUnitName;
4045   end;
4046 end;
4047 
GetPrioritynull4048 function TPkgComponent.GetPriority: TComponentPriority;
4049 begin
4050   Result:=PkgFile.ComponentPriority;
4051 end;
4052 
4053 procedure TPkgComponent.ConsistencyCheck;
4054 begin
4055   inherited ConsistencyCheck;
4056   if FPkgFile=nil then
4057     RaiseGDBException('TIDEComponent.ConsistencyCheck FPkgFile=nil');
4058   if FPkgFile.LazPackage=nil then
4059     RaiseGDBException('TIDEComponent.ConsistencyCheck FPkgFile.LazPackage=nil');
4060   if FPkgFile.LazPackage.IndexOfPkgComponent(Self)<0 then
4061     RaiseGDBException('TIDEComponent.ConsistencyCheck FPkgFile.LazPackage.IndexOfPkgComponent(Self)<0');
4062   if PkgFile.FComponents=nil then
4063     RaiseGDBException('TIDEComponent.ConsistencyCheck PkgFile.FComponents=nil');
4064   if PkgFile.FComponents.IndexOf(Self)<0 then
4065     RaiseGDBException('TIDEComponent.ConsistencyCheck PkgFile.FComponents.IndexOf(Self)<0');
4066 end;
4067 
4068 class function TPkgComponent.Images: TCustomImageList;
4069 begin
4070   Result := IDEImages.Images_24;
4071 end;
4072 
HasIconnull4073 function TPkgComponent.HasIcon: boolean;
4074 begin
4075   Result:=RealPage.PageName<>'';
4076 end;
4077 
ImageIndexnull4078 function TPkgComponent.ImageIndex: TImageIndex;
4079 begin
4080   Result := IDEImages.GetImageIndex(ComponentClass.ClassName, 24);
4081   if Result=-1 then
4082     Result := IDEImages.GetImageIndex('default', 24);
4083 end;
4084 
CanBeCreatedInDesignernull4085 function TPkgComponent.CanBeCreatedInDesigner: boolean;
4086 begin
4087   Result:=(not PkgFile.Removed);
4088 end;
4089 
4090 { TPkgCompilerOptions }
4091 
4092 procedure TPkgCompilerOptions.LoadFromXMLConfig(AXMLConfig: TXMLConfig;
4093   const Path: string);
4094 begin
4095   inherited LoadFromXMLConfig(AXMLConfig,Path);
4096 
4097   FSkipCompiler := AXMLConfig.GetValue(Path+'SkipCompiler/Value', False);
4098 end;
4099 
4100 procedure TPkgCompilerOptions.SaveToXMLConfig(AXMLConfig: TXMLConfig; const Path: string);
4101 begin
4102   inherited SaveToXMLConfig(AXMLConfig,Path);
4103 
4104   AXMLConfig.SetDeleteValue(Path+'SkipCompiler/Value', FSkipCompiler, False);
4105 end;
4106 
4107 procedure TPkgCompilerOptions.SetLazPackage(const AValue: TLazPackage);
4108 begin
4109   if FLazPackage=AValue then exit;
4110   FLazPackage:=AValue;
4111 end;
4112 
4113 procedure TPkgCompilerOptions.SetCustomOptions(const AValue: string);
4114 begin
4115   if CustomOptions=AValue then exit;
4116   InvalidateOptions;
4117   inherited SetCustomOptions(AValue);
4118   if LazPackage<>nil then
4119     LazPackage.DefineTemplates.CustomDefinesChanged;
4120 end;
4121 
4122 procedure TPkgCompilerOptions.SetIncludePaths(const AValue: string);
4123 begin
4124   if IncludePath=AValue then exit;
4125   InvalidateOptions;
4126   inherited SetIncludePaths(AValue);
4127 end;
4128 
4129 procedure TPkgCompilerOptions.SetLibraryPaths(const AValue: string);
4130 begin
4131   if Libraries=AValue then exit;
4132   InvalidateOptions;
4133   inherited SetLibraryPaths(AValue);
4134 end;
4135 
4136 procedure TPkgCompilerOptions.SetLinkerOptions(const AValue: string);
4137 begin
4138   if LinkerOptions=AValue then exit;
4139   InvalidateOptions;
4140   inherited SetLinkerOptions(AValue);
4141 end;
4142 
4143 procedure TPkgCompilerOptions.SetObjectPath(const AValue: string);
4144 begin
4145   if ObjectPath=AValue then exit;
4146   InvalidateOptions;
4147   inherited SetObjectPath(AValue);
4148 end;
4149 
4150 procedure TPkgCompilerOptions.SetSrcPath(const AValue: string);
4151 begin
4152   if SrcPath=AValue then exit;
4153   InvalidateOptions;
4154   inherited SetSrcPath(AValue);
4155 end;
4156 
4157 procedure TPkgCompilerOptions.SetUnitPaths(const AValue: string);
4158 begin
4159   if OtherUnitFiles=AValue then exit;
4160   InvalidateOptions;
4161   inherited SetUnitPaths(AValue);
4162 end;
4163 
4164 procedure TPkgCompilerOptions.SetUnitOutputDir(const AValue: string);
4165 begin
4166   if UnitOutputDirectory=AValue then exit;
4167   InvalidateOptions;
4168   inherited SetUnitOutputDir(AValue);
4169   if LazPackage<>nil then
4170     LazPackage.DefineTemplates.OutputDirectoryChanged;
4171 end;
4172 
4173 procedure TPkgCompilerOptions.SetConditionals(AValue: string);
4174 begin
4175   AValue:=UTF8Trim(AValue,[]);
4176   if Conditionals=AValue then exit;
4177   InvalidateOptions;
4178   inherited SetConditionals(AValue);
4179 end;
4180 
4181 constructor TPkgCompilerOptions.Create(const AOwner: TObject);
4182 begin
4183   inherited Create(AOwner);
4184   if AOwner<>nil then
4185     FLazPackage := AOwner as TLazPackage;
4186   ParsedOpts.MacroValues.ProjValuesAvailable:=true;
4187 end;
4188 
4189 class function TPkgCompilerOptions.GetGroupCaption: string;
4190 begin
4191   Result := dlgCompilerOptions;
4192 end;
4193 
4194 class function TPkgCompilerOptions.GetInstance: TAbstractIDEOptions;
4195 begin
4196   if Package1<>nil then
4197     Result := Package1.CompilerOptions
4198   else
4199     Result := nil;
4200 end;
4201 
IsActivenull4202 function TPkgCompilerOptions.IsActive: boolean;
4203 begin
4204   Result:=(LazPackage<>nil) and (LazPackage.CompilerOptions=Self);
4205 end;
4206 
4207 procedure TPkgCompilerOptions.Clear;
4208 begin
4209   inherited Clear;
4210   FSkipCompiler:=false;
4211 end;
4212 
4213 procedure TPkgCompilerOptions.GetInheritedCompilerOptions(
4214   var OptionsList: TFPList);
4215 begin
4216   if LazPackage<>nil then
4217     LazPackage.GetInheritedCompilerOptions(OptionsList);
4218 end;
4219 
GetOwnerNamenull4220 function TPkgCompilerOptions.GetOwnerName: string;
4221 begin
4222   if LazPackage<>nil then
4223     Result:=LazPackage.IDAsString
4224   else
4225     Result:='';
4226 end;
4227 
4228 procedure TPkgCompilerOptions.InvalidateOptions;
4229 begin
4230   if (LazPackage=nil) then exit;
4231   if LazPackage.UsageOptions=nil then RaiseGDBException('');
4232   if LazPackage.UsageOptions.ParsedOpts=nil then RaiseGDBException('');
4233   LazPackage.UsageOptions.ParsedOpts.InvalidateAll;
4234 end;
4235 
GetDefaultMainSourceFileNamenull4236 function TPkgCompilerOptions.GetDefaultMainSourceFileName: string;
4237 begin
4238   if LazPackage<>nil then
4239     Result:=LazPackage.GetCompileSourceFilename
4240   else
4241     Result:='';
4242   if Result='' then
4243     Result:=inherited GetDefaultMainSourceFileName;
4244 end;
4245 
CreateTargetFilenamenull4246 function TPkgCompilerOptions.CreateTargetFilename: string;
4247 begin
4248   Result:='';
4249 end;
4250 
HasCompilerCommandnull4251 function TPkgCompilerOptions.HasCompilerCommand: boolean;
4252 begin
4253   Result:=(not SkipCompiler) and (CompilerPath<>'');
4254 end;
4255 
4256 procedure TPkgCompilerOptions.Assign(Source: TPersistent);
4257 begin
4258   inherited Assign(Source);
4259   if Source is TPkgCompilerOptions
4260   then begin
4261     FSkipCompiler := TPkgCompilerOptions(Source).FSkipCompiler;
4262   end
4263   else begin
4264     FSkipCompiler := False;
4265   end;
4266 end;
4267 
CreateDiffnull4268 function TPkgCompilerOptions.CreateDiff(CompOpts: TBaseCompilerOptions;
4269   Tool: TCompilerDiffTool): boolean;
4270 begin
4271   if (CompOpts is TPkgCompilerOptions) then begin
4272     Result:=Tool.AddDiff('SkipCompiler',FSkipCompiler,
4273                  TPkgCompilerOptions(CompOpts).FSkipCompiler);
4274   end else begin
4275     Result:=true;
4276     if Tool<>nil then Tool.Differ:=true;
4277   end;
4278   Result:=Result or inherited CreateDiff(CompOpts, Tool);
4279 end;
4280 
4281 { TPkgAdditionalCompilerOptions }
4282 
4283 procedure TPkgAdditionalCompilerOptions.SetLazPackage(const AValue: TLazPackage);
4284 begin
4285   if FLazPackage=AValue then exit;
4286   FLazPackage:=AValue;
4287 end;
4288 
4289 procedure TPkgAdditionalCompilerOptions.SetCustomOptions(const AValue: string);
4290 begin
4291   if AValue=CustomOptions then exit;
4292   inherited SetCustomOptions(AValue);
4293   LazPackage.Modified:=true;
4294 end;
4295 
4296 procedure TPkgAdditionalCompilerOptions.SetIncludePath(const AValue: string);
4297 begin
4298   if AValue=IncludePath then exit;
4299   inherited SetIncludePath(AValue);
4300   LazPackage.Modified:=true;
4301 end;
4302 
4303 procedure TPkgAdditionalCompilerOptions.SetLibraryPath(const AValue: string);
4304 begin
4305   if AValue=LibraryPath then exit;
4306   inherited SetLibraryPath(AValue);
4307   LazPackage.Modified:=true;
4308 end;
4309 
4310 procedure TPkgAdditionalCompilerOptions.SetLinkerOptions(const AValue: string);
4311 begin
4312   if AValue=LinkerOptions then exit;
4313   inherited SetLinkerOptions(AValue);
4314   LazPackage.Modified:=true;
4315 end;
4316 
4317 procedure TPkgAdditionalCompilerOptions.SetObjectPath(const AValue: string);
4318 begin
4319   if AValue=ObjectPath then exit;
4320   inherited SetObjectPath(AValue);
4321   LazPackage.Modified:=true;
4322 end;
4323 
4324 procedure TPkgAdditionalCompilerOptions.SetUnitPath(const AValue: string);
4325 begin
4326   if AValue=UnitPath then exit;
4327   inherited SetUnitPath(AValue);
4328   LazPackage.Modified:=true;
4329 end;
4330 
4331 procedure TPkgAdditionalCompilerOptions.SetSrcPath(const AValue: string);
4332 begin
4333   if AValue=SrcPath then exit;
4334   inherited SetSrcPath(AValue);
4335   LazPackage.Modified:=true;
4336 end;
4337 
4338 constructor TPkgAdditionalCompilerOptions.Create(ThePackage: TLazPackage);
4339 begin
4340   inherited Create(ThePackage);
4341   FLazPackage:=ThePackage;
4342 end;
4343 
4344 procedure TPkgAdditionalCompilerOptions.AssignOptions(Source: TObject);
4345 begin
4346   inherited AssignOptions(Source);
4347   if Source is TPkgAdditionalCompilerOptions then begin
4348     //Src:=TPkgAdditionalCompilerOptions(Source);
4349     // nothing to do
4350   end;
4351 end;
4352 
GetOwnerNamenull4353 function TPkgAdditionalCompilerOptions.GetOwnerName: string;
4354 begin
4355   Result:=LazPackage.IDAsString;
4356 end;
4357 
GetBaseCompilerOptionsnull4358 function TPkgAdditionalCompilerOptions.GetBaseCompilerOptions: TBaseCompilerOptions;
4359 begin
4360   Result:=LazPackage.CompilerOptions;
4361 end;
4362 
4363 { TLazPackageDefineTemplates }
4364 
4365 constructor TLazPackageDefineTemplates.Create(AOwner: IProjPack);
4366 begin
4367   inherited Create(AOwner);
4368   Include(FFlags, ptfIsPackageTemplate);
4369   fLastSourceDirStamp:=LUInvalidChangeStamp;
4370 end;
4371 
4372 destructor TLazPackageDefineTemplates.Destroy;
4373 begin
4374   inherited Destroy;
4375 end;
4376 
4377 procedure TLazPackageDefineTemplates.ClearFlags;
4378 begin
4379   FFlags:=FFlags+[ptfIDChanged,ptfOutputDirChanged,ptfSourceDirsChanged,
4380                   ptfCustomDefinesChanged];
4381 end;
4382 
4383 procedure TLazPackageDefineTemplates.AllChanged(AActivating: boolean);
4384 begin
4385   IDChanged;
4386   if not AActivating then // Create the SrcDirIfDef for IDE add-ons
4387     UpdateSrcDirIfDef;    // (Will be called from other methods during activation)
4388   SourceDirectoriesChanged;
4389   OutputDirectoryChanged;
4390   CustomDefinesChanged;
4391 end;
4392 
4393 procedure TLazPackageDefineTemplates.UpdateMain;
4394 begin
4395   if (not Owner.NeedsDefineTemplates) or (not Active) then exit;
4396   // update the package block define template (the container for all other
4397   // define templates of the package)
4398   if FMain=nil then begin
4399     FMain:=CreatePackageTemplateWithID(Owner.IDAsWord);
4400     FMain.SetDefineOwner(Owner as TLazPackage,false);
4401     FMain.SetFlags([dtfAutoGenerated],[],false);
4402   end else
4403     FMain.Name:=Owner.IDAsWord;
4404   // ClearCache is here unnessary, because it is only a block
4405 end;
4406 
UpdateSrcDirIfDefnull4407 function TLazPackageDefineTemplates.UpdateSrcDirIfDef: Boolean;
4408 var
4409   NewVariable: String;
4410   UnitPathDefTempl: TDefineTemplate;
4411   IncPathDefTempl: TDefineTemplate;
4412 begin
4413   // create custom options
4414   // The custom options are enclosed by an IFDEF #PkgSrcMark<PckId> template.
4415   // Each source directory defines this variable, so that the settings can be
4416   // activated for each source directory by a simple DEFINE.
4417   if (FMain=nil) then UpdateMain;
4418   if FMain=nil then exit;
4419   if FSrcDirectories=nil then begin
4420     FSrcDirectories:=TDefineTemplate.Create('Source Directories',
4421       'Source Directories','','',
4422       da_Block);
4423     FMain.AddChild(FSrcDirectories);
4424   end;
4425   Result:=false;
4426   if FSrcDirIf=nil then begin
4427     FSrcDirIf:=TDefineTemplate.Create('Source Directory Additions',
4428       'Additional defines for package source directories',
4429       '#PkgSrcMark'+Owner.IDAsWord, '', da_IfDef);
4430     FMain.AddChild(FSrcDirIf);
4431 
4432     // create unit path template for this directory
4433     UnitPathDefTempl:=TDefineTemplate.Create('UnitPath', lisPkgDefsUnitPath,
4434       '#UnitPath','$(#UnitPath);$PkgUnitPath('+Owner.IDAsString+')',
4435       da_Define);
4436     FSrcDirIf.AddChild(UnitPathDefTempl);
4437     // create include path template for this directory
4438     IncPathDefTempl:=TDefineTemplate.Create('IncPath','Include Path',
4439       '#IncPath','$(#IncPath);$PkgIncPath('+Owner.IDAsString+')',
4440       da_Define);
4441     FSrcDirIf.AddChild(IncPathDefTempl);
4442     Result:=true;
4443   end else begin
4444     NewVariable:='#PkgSrcMark'+Owner.IDAsWord;
4445     if NewVariable<>FSrcDirIf.Variable then begin
4446       FSrcDirIf.Variable:=NewVariable;
4447       // unit path
4448       UnitPathDefTempl:=FSrcDirIf.FindChildByName('UnitPath');
4449       if UnitPathDefTempl<>nil then
4450         UnitPathDefTempl.Value:='$(#UnitPath);$PkgUnitPath('+Owner.IDAsString+')';
4451       // include path
4452       IncPathDefTempl:=FSrcDirIf.FindChildByName('IncPath');
4453       if IncPathDefTempl<>nil then
4454         IncPathDefTempl.Value:='$(#IncPath);$PkgIncPath('+Owner.IDAsString+')';
4455       Result:=true;
4456     end;
4457   end;
4458 end;
4459 
4460 procedure TLazPackageDefineTemplates.UpdateOutputDirectory;
4461 var
4462   LazPackage: TLazPackage;
4463 begin
4464   if FMain=nil then UpdateMain;
4465   if FMain=nil then exit;
4466 
4467   LazPackage := Owner as TLazPackage;
4468   if FOutputDir=nil then begin
4469     FOutputDir:=TDefineTemplate.Create(PkgOutputDirDefTemplName,
4470       lisPkgDefsOutputDirectory, '', LazPackage.GetOutputDirectory, da_Directory);
4471     FOutputDir.SetDefineOwner(LazPackage,false);
4472     FOutputDir.SetFlags([dtfAutoGenerated],[],false);
4473     DisableDefaultsInDirectories(FOutputDir,false);
4474     FMain.AddChild(FOutputDir);
4475   end else begin
4476     FOutputDir.Value:=LazPackage.GetOutputDirectory;
4477   end;
4478 
4479   if (FOutPutSrcPath=nil)
4480   or (fLastOutputDirSrcPathIDAsString<>Owner.IDAsString) then begin
4481     fLastOutputDirSrcPathIDAsString:=Owner.IDAsString;
4482     FOutputSrcPath:=TDefineTemplate.Create('CompiledSrcPath',
4483       lisPkgDefsCompiledSrcPathAddition, CompiledSrcPathMacroName,
4484       '$PkgSrcPath('+fLastOutputDirSrcPathIDAsString+');'+'$('+CompiledSrcPathMacroName+')',
4485       da_Define);
4486     FOutputSrcPath.SetDefineOwner(LazPackage,false);
4487     FOutputSrcPath.SetFlags([dtfAutoGenerated],[],false);
4488     CodeToolBoss.DefineTree.ReplaceChild(FOutputDir,FOutputSrcPath,FOutputSrcPath.Name);
4489   end;
4490 end;
4491 
4492 procedure TLazPackageDefineTemplates.UpdateSourceDirectories;
4493 var
4494   i: Integer;
4495   SrcDirDefTempl, SrcDirMarkDefTempl: TDefineTemplate;
4496   IDHasChanged: Boolean;
4497   CurUnitPath, SrcDirs: String;
4498 begin
4499   if (not Owner.NeedsDefineTemplates) or (not Active) then exit;
4500 
4501   // quick check if something has changed
4502   IDHasChanged:=fLastSourceDirsIDAsString<>Owner.IDAsString;
4503   CurUnitPath:=Owner.BaseCompilerOptions.ParsedOpts.GetParsedValue(pcosUnitPath);
4504   SrcDirs:=Owner.SourceDirectories.CreateSearchPathFromAllFiles;
4505   CurUnitPath:=TrimSearchPath(SrcDirs+';'+CurUnitPath+';.',
4506                               Owner.BaseCompilerOptions.BaseDirectory,true);
4507 
4508   if (fLastSourceDirectories<>nil)
4509   and (fLastSourceDirStamp=Owner.SourceDirectories.TimeStamp)
4510   and (not IDHasChanged)
4511   and (CurUnitPath=fLastUnitPath) then
4512     exit;
4513   //debugln(['TLazPackageDefineTemplates.UpdateSourceDirectories ',LazPackage.Name,' CurUnitPath=',CurUnitPath]);
4514   fLastSourceDirStamp:=Owner.SourceDirectories.TimeStamp;
4515   fLastSourceDirsIDAsString:=Owner.IDAsString;
4516   fLastUnitPath:=CurUnitPath;
4517 
4518   // clear old define templates
4519   if fLastSourceDirectories<>nil then begin
4520     for i:=0 to fLastSourceDirectories.Count-1 do begin
4521       SrcDirDefTempl:=TDefineTemplate(fLastSourceDirectories.Objects[i]);
4522       SrcDirDefTempl.Unbind;
4523       SrcDirDefTempl.Free;
4524     end;
4525     fLastSourceDirectories.Clear;
4526   end else
4527     fLastSourceDirectories:=TStringList.Create;
4528 
4529   // build source directory define templates
4530   FreeAndNil(fLastSourceDirectories);
4531   fLastSourceDirectories:=SearchPathToList(CurUnitPath);
4532   if (fLastSourceDirectories.Count>0) and ((FSrcDirIf=nil) or IDHasChanged) then
4533     UpdateSrcDirIfDef;
4534   for i:=0 to fLastSourceDirectories.Count-1 do begin
4535     // create directory template
4536     SrcDirDefTempl:=TDefineTemplate.Create('Source Directory '+IntToStr(i+1),
4537       fLastSourceDirectories[i],'',fLastSourceDirectories[i],da_Directory);
4538     DisableDefaultsInDirectories(SrcDirDefTempl,false);
4539     fLastSourceDirectories.Objects[i]:=SrcDirDefTempl;
4540     // add package source directory marker
4541     SrcDirMarkDefTempl:=TDefineTemplate.Create('PkgSrcDirMark',
4542       lisPkgDefsSrcDirMark,'#PkgSrcMark'+Owner.IDAsWord,'',da_Define);
4543     SrcDirDefTempl.AddChild(SrcDirMarkDefTempl);
4544 
4545     SrcDirDefTempl.SetDefineOwner(Owner as TLazPackage,false);
4546     SrcDirDefTempl.SetFlags([dtfAutoGenerated],[],false);
4547     // add directory
4548     FSrcDirectories.AddChild(SrcDirDefTempl);
4549   end;
4550   CodeToolBoss.DefineTree.ClearCache;
4551 end;
4552 
4553 procedure TLazPackageDefineTemplates.UpdateDefinesForCustomDefines;
4554 var
4555   OptionsDefTempl: TDefineTemplate;
4556   NewCustomOptions: String;
4557 begin
4558   if (not Owner.NeedsDefineTemplates) or (not Active) then exit;
4559 
4560   // check if something has changed
4561   NewCustomOptions:=Owner.BaseCompilerOptions.GetOptionsForCTDefines;
4562   if FLastCustomOptions=NewCustomOptions then exit;
4563 
4564   FLastCustomOptions:=NewCustomOptions;
4565   OptionsDefTempl:=CodeToolBoss.DefinePool.CreateFPCCommandLineDefines(
4566               'Custom Options', FLastCustomOptions, false, Owner as TLazPackage);
4567   if OptionsDefTempl=nil then begin
4568     // no custom options -> delete old template
4569     if (FSrcDirIf<>nil) and FSrcDirIf.DeleteChild('Custom Options') then
4570       CodeToolBoss.DefineTree.ClearCache;
4571   end else begin
4572     UpdateSrcDirIfDef;
4573     FSrcDirIf.ReplaceChild(OptionsDefTempl);
4574   end;
4575 end;
4576 
4577 { TBasePackageEditor }
4578 
GetLazPackagenull4579 function TBasePackageEditor.GetLazPackage: TLazPackage;
4580 begin
4581   Result:=nil;
4582 end;
4583 
4584 { TPublishPackageOptions }
4585 
4586 procedure TPublishPackageOptions.DoOnModifyChange;
4587 begin
4588   if Modified then
4589     TLazPackage(Owner).Modified:=true;
4590 end;
4591 
GetDefaultDestinationDirnull4592 function TPublishPackageOptions.GetDefaultDestinationDir: string;
4593 begin
4594   Result:='$(TestDir)/publishedpackage/';
4595 end;
4596 
4597 { TPkgPairTree }
4598 
4599 function ComparePkgPairs(Pair1, Pair2: Pointer): integer;
4600 begin
4601   Result:=TPkgPair(Pair1).Compare(TPkgPair(Pair2));
4602 end;
4603 
4604 constructor TPkgPairTree.Create;
4605 begin
4606   inherited Create(@ComparePkgPairs);
4607 end;
4608 
4609 destructor TPkgPairTree.Destroy;
4610 begin
4611   FreeAndClear;
4612   inherited Destroy;
4613 end;
4614 
FindPairnull4615 function TPkgPairTree.FindPair(Pkg1, Pkg2: TLazPackage; IgnoreOrder: boolean): TPkgPair;
4616 var
4617   Comp: integer;
4618   ANode: TAVLTreeNode;
4619 begin
4620   ANode:=Root;
4621   while (ANode<>nil) do begin
4622     Result:=TPkgPair(ANode.Data);
4623     Comp:=Result.ComparePair(Pkg1,Pkg2);
4624     if Comp=0 then exit;
4625     if Comp>0 then begin
4626       ANode:=ANode.Left
4627     end else begin
4628       ANode:=ANode.Right
4629     end;
4630   end;
4631   if IgnoreOrder and (Pkg1<>Pkg2) then
4632     Result:=FindPair(Pkg2,Pkg1,false)
4633   else
4634     Result:=nil;
4635 end;
4636 
AddPairnull4637 function TPkgPairTree.AddPair(Pkg1, Pkg2: TLazPackage): TPkgPair;
4638 begin
4639   Result:=TPkgPair.Create(Pkg1,Pkg2);
4640   Add(Result);
4641 end;
4642 
AddPairIfNotExistsnull4643 function TPkgPairTree.AddPairIfNotExists(Pkg1, Pkg2: TLazPackage): TPkgPair;
4644 begin
4645   Result:=FindPair(Pkg1,Pkg2,true);
4646   if Result=nil then
4647     Result:=AddPair(Pkg1,Pkg2);
4648 end;
4649 
4650 { TPkgPair }
4651 
4652 constructor TPkgPair.Create(Pkg1, Pkg2: TLazPackage);
4653 begin
4654   Package1:=Pkg1;
4655   Package2:=Pkg2;
4656 end;
4657 
ComparePairnull4658 function TPkgPair.ComparePair(Pkg1, Pkg2: TLazPackage): integer;
4659 begin
4660   Result:=Package1.Compare(Pkg1);
4661   if Result=0 then
4662     Result:=Package2.Compare(Pkg2);
4663 end;
4664 
Comparenull4665 function TPkgPair.Compare(PkgPair: TPkgPair): integer;
4666 begin
4667   Result:=ComparePair(PkgPair.Package1,PkgPair.Package2);
4668 end;
4669 
AsStringnull4670 function TPkgPair.AsString: string;
4671 begin
4672   Result:=Package1.IDAsString+' - '+Package2.IDAsString;
4673 end;
4674 
4675 { TPkgUnitsTree }
4676 
FindNodeWithUnitNamenull4677 function TPkgUnitsTree.FindNodeWithUnitName(const AUnitName: string): TAVLTreeNode;
4678 var
4679   Comp: integer;
4680   PkgFile: TPkgFile;
4681 begin
4682   Result:=Root;
4683   while (Result<>nil) do begin
4684     PkgFile:=TPkgFile(Result.Data);
4685     Comp:=SysUtils.CompareText(AUnitName,PkgFile.Unit_Name);
4686     if Comp=0 then exit;
4687     if Comp<0 then begin
4688       Result:=Result.Left
4689     end else begin
4690       Result:=Result.Right
4691     end;
4692   end;
4693 end;
4694 
FindPkgFileWithUnitNamenull4695 function TPkgUnitsTree.FindPkgFileWithUnitName(const AUnitName: string): TPkgFile;
4696 var
4697   ANode: TAVLTreeNode;
4698 begin
4699   ANode:=FindNodeWithUnitName(AUnitName);
4700   if ANode=nil then
4701     Result:=nil
4702   else
4703     Result:=TPkgFile(ANode.Data);
4704 end;
4705 
4706 function ComparePkgFilesUnitname(PkgFile1, PkgFile2: Pointer): integer;
4707 begin
4708   Result := SysUtils.CompareText(
4709               TPkgFile(PkgFile1).Unit_Name,
4710               TPkgFile(PkgFile2).Unit_Name);
4711 end;
4712 
4713 constructor TPkgUnitsTree.Create(ThePackage: TLazPackage);
4714 begin
4715   fLazPackage:=ThePackage;
4716   inherited Create(@ComparePkgFilesUnitname);
4717 end;
4718 
4719 initialization
4720   RegisterIDEOptionsGroup(GroupPackage, TPackageIDEOptions);
4721   RegisterIDEOptionsGroup(GroupPkgCompiler, TPkgCompilerOptions);
4722   PackageDependencies:=TAVLTree.Create(@ComparePkgDependencyNames);
4723 
4724 finalization
4725   FreeThenNil(PackageDependencies);
4726 
4727 end.
4728 
4729