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