{ *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** Author: Mattias Gaertner Abstract: This unit is a support unit for the code tools. It manages compilation information, which is not stored in the source, like Makefile information and compiler command line options. This information is needed to successfully find the right units, include files, predefined variables, etc.. The information is stored in a TDefineTree, which contains nodes of type TDefineTemplate. Each TDefineTemplate is a tree of defines, undefines, definerecurses, ifdefs, ifndefs, elses, elseifs, directories ... . Simply give a TDefineTree a directory and it will return all predefined variables for that directory. These values can be used to parse a unit in the directory. TDefineTree can be saved to and loaded from a XML file. The TDefinePool contains a list of TDefineTemplate trees, and can generate some default templates for Lazarus and FPC sources. } unit DefineTemplates; {$mode objfpc}{$H+} { $Define VerboseDefineCache} { $Define VerboseFPCSrcScan} { $Define ShowTriedFiles} { $Define ShowTriedUnits} interface uses // RTL + FCL Classes, SysUtils, contnrs, process, Laz_AVL_Tree, // CodeTools CodeToolsStrConsts, ExprEval, DirectoryCacher, BasicCodeTools, CodeToolsStructs, KeywordFuncLists, LinkScanner, FileProcs, // LazUtils LazStringUtils, LazFileUtils, FileUtil, LazFileCache, LazUTF8, UTF8Process, LazDbgLog, AvgLvlTree, Laz2_XMLCfg; const ExternalMacroStart = ExprEval.ExternalMacroStart; // Standard Template Names (do not translate them) StdDefTemplFPC = 'Free Pascal Compiler'; StdDefTemplFPCSrc = 'Free Pascal sources'; StdDefTemplLazarusSources = 'Lazarus sources'; StdDefTemplLazarusSrcDir = 'Lazarus source directory'; StdDefTemplLazarusBuildOpts = 'Lazarus build options'; StdDefTemplLCLProject = 'LCL project'; // Standard macros DefinePathMacroName = ExternalMacroStart+'DefinePath'; // the current directory UnitPathMacroName = ExternalMacroStart+'UnitPath'; // unit search path separated by semicolon (same as given to FPC) IncludePathMacroName = ExternalMacroStart+'IncPath'; // include file search path separated by semicolon (same as given to FPC) SrcPathMacroName = ExternalMacroStart+'SrcPath'; // unit source search path separated by semicolon (not given to FPC) PPUSrcPathMacroName = ExternalMacroStart+'PPUSrcPath'; DCUSrcPathMacroName = ExternalMacroStart+'DCUSrcPath'; CompiledSrcPathMacroName = ExternalMacroStart+'CompiledSrcPath'; UnitLinksMacroName = ExternalMacroStart+'UnitLinks'; UnitSetMacroName = ExternalMacroStart+'UnitSet'; FPCUnitPathMacroName = ExternalMacroStart+'FPCUnitPath'; TargetOSMacroName = ExternalMacroStart+'TargetOS'; TargetCPUMacroName = ExternalMacroStart+'TargetCPU'; NamespacesMacroName = ExternalMacroStart+'Namespaces'; DefinePathMacro = '$('+DefinePathMacroName+')'; // the path of the define template UnitPathMacro = '$('+UnitPathMacroName+')'; IncludePathMacro = '$('+IncludePathMacroName+')'; SrcPathMacro = '$('+SrcPathMacroName+')'; PPUSrcPathMacro = '$('+PPUSrcPathMacroName+')'; DCUSrcPathMacro = '$('+DCUSrcPathMacroName+')'; CompiledSrcPathMacro = '$('+CompiledSrcPathMacroName+')'; UnitLinksMacro = '$('+UnitLinksMacroName+')'; UnitSetMacro = '$('+UnitSetMacroName+')'; FPCUnitPathMacro = '$('+FPCUnitPathMacroName+')'; TargetOSMacro = '$('+TargetOSMacroName+')'; TargetCPUMacro = '$('+TargetCPUMacroName+')'; NamespacesMacro = '$('+NamespacesMacroName+')'; MacOSMinSDKVersionMacro = 'MAC_OS_X_VERSION_MIN_REQUIRED'; // virtual directories VirtualDirectory='VIRTUALDIRECTORY'; VirtualTempDir='TEMPORARYDIRECTORY'; // FPC operating systems and processor types FPCOperatingSystemNames: array[1..38] of shortstring =( 'linux', 'win32','win64','wince', 'darwin','macos', 'freebsd','netbsd','openbsd','dragonfly', 'aix', 'amiga', 'android', 'aros', 'atari', 'beos', 'embedded', 'emx', 'freertos', 'gba', 'go32v2', 'haiku', 'iphonesim', 'ios', 'java', 'msdos', 'morphos', 'nds', 'netware', 'netwlibc', 'os2', 'palmos', 'qnx', 'solaris', 'symbian', 'watcom', 'wdosx', 'wii' ); FPCOperatingSystemCaptions: array[1..38] of shortstring =( 'AIX', 'Amiga', 'Android', 'AROS', 'Atari', 'BeOS', 'Darwin', 'DragonFly', 'Embedded', 'emx', 'FreeBSD', 'FreeRTOS', 'GBA', 'Go32v2', 'Haiku', 'iPhoneSim', 'iOS', 'Java', 'Linux', 'MacOS', 'MorphOS', 'MSDOS', 'NDS', 'NetBSD', 'NetWare', 'NetwLibC', 'OpenBSD', 'OS2', 'PalmOS', 'QNX', 'Solaris', 'Symbian', 'Watcom', 'wdosx', 'Win32', 'Win64', 'WinCE', 'Wii' ); FPCOperatingSystemAlternativeNames: array[1..2] of shortstring =( 'unix', 'win' // see GetDefaultSrcOSForTargetOS ); FPCOperatingSystemAlternative2Names: array[1..2] of shortstring =( 'bsd', 'linux' // see GetDefaultSrcOS2ForTargetOS ); FPCProcessorNames: array[1..14] of shortstring =( 'aarch64', 'arm', 'avr', 'i386', 'i8086', 'jvm', 'm68k', 'mips', 'mipsel', 'powerpc', 'powerpc64', 'sparc', 'x86_64', 'xtensa' ); FPCSyntaxModes: array[1..6] of shortstring = ( 'FPC', 'ObjFPC', 'Delphi', 'TP', 'MacPas', 'ISO' ); Pas2jsPlatformNames: array[1..2] of shortstring = ( 'Browser', 'NodeJS' ); Pas2jsProcessorNames: array[1..2] of shortstring = ( 'ECMAScript5', 'ECMAScript6' ); Lazarus_CPU_OS_Widget_Combinations: array[1..106] of shortstring = ( 'i386-linux-gtk', 'i386-linux-gtk2', 'i386-linux-qt', 'i386-linux-qt5', 'i386-linux-fpgui', 'i386-linux-nogui', 'i386-freebsd-gtk', 'i386-freebsd-gtk2', 'i386-freebsd-qt', 'i386-freebsd-qt5', 'i386-freebsd-nogui', 'i386-openbsd-gtk', 'i386-openbsd-gtk2', 'i386-openbsd-qt', 'i386-openbsd-qt5', 'i386-openbsd-nogui', 'i386-netbsd-gtk', 'i386-netbsd-gtk2', 'i386-netbsd-qt', 'i386-netbsd-qt5', 'i386-netbsd-nogui', 'i386-win32-win32', 'i386-win32-gtk2', 'i386-win32-qt', 'i386-win32-qt5', 'i386-win32-fpgui', 'i386-win32-nogui', 'i386-wince-wince', 'i386-wince-fpgui', 'i386-wince-nogui', 'i386-darwin-gtk', 'i386-darwin-gtk2', 'i386-darwin-carbon', 'i386-darwin-qt', 'i386-darwin-qt5', 'i386-darwin-fpgui', 'i386-darwin-nogui', 'i386-haiku-qt', 'i386-haiku-qt5', 'i386-haiku-nogui', 'i386-aros-mui', 'i386-aros-nogui', 'powerpc-darwin-gtk', 'powerpc-darwin-gtk2', 'powerpc-darwin-carbon', 'powerpc-linux-gtk', 'powerpc-linux-gtk2', 'powerpc-linux-nogui', 'powerpc-morphos-mui', 'powerpc-morphos-nogui', 'powerpc64-darwin-gtk', 'powerpc64-darwin-gtk2', 'powerpc64-darwin-cocoa', 'powerpc64-darwin-nogui', 'powerpc64-linux-gtk', 'powerpc64-linux-gtk2', 'powerpc64-linux-nogui', 'powerpc64-aix-gtk', 'powerpc64-aix-gtk2', 'powerpc64-aix-nogui', 'sparc-linux-gtk', 'sparc-linux-gtk2', 'sparc-linux-nogui', 'arm-wince-wince', 'arm-wince-fpgui', 'arm-wince-nogui', 'arm-linux-gtk', 'arm-linux-gtk2', 'arm-linux-qt', 'arm-linux-qt5', 'arm-linux-android', 'arm-linux-nogui', 'arm-darwin-carbon', 'arm-darwin-nogui', 'x86_64-freebsd-gtk', 'x86_64-freebsd-gtk2', 'x86_64-freebsd-qt', 'x86_64-freebsd-qt5', 'x86_64-freebsd-fpgui', 'x86_64-freebsd-nogui', 'x86_64-openbsd-gtk2', 'x86_64-openbsd-qt', 'x86_64-openbsd-qt5', 'x86_64-openbsd-fpgui', 'x86_64-openbsd-nogui', 'x86_64-netbsd-gtk2', 'x86_64-netbsd-qt', 'x86_64-netbsd-qt5', 'x86_64-netbsd-fpgui', 'x86_64-netbsd-nogui', 'x86_64-dragonfly-gtk2', 'x86_64-dragonfly-qt', 'x86_64-dragonfly-qt5', 'x86_64-dragonfly-fpgui', 'x86_64-dragonfly-nogui', 'x86_64-linux-gtk', 'x86_64-linux-gtk2', 'x86_64-linux-qt', 'x86_64-linux-qt5', 'x86_64-linux-fpgui', 'x86_64-linux-nogui', 'x86_64-win64-win32', 'x86_64-win64-fpgui', 'x86_64-win64-nogui', 'm68k-amiga-mui', 'm68k-amiga-nogui' ); type //--------------------------------------------------------------------------- // TDefineTemplate stores a define action, the variablename and the value TDefineAction = ( da_None, da_Block, da_Define, da_DefineRecurse, da_Undefine, da_UndefineRecurse, da_UndefineAll, da_If, da_IfDef, da_IfNDef, da_ElseIf, da_Else, da_Directory ); const DefineActionBlocks = [da_Block, da_Directory, da_If, da_IfDef, da_IfNDef, da_ElseIf, da_Else]; DefineActionDefines = [da_Define,da_DefineRecurse,da_Undefine, da_UndefineRecurse,da_UndefineAll]; DefineActionNames: array[TDefineAction] of string = ( 'None', 'Block', 'Define', 'DefineRecurse', 'Undefine', 'UndefineRecurse', 'UndefineAll', 'If', 'IfDef', 'IfNDef', 'ElseIf', 'Else', 'Directory' ); var DefineActionImages: array[TDefineAction] of integer; AutogeneratedImage: Integer; type TDefineTree = class; TDefineTemplateFlag = ( dtfAutoGenerated ); TDefineTemplateFlags = set of TDefineTemplateFlag; TDefineTemplate = class private FChildCount: integer; FFirstChild: TDefineTemplate; FLastChild: TDefineTemplate; FMarked: boolean; FMergeNameBehind: string; FMergeNameInFront: string; FNext: TDefineTemplate; FParent: TDefineTemplate; FPrior: TDefineTemplate; public Name: string; Description: string; Variable: string; Value: string; Action: TDefineAction; Flags: TDefineTemplateFlags; Owner: TObject; class procedure MergeTemplates(ParentDefTempl: TDefineTemplate; var FirstSibling, LastSibling:TDefineTemplate; SourceTemplate: TDefineTemplate; WithSiblings: boolean; const NewNamePrefix: string); class procedure MergeXMLConfig(ParentDefTempl: TDefineTemplate; var FirstSibling, LastSibling:TDefineTemplate; XMLConfig: TXMLConfig; const Path, NewNamePrefix: string); constructor Create(const AName, ADescription, AVariable, AValue: string; AnAction: TDefineAction); constructor Create; destructor Destroy; override; procedure ConsistencyCheck; procedure CalcMemSize(Stats: TCTMemStats); function CreateCopy(OnlyMarked: boolean = false; WithSiblings: boolean = true; WithChilds: boolean = true): TDefineTemplate; function CreateMergeCopy: TDefineTemplate; function FindByName(const AName: string; WithSubChilds, WithNextSiblings: boolean): TDefineTemplate; function FindChildByName(const AName: string): TDefineTemplate; function FindRoot: TDefineTemplate; function FindUniqueName(const Prefix: string): string; function GetFirstSibling: TDefineTemplate; function HasDefines(OnlyMarked, WithSiblings: boolean): boolean; function IsAutoGenerated: boolean; function IsEqual(ADefineTemplate: TDefineTemplate; CheckSubNodes, CheckNextSiblings: boolean): boolean; function Level: integer; function LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string; ClearOldSiblings, WithMergeInfo: boolean): boolean; function SelfOrParentContainsFlag(AFlag: TDefineTemplateFlag): boolean; procedure AddChild(ADefineTemplate: TDefineTemplate); procedure ReplaceChild(ADefineTemplate: TDefineTemplate); function DeleteChild(const AName: string): boolean; procedure Assign(ADefineTemplate: TDefineTemplate; WithSubNodes, WithNextSiblings, ClearOldSiblings: boolean); virtual; procedure AssignValues(ADefineTemplate: TDefineTemplate); procedure Clear(WithSiblings: boolean); procedure CreateMergeInfo(WithSiblings, OnlyMarked: boolean); procedure InheritMarks(WithSiblings, WithChilds, Down, Up: boolean); procedure InsertBehind(APrior: TDefineTemplate); procedure InsertInFront(ANext: TDefineTemplate); procedure MoveToLast(Child: TDefineTemplate); procedure LoadValuesFromXMLConfig(XMLConfig: TXMLConfig; const Path: string; WithMergeInfo: boolean); procedure MarkFlags(const MustFlags, NotFlags: TDefineTemplateFlags; WithSiblings, WithChilds: boolean); procedure MarkNodes(WithSiblings, WithChilds: boolean); procedure MarkOwnedBy(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags; WithSiblings, WithChilds: boolean); procedure RemoveFlags(TheFlags: TDefineTemplateFlags); procedure RemoveLeaves(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags; WithSiblings: boolean; var FirstDefTemplate: TDefineTemplate); procedure RemoveMarked(WithSiblings: boolean; var FirstDefTemplate: TDefineTemplate); procedure RemoveOwner(TheOwner: TObject; WithSiblings: boolean); procedure ReverseMarks(WithSiblings, WithChilds: boolean); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string; WithSiblings, OnlyMarked, WithMergeInfo, UpdateMergeInfo: boolean); procedure SaveValuesToXMLConfig(XMLConfig: TXMLConfig; const Path: string; WithMergeInfo: boolean); procedure SetDefineOwner(NewOwner: TObject; WithSiblings: boolean); procedure SetFlags(AddFlags, SubFlags: TDefineTemplateFlags; WithSiblings: boolean); procedure Unbind; procedure UnmarkNodes(WithSiblings, WithChilds: boolean); procedure WriteDebugReport(OnlyMarked: boolean); function GetNext: TDefineTemplate; function GetNextSkipChildren: TDefineTemplate; public property ChildCount: integer read FChildCount; property FirstChild: TDefineTemplate read FFirstChild; property LastChild: TDefineTemplate read FLastChild; property Marked: boolean read FMarked write FMarked; property Next: TDefineTemplate read FNext; property Parent: TDefineTemplate read FParent; property Prior: TDefineTemplate read FPrior; property MergeNameInFront: string read FMergeNameInFront write FMergeNameInFront; property MergeNameBehind: string read FMergeNameBehind write FMergeNameBehind; end; //--------------------------------------------------------------------------- // { TDirectoryDefines } TDirectoryDefines = class public Path: string; Values: TExpressionEvaluator; constructor Create; destructor Destroy; override; procedure CalcMemSize(Stats: TCTMemStats); end; TOnGetVirtualDirectoryDefines = procedure(Sender: TDefineTree; Defines: TDirectoryDefines) of object; //--------------------------------------------------------------------------- // TDefineTree caches the define values for directories TOnReadValue = procedure(Sender: TObject; const VariableName: string; var Value: string; var Handled: boolean) of object; TOnGetVirtualDirectoryAlias = procedure(Sender: TObject; var RealDir: string) of object; TReadFunctionData = record Param: string; Result: string; end; PReadFunctionData = ^TReadFunctionData; TDefTreeCalculate = procedure(Tree: TDefineTree; Node: TDefineTemplate; ValueParsed: boolean; const ParsedValue: string; ExpressionCalculated: boolean; const ExpressionResult: string; Execute: boolean) of object; TDefineTree = class private FDirectoryCachePool: TCTDirectoryCachePool; FFirstDefineTemplate: TDefineTemplate; FCache: TAVLTree; // tree of TDirectoryDefines FDefineStrings: TStringTree; FChangeStep: integer; FErrorDescription: string; FErrorTemplate: TDefineTemplate; FMacroFunctions: TKeyWordFunctionList; FMacroVariables: TKeyWordFunctionList; FOnCalculate: TDefTreeCalculate; FOnGetVirtualDirectoryAlias: TOnGetVirtualDirectoryAlias; FOnGetVirtualDirectoryDefines: TOnGetVirtualDirectoryDefines; FOnPrepareTree: TNotifyEvent; FOnReadValue: TOnReadValue; FVirtualDirCache: TDirectoryDefines; // Used by Calculate. FExpandedDirectory: string; FDirDef: TDirectoryDefines; function Calculate(DirDef: TDirectoryDefines): boolean; procedure CalculateTemplate(DefTempl: TDefineTemplate; const CurPath: string); procedure IncreaseChangeStep; procedure SetDirectoryCachePool(const AValue: TCTDirectoryCachePool); procedure RemoveDoubles(Defines: TDirectoryDefines); protected function FindDirectoryInCache(const Path: string): TDirectoryDefines; function GetDirDefinesForDirectory(const Path: string; WithVirtualDir: boolean): TDirectoryDefines; function GetDirDefinesForVirtualDirectory: TDirectoryDefines; function MacroFuncExtractFileExt(Data: Pointer): boolean; function MacroFuncExtractFilePath(Data: Pointer): boolean; function MacroFuncExtractFileName(Data: Pointer): boolean; function MacroFuncExtractFileNameOnly(Data: Pointer): boolean; procedure DoClearCache; procedure DoPrepareTree; public property RootTemplate: TDefineTemplate read FFirstDefineTemplate write FFirstDefineTemplate; property ChangeStep: integer read FChangeStep; property ErrorTemplate: TDefineTemplate read FErrorTemplate; property ErrorDescription: string read FErrorDescription; property OnGetVirtualDirectoryAlias: TOnGetVirtualDirectoryAlias read FOnGetVirtualDirectoryAlias write FOnGetVirtualDirectoryAlias; property OnGetVirtualDirectoryDefines: TOnGetVirtualDirectoryDefines read FOnGetVirtualDirectoryDefines write FOnGetVirtualDirectoryDefines; property OnReadValue: TOnReadValue read FOnReadValue write FOnReadValue; property OnPrepareTree: TNotifyEvent read FOnPrepareTree write FOnPrepareTree; property OnCalculate: TDefTreeCalculate read FOnCalculate write FOnCalculate; property MacroFunctions: TKeyWordFunctionList read FMacroFunctions; property MacroVariables: TKeyWordFunctionList read FMacroVariables; public constructor Create; destructor Destroy; override; procedure ConsistencyCheck; procedure CalcMemSize(Stats: TCTMemStats); function ExtractNonAutoCreated: TDefineTemplate; function ExtractTemplatesOwnedBy(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags): TDefineTemplate; function FindDefineTemplateByName(const AName: string; OnlyRoots: boolean): TDefineTemplate; function GetCompiledSrcPathForDirectory(const Directory: string): string; function GetDCUSrcPathForDirectory(const Directory: string): string; function GetDefinesForDirectory(const Path: string; WithVirtualDir: boolean): TExpressionEvaluator; function GetDefinesForVirtualDirectory: TExpressionEvaluator; function GetIncludePathForDirectory(const Directory: string): string; function GetLastRootTemplate: TDefineTemplate; function GetPPUSrcPathForDirectory(const Directory: string): string; function GetSrcPathForDirectory(const Directory: string): string; function GetUnitPathForDirectory(const Directory: string): string; function IsEqual(SrcDefineTree: TDefineTree): boolean; procedure Add(ADefineTemplate: TDefineTemplate); procedure AddChild(ParentTemplate, NewDefineTemplate: TDefineTemplate); procedure AddFirst(ADefineTemplate: TDefineTemplate); procedure MoveToLast(ADefineTemplate: TDefineTemplate); procedure Assign(SrcDefineTree: TDefineTree); procedure AssignNonAutoCreated(SrcDefineTree: TDefineTree); procedure Clear; procedure ClearCache; procedure MarkNonAutoCreated; procedure MarkTemplatesOwnedBy(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags); procedure MergeDefineTemplates(SourceTemplate: TDefineTemplate; const NewNamePrefix: string); procedure MergeTemplates(SourceTemplate: TDefineTemplate; const NewNamePrefix: string); procedure ReadValue(const DirDef: TDirectoryDefines; const PreValue, CurDefinePath: string; out NewValue: string); procedure RemoveDefineTemplate(ADefTempl: TDefineTemplate); procedure RemoveMarked; procedure RemoveRootDefineTemplateByName(const AName: string); procedure RemoveTemplatesOwnedBy(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags); procedure ReplaceChild(ParentTemplate, NewDefineTemplate: TDefineTemplate; const ChildName: string); procedure ReplaceRootSameName(ADefineTemplate: TDefineTemplate); procedure ReplaceRootSameName(const Name: string; ADefineTemplate: TDefineTemplate); procedure ReplaceRootSameNameAddFirst(ADefineTemplate: TDefineTemplate); procedure WriteDebugReport; property DirectoryCachePool: TCTDirectoryCachePool read FDirectoryCachePool write SetDirectoryCachePool; end; //--------------------------------------------------------------------------- { TDefinePool } TDefinePoolProgress = procedure(Sender: TObject; Index, MaxIndex: integer; // MaxIndex=-1 if unknown const Msg: string; var Abort: boolean) of object; TDefinePool = class private FEnglishErrorMsgFilename: string; FItems: TFPList; // list of TDefineTemplate; FOnProgress: TDefinePoolProgress; function GetItems(Index: integer): TDefineTemplate; procedure SetEnglishErrorMsgFilename(const AValue: string); function CheckAbort(ProgressID, MaxIndex: integer; const Msg: string ): boolean; public property Items[Index: integer]: TDefineTemplate read GetItems; default; function Count: integer; procedure Add(ADefineTemplate: TDefineTemplate); procedure Insert(Index: integer; ADefineTemplate: TDefineTemplate); procedure Delete(Index: integer); procedure Move(SrcIndex, DestIndex: integer); property EnglishErrorMsgFilename: string read FEnglishErrorMsgFilename write SetEnglishErrorMsgFilename; // FPC templates function CreateFPCTemplate(const CompilerPath, CompilerOptions, TestPascalFile: string; out UnitSearchPath, TargetOS, aTargetCPU: string; Owner: TObject): TDefineTemplate; function GetFPCVerFromFPCTemplate(Template: TDefineTemplate; out FPCVersion, FPCRelease, FPCPatch: integer): boolean; function CreateFPCCommandLineDefines(const Name, CmdLine: string; RecursiveDefines: boolean; Owner: TObject; AlwaysCreate: boolean = false; AddPaths: boolean = false ): TDefineTemplate; // Lazarus templates function CreateLazarusSrcTemplate( const LazarusSrcDir, WidgetType, ExtraOptions: string; Owner: TObject): TDefineTemplate; function CreateLCLProjectTemplate(const LazarusSrcDir, WidgetType, ProjectDir: string; Owner: TObject): TDefineTemplate; // Delphi templates function CreateDelphiSrcPath(DelphiVersion: integer; const PathPrefix: string): string; function CreateDelphiCompilerDefinesTemplate(DelphiVersion: integer; Owner: TObject): TDefineTemplate; function CreateDelphiDirectoryTemplate(const DelphiDirectory: string; DelphiVersion: integer; Owner: TObject): TDefineTemplate; function CreateDelphiProjectTemplate(const ProjectDir, DelphiDirectory: string; DelphiVersion: integer; Owner: TObject): TDefineTemplate; // Kylix templates function CreateKylixCompilerDefinesTemplate(KylixVersion: integer; Owner: TObject): TDefineTemplate; function CreateKylixSrcPath({%H-}KylixVersion: integer; const PathPrefix: string): string; function CreateKylixDirectoryTemplate(const KylixDirectory: string; KylixVersion: integer; Owner: TObject): TDefineTemplate; function CreateKylixProjectTemplate(const ProjectDir, KylixDirectory: string; KylixVersion: integer; Owner: TObject): TDefineTemplate; constructor Create; destructor Destroy; override; procedure Clear; property OnProgress: TDefinePoolProgress read FOnProgress write FOnProgress; procedure ConsistencyCheck; procedure WriteDebugReport; procedure CalcMemSize(Stats: TCTMemStats); end; { TFPCSourceRule } TFPCSourceRule = class public Filename: string; Score: integer; Targets: string; // comma separated list of OS, CPU, e.g. win32,unix,i386 or * for all function FitsTargets(const FilterTargets: string): boolean; function FitsFilename(const aFilename: string): boolean; function IsEqual(Rule: TFPCSourceRule): boolean; procedure Assign(Rule: TFPCSourceRule); end; { TFPCSourceRules } TFPCSourceRules = class private FChangeStamp: integer; FItems: TFPList;// list of TFPCSourceRule FScore: integer; FTargets: string; function GetItems(Index: integer): TFPCSourceRule; procedure SetTargets(const AValue: string); public constructor Create; destructor Destroy; override; procedure Clear; function IsEqual(Rules: TFPCSourceRules): boolean; procedure Assign(Rules: TFPCSourceRules); function Clone: TFPCSourceRules; property Items[Index: integer]: TFPCSourceRule read GetItems; default; function Count: integer; function Add(const Filename: string): TFPCSourceRule; function GetDefaultTargets(TargetOS, TargetCPU: string): string; procedure GetRulesForTargets(Targets: string; var RulesSortedForFilenameStart: TAVLTree); function GetScore(Filename: string; RulesSortedForFilenameStart: TAVLTree): integer; property Score: integer read FScore write FScore; // used for Add property Targets: string read FTargets write SetTargets; // used for Add, e.g. win32,unix,bsd or * for all property ChangeStamp: integer read FChangeStamp; procedure IncreaseChangeStamp; end; var DefaultFPCSourceRules: TFPCSourceRules; const DefineTemplateFlagNames: array[TDefineTemplateFlag] of shortstring = ( 'AutoGenerated' ); type TFPCInfoType = ( fpciCompilerDate, // -iD Return compiler date fpciShortVersion, // -iV Return short compiler version fpciFullVersion, // -iW Return full compiler version fpciCompilerOS, // -iSO Return compiler OS fpciCompilerProcessor, // -iSP Return compiler host processor fpciTargetOS, // -iTO Return target OS fpciTargetProcessor // -iTP Return target processor ); TFPCInfoTypes = set of TFPCInfoType; TFPCInfoStrings = array[TFPCInfoType] of string; const fpciAll = [low(TFPCInfoType)..high(TFPCInfoType)]; type { TPCConfigFileState Stores if a config file exists and its modification date } TPCConfigFileState = class public Filename: string; FileExists: boolean; FileDate: longint; constructor Create(const aFilename: string; aFileExists: boolean; aFileDate: longint); function Equals(Other: TPCConfigFileState; CheckDate: boolean): boolean; reintroduce; procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); end; TFPCConfigFileState = TPCConfigFileState deprecated 'use TPCConfigFileState'; // Laz 1.9 { TPCConfigFileStateList list of TPCConfigFileState } TPCConfigFileStateList = class private fItems: TFPList; function GetItems(Index: integer): TPCConfigFileState; public constructor Create; destructor Destroy; override; procedure Clear; procedure Assign(List: TPCConfigFileStateList); function Equals(List: TPCConfigFileStateList; CheckDates: boolean): boolean; reintroduce; function Add(aFilename: string; aFileExists: boolean; aFileDate: longint): TPCConfigFileState; function Count: integer; property Items[Index: integer]: TPCConfigFileState read GetItems; default; procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); end; TFPCConfigFileStateList = TPCConfigFileStateList deprecated 'use TPCConfigFileStateList'; // Laz 1.9 { TPCFPMFileState Stores information about a fppkg .fpm file } TPCFPMFileState = class public Name: string; FPMFilename: string; FileDate: longint; SourcePath: string; UnitToSrc: TStringToStringTree; // case insensitive unit name to source file constructor Create; destructor Destroy; override; procedure Clear; procedure Assign(List: TPCFPMFileState); function Equals(List: TPCFPMFileState; CheckDates: boolean): boolean; reintroduce; procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); end; TPCTargetConfigCaches = class; { TPCTargetConfigCache Storing all information (macros, search paths) of one compiler with one specific TargetOS and TargetCPU. } TPCTargetConfigCache = class(TComponent) private FChangeStamp: integer; public // key TargetOS: string; // will be passed lowercase TargetCPU: string; // will be passed lowercase Compiler: string; // full file name CompilerOptions: string; // e.g. -V -Xp // values Kind: TPascalCompiler; CompilerDate: longint; RealCompiler: string; // when Compiler is fpc.exe, this is the real compiler (e.g. ppc386.exe) RealCompilerDate: longint; RealTargetOS: string; RealTargetCPU: string; RealTargetCPUCompiler: string; // the ppc.exe in PATH for TargetCPU FullVersion: string; // Version.Release.Patch ConfigFiles: TPCConfigFileStateList; UnitPaths: TStrings; IncludePaths: TStrings; UnitScopes: TStrings; Defines: TStringToStringTree; // macro to value Undefines: TStringToStringTree; // macro Units: TStringToStringTree; // unit name to file name Includes: TStringToStringTree; // inc name to file name UnitToFPM: TStringToPointerTree; // unitname to TPCFPMFileState FPMNameToFPM: TStringToPointerTree; // fpm name to TPCFPMFileState ErrorMsg: string; ErrorTranslatedMsg: string; Caches: TPCTargetConfigCaches; HasPPUs: boolean; constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Clear; // values, not keys function Equals(Item: TPCTargetConfigCache; CompareKey: boolean = true): boolean; reintroduce; procedure Assign(Source: TPersistent); override; procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure LoadFromFile(Filename: string); procedure SaveToFile(Filename: string); function NeedsUpdate: boolean; function GetFPCInfoCmdLineOptions(ExtraOptions: string): string; function Update(TestFilename: string; ExtraOptions: string = ''; const OnProgress: TDefinePoolProgress = nil): boolean; function FindDefaultTargetCPUCompiler(aTargetCPU: string; ResolveLinks: boolean): string; function GetUnitPaths: string; function GetFPCVerNumbers(out FPCVersion, FPCRelease, FPCPatch: integer): boolean; function GetFPCVer: string; // e.g. 2.7.1 function GetFPC_FULLVERSION: integer; // e.g. 20701 function IndexOfUsedCfgFile: integer; procedure IncreaseChangeStamp; property ChangeStamp: integer read FChangeStamp; end; { TPCTargetConfigCaches List of TPCTargetConfigCache } TPCTargetConfigCaches = class(TComponent) private FChangeStamp: integer; FExtraOptions: string; fItems: TAVLTree; // tree of TPCTargetConfigCache FTestFilename: string; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Clear; function Equals(Caches: TPCTargetConfigCaches): boolean; reintroduce; procedure Assign(Source: TPersistent); override; procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure LoadFromFile(Filename: string); procedure SaveToFile(Filename: string); procedure IncreaseChangeStamp; property ChangeStamp: integer read FChangeStamp; function Find(CompilerFilename, CompilerOptions, TargetOS, TargetCPU: string; CreateIfNotExists: boolean): TPCTargetConfigCache; procedure GetDefaultCompilerTarget(const CompilerFilename,CompilerOptions: string; out TargetOS, TargetCPU: string); function GetListing: string; property TestFilename: string read FTestFilename write FTestFilename; // an empty file to test the compiler, will be auto created property ExtraOptions: string read FExtraOptions write FExtraOptions; // additional compiler options not used as key, e.g. -Fr end; TFPCSourceCaches = class; { TFPCSourceCache All source files of one FPC source directory } TFPCSourceCache = class(TComponent) private FChangeStamp: integer; public Directory: string; Valid: boolean; Files: TStringList; Caches: TFPCSourceCaches; constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Clear; procedure Assign(Source: TPersistent); override; function Equals(Cache: TFPCSourceCache): boolean; reintroduce; procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure LoadFromFile(Filename: string); procedure SaveToFile(Filename: string); procedure Update(const OnProgress: TDefinePoolProgress = nil); procedure Update(var NewFiles: TStringList); // NewFiles is used for Files! do not free NewFiles procedure IncreaseChangeStamp; property ChangeStamp: integer read FChangeStamp; end; { TFPCSourceCaches } TFPCSourceCaches = class(TComponent) private FChangeStamp: integer; fItems: TAVLTree; // tree of TFPCSourceCacheItem public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Clear; procedure Assign(Source: TPersistent); override; function Equals(Caches: TFPCSourceCaches): boolean; reintroduce; procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure LoadFromFile(Filename: string); procedure SaveToFile(Filename: string); procedure IncreaseChangeStamp; property ChangeStamp: integer read FChangeStamp; function Find(Directory: string; CreateIfNotExists: boolean): TFPCSourceCache; end; TCompilerDefinesCache = class; TFPCUnitToSrcCacheFlag = ( fuscfSrcRulesNeedUpdate, fuscfUnitTreeNeedsUpdate ); TFPCUnitToSrcCacheFlags = set of TFPCUnitToSrcCacheFlag; { TFPCUnitSetCache Unit name to FPC source file. Specific to one compiler, compileroptions, targetos, targetcpu and FPC source directory. } TFPCUnitSetCache = class(TComponent) private FCaches: TCompilerDefinesCache; FChangeStamp: integer; FCompilerFilename: string; FCompilerOptions: string; FFPCSourceDirectory: string; FTargetCPU: string; FTargetOS: string; FConfigCache: TPCTargetConfigCache; fSourceCache: TFPCSourceCache; fSourceRules: TFPCSourceRules; fRulesStampOfConfig: integer; // fSourceCache.ChangeStamp while creation of fFPCSourceRules fUnitToSourceTree: TStringToStringTree; // unit name to file name (maybe relative) fUnitStampOfFPC: integer; // FConfigCache.ChangeStamp at creation of fUnitToSourceTree fUnitStampOfFiles: integer; // fSourceCache.ChangeStamp at creation of fUnitToSourceTree fUnitStampOfRules: integer; // fSourceRules.ChangeStamp at creation of fUnitToSourceTree fSrcDuplicates: TStringToStringTree; // unit to list of files (semicolon separated) fFlags: TFPCUnitToSrcCacheFlags; procedure SetCompilerFilename(const AValue: string); procedure SetCompilerOptions(const AValue: string); procedure SetFPCSourceDirectory(const AValue: string); procedure SetTargetCPU(const AValue: string); procedure SetTargetOS(const AValue: string); procedure ClearConfigCache; procedure ClearSourceCache; protected procedure Notification(AComponent: TComponent; Operation: TOperation); override; public constructor Create(TheOwner: TComponent); override; destructor Destroy; override; procedure Clear; procedure Init; property Caches: TCompilerDefinesCache read FCaches; property CompilerFilename: string read FCompilerFilename write SetCompilerFilename; property CompilerOptions: string read FCompilerOptions write SetCompilerOptions; property TargetOS: string read FTargetOS write SetTargetOS; // case insensitive, will be passed lowercase property TargetCPU: string read FTargetCPU write SetTargetCPU; // case insensitive, will be passed lowercase property FPCSourceDirectory: string read FFPCSourceDirectory write SetFPCSourceDirectory; function GetConfigCache(AutoUpdate: boolean): TPCTargetConfigCache; function GetSourceCache(AutoUpdate: boolean): TFPCSourceCache; function GetSourceRules(AutoUpdate: boolean): TFPCSourceRules; function GetUnitToSourceTree(AutoUpdate: boolean): TStringToStringTree; // unit name to file name (maybe relative) function GetSourceDuplicates(AutoUpdate: boolean): TStringToStringTree; // unit to semicolon separated list of files function GetUnitSrcFile(const AnUnitName: string; SrcSearchRequiresPPU: boolean = true; SkipPPUCheckIfTargetIsSourceOnly: boolean = true): string; function GetCompiledUnitFile(const AUnitName: string): string; property ChangeStamp: integer read FChangeStamp; class function GetInvalidChangeStamp: integer; procedure IncreaseChangeStamp; function GetUnitSetID: string; function GetFirstFPCCfg: string; function GetUnitScopes: string; function GetCompilerKind: TPascalCompiler; end; { TCompilerDefinesCache } TCompilerDefinesCache = class(TComponent) private FConfigCaches: TPCTargetConfigCaches; FConfigCachesSaveStamp: integer; FSourceCaches: TFPCSourceCaches; FSourceCachesSaveStamp: integer; fUnitToSrcCaches: TFPList; // list of TFPCUnitSetCache function GetExtraOptions: string; function GetTestFilename: string; procedure SetConfigCaches(const AValue: TPCTargetConfigCaches); procedure SetExtraOptions(AValue: string); procedure SetSourceCaches(const AValue: TFPCSourceCaches); procedure ClearUnitToSrcCaches; procedure SetTestFilename(AValue: string); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Clear; procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure LoadFromFile(Filename: string); procedure SaveToFile(Filename: string); function NeedsSave: boolean; property SourceCaches: TFPCSourceCaches read FSourceCaches write SetSourceCaches; property ConfigCaches: TPCTargetConfigCaches read FConfigCaches write SetConfigCaches; property TestFilename: string read GetTestFilename write SetTestFilename; // an empty file to test the compiler, will be auto created property ExtraOptions: string read GetExtraOptions write SetExtraOptions; // additional compiler options not used as key, e.g. -Fr function GetFPCVersion(const CompilerFilename, TargetOS, TargetCPU: string; UseCompiledVersionAsDefault: boolean): string; deprecated 'use GetPCVersion'; // 2.0.1 function GetPCVersion(const CompilerFilename, TargetOS, TargetCPU: string; UseCompiledVersionAsDefault: boolean; out Kind: TPascalCompiler): string; function FindUnitSet(const CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir: string; CreateIfNotExists: boolean): TFPCUnitSetCache; function FindUnitSetWithID(const UnitSetID: string; out Changed: boolean; CreateIfNotExists: boolean): TFPCUnitSetCache; function GetUnitSetID(CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir: string; ChangeStamp: integer): string; procedure ParseUnitSetID(const ID: string; out CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir: string; out ChangeStamp: integer); end; TFPCDefinesCache = TCompilerDefinesCache deprecated 'use TCompilerDefinesCache'; // 1.9 function DefineActionNameToAction(const s: string): TDefineAction; function DefineTemplateFlagsToString(Flags: TDefineTemplateFlags): string; function GetDefaultSrcOSForTargetOS(const TargetOS: string): string; function GetDefaultSrcOS2ForTargetOS(const TargetOS: string): string; function GetDefaultSrcCPUForTargetCPU(const TargetCPU: string): string; procedure SplitLazarusCPUOSWidgetCombo(const Combination: string; out CPU, OS, WidgetSet: string); function GetCompiledFPCVersion: integer; function GetCompiledTargetOS: string; function GetCompiledTargetCPU: string; function GetDefaultCompilerFilename(const TargetCPU: string = ''; Cross: boolean = false): string; procedure GetTargetProcessors(const TargetCPU: string; aList: TStrings); function GetFPCTargetOS(TargetOS: string): string; // normalize function GetFPCTargetCPU(TargetCPU: string): string; // normalize function IsPas2jsTargetOS(TargetOS: string): boolean; function IsPas2jsTargetCPU(TargetCPU: string): boolean; function IsCTExecutable(AFilename: string; out ErrorMsg: string): boolean; // not thread-safe function GuessPascalCompilerFromExeName(Filename: string): TPascalCompiler; // thread-safe function IsCompilerExecutable(AFilename: string; out ErrorMsg: string; out Kind: TPascalCompiler; Run: boolean): boolean; // not thread-safe function IsFPCExecutable(AFilename: string; out ErrorMsg: string; Run: boolean): boolean; deprecated; // 2.1, not thread-safe function IsPas2JSExecutable(AFilename: string; out ErrorMsg: string; Run: boolean): boolean; deprecated; // 2.1, not thread-safe // functions to quickly setup some defines function CreateDefinesInDirectories(const SourcePaths, FlagName: string ): TDefineTemplate; function GatherFiles(Directory, ExcludeDirMask, IncludeFileMask: string; MaxLevel: integer; const OnProgress: TDefinePoolProgress): TStringList; // thread safe function GatherFilesInFPCSources(Directory: string; const OnProgress: TDefinePoolProgress): TStringList; // thread safe function MakeRelativeFileList(Files: TStrings; out BaseDir: string): TStringList; function Compress1FileList(Files: TStrings): TStringList; // thread-safe function Decompress1FileList(Files: TStrings): TStringList; // thread-safe function RunTool(const Filename: string; Params: TStrings; WorkingDirectory: string = ''; Quiet: boolean = false): TStringList; // thread-safe function RunTool(const Filename, Params: string; WorkingDirectory: string = ''; Quiet: boolean = false): TStringList; // thread-safe type // fpc parameter effecting search for compiler TFPCFrontEndParam = ( fpcpT, // -T fpcpP, // -P fpcpV, // -V fpcpXp // -Xp ); TFPCFrontEndParams = set of TFPCFrontEndParam; const AllFPCFrontEndParams = [low(TFPCFrontEndParam)..high(TFPCFrontEndParam)]; function ParseFPCInfo(FPCInfo: string; InfoTypes: TFPCInfoTypes; out Infos: TFPCInfoStrings): boolean; function RunFPCInfo(const CompilerFilename: string; InfoTypes: TFPCInfoTypes; const Options: string =''): string; function FPCVersionToNumber(const FPCVersionString: string): integer; // 2.7.1 -> 20701 function SplitFPCVersion(const FPCVersionString: string; out FPCVersion, FPCRelease, FPCPatch: integer): boolean; // 2.7.1 -> 2,7,1 function ParseFPCVerbose(List: TStrings; // fpc -va output const WorkDir: string; out ConfigFiles: TStrings; // prefix '-' for file not found, '+' for found and read out RealCompilerFilename: string; // what compiler is used by fpc out UnitPaths: TStrings; // unit search paths out IncludePaths: TStrings; // include search paths out UnitScopes: TStrings; // unit scopes/namespaces out Defines, Undefines: TStringToStringTree): boolean; function RunFPCVerbose(const CompilerFilename, TestFilename: string; out ConfigFiles: TStrings; out RealCompilerFilename: string; out UnitPaths: TStrings; out IncludePaths: TStrings; out UnitScopes: TStrings; // unit scopes/namespaces out Defines, Undefines: TStringToStringTree; const Options: string = ''): boolean; procedure GatherUnitsInSearchPaths(SearchUnitPaths, SearchIncludePaths: TStrings; const OnProgress: TDefinePoolProgress; out Units: TStringToStringTree; out Includes: TStringToStringTree); // unit names to full file name procedure GatherUnitsInFPMSources(Units: TStringToStringTree; // unit names to full file name out UnitToFPM: TStringToPointerTree; out FPMNameToFPM: TStringToPointerTree; // TPCFPMFileState const OnProgress: TDefinePoolProgress = nil ); function GatherUnitSourcesInDirectory(Directory: string; MaxLevel: integer = 1): TStringToStringTree; // unit names to full file name procedure AdjustFPCSrcRulesForPPUPaths(Units: TStringToStringTree; Rules: TFPCSourceRules); // not for pas2js function GatherUnitsInFPCSources(Files: TStringList; TargetOS: string = ''; TargetCPU: string = ''; Duplicates: TStringToStringTree = nil; // unit to semicolon separated list of files Rules: TFPCSourceRules = nil; const DebugUnitName: string = ''): TStringToStringTree; // not for pas2js function CreateFPCTemplate(Config: TPCTargetConfigCache; Owner: TObject): TDefineTemplate; overload; function CreateFPCTemplate(Config: TFPCUnitSetCache; Owner: TObject): TDefineTemplate; overload; function CreateFPCSourceTemplate(Config: TFPCUnitSetCache; Owner: TObject): TDefineTemplate; overload; // not for pas2js function CreateFPCSourceTemplate(FPCSrcDir: string; Owner: TObject): TDefineTemplate; overload; // not for pas2js procedure CheckPPUSources(PPUFiles, // unitname to filename UnitToSource, // unitname to file name UnitToDuplicates: TStringToStringTree; // unitname to semicolon separated list of files var Duplicates, Missing: TStringToStringTree); // not for pas2js procedure LoadFPCCacheFromFile(Filename: string; var Configs: TPCTargetConfigCaches; var Sources: TFPCSourceCaches); procedure SaveFPCCacheToFile(Filename: string; Configs: TPCTargetConfigCaches; Sources: TFPCSourceCaches); // FPC const FPCParamEnabled = 'true'; type TFPCParamKind = ( fpkUnknown, fpkBoolean, // Values: true = FPCParamEnabled otherwise false fpkValue, fpkMultiValue, // e.g. -k fpkDefine, // -d and -u options fpkConfig, // @ parameter fpkNonOption // e.g. source file ); TFPCParamFlag = ( fpfUnset, // use default, e.g. turns an fpkDefine into an Undefine fpfSetTwice, fpfValueChanged); TFPCParamFlags = set of TFPCParamFlag; { TFPCParamValue } TFPCParamValue = class public Name: string; Value: string; Kind: TFPCParamKind; Flags: TFPCParamFlags; constructor Create(const aName, aValue: string; aKind: TFPCParamKind; aFlags: TFPCParamFlags = []); end; procedure ParseFPCParameters(const CmdLineParams: string; Params: TObjectList { list of TFPCParamValue }; ReadBackslash: boolean = false); procedure ParseFPCParameters(CmdLineParams: TStrings; ParsedParams: TObjectList { list of TFPCParamValue }); procedure ParseFPCParameter(const CmdLineParam: string; ParsedParams: TObjectList { list of TFPCParamValue }); function IndexOfFPCParamValue(ParsedParams: TObjectList { list of TFPCParamValue }; const Name: string): integer; function GetFPCParamValue(ParsedParams: TObjectList { list of TFPCParamValue }; const Name: string): TFPCParamValue; function dbgs(k: TFPCParamKind): string; overload; function dbgs(f: TFPCParamFlag): string; overload; function dbgs(const Flags: TFPCParamFlags): string; overload; function ExtractFPCFrontEndParameters(const CmdLineParams: string; const Kinds: TFPCFrontEndParams = AllFPCFrontEndParams): string; procedure ReadMakefileFPC(const Filename: string; List: TStrings); procedure ParseMakefileFPC(const Filename, SrcOS: string; out Dirs, SubDirs: string); function CompareFPCSourceRulesViaFilename(Rule1, Rule2: Pointer): integer; function CompareFPCTargetConfigCacheItems(CacheItem1, CacheItem2: Pointer): integer; function CompareFPCSourceCacheItems(CacheItem1, CacheItem2: Pointer): integer; function CompareDirectoryWithFPCSourceCacheItem(AString, CacheItem: Pointer): integer; implementation type TUnitNameLink = class public Unit_Name: string; Filename: string; ConflictFilename: string; MacroCount: integer; UsedMacroCount: integer; Score: integer; end; function CompareUnitNameLinks(Link1, Link2: Pointer): integer; var UnitLink1: TUnitNameLink absolute Link1; UnitLink2: TUnitNameLink absolute Link2; begin Result:=CompareNames(UnitLink1.Unit_Name,UnitLink2.Unit_Name); end; function CompareUnitNameWithUnitNameLink(Name, Link: Pointer): integer; var UnitLink: TUnitNameLink absolute Link; begin Result:=CompareNames(AnsiString(Name),UnitLink.Unit_Name); end; // some useful functions function GatherFiles(Directory, ExcludeDirMask, IncludeFileMask: string; MaxLevel: integer; const OnProgress: TDefinePoolProgress): TStringList; { ExcludeDirMask: check FilenameIsMatching vs the short file name of a directory IncludeFileMask: check FilenameIsMatching vs the short file name of a file } var Files: TAVLTree; // tree of ansistring FileCount: integer; Abort: boolean; procedure Add(Filename: string); var s: String; begin if Filename='' then exit; // increase refcount s:=Filename; // add Files.Add(PChar(s)); // keep refcount Pointer(s):=nil; end; procedure Search(CurDir: string; Level: integer); var FileInfo: TSearchRec; ShortFilename: String; Filename: String; begin if Level>MaxLevel then exit; //DebugLn(['Search CurDir=',CurDir]); if FindFirstUTF8(Directory+CurDir+FileMask,faAnyFile,FileInfo)=0 then begin repeat inc(FileCount); if (FileCount mod 100=0) and Assigned(OnProgress) then begin OnProgress(nil,0,-1,'Scanned files: '+IntToStr(FileCount),Abort); if Abort then break; end; ShortFilename:=FileInfo.Name; if (ShortFilename='') or (ShortFilename='.') or (ShortFilename='..') then continue; //debugln(['Search ShortFilename=',ShortFilename,' IsDir=',(FileInfo.Attr and faDirectory)>0]); Filename:=CurDir+ShortFilename; if (FileInfo.Attr and faDirectory)>0 then begin // directory if (ExcludeDirMask='') or (not FilenameIsMatching(ExcludeDirMask,ShortFilename,true)) then begin Search(Filename+PathDelim,Level+1); if Abort then break; end else begin //DebugLn(['Search DIR MISMATCH ',Filename]); end; end else begin // file if (IncludeFileMask='') or FilenameIsMatching(IncludeFileMask,ShortFilename,true) then begin //DebugLn(['Search ADD ',Filename]); Add(Filename); end else begin //DebugLn(['Search MISMATCH ',Filename]); end; end; until FindNextUTF8(FileInfo)<>0; end; FindCloseUTF8(FileInfo); end; var Node: TAVLTreeNode; s: String; NodeMgr: TAVLTreeNodeMemManager; begin Result:=nil; Files:=TAVLTree.Create(@CompareAnsiStringFilenames); NodeMgr:=TAVLTreeNodeMemManager.Create; Files.SetNodeManager(NodeMgr); Abort:=false; try FileCount:=0; Directory:=TrimAndExpandDirectory(Directory); if Directory='' then exit; Search('',0); finally if not Abort then Result:=TStringList.Create; Node:=Files.FindLowest; while Node<>nil do begin Pointer(s):=Node.Data; if Result<>nil then Result.Add(s); s:=''; Node:=Files.FindSuccessor(Node); end; FreeAndNil(Files); FreeAndNil(NodeMgr); end; end; function GatherFilesInFPCSources(Directory: string; const OnProgress: TDefinePoolProgress): TStringList; begin Result:=GatherFiles(Directory,'{.*,CVS}', '{*.pas,*.pp,*.p,*.inc,Makefile.fpc}',8,OnProgress); end; function MakeRelativeFileList(Files: TStrings; out BaseDir: string): TStringList; var BaseDirLen: Integer; i: Integer; Filename: string; begin BaseDir:=''; Result:=TStringList.Create; if (Files=nil) or (Files.Count=0) then exit; Result.Assign(Files); // delete empty lines for i:=Result.Count-1 downto 0 do if Result[i]='' then Result.Delete(i); if Result.Count=0 then exit; // find shortest common BaseDir BaseDir:=ChompPathDelim(ExtractFilepath(Result[0])); BaseDirLen:=length(BaseDir); for i:=1 to Result.Count-1 do begin Filename:=Result[i]; while (BaseDirLen>0) do begin if (BaseDirLen<=length(Filename)) and ((BaseDirLen=length(Filename)) or (Filename[BaseDirLen+1]=PathDelim)) and (CompareFilenames(BaseDir,copy(Filename,1,BaseDirLen))=0) then break; BaseDir:=ChompPathDelim(ExtractFilePath(copy(BaseDir,1,BaseDirLen-1))); BaseDirLen:=length(BaseDir); if (BaseDir='') or (BaseDir[length(BaseDir)]=PathDelim) then break; end; end; // create relative paths if (BaseDir<>'') then for i:=0 to Result.Count-1 do begin Filename:=Result[i]; delete(Filename,1,BaseDirLen); if (Filename<>'') and (Filename[1]=PathDelim) then System.Delete(Filename,1,1); Result[i]:=Filename; end; end; function Compress1FileList(Files: TStrings): TStringList; var i: Integer; Filename: string; LastFilename: String; p: Integer; begin Result:=TStringList.Create; LastFilename:=''; for i:=0 to Files.Count-1 do begin Filename:=TrimFilename(Files[i]); p:=1; while (p<=length(Filename)) and (p<=length(LastFilename)) and (Filename[p]=LastFilename[p]) do inc(p); Result.Add(IntToStr(p-1)+':'+copy(Filename,p,length(Filename))); LastFilename:=Filename; end; end; function Decompress1FileList(Files: TStrings): TStringList; var LastFilename: String; i: Integer; Filename: string; p: Integer; Same: Integer; begin Result:=TStringList.Create; LastFilename:=''; try for i:=0 to Files.Count-1 do begin Filename:=Files[i]; p:=1; Same:=0; while (p<=length(Filename)) and (Filename[p] in ['0'..'9']) do begin Same:=Same*10+ord(Filename[p])-ord('0'); inc(p); end; inc(p); Filename:=copy(LastFilename,1,Same)+copy(Filename,p,length(Filename)); Result.Add(Filename); LastFilename:=Filename; end; except end; end; function RunTool(const Filename: string; Params: TStrings; WorkingDirectory: string; Quiet: boolean): TStringList; var buf: string; TheProcess: TProcessUTF8; OutputLine: String; OutLen: Integer; LineStart, i: Integer; begin Result:=nil; if not FileIsExecutable(Filename) then exit(nil); if (WorkingDirectory<>'') and not DirPathExists(WorkingDirectory) then exit(nil); Result:=TStringList.Create; try buf:=''; if (MainThreadID=GetCurrentThreadId) and not Quiet then begin DbgOut(['Hint: (lazarus) [RunTool] "',Filename,'"']); for i:=0 to Params.Count-1 do dbgout(' "',Params[i],'"'); Debugln; end; TheProcess := TProcessUTF8.Create(nil); try TheProcess.Executable := Filename; TheProcess.Parameters:=Params; TheProcess.Options:= [poUsePipes, poStdErrToOutPut]; TheProcess.ShowWindow := swoHide; TheProcess.CurrentDirectory:=WorkingDirectory; TheProcess.Execute; OutputLine:=''; SetLength(buf,4096); repeat if (TheProcess.Output<>nil) then begin OutLen:=TheProcess.Output.Read(Buf[1],length(Buf)); end else OutLen:=0; //debugln(['RunTool OutLen=',OutLen,' Buf="',copy(Buf,1,OutLen),'"']); LineStart:=1; i:=1; while i<=OutLen do begin if Buf[i] in [#10,#13] then begin OutputLine:=OutputLine+copy(Buf,LineStart,i-LineStart); Result.Add(OutputLine); OutputLine:=''; if (iBuf[i+1]) then inc(i); LineStart:=i+1; end; inc(i); end; OutputLine:=OutputLine+copy(Buf,LineStart,OutLen-LineStart+1); until OutLen=0; //debugln(['RunTool Last=',OutputLine]); if OutputLine<>'' then Result.Add(OutputLine); //debugln(['RunTool Result=',Result[Result.Count-1]]); TheProcess.WaitOnExit; finally TheProcess.Free; end; except FreeAndNil(Result); end; end; function RunTool(const Filename, Params: string; WorkingDirectory: string; Quiet: boolean): TStringList; var ParamList: TStringList; begin ParamList:=TStringList.Create; try SplitCmdLineParams(Params,ParamList); Result:=RunTool(Filename,ParamList,WorkingDirectory,Quiet); finally ParamList.Free; end; end; function ParseFPCInfo(FPCInfo: string; InfoTypes: TFPCInfoTypes; out Infos: TFPCInfoStrings): boolean; var i: TFPCInfoType; p: PChar; StartPos: PChar; begin Result:=false; if FPCInfo='' then exit(InfoTypes=[]); if copy(FPCInfo,1,6)='Error:' then exit(false); p:=PChar(FPCInfo); for i:=low(TFPCInfoType) to high(TFPCInfoType) do begin if not (i in InfoTypes) then continue; StartPos:=p; while not (p^ in [' ',#0]) do inc(p); if (p=StartPos) then exit(false); Infos[i]:=copy(FPCInfo,StartPos-PChar(FPCInfo)+1,p-StartPos); // skip space if p^<>#0 then inc(p); end; Result:=true; end; function RunFPCInfo(const CompilerFilename: string; InfoTypes: TFPCInfoTypes; const Options: string): string; var Param: String; List: TStringList; Params: TStringList; begin Result:=''; Param:=''; if fpciCompilerDate in InfoTypes then Param:=Param+'D'; if fpciShortVersion in InfoTypes then Param:=Param+'V'; if fpciFullVersion in InfoTypes then Param:=Param+'W'; if fpciCompilerOS in InfoTypes then Param:=Param+'SO'; if fpciCompilerProcessor in InfoTypes then Param:=Param+'SP'; if fpciTargetOS in InfoTypes then Param:=Param+'TO'; if fpciTargetProcessor in InfoTypes then Param:=Param+'TP'; if Param='' then exit; Param:='-i'+Param; List:=nil; Params:=TStringList.Create; try Params.Add(Param); SplitCmdLineParams(Options,Params); List:=RunTool(CompilerFilename,Params); if (List=nil) or (List.Count<1) then exit; Result:=List[0]; if copy(Result,1,6)='Error:' then Result:=''; finally Params.Free; List.free; end; end; function FPCVersionToNumber(const FPCVersionString: string): integer; var FPCVersion, FPCRelease, FPCPatch: integer; begin if SplitFPCVersion(FPCVersionString,FPCVersion,FPCRelease,FPCPatch) then Result:=FPCVersion*10000+FPCRelease*100+FPCPatch else Result:=0; end; function SplitFPCVersion(const FPCVersionString: string; out FPCVersion, FPCRelease, FPCPatch: integer): boolean; // for example 2.5.1 var p: PChar; function ReadWord(out v: integer): boolean; var Empty: Boolean; begin v:=0; Empty:=true; while (p^ in ['0'..'9']) do begin if v>10000 then exit(false); v:=v*10+ord(p^)-ord('0'); inc(p); Empty:=false; end; Result:=not Empty; end; begin Result:=false; FPCVersion:=0; FPCRelease:=0; FPCPatch:=0; if FPCVersionString='' then exit; p:=PChar(FPCVersionString); if not ReadWord(FPCVersion) then exit; if (p^<>'.') then exit; inc(p); if not ReadWord(FPCRelease) then exit; if (p^<>'.') then exit; inc(p); if not ReadWord(FPCPatch) then exit; Result:=true; end; function ParseFPCVerbose(List: TStrings; const WorkDir: string; out ConfigFiles: TStrings; out RealCompilerFilename: string; out UnitPaths: TStrings; out IncludePaths: TStrings; out UnitScopes: TStrings; out Defines, Undefines: TStringToStringTree): boolean; function DeQuote(const s: string): string; begin if (length(s)>1) and (s[1]='"') and (s[length(s)]='"') then Result:=AnsiDequotedStr(s,'"') else Result:=s; end; procedure UndefineSymbol(const MacroName: string); begin {$IFDEF VerboseFPCSrcScan} DebugLn(['UndefineSymbol ',MacroName]); {$ENDIF} Defines.Remove(MacroName); Undefines[MacroName]:=''; end; procedure DefineSymbol(const MacroName, Value: string); begin {$IFDEF VerboseFPCSrcScan} if Value='' then DebugLn(['DefineSymbol ',MacroName]) else DebugLn(['DefineSymbol ',MacroName,':=',Value]); {$ENDIF} Undefines.Remove(MacroName); Defines[MacroName]:=Value; end; function ExpFile(const aFilename: string): string; begin Result:=DeQuote(aFilename); if FilenameIsAbsolute(Result) then exit; Result:=AppendPathDelim(WorkDir)+Result; end; procedure ProcessOutputLine(Line: string); var UpLine: string; function IsUpLine(p: integer; const s: string): boolean; begin Result:=StrLComp(@UpLine[p], PChar(s), length(s)) = 0; end; var SymbolName, SymbolValue, NewPath: string; i, len, CurPos: integer; Filename: String; p: SizeInt; begin Line:=SysToUtf8(Line); len := length(Line); if len <= 6 then Exit; // shortest match CurPos := 1; // skip timestamp e.g. [0.306] if Line[CurPos] = '[' then begin repeat inc(CurPos); if CurPos > len then Exit; until line[CurPos] = ']'; Inc(CurPos, 2); // skip space too if len - CurPos < 6 then Exit; // shortest match end; UpLine:=UpperCaseStr(Line); case UpLine[CurPos] of 'I': if IsUpLine(CurPos,'INFO: ') then inc(CurPos,6); 'E': if IsUpLine(CurPos,'ERROR: ') then begin inc(CurPos,7); if RealCompilerFilename='' then begin p:=Pos(' returned an error exitcode',Line); if p>0 then RealCompilerFilename:=copy(Line,CurPos,p-CurPos); end; exit; end; end; case UpLine[CurPos] of 'C': if IsUpLine(CurPos,'CONFIGFILE SEARCH: ') then begin // skip keywords Inc(CurPos, 19); Filename:=ExpFile(GetForcedPathDelims(copy(Line,CurPos,length(Line)))); ConfigFiles.Add('-'+Filename); end else if IsUpLine(CurPos,'COMPILER: ') then begin // skip keywords Inc(CurPos, 10); RealCompilerFilename:=ExpFile(copy(Line,CurPos,length(Line))); end; 'M': if IsUpLine(CurPos,'MACRO ') then begin // skip keyword macro Inc(CurPos, 6); if IsUpLine(CurPos,'DEFINED: ') then begin Inc(CurPos, 9); SymbolName:=copy(Line, CurPos, len); if (SameText(SymbolName,'PAS2JS_FULLVERSION') or SameText(SymbolName,'FPC_FULLVERSION')) and Defines.Contains(SymbolName) then begin // keep the FULLVERSION value // Note: pas2js <1.4 had a bug, it gave out DEFINED exit; end; DefineSymbol(SymbolName,''); Exit; end; if IsUpLine(CurPos,'UNDEFINED: ') then begin Inc(CurPos, 11); SymbolName:=copy(Line,CurPos,len); UndefineSymbol(SymbolName); Exit; end; // MACRO something... i := CurPos; while (i <= len) and (Line[i]<>' ') do inc(i); SymbolName:=copy(Line,CurPos,i-CurPos); CurPos := i + 1; // skip space if IsUpLine(CurPos,'SET TO ') then begin // MACRO name SET TO "value" Inc(CurPos, 7); SymbolValue:=DeQuote(copy(Line, CurPos, len)); DefineSymbol(SymbolName, SymbolValue); end; end; 'R': if IsUpLine(CurPos,'READING OPTIONS FROM FILE ') then begin // skip keywords Inc(CurPos, 26); Filename:=ExpFile(GetForcedPathDelims(copy(Line,CurPos,length(Line)))); if (ConfigFiles.Count>0) and (ConfigFiles[ConfigFiles.Count-1]='-'+Filename) then ConfigFiles.Delete(ConfigFiles.Count-1); {$IFDEF VerboseFPCSrcScan} DebugLn('Used options file: "',Filename,'"'); {$ENDIF} ConfigFiles.Add('+'+Filename); end; 'U': if IsUpLine(CurPos,'USING UNIT PATH: ') then begin Inc(CurPos, 17); NewPath:=ExpFile(GetForcedPathDelims(DeQuote(copy(Line,CurPos,len)))); NewPath:=ChompPathDelim(TrimFilename(NewPath)); {$IFDEF VerboseFPCSrcScan} DebugLn('Using unit path: "',NewPath,'"'); {$ENDIF} UnitPaths.Add(NewPath); end else if IsUpLine(CurPos,'USING INCLUDE PATH: ') then begin Inc(CurPos, 20); NewPath:=ExpFile(GetForcedPathDelims(DeQuote(copy(Line,CurPos,len)))); NewPath:=ChompPathDelim(TrimFilename(NewPath)); {$IFDEF VerboseFPCSrcScan} DebugLn('Using include path: "',NewPath,'"'); {$ENDIF} IncludePaths.Add(NewPath); end else if IsUpLine(CurPos,'USING UNIT SCOPE: ') then begin Inc(CurPos, 18); NewPath:=Trim(DeQuote(copy(Line,CurPos,len))); {$IFDEF VerboseFPCSrcScan} DebugLn('Using unit scope: "',NewPath,'"'); {$ENDIF} UnitScopes.Add(NewPath); end; end; end; var i: Integer; begin Result:=false; ConfigFiles:=TStringList.Create; RealCompilerFilename:=''; UnitPaths:=TStringList.Create; IncludePaths:=TStringList.Create; UnitScopes:=TStringList.Create; Defines:=TStringToStringTree.Create(false); Undefines:=TStringToStringTree.Create(false); try for i:=0 to List.Count-1 do ProcessOutputLine(List[i]); Result:=true; finally if not Result then begin FreeAndNil(ConfigFiles); FreeAndNil(UnitPaths); FreeAndNil(IncludePaths); FreeAndNil(UnitScopes); FreeAndNil(Undefines); FreeAndNil(Defines); end; end; end; function RunFPCVerbose(const CompilerFilename, TestFilename: string; out ConfigFiles: TStrings; out RealCompilerFilename: string; out UnitPaths: TStrings; out IncludePaths: TStrings; out UnitScopes: TStrings; out Defines, Undefines: TStringToStringTree; const Options: string): boolean; var Params: TStringList; Filename: String; WorkDir: String; List: TStringList; fs: TFileStream; begin Result:=false; ConfigFiles:=nil; RealCompilerFilename:=''; UnitPaths:=nil; IncludePaths:=nil; UnitScopes:=nil; Defines:=nil; Undefines:=nil; Params:=TStringList.Create; List:=nil; try Params.Add('-va'); if TestFilename<>'' then begin // create empty file try fs:=TFileStream.Create(TestFilename,fmCreate); fs.Free; except debugln(['Warning: [RunFPCVerbose] unable to create test file "'+TestFilename+'"']); exit; end; Filename:=ExtractFileName(TestFilename); WorkDir:=ExtractFilePath(TestFilename); Params.Add(Filename); end else WorkDir:=''; SplitCmdLineParams(Options,Params); //DebugLn(['RunFPCVerbose ',CompilerFilename,' ',Params,' ',WorkDir]); List:=RunTool(CompilerFilename,Params,WorkDir); if (List=nil) or (List.Count=0) then begin debugln(['Warning: RunFPCVerbose failed: ',CompilerFilename,' ',Params]); exit; end; Result:=ParseFPCVerbose(List,WorkDir,ConfigFiles,RealCompilerFilename, UnitPaths,IncludePaths,UnitScopes,Defines,Undefines); finally Params.Free; List.Free; if TestFilename<>'' then DeleteFileUTF8(TestFilename); end; end; procedure GatherUnitsInSearchPaths(SearchUnitPaths, SearchIncludePaths: TStrings; const OnProgress: TDefinePoolProgress; out Units: TStringToStringTree; out Includes: TStringToStringTree); { returns a stringtree, where name is unitname and value is the full file name SearchUnitsPaths are searched from last to start first found wins pas, pp, p replaces ppu } var i: Integer; Directory: String; FileCount: Integer; Abort: boolean; FileInfo: TSearchRec; ShortFilename, Filename, File_Name: String; begin // units sources Units:=TStringToStringTree.Create(false); FileCount:=0; Abort:=false; if Assigned(SearchUnitPaths) then for i:=SearchUnitPaths.Count-1 downto 0 do begin Directory:=TrimAndExpandDirectory(SearchUnitPaths[i]); if (Directory='') then continue; if FindFirstUTF8(Directory+FileMask,faAnyFile,FileInfo)=0 then begin repeat inc(FileCount); if (FileCount mod 100=0) and Assigned(OnProgress) then begin OnProgress(nil, 0, -1, Format(ctsScannedFiles, [IntToStr(FileCount)] ), Abort); if Abort then break; end; ShortFilename:=FileInfo.Name; if (ShortFilename='') or (ShortFilename='.') or (ShortFilename='..') then continue; //debugln(['GatherUnitsInSearchPaths ShortFilename=',ShortFilename,' IsDir=',(FileInfo.Attr and faDirectory)>0]); Filename:=Directory+ShortFilename; if FilenameExtIn(ShortFilename,['.pas','.pp','.p','.ppu']) then begin File_Name:=ExtractFileNameOnly(Filename); if (not Units.Contains(File_Name)) or (not FilenameExtIs(ShortFilename,'.ppu',true) and FilenameExtIs(Units[File_Name],'ppu',true) ) then Units[File_Name]:=Filename; end; until FindNextUTF8(FileInfo)<>0; end; FindCloseUTF8(FileInfo); end; // inc files Includes:=TStringToStringTree.Create(false); if Assigned(SearchIncludePaths) then for i:=SearchIncludePaths.Count-1 downto 0 do begin Directory:=TrimAndExpandDirectory(SearchIncludePaths[i]); if (Directory='') then continue; if FindFirstUTF8(Directory+FileMask,faAnyFile,FileInfo)=0 then begin repeat inc(FileCount); if (FileCount mod 100=0) and Assigned(OnProgress) then begin OnProgress(nil, 0, -1, Format(ctsScannedFiles, [IntToStr(FileCount)] ), Abort); if Abort then break; end; ShortFilename:=FileInfo.Name; if (ShortFilename='') or (ShortFilename='.') or (ShortFilename='..') then continue; //debugln(['GatherUnitsInSearchPaths ShortFilename=',ShortFilename,' IsDir=',(FileInfo.Attr and faDirectory)>0]); Filename:=Directory+ShortFilename; if FilenameExtIs(ShortFilename,'.inc') then begin File_Name:=ExtractFileName(Filename); if (not Includes.Contains(File_Name)) then Includes[File_Name]:=Filename; end; until FindNextUTF8(FileInfo)<>0; end; FindCloseUTF8(FileInfo); end; end; procedure GatherUnitsInFPMSources(Units: TStringToStringTree; out UnitToFPM: TStringToPointerTree; out FPMNameToFPM: TStringToPointerTree; const OnProgress: TDefinePoolProgress); { check for each UnitPath of the form lib/fpc//units/// if there is lib/fpc//fpmkinst/>/.fpm and search line SourcePath= then search source files in this directory including subdirectories } function SearchPriorPathDelim(var p: integer; const Filename: string): boolean; inline; begin repeat dec(p); if p<1 then exit(false) until Filename[p]=PathDelim; Result:=true; end; var Abort: boolean; AVLNode: TAVLTreeNode; S2SItem: PStringToStringItem; CurUnitName, Filename, PkgName, FPMFilename, FPMSourcePath, Line: String; p, EndPos, FPCTargetEndPos, i, FileCount: Integer; sl: TStringList; FPM: TPCFPMFileState; begin // try to resolve .ppu files via fpmkinst .fpm files UnitToFPM:=TStringToPointerTree.Create(false); FPMNameToFPM:=TStringToPointerTree.Create(false); FPMNameToFPM.FreeValues:=true; if Units=nil then exit; FileCount:=0; Abort:=false; AVLNode:=Units.Tree.FindLowest; while AVLNode<>nil do begin S2SItem:=PStringToStringItem(AVLNode.Data); CurUnitName:=S2SItem^.Name; Filename:=S2SItem^.Value; // trimmed and expanded filename //if Pos('lazmkunit',Filename)>0 then //debugln(['GatherUnitsInFPMSources ===== ',Filename]); AVLNode:=Units.Tree.FindSuccessor(AVLNode); if not FilenameExtIs(Filename,'ppu',true) then continue; // check if filename has the form // /something/units///.ppu // and if there is /something/fpmkinst//.fpm p:=length(Filename); if not SearchPriorPathDelim(p,Filename) then exit; // EndPos:=p; if not SearchPriorPathDelim(p,Filename) then exit; PkgName:=copy(Filename,p+1,EndPos-p-1); if PkgName='' then continue; FPCTargetEndPos:=p; if not SearchPriorPathDelim(p,Filename) then exit; // EndPos:=p; if not SearchPriorPathDelim(p,Filename) then exit; // 'units' if (EndPos-p<>6) or (CompareIdentifiers(@Filename[p+1],'units')<>0) then continue; FPMFilename:=copy(Filename,1,p)+'fpmkinst' +copy(Filename,EndPos,FPCTargetEndPos-EndPos+1)+PkgName+'.fpm'; FPM:=TPCFPMFileState(FPMNameToFPM[PkgName]); if FPM=nil then begin inc(FileCount); if (FileCount mod 100=0) and Assigned(OnProgress) then begin OnProgress(nil, 0, -1, Format(ctsScannedFiles, [IntToStr(FileCount)] ), Abort); if Abort then break; end; FPMSourcePath:=''; if FileExistsCached(FPMFilename) then begin //debugln(['GatherUnitsInFPMSources Found .fpm: ',FPMFilename]); sl:=TStringList.Create; try try sl.LoadFromFile(FPMFilename); for i:=0 to sl.Count-1 do begin Line:=sl[i]; if LeftStr(Line,length('SourcePath='))='SourcePath=' then begin FPMSourcePath:=TrimAndExpandDirectory(copy(Line,length('SourcePath=')+1,length(Line))); break; end; end; except on E: Exception do debugln(['Warning: (lazarus) [GatherUnitsInFPMSources] ',E.Message]); end; finally sl.Free; end; FPM:=TPCFPMFileState.Create; FPM.Name:=PkgName; FPM.FPMFilename:=FPMFilename; FPM.SourcePath:=FPMSourcePath; FPMNameToFPM[PkgName]:=FPM; UnitToFPM[CurUnitName]:=FPM; if FPMSourcePath<>'' then begin //debugln(['GatherUnitsInFPMSources ',FPMFilename,' ',FPMSourcePath]); FreeAndNil(FPM.UnitToSrc); FPM.UnitToSrc:=GatherUnitSourcesInDirectory(FPMSourcePath,3); end; end; end; end; end; function GatherUnitSourcesInDirectory(Directory: string; MaxLevel: integer ): TStringToStringTree; procedure Traverse(Dir: string; Tree: TStringToStringTree; Lvl: integer); var Info: TSearchRec; Filename: String; AnUnitName: String; begin if FindFirstUTF8(Dir+AllFilesMask,faAnyFile,Info)=0 then begin repeat Filename:=Info.Name; if (Filename='') or (Filename='.') or (Filename='..') then continue; if faDirectory and Info.Attr>0 then begin if Lvl0; end; FindCloseUTF8(Info); end; begin Result:=TStringToStringTree.Create(false); if MaxLevel<1 then exit; Directory:=AppendPathDelim(Directory); Traverse(Directory,Result,1); end; procedure AdjustFPCSrcRulesForPPUPaths(Units: TStringToStringTree; Rules: TFPCSourceRules); var Filename: string; Rule: TFPCSourceRule; begin if Units.CaseSensitive then raise Exception.Create('AdjustFPCSrcRulesForPPUPaths Units is case sensitive'); // check unit httpd Filename:=Units['httpd']; if Filename<>'' then begin Filename:=ChompPathDelim(ExtractFilePath(Filename)); Rule:=Rules.Add('packages/'+ExtractFileName(Filename)); Rule.Score:=10; Rule.Targets:='*'; //DebugLn(['AdjustFPCSrcRulesForPPUPaths ',Rule.Filename,' ',Filename]); end; end; function GatherUnitsInFPCSources(Files: TStringList; TargetOS: string; TargetCPU: string; Duplicates: TStringToStringTree; Rules: TFPCSourceRules; const DebugUnitName: string): TStringToStringTree; { returns tree unit name to file name (maybe relative) } function CountMatches(Targets, aTxt: PChar): integer; // check how many of the comma separated words in Targets are in words of aTxt var TxtStartPos: PChar; TargetPos: PChar; TxtPos: PChar; begin Result:=0; if (aTxt=nil) or (Targets=nil) then exit; TxtStartPos:=aTxt; while true do begin while (not (IsIdentChar[TxtStartPos^])) do begin if TxtStartPos^=#0 then exit; inc(TxtStartPos); end; //DebugLn(['CountMatches TxtStartPos=',TxtStartPos]); TargetPos:=Targets; repeat while (TargetPos^=',') do inc(TargetPos); if TargetPos^=#0 then break; //DebugLn(['CountMatches TargetPos=',TargetPos]); TxtPos:=TxtStartPos; while (TxtPos^=TargetPos^) and (not (TargetPos^ in [#0,','])) do begin inc(TargetPos); inc(TxtPos); end; //DebugLn(['CountMatches Test TargetPos=',TargetPos,' TxtPos=',TxtPos]); if (TargetPos^ in [#0,',']) and (not IsIdentChar[TxtPos^]) then begin // the target fits //DebugLn(['CountMatches FITS']); inc(Result); end; // try next target while not (TargetPos^ in [#0,',']) do inc(TargetPos); until TargetPos^=#0; // next txt word while IsIdentChar[TxtStartPos^] do inc(TxtStartPos); end; end; var i: Integer; Filename: string; Links: TAVLTree; Unit_Name: String; LastDirectory: String; LastDirScore: Integer; Directory: String; DirScore: LongInt; Node: TAVLTreeNode; Link: TUnitNameLink; TargetRules: TAVLTree; Score: LongInt; Targets: string; begin Result:=nil; if (Files=nil) or (Files.Count=0) then exit; if (Duplicates<>nil) and Duplicates.CaseSensitive then raise Exception.Create('GatherUnitsInFPCSources: Duplicates case sensitive'); // get default targets if Rules=nil then Rules:=DefaultFPCSourceRules; Targets:=Rules.GetDefaultTargets(TargetOS,TargetCPU); TargetRules:=nil; Links:=TAVLTree.Create(@CompareUnitNameLinks); try // get Score rules for duplicate units Rules.GetRulesForTargets(Targets,TargetRules); //DebugLn(['GatherUnitsInFPCSources ',Rules.GetScore('packages/h',TargetRules)]); //exit; if (TargetRules<>nil) and (TargetRules.Count=0) then FreeAndNil(TargetRules); LastDirectory:=''; LastDirScore:=0; for i:=0 to Files.Count-1 do begin Filename:=Files[i]; if FilenameHasPascalExt(Filename) then begin if CompareFilenameOnly(PChar(Filename),length(Filename),'fpmake',6,true)=0 then continue; // skip the fpmake.pp files // Filename is a pascal unit source Directory:=ExtractFilePath(Filename); if LastDirectory=Directory then begin // same directory => reuse directory Score DirScore:=LastDirScore; end else begin // a new directory => recompute directory score // default heuristic: add one point for every target in directory DirScore:=CountMatches(PChar(Targets),PChar(Directory)); end; Score:=DirScore; // apply target rules if TargetRules<>nil then inc(Score,Rules.GetScore(Filename,TargetRules)); // add or update unitlink Unit_Name:=ExtractFileNameOnly(Filename); Node:=Links.FindKey(Pointer(Unit_Name),@CompareUnitNameWithUnitNameLink); if Node<>nil then begin // duplicate unit Link:=TUnitNameLink(Node.Data); if Link.Score'') and (SysUtils.CompareText(Unit_Name,DebugUnitName)=0) then debugln(['GatherUnitsInFPCSources UnitName=',Unit_Name,' File=',Filename,' Score=',Score,' => better than ',Link.Score]); Link.Unit_Name:=Unit_Name; Link.Filename:=Filename; Link.ConflictFilename:=''; Link.Score:=Score; end else if Link.Score=Score then begin // unit with same Score => maybe a conflict // be deterministic and choose the highest if (DebugUnitName<>'') and (SysUtils.CompareText(Unit_Name,DebugUnitName)=0) then debugln(['GatherUnitsInFPCSources UnitName=',Unit_Name,' File=',Filename,' Score=',Score,' => duplicate']); if CompareStr(Filename,Link.Filename)>0 then begin if Link.ConflictFilename<>'' then Link.ConflictFilename:=Link.ConflictFilename+';'+Link.Filename else Link.ConflictFilename:=Link.Filename; Link.Filename:=Filename; end else begin Link.ConflictFilename:=Link.ConflictFilename+';'+Filename; end; end; end else begin // new unit source found => add to list if (DebugUnitName<>'') and (SysUtils.CompareText(Unit_Name,DebugUnitName)=0) then debugln(['GatherUnitsInFPCSources UnitName=',Unit_Name,' File=',Filename,' Score=',Score]); Link:=TUnitNameLink.Create; Link.Unit_Name:=Unit_Name; Link.Filename:=Filename; Link.Score:=Score; Links.Add(Link); end; LastDirectory:=Directory; LastDirScore:=DirScore; end; end; Result:=TStringToStringTree.Create(false); Node:=Links.FindLowest; while Node<>Nil do begin Link:=TUnitNameLink(Node.Data); Result[Link.Unit_Name]:=Link.Filename; if (Link.ConflictFilename<>'') and (Link.Score>0) then begin if (DebugUnitName<>'') and (SysUtils.CompareText(Link.Unit_Name,DebugUnitName)=0) then DebugLn(['GatherUnitsInFPCSources Ambiguous: ',Link.Score,' ',Link.Filename,' ',Link.ConflictFilename]); if Duplicates<>nil then Duplicates[Link.Unit_Name]:=Link.Filename+';'+Link.ConflictFilename; end; Node:=Links.FindSuccessor(Node); end; finally TargetRules.Free; Links.FreeAndClear; Links.Free; end; end; function CreateFPCTemplate(Config: TPCTargetConfigCache; Owner: TObject): TDefineTemplate; var Node: TAVLTreeNode; StrItem: PStringToStringItem; NewDefTempl: TDefineTemplate; TargetOS: String; SrcOS: String; SrcOS2: String; TargetCPU: String; begin Result:=TDefineTemplate.Create(StdDefTemplFPC, ctsFreePascalCompilerInitialMacros,'','',da_Block); // define #TargetOS TargetOS:=Config.RealTargetOS; if TargetOS='' then TargetOS:=Config.TargetOS; if TargetOS='' then TargetOS:=GetCompiledTargetOS; NewDefTempl:=TDefineTemplate.Create('Define TargetOS', ctsDefaultFPCTargetOperatingSystem, ExternalMacroStart+'TargetOS',TargetOS,da_DefineRecurse); Result.AddChild(NewDefTempl); // define #SrcOS SrcOS:=GetDefaultSrcOSForTargetOS(TargetOS); if SrcOS='' then SrcOS:=TargetOS; NewDefTempl:=TDefineTemplate.Create('Define SrcOS', ctsDefaultFPCSourceOperatingSystem, ExternalMacroStart+'SrcOS',SrcOS,da_DefineRecurse); Result.AddChild(NewDefTempl); // define #SrcOS2 SrcOS2:=GetDefaultSrcOS2ForTargetOS(TargetOS); if SrcOS2='' then SrcOS2:=TargetOS; NewDefTempl:=TDefineTemplate.Create('Define SrcOS2', ctsDefaultFPCSource2OperatingSystem, ExternalMacroStart+'SrcOS2',SrcOS2,da_DefineRecurse); Result.AddChild(NewDefTempl); // define #TargetCPU TargetCPU:=Config.RealTargetCPU; if TargetCPU='' then TargetCPU:=Config.TargetCPU; if TargetCPU='' then TargetCPU:=GetCompiledTargetCPU; NewDefTempl:=TDefineTemplate.Create('Define TargetCPU', ctsDefaultFPCTargetProcessor, TargetCPUMacroName,TargetCPU, da_DefineRecurse); Result.AddChild(NewDefTempl); if Config.Defines<>nil then begin Node:=Config.Defines.Tree.FindLowest; while Node<>nil do begin StrItem:=PStringToStringItem(Node.Data); NewDefTempl:=TDefineTemplate.Create('Define '+StrItem^.Name, 'Macro',StrItem^.Name,StrItem^.Value,da_DefineRecurse); Result.AddChild(NewDefTempl); Node:=Config.Defines.Tree.FindSuccessor(Node); end; end; if Config.Undefines<>nil then begin Node:=Config.Undefines.Tree.FindLowest; while Node<>nil do begin StrItem:=PStringToStringItem(Node.Data); NewDefTempl:=TDefineTemplate.Create('Undefine '+StrItem^.Name, 'Macro',StrItem^.Name,'',da_UndefineRecurse); Result.AddChild(NewDefTempl); Node:=Config.Undefines.Tree.FindSuccessor(Node); end; end; Result.SetFlags([dtfAutoGenerated],[],false); Result.SetDefineOwner(Owner,true); end; function CreateFPCTemplate(Config: TFPCUnitSetCache; Owner: TObject): TDefineTemplate; overload; begin Result:=CreateFPCTemplate(Config.GetConfigCache(false),Owner); Result.AddChild(TDefineTemplate.Create('UnitSet','UnitSet identifier', UnitSetMacroName,Config.GetUnitSetID,da_DefineRecurse)); end; function CreateFPCSourceTemplate(FPCSrcDir: string; Owner: TObject): TDefineTemplate; const RTLPkgDirs: array[1..4] of string = ('rtl-console','rtl-extra','rtl-objpas','rtl-unicode'); var Dir, SrcOS, SrcOS2, aTargetCPU, IncPathMacro: string; DS: char; // dir separator function d(const Filenames: string): string; begin Result:=GetForcedPathDelims(Filenames); end; procedure AddSrcOSDefines(ParentDefTempl: TDefineTemplate); var IfTargetOSIsNotSrcOS: TDefineTemplate; RTLSrcOSDir: TDefineTemplate; IfTargetOSIsNotSrcOS2: TDefineTemplate; RTLSrcOS2Dir: TDefineTemplate; begin // if TargetOS<>SrcOS IfTargetOSIsNotSrcOS:=TDefineTemplate.Create( 'IF TargetOS<>SrcOS', ctsIfTargetOSIsNotSrcOS,'',''''+TargetOSMacro+'''<>'''+SrcOS+'''',da_If); // rtl/$(#SrcOS) RTLSrcOSDir:=TDefineTemplate.Create('SrcOS',SrcOS,'', SrcOS,da_Directory); IfTargetOSIsNotSrcOS.AddChild(RTLSrcOSDir); // add include path inc RTLSrcOSDir.AddChild(TDefineTemplate.Create('Include Path', 'include path', IncludePathMacroName,IncPathMacro+';inc', da_Define)); // add include path $(TargetOS) RTLSrcOSDir.AddChild(TDefineTemplate.Create('Include Path', 'include path to TargetCPU directories', IncludePathMacroName,IncPathMacro+';'+aTargetCPU, da_Define)); ParentDefTempl.AddChild(IfTargetOSIsNotSrcOS); // if TargetOS<>SrcOS2 IfTargetOSIsNotSrcOS2:=TDefineTemplate.Create( 'IF TargetOS is not SrcOS2', ctsIfTargetOSIsNotSrcOS,'',''''+TargetOSMacro+'''<>'''+SrcOS2+'''',da_If); // rtl/$(#SrcOS2) RTLSrcOS2Dir:=TDefineTemplate.Create('SrcOS2',SrcOS2,'', SrcOS2,da_Directory); IfTargetOSIsNotSrcOS2.AddChild(RTLSrcOS2Dir); RTLSrcOS2Dir.AddChild(TDefineTemplate.Create('Include Path', 'include path to TargetCPU directories', IncludePathMacroName,IncPathMacro+';'+aTargetCPU, da_DefineRecurse)); ParentDefTempl.AddChild(IfTargetOSIsNotSrcOS2); end; var DefTempl, MainDir, FCLDir, RTLDir, RTLOSDir, PackagesDir, CompilerDir, UtilsDir, DebugSvrDir: TDefineTemplate; s: string; FCLDBDir: TDefineTemplate; FCLDBInterbaseDir: TDefineTemplate; InstallerDir: TDefineTemplate; IFTempl: TDefineTemplate; FCLBaseDir: TDefineTemplate; FCLBaseSrcDir: TDefineTemplate; PackagesFCLAsyncDir: TDefineTemplate; PackagesExtraDir: TDefineTemplate; PackagesFCLExtraDir: TDefineTemplate; PackagesSubDir: TDefineTemplate; PkgExtraGraphDir: TDefineTemplate; PkgExtraAMunitsDir: TDefineTemplate; FCLSubSrcDir: TDefineTemplate; FCLSubDir, SubPkgDir: TDefineTemplate; Ok: Boolean; begin {$IFDEF VerboseFPCSrcScan} DebugLn('CreateFPCSrcTemplate FPCSrcDir="',FPCSrcDir,'"'); {$ENDIF} Result:=nil; Ok:=false; try if (FPCSrcDir='') or (not DirPathExists(FPCSrcDir)) then begin DebugLn(['Warning: [CreateFPCSrcTemplate] FPCSrcDir does not exist: FPCSrcDir="',FPCSrcDir,'"']); exit; end; DS:=PathDelim; Dir:=AppendPathDelim(FPCSrcDir); SrcOS:='$('+ExternalMacroStart+'SrcOS)'; SrcOS2:='$('+ExternalMacroStart+'SrcOS2)'; aTargetCPU:=TargetCPUMacro; IncPathMacro:=IncludePathMacro; Result:=TDefineTemplate.Create(StdDefTemplFPCSrc, Format(ctsFreePascalSourcesPlusDesc,['RTL, FCL, Packages, Compiler']), '','',da_Block); // The Free Pascal sources build a world of their own // => reset all search paths MainDir:=TDefineTemplate.Create('Free Pascal Source Directory', ctsFreePascalSourceDir,'',FPCSrcDir,da_Directory); Result.AddChild(MainDir); DefTempl:=TDefineTemplate.Create('Reset SrcPath', ctsSrcPathInitialization,ExternalMacroStart+'SrcPath','',da_DefineRecurse); MainDir.AddChild(DefTempl); DefTempl:=TDefineTemplate.Create('Reset UnitPath', ctsUnitPathInitialization,UnitPathMacroName,'',da_DefineRecurse); MainDir.AddChild(DefTempl); DefTempl:=TDefineTemplate.Create('Reset IncPath', ctsUnitPathInitialization,IncludePathMacroName,'',da_DefineRecurse); MainDir.AddChild(DefTempl); // rtl RTLDir:=TDefineTemplate.Create('RTL',ctsRuntimeLibrary,'','rtl',da_Directory); MainDir.AddChild(RTLDir); // rtl include paths s:=IncPathMacro +';'+Dir+'rtl'+DS+'objpas'+DS +';'+Dir+'rtl'+DS+'objpas'+DS+'sysutils' +';'+Dir+'rtl'+DS+'objpas'+DS+'classes' +';'+Dir+'rtl'+DS+'inc'+DS +';'+Dir+'rtl'+DS+'inc'+DS+'graph'+DS +';'+Dir+'rtl'+DS+SrcOS+DS +';'+Dir+'rtl'+DS+TargetOSMacro+DS +';'+Dir+'rtl'+DS+SrcOS2+DS +';'+Dir+'rtl'+DS+SrcOS2+DS+aTargetCPU +';'+Dir+'rtl'+DS+aTargetCPU+DS +';'+Dir+'rtl'+DS+TargetOSMacro+DS+aTargetCPU+DS; RTLDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs, ['objpas, inc,'+aTargetCPU+','+SrcOS]), IncludePathMacroName,s,da_DefineRecurse)); // if solaris or darwin or beos then define FPC_USE_LIBC IFTempl:=TDefineTemplate.Create('IF darwin or solaris or beos', 'If Darwin or Solaris or Beos', '', 'defined(darwin) or defined(solaris) or defined(beos)', da_If); // then define FPC_USE_LIBC IFTempl.AddChild(TDefineTemplate.Create('define FPC_USE_LIBC', 'define FPC_USE_LIBC','FPC_USE_LIBC','',da_DefineRecurse)); RTLDir.AddChild(IFTempl); // rtl: IF SrcOS=win then add include path rtl/TargetOS/wininc;rtl/win/wininc;rtl/win IFTempl:=TDefineTemplate.Create('If SrcOS=win','If SrcOS=win', '',''''+SrcOS+'''=''win''',da_If); IFTempl.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['wininc']), IncludePathMacroName, IncPathMacro +';'+Dir+'rtl'+DS+TargetOSMacro+DS+'wininc' +';'+Dir+'rtl'+DS+'win'+DS+'wininc' +';'+Dir+'rtl'+DS+'win', da_DefineRecurse)); RTLDir.AddChild(IFTempl); // rtl: IF TargetOS=iphonesim then add include path rtl/unix, rtl/bsd, rtl/darwin IFTempl:=TDefineTemplate.Create('If TargetOS=iphonesim','If TargetOS=iphonesim', '',''''+TargetOSMacro+'''=''iphonesim''',da_If); IFTempl.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['unix,bsd,darwin']), IncludePathMacroName, IncPathMacro +';'+Dir+'rtl'+DS+'unix' +';'+Dir+'rtl'+DS+'bsd' +';'+Dir+'rtl'+DS+'darwin', da_DefineRecurse)); RTLDir.AddChild(IFTempl); // add processor and SrcOS alias defines for the RTL AddSrcOSDefines(RTLDir); // rtl/$(#TargetOS) RTLOSDir:=TDefineTemplate.Create('TargetOS','Target OS','', TargetOSMacro,da_Directory); s:=IncPathMacro +';'+Dir+'rtl'+DS+TargetOSMacro+DS+SrcOS+'inc' // e.g. rtl/win32/inc/ +';'+Dir+'rtl'+DS+TargetOSMacro+DS+aTargetCPU+DS ; RTLOSDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,[aTargetCPU]), IncludePathMacroName, s,da_DefineRecurse)); s:=SrcPathMacro +';'+Dir+'rtl'+DS+'objpas'+DS; RTLOSDir.AddChild(TDefineTemplate.Create('Src Path', Format(ctsAddsDirToSourcePath,[aTargetCPU]), ExternalMacroStart+'SrcPath',s,da_DefineRecurse)); RTLDir.AddChild(RTLOSDir); // fcl FCLDir:=TDefineTemplate.Create('FCL',ctsFreePascalComponentLibrary,'','fcl', da_Directory); MainDir.AddChild(FCLDir); FCLDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['inc,'+SrcOS]), IncludePathMacroName, d( DefinePathMacro+'/inc/' +';'+DefinePathMacro+'/classes/' +';'+DefinePathMacro+'/'+TargetOSMacro+DS // TargetOS before SrcOS ! +';'+DefinePathMacro+'/'+SrcOS+DS +';'+IncPathMacro) ,da_DefineRecurse)); // fcl/db FCLDBDir:=TDefineTemplate.Create('DB','DB','','db',da_Directory); FCLDir.AddChild(FCLDBDir); FCLDBInterbaseDir:=TDefineTemplate.Create('interbase','interbase','', 'interbase',da_Directory); FCLDBDir.AddChild(FCLDBInterbaseDir); FCLDBInterbaseDir.AddChild(TDefineTemplate.Create('SrcPath', 'SrcPath addition', ExternalMacroStart+'SrcPath', d(Dir+'/packages/base/ibase;'+SrcPathMacro) ,da_Define)); // packages PackagesDir:=TDefineTemplate.Create('Packages',ctsPackageDirectories,'', 'packages',da_Directory); MainDir.AddChild(PackagesDir); // packages/rtl-* for s in RTLPkgDirs do begin SubPkgDir:=TDefineTemplate.Create(s,s,'',s,da_Directory); PackagesDir.AddChild(SubPkgDir); SubPkgDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['inc']), IncludePathMacroName, d(DefinePathMacro+'/inc'),da_DefineRecurse)); end; // packages/rtl-console PackagesSubDir:=TDefineTemplate.Create('rtl-console','rtl-console','','rtl-console',da_Directory); PackagesDir.AddChild(PackagesSubDir); PackagesSubDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['packages/rtl-console/src/inc']), IncludePathMacroName, d(DefinePathMacro+'/src/inc;' +IncPathMacro) ,da_DefineRecurse)); // packages/rtl-extra PackagesSubDir:=TDefineTemplate.Create('rtl-extra','rtl-extra','','rtl-extra',da_Directory); PackagesDir.AddChild(PackagesSubDir); PackagesSubDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['packages/rtl-extra/src/OS']), IncludePathMacroName, d(DefinePathMacro+'/src/inc;' +DefinePathMacro+'/src/'+TargetOSMacro+';' +DefinePathMacro+'/src/'+SrcOS+';' +DefinePathMacro+'/src/'+SrcOS2+';' +IncPathMacro) ,da_DefineRecurse)); // packages/rtl-objpas PackagesSubDir:=TDefineTemplate.Create('rtl-objpas','rtl-objpas','','rtl-objpas',da_Directory); PackagesDir.AddChild(PackagesSubDir); PackagesSubDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['packages/rtl-objpas/src/inc']), IncludePathMacroName, d(DefinePathMacro+'/src/inc;' +IncPathMacro) ,da_DefineRecurse)); // packages/fcl-base FCLBaseDir:=TDefineTemplate.Create('FCL-base', ctsFreePascalComponentLibrary,'','fcl-base', da_Directory); PackagesDir.AddChild(FCLBaseDir); // packages/fcl-base/src FCLBaseSrcDir:=TDefineTemplate.Create('src', 'src','','src', da_Directory); FCLBaseDir.AddChild(FCLBaseSrcDir); FCLBaseSrcDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['inc,'+SrcOS]), IncludePathMacroName, d( DefinePathMacro+'/inc/' +';'+DefinePathMacro+'/'+TargetOSMacro+DS // TargetOS before SrcOS ! +';'+DefinePathMacro+'/'+SrcOS+DS +';'+IncPathMacro) ,da_DefineRecurse)); // packages/fcl-process FCLSubDir:=TDefineTemplate.Create('FCL-process', 'fcl-process','','fcl-process', da_Directory); PackagesDir.AddChild(FCLSubDir); // packages/fcl-process/src FCLSubSrcDir:=TDefineTemplate.Create('src', 'src','','src', da_Directory); FCLSubDir.AddChild(FCLSubSrcDir); FCLSubSrcDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['inc,'+SrcOS]), IncludePathMacroName, d( DefinePathMacro+'/'+TargetOSMacro+DS // TargetOS before SrcOS ! +';'+DefinePathMacro+'/'+SrcOS+DS +';'+IncPathMacro) ,da_DefineRecurse)); // packages/fcl-process/src // IF SrcOS=win then add include path winall IFTempl:=TDefineTemplate.Create('If SrcOS=win','If SrcOS=win', '',''''+SrcOS+'''=''win''',da_If); IFTempl.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['winall']), IncludePathMacroName, IncPathMacro +';winall', da_DefineRecurse)); FCLSubDir.AddChild(IFTempl); // packages/fcl-async PackagesFCLAsyncDir:=TDefineTemplate.Create('fcl-async','fcl-async','','fcl-async',da_Directory); PackagesDir.AddChild(PackagesFCLAsyncDir); // packages/fcl-async/src PackagesFCLAsyncDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['packages/fcl-async/src']), IncludePathMacroName, d( DefinePathMacro+'/src/' +';'+IncPathMacro) ,da_DefineRecurse)); // packages/fcl-extra PackagesFCLExtraDir:=TDefineTemplate.Create('fcl-extra','fcl-extra','','fcl-extra',da_Directory); PackagesDir.AddChild(PackagesFCLExtraDir); // packages/fcl-extra/src PackagesFCLExtraDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['packages/fcl-extra/src']), IncludePathMacroName, d( DefinePathMacro+'/src/'+SrcOS +';'+IncPathMacro) ,da_DefineRecurse)); // packages/extra PackagesExtraDir:=TDefineTemplate.Create('extra','extra','','extra',da_Directory); PackagesDir.AddChild(PackagesExtraDir); // packages/extra/graph PkgExtraGraphDir:=TDefineTemplate.Create('graph','graph','','graph', da_Directory); PackagesExtraDir.AddChild(PkgExtraGraphDir); PkgExtraGraphDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['inc']), IncludePathMacroName, d( DefinePathMacro+'/inc/' +';'+IncPathMacro) ,da_DefineRecurse)); // packages/extra/amunits PkgExtraAMunitsDir:=TDefineTemplate.Create('amunits','amunits','','amunits', da_Directory); PackagesExtraDir.AddChild(PkgExtraAMunitsDir); PkgExtraAMunitsDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['inc']), IncludePathMacroName, d( DefinePathMacro+'/inc/' +';'+IncPathMacro) ,da_DefineRecurse)); // packages/graph PackagesSubDir:=TDefineTemplate.Create('graph','graph','','graph',da_Directory); PackagesDir.AddChild(PackagesSubDir); PackagesSubDir.AddChild(TDefineTemplate.Create('Include Path', Format(ctsIncludeDirectoriesPlusDirs,['packages/graph/src/inc']), IncludePathMacroName, d(DefinePathMacro+'/src/inc;' +IncPathMacro) ,da_DefineRecurse)); // utils UtilsDir:=TDefineTemplate.Create('Utils',ctsUtilsDirectories,'', 'utils',da_Directory); MainDir.AddChild(UtilsDir); // utils/debugsvr DebugSvrDir:=TDefineTemplate.Create('DebugSvr','Debug Server','', 'debugsvr',da_Directory); UtilsDir.AddChild(DebugSvrDir); DebugSvrDir.AddChild(TDefineTemplate.Create('Interface Path', Format(ctsAddsDirToSourcePath,['..']),ExternalMacroStart+'SrcPath', '..;'+ExternalMacroStart+'SrcPath',da_DefineRecurse)); // installer InstallerDir:=TDefineTemplate.Create('Installer',ctsInstallerDirectories,'', 'installer',da_Directory); InstallerDir.AddChild(TDefineTemplate.Create('SrcPath','SrcPath addition', ExternalMacroStart+'SrcPath', SrcPathMacro+';'+Dir+'ide;'+Dir+'fv',da_Define)); MainDir.AddChild(InstallerDir); // compiler CompilerDir:=TDefineTemplate.Create('Compiler',ctsCompiler,'','compiler', da_Directory); CompilerDir.AddChild(TDefineTemplate.Create('SrcPath','SrcPath addition', ExternalMacroStart+'SrcPath', SrcPathMacro+';'+Dir+aTargetCPU,da_Define)); CompilerDir.AddChild(TDefineTemplate.Create('IncPath','IncPath addition', IncludePathMacroName, IncPathMacro+';'+Dir+'compiler',da_DefineRecurse)); MainDir.AddChild(CompilerDir); // compiler/utils UtilsDir:=TDefineTemplate.Create('utils',ctsUtilsDirectories,'', 'utils',da_Directory); UtilsDir.AddChild(TDefineTemplate.Create('SrcPath','SrcPath addition', ExternalMacroStart+'SrcPath', SrcPathMacro+';..',da_Define)); CompilerDir.AddChild(UtilsDir); Result.SetDefineOwner(Owner,true); Result.SetFlags([dtfAutoGenerated],[],false); Ok:=true; finally if not ok then FreeAndNil(Result); end; end; function CreateFPCSourceTemplate(Config: TFPCUnitSetCache; Owner: TObject ): TDefineTemplate; begin Result:=CreateFPCSourceTemplate(Config.FPCSourceDirectory,Owner); end; procedure CheckPPUSources(PPUFiles, UnitToSource, UnitToDuplicates: TStringToStringTree; var Duplicates, Missing: TStringToStringTree); var Node: TAVLTreeNode; Item: PStringToStringItem; Unit_Name: String; Filename: String; SrcFilename: string; DuplicateFilenames: string; begin if PPUFiles.CaseSensitive then raise Exception.Create('CheckPPUSources PPUFiles is case sensitive'); if UnitToSource.CaseSensitive then raise Exception.Create('CheckPPUSources UnitToSource is case sensitive'); if UnitToDuplicates.CaseSensitive then raise Exception.Create('CheckPPUSources UnitToDuplicates is case sensitive'); if (Duplicates<>nil) and Duplicates.CaseSensitive then raise Exception.Create('CheckPPUSources Duplicates is case sensitive'); if (Missing<>nil) and Missing.CaseSensitive then raise Exception.Create('CheckPPUSources Missing is case sensitive'); Node:=PPUFiles.Tree.FindLowest; while Node<>nil do begin Item:=PStringToStringItem(Node.Data); Unit_Name:=Item^.Name; Filename:=Item^.Value; if FilenameExtIs(Filename,'ppu',true) then begin SrcFilename:=UnitToSource[Unit_Name]; if SrcFilename<>'' then begin DuplicateFilenames:=UnitToDuplicates[Unit_Name]; if (DuplicateFilenames<>'') and (Duplicates<>nil) then Duplicates[Unit_Name]:=DuplicateFilenames; end else begin if Missing<>nil then Missing[Unit_Name]:=Filename; end; end; Node:=PPUFiles.Tree.FindSuccessor(Node); end; end; procedure LoadFPCCacheFromFile(Filename: string; var Configs: TPCTargetConfigCaches; var Sources: TFPCSourceCaches); var XMLConfig: TXMLConfig; begin if Configs=nil then Configs:=TPCTargetConfigCaches.Create(nil); if Sources=nil then Sources:=TFPCSourceCaches.Create(nil); if not FileExistsUTF8(Filename) then exit; XMLConfig:=TXMLConfig.Create(Filename); try Configs.LoadFromXMLConfig(XMLConfig,'FPCConfigs/'); Sources.LoadFromXMLConfig(XMLConfig,'FPCSourceDirectories/'); finally XMLConfig.Free; end; end; procedure SaveFPCCacheToFile(Filename: string; Configs: TPCTargetConfigCaches; Sources: TFPCSourceCaches); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.CreateClean(Filename); try Configs.SaveToXMLConfig(XMLConfig,'FPCConfigs/'); Sources.SaveToXMLConfig(XMLConfig,'FPCSourceDirectories/'); finally XMLConfig.Free; end; end; { TPCFPMFileState } constructor TPCFPMFileState.Create; begin UnitToSrc:=TStringToStringTree.Create(false); end; destructor TPCFPMFileState.Destroy; begin FreeAndNil(UnitToSrc); inherited Destroy; end; procedure TPCFPMFileState.Clear; begin UnitToSrc.Clear; FileDate:=-1; end; procedure TPCFPMFileState.Assign(List: TPCFPMFileState); begin // do not assign Name FPMFilename:=List.FPMFilename; FileDate:=List.FileDate; SourcePath:=List.SourcePath; UnitToSrc.Assign(List.UnitToSrc); end; function TPCFPMFileState.Equals(List: TPCFPMFileState; CheckDates: boolean ): boolean; begin Result:=false; if Name<>List.Name then exit; if FPMFilename<>List.FPMFilename then exit; if CheckDates and (FileDate<>List.FileDate) then exit; if SourcePath<>List.SourcePath then exit; if not UnitToSrc.Equals(List.UnitToSrc) then exit; Result:=true; end; procedure TPCFPMFileState.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); var Cnt, i: Integer; SubPath, CurName, CurFilename: String; begin // do not read Name FPMFilename:=XMLConfig.GetValue(Path+'FPMFile',''); FileDate:=XMLConfig.GetValue(Path+'FileDate',0); SourcePath:=TrimAndExpandDirectory(XMLConfig.GetValue(Path+'SourcePath','')); UnitToSrc.Clear; Cnt:=XMLConfig.GetValue(Path+'Units/Count',0); for i:=1 to Cnt do begin SubPath:=Path+'Units/Item'+IntToStr(i)+'/'; CurName:=XMLConfig.GetValue(SubPath+'Name',''); CurFilename:=XMLConfig.GetValue(SubPath+'File',''); UnitToSrc[CurName]:=SourcePath+CurFilename; end; end; procedure TPCFPMFileState.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); var Node: TAVLTreeNode; S2PItem: PStringToStringItem; i: Integer; SubPath: String; begin XMLConfig.SetDeleteValue(Path+'Name',Name,''); XMLConfig.SetDeleteValue(Path+'File',FPMFilename,''); XMLConfig.SetDeleteValue(Path+'FileDate',FileDate,0); XMLConfig.SetDeleteValue(Path+'SourcePath',SourcePath,''); XMLConfig.SetDeleteValue(Path+'Units/Count',UnitToSrc.Count,0); i:=0; Node:=UnitToSrc.Tree.FindLowest; while Node<>nil do begin S2PItem:=PStringToStringItem(Node.Data); inc(i); SubPath:=Path+'Units/Item'+IntToStr(i)+'/'; XMLConfig.SetDeleteValue(SubPath+'Name',S2PItem^.Name,''); XMLConfig.SetDeleteValue(SubPath+'File',CreateRelativePath(S2PItem^.Value,SourcePath),''); Node:=Node.Successor; end; end; { TFPCParamValue } constructor TFPCParamValue.Create(const aName, aValue: string; aKind: TFPCParamKind; aFlags: TFPCParamFlags); begin Name:=aName; Value:=aValue; Kind:=aKind; Flags:=aFlags; end; procedure ParseFPCParameters(const CmdLineParams: string; Params: TObjectList; ReadBackslash: boolean); var ParamList: TStringList; begin ParamList:=TStringList.Create; try SplitCmdLineParams(CmdLineParams,ParamList,ReadBackslash); ParseFPCParameters(ParamList,Params); finally ParamList.Free; end; end; procedure ParseFPCParameters(CmdLineParams: TStrings; ParsedParams: TObjectList); var i: Integer; begin if (CmdLineParams=nil) or (CmdLineParams.Count=0) or (ParsedParams=nil) then exit; for i:=0 to CmdLineParams.Count-1 do ParseFPCParameter(CmdLineParams[i],ParsedParams); end; procedure ParseFPCParameter(const CmdLineParam: string; ParsedParams: TObjectList); { $DEFINE VerboseParseFPCParameter} const AlphaNum = ['a'..'z','A'..'Z','0'..'9']; procedure Add(aName, aValue: string; aKind: TFPCParamKind; aFlags: TFPCParamFlags = []); var i: Integer; Param: TFPCParamValue; begin {$IFDEF VerboseParseFPCParameter} debugln(['ParseFPCParameter.Add Name="',aName,'" Value="',aValue,'" Kind=',dbgs(aKind),' Flags=',dbgs(aFlags)]); {$ENDIF} if (aName='O1') or (aName='O2') or (aName='O3') or (aName='O4') then begin aValue:=aName[2]; aName:='O'; aKind:=fpkValue; end; if (aKind in [fpkBoolean,fpkValue,fpkDefine]) then // check for duplicates for i:=0 to ParsedParams.Count-1 do begin Param:=TFPCParamValue(ParsedParams[i]); if aKind=fpkDefine then begin if CompareText(Param.Name,aName)<>0 then continue; end else begin if (Param.Name<>aName) then continue; end; if (aKind=fpkDefine) <> (Param.Kind=fpkDefine) then continue; // was already set Include(Param.Flags,fpfSetTwice); if (aValue<>Param.Value) or ((fpfUnset in aFlags)<>(fpfUnset in Param.Flags)) or (aKind<>Param.Kind) then Include(Param.Flags,fpfValueChanged); Param.Kind:=aKind; Param.Value:=aValue; if fpfUnset in aFlags then Include(Param.Flags,fpfUnset) else Exclude(Param.Flags,fpfUnset); exit; end; ParsedParams.Add(TFPCParamValue.Create(aName, aValue, aKind, aFlags)); // alias if aName='S2' then Add('M','objfpc',fpkValue,aFlags) else if aName='Sd' then Add('M','delphi',fpkValue,aFlags) else if aName='So' then Add('M','tp',fpkValue,aFlags) else if aName='?' then Add('h',aValue,aKind,aFlags); end; procedure AddBooleanFlag(var p: PChar; Len: integer; Prefix: string = ''); var aName: string; PrefixLen: Integer; begin PrefixLen:=length(Prefix); SetLength(aName,PrefixLen+Len); if PrefixLen>0 then Move(Prefix[1],aName[1],PrefixLen); if Len>0 then Move(p^,aName[PrefixLen+1],Len); {$IFDEF VerboseParseFPCParameter} debugln(['ParseFPCParameter.AddBooleanFlag p="',p,'" Len=',Len,' Prefix="',Prefix,'" Name="'+aName+'"']); {$ENDIF} inc(p,Len); if p^='-' then begin Add(aName,'',fpkBoolean,[fpfUnset]); inc(p); end else begin Add(aName,FPCParamEnabled,fpkBoolean); if p^='+' then inc(p); end; end; procedure ReadSequence(p: PChar; const Specials: string = ''); // e.g. -Ci-n+o p points to the 'C' // Specials is a space separated list of params: // SO : a two letter option 'SO' // h: : a one letter option 'h' followed by a value // ma& : a two letter option 'ma' followed by a multi value // T* : a boolean option starting with T, e.g. Tcld // P= : a one letter option 'P' followed by a name=value pair var Option, c: Char; Opt, Opt2, p2: PChar; aName: string; begin if not (p[1] in AlphaNum) then begin AddBooleanFlag(p,1,''); exit; end; Option:=p^; inc(p); repeat c:=p^; if not (c in AlphaNum) then break; // invalid option if (p[1]<>#0) and (Specials<>'') then begin Opt:=PChar(Specials); while Opt^<>#0 do begin while Opt^=' ' do inc(Opt); p2:=p; Opt2:=Opt; while (Opt2^ in AlphaNum) and (p2^=Opt2^) do begin inc(p2); inc(Opt2); end; case Opt2^ of ' ',#0: // boolean option begin AddBooleanFlag(p,Opt2-Opt,Option); break; end; ':': // option followed by value begin Add(Option+copy(Specials,Opt-PChar(Specials)+1,Opt2-Opt),p2,fpkValue); exit; end; '&': // option followed by multi value begin Add(Option+copy(Specials,Opt-PChar(Specials)+1,Opt2-Opt),p2,fpkMultiValue); exit; end; '*': // boolean option with arbitrary name begin while p2^ in AlphaNum do inc(p2); AddBooleanFlag(p,p2-p,Option); break; end; '=': // name=value begin if not (p2^ in AlphaNum) then exit; // invalid option while p2^ in AlphaNum do inc(p2); if (p2^<>'=') then exit; // invalid option SetLength(aName,p2-p); Move(p^,aName[1],p2-p); inc(p2); Add(Option+aName,p2,fpkValue); exit; end else // mismatch -> try next special option Opt:=Opt2; while not (Opt^ in [#0,' ']) do inc(Opt); end; end; if Opt^<>#0 then continue; end; // default: single char flag AddBooleanFlag(p,1,Option); until false; end; procedure DisableAllFlags(const Prefix: string); var i: Integer; Param: TFPCParamValue; begin for i:=0 to ParsedParams.Count-1 do begin Param:=TFPCParamValue(ParsedParams[i]); if not (Param.Kind in [fpkBoolean,fpkValue,fpkMultiValue]) then continue; if LeftStr(Param.Name,length(Prefix))<>Prefix then continue; Include(Param.Flags,fpfSetTwice); if not (fpfUnset in Param.Flags) then Include(Param.Flags,fpfValueChanged); Param.Value:=''; Include(Param.Flags,fpfUnset); end; end; var p, p2: PChar; begin {$IFDEF VerboseParseFPCParameter} debugln(['ParseFPCParameter "',CmdLineParam,'"']); {$ENDIF} if CmdLineParam='' then exit; p:=PChar(CmdLineParam); case p^ of '-': // option begin inc(p); case p^ of 'a': ReadSequence(p); 'C': ReadSequence(p,'a: c: f: F: h: p: P= s: T*'); 'd': Add(copy(CmdLineParam,3,255),'',fpkDefine); 'D': begin inc(p); case p^ of 'd','v': Add('D'+p^,PChar(@p[1]),fpkValue); else AddBooleanFlag(p,1,'D'); end; end; 'e': Add('e',PChar(@p[1]),fpkValue); 'F': case p[1] of 'a','f','i','l','N','o','u': Add('F'+p[1],PChar(@p[2]),fpkMultiValue); 'c','C','D','e','E','L','m','M','r','R','U','W','w': Add('F'+p[1],PChar(@p[2]),fpkValue); else AddBooleanFlag(p,2); end; 'g': if p[1] in [#0,'+'] then begin Add('g',FPCParamEnabled,fpkBoolean,[]); end else if p[1]='-' then begin DisableAllFlags('g'); Add('g','',fpkBoolean,[fpfUnset]); end else begin inc(p); repeat case p^ of 'o': begin Add('g'+p,FPCParamEnabled,fpkBoolean,[]); exit; end; 'w': case p[1] of '2'..'9': begin Add('gw',p[1],fpkValue); inc(p,2); end; else Add('gw','2',fpkValue); inc(p); end; 'a'..'n','p'..'v','A'..'Z','0'..'9': AddBooleanFlag(p,1,'g'); else break; end; until false; end; 'i': ReadSequence(p,'SO SP TO TP'); 'I': Add(p^,PChar(@p[1]),fpkMultiValue); 'k': Add(p^,PChar(@p[1]),fpkMultiValue); 'M': Add(p^,PChar(@p[1]),fpkValue); 'N': case p[1] of 'S': Add('NS',PChar(@p[2]),fpkMultiValue); // -NS namespaces end; 'o': Add(p^,PChar(@p[1]),fpkValue); 'O': case p[1] of '-': DisableAllFlags('O'); else ReadSequence(p,'a= o* p: W: w:'); end; 'P': ; // ToDo 'R': Add(p^,PChar(@p[1]),fpkValue); 'S': ReadSequence(p,'e: I:'); 's': ReadSequence(p); 'T': Add(p^,PChar(@p[1]),fpkValue); 'u': Add(copy(CmdLineParam,3,255),'',fpkDefine,[fpfUnset]); 'U': ReadSequence(p); 'v': ReadSequence(p,'m&'); 'V': Add(p^,PChar(@p[1]),fpkValue); 'W': ReadSequence(p,'B: M: P:'); 'X': ReadSequence(p,'LA LO LD M: P: r: R:'); else p2:=p; while p2^ in AlphaNum do inc(p2); AddBooleanFlag(p,p2-p); end; end; '@': // config Add('',PChar(@p[1]),fpkConfig); else // filename Add('',p,fpkNonOption); end; end; function IndexOfFPCParamValue(ParsedParams: TObjectList; const Name: string ): integer; begin if ParsedParams=nil then exit(-1); for Result:=0 to ParsedParams.Count-1 do if TFPCParamValue(ParsedParams[Result]).Name=Name then exit; Result:=-1; end; function GetFPCParamValue(ParsedParams: TObjectList; const Name: string ): TFPCParamValue; var i: Integer; begin i:=IndexOfFPCParamValue(ParsedParams,Name); if i<0 then Result:=nil else Result:=TFPCParamValue(ParsedParams[i]); end; function dbgs(k: TFPCParamKind): string; begin str(k,Result); end; function dbgs(f: TFPCParamFlag): string; begin str(f,Result); end; function dbgs(const Flags: TFPCParamFlags): string; var f: TFPCParamFlag; begin Result:=''; for f in TFPCParamFlag do if f in Flags then begin if Result<>'' then Result+=','; Result+=dbgs(f); end; Result:='['+Result+']'; end; function ExtractFPCFrontEndParameters(const CmdLineParams: string; const Kinds: TFPCFrontEndParams): string; // extract the parameters for the FPC frontend tool fpc.exe // The result is normalized: // - only the last value // - order is: -T -P -V -Xp procedure Add(const Name, Value: string); begin if Value='' then exit; if Result<>'' then Result+=' '; Result+='-'+Name+StrToCmdLineParam(Value); end; var Position: Integer; Param, ParamT, ParamP, ParamV, ParamXp: String; StartPos: integer; p: PChar; begin Result:=''; ParamT:=''; ParamP:=''; ParamV:=''; ParamXp:=''; Position:=1; while ReadNextFPCParameter(CmdLineParams,Position,StartPos) do begin Param:=ExtractFPCParameter(CmdLineParams,StartPos); if Param='' then continue; p:=PChar(Param); if p^<>'-' then continue; case p[1] of 'T': if fpcpT in Kinds then ParamT:=copy(Param,3,255); 'P': if fpcpP in Kinds then ParamP:=copy(Param,3,255); 'V': if fpcpV in Kinds then ParamV:=copy(Param,3,length(Param)); 'X': case p[2] of 'p': if fpcpXp in Kinds then ParamXp:=copy(Param,4,length(Param)); end; end; end; // add parameters Add('Xp',ParamXp); Add('T',ParamT); Add('P',ParamP); Add('V',ParamV); end; procedure ReadMakefileFPC(const Filename: string; List: TStrings); var MakefileFPC: TStringList; i: Integer; Line: string; p: LongInt; NameValue: String; begin MakefileFPC:=TStringList.Create; MakefileFPC.LoadFromFile(Filename); i:=0; while i=1) and (NameValue[p] in [' ',#9]) do dec(p); //List.Add(' NameValue="'+NameValue+'" p='+IntToStr(p)+' "'+NameValue[p]+'"'); if (p>=1) and (NameValue[p]='\') and ((p=1) or (NameValue[p-1]<>'\')) then begin // append next line NameValue:=copy(NameValue,1,p-1); inc(i); if i>=MakefileFPC.Count then break; NameValue:=NameValue+MakefileFPC[i]; end else break; until false; List.Add(NameValue); end; inc(i); end; MakefileFPC.Free; end; procedure ParseMakefileFPC(const Filename, SrcOS: string; out Dirs, SubDirs: string); function MakeSearchPath(const s: string): string; var SrcPos: Integer; DestPos: Integer; begin // check how much space is needed SrcPos:=1; DestPos:=0; while (SrcPos<=length(s)) do begin if s[SrcPos] in [#0..#31] then begin // space is a delimiter inc(SrcPos); // skip multiple spaces while (SrcPos<=length(s)) and (s[SrcPos] in [#0..#31]) do inc(SrcPos); if (DestPos>0) and (SrcPos<=length(s)) then begin inc(DestPos);// add semicolon end; end else begin inc(DestPos); inc(SrcPos); end; end; // allocate space SetLength(Result,DestPos); // create semicolon delimited search path SrcPos:=1; DestPos:=0; while (SrcPos<=length(s)) do begin if s[SrcPos] in [#0..#32] then begin // space is a delimiter inc(SrcPos); // skip multiple spaces while (SrcPos<=length(s)) and (s[SrcPos] in [#0..#32]) do inc(SrcPos); if (DestPos>0) and (SrcPos<=length(s)) then begin inc(DestPos);// add semicolon Result[DestPos]:=';'; end; end else begin inc(DestPos); Result[DestPos]:=s[SrcPos]; inc(SrcPos); end; end; end; var Params: TStringList; i: Integer; Line: string; p: LongInt; Name: String; SubDirsName: String; begin SubDirs:=''; Dirs:=''; Params:=TStringList.Create; try ReadMakefileFPC(Filename,Params); SubDirsName:=''; if SrcOS<>'' then SubDirsName:='dirs_'+SrcOS; for i:=0 to Params.Count-1 do begin Line:=Params[i]; if Line='' then continue; if (Line[1] in ['a'..'z','A'..'Z','0'..'9','_']) then begin p:=System.Pos('=',Line); if p<1 then continue; Name:=copy(Line,1,p-1); if Name=SubDirsName then begin SubDirs:=MakeSearchPath(copy(Line,p+1,length(Line))); end else if Name='dirs' then begin Dirs:=MakeSearchPath(copy(Line,p+1,length(Line))); end; end; end; except on e: Exception do begin debugln('Error: [ParseMakefileFPC] Filename=',Filename,': ',E.Message); end; end; Params.Free; end; function CompareFPCSourceRulesViaFilename(Rule1, Rule2: Pointer): integer; var SrcRule1: TFPCSourceRule absolute Rule1; SrcRule2: TFPCSourceRule absolute Rule2; begin Result:=CompareFilenames(SrcRule1.Filename,SrcRule2.Filename); end; function CompareFPCTargetConfigCacheItems(CacheItem1, CacheItem2: Pointer): integer; var Item1: TPCTargetConfigCache absolute CacheItem1; Item2: TPCTargetConfigCache absolute CacheItem2; begin Result:=CompareStr(Item1.TargetOS,Item2.TargetOS); if Result<>0 then exit; Result:=CompareStr(Item1.TargetCPU,Item2.TargetCPU); if Result<>0 then exit; Result:=CompareFilenames(Item1.Compiler,Item2.Compiler); if Result<>0 then exit; Result:=CompareFilenames(Item1.CompilerOptions,Item2.CompilerOptions); end; function CompareFPCSourceCacheItems(CacheItem1, CacheItem2: Pointer): integer; var Src1: TFPCSourceCache absolute CacheItem1; Src2: TFPCSourceCache absolute CacheItem2; begin Result:=CompareFilenames(Src1.Directory,Src2.Directory); end; function CompareDirectoryWithFPCSourceCacheItem(AString, CacheItem: Pointer ): integer; var Src: TFPCSourceCache absolute CacheItem; begin Result:=CompareFilenames(AnsiString(AString),Src.Directory); end; function DefineActionNameToAction(const s: string): TDefineAction; begin for Result:=Low(TDefineAction) to High(TDefineAction) do if CompareText(s,DefineActionNames[Result])=0 then exit; Result:=da_None; end; function DefineTemplateFlagsToString(Flags: TDefineTemplateFlags): string; var f: TDefineTemplateFlag; begin Result:=''; for f:=Low(TDefineTemplateFlag) to High(TDefineTemplateFlag) do begin if f in Flags then begin if Result<>'' then Result:=Result+','; Result:=Result+DefineTemplateFlagNames[f]; end; end; end; function CompareUnitLinkNodes(NodeData1, NodeData2: pointer): integer; var Link1, Link2: TUnitNameLink; begin Link1:=TUnitNameLink(NodeData1); Link2:=TUnitNameLink(NodeData2); Result:=CompareText(Link1.Unit_Name,Link2.Unit_Name); end; function CompareUnitNameWithUnitLinkNode(AUnitName: Pointer; NodeData: pointer): integer; begin Result:=CompareText(String(AUnitName),TUnitNameLink(NodeData).Unit_Name); end; function CompareDirectoryDefines(NodeData1, NodeData2: pointer): integer; var DirDef1, DirDef2: TDirectoryDefines; begin DirDef1:=TDirectoryDefines(NodeData1); DirDef2:=TDirectoryDefines(NodeData2); Result:=CompareFilenames(DirDef1.Path,DirDef2.Path); end; function GetDefaultSrcOSForTargetOS(const TargetOS: string): string; begin Result:=''; if (CompareText(TargetOS,'linux')=0) or (CompareText(TargetOS,'freebsd')=0) or (CompareText(TargetOS,'netbsd')=0) or (CompareText(TargetOS,'openbsd')=0) or (CompareText(TargetOS,'dragonfly')=0) or (CompareText(TargetOS,'darwin')=0) or (CompareText(TargetOS,'ios')=0) or (CompareText(TargetOS,'solaris')=0) or (CompareText(TargetOS,'haiku')=0) or (CompareText(TargetOS,'android')=0) then Result:='unix' else if (CompareText(TargetOS,'win32')=0) or (CompareText(TargetOS,'win64')=0) or (CompareText(TargetOS,'wince')=0) then Result:='win'; end; function GetDefaultSrcOS2ForTargetOS(const TargetOS: string): string; begin Result:=''; if (CompareText(TargetOS,'freebsd')=0) or (CompareText(TargetOS,'netbsd')=0) or (CompareText(TargetOS,'openbsd')=0) or (CompareText(TargetOS,'dragonfly')=0) or (CompareText(TargetOS,'darwin')=0) then Result:='bsd' else if (CompareText(TargetOS,'android')=0) then Result:='linux'; end; function GetDefaultSrcCPUForTargetCPU(const TargetCPU: string): string; begin Result:=''; if (CompareText(TargetCPU,'i386')=0) or (CompareText(TargetCPU,'x86_64')=0) then Result:='x86'; end; procedure SplitLazarusCPUOSWidgetCombo(const Combination: string; out CPU, OS, WidgetSet: string); var StartPos, EndPos: integer; begin StartPos:=1; EndPos:=StartPos; while (EndPos<=length(Combination)) and (Combination[EndPos]<>'-') do inc(EndPos); CPU:=copy(Combination,StartPos,EndPos-StartPos); StartPos:=EndPos+1; EndPos:=StartPos; while (EndPos<=length(Combination)) and (Combination[EndPos]<>'-') do inc(EndPos); OS:=copy(Combination,StartPos,EndPos-StartPos); StartPos:=EndPos+1; EndPos:=StartPos; while (EndPos<=length(Combination)) and (Combination[EndPos]<>'-') do inc(EndPos); WidgetSet:=copy(Combination,StartPos,EndPos-StartPos); end; function GetCompiledFPCVersion: integer; begin Result:=FPCVersionToNumber({$I %FPCVERSION%}); end; function GetCompiledTargetOS: string; begin Result:=lowerCase({$I %FPCTARGETOS%}); end; function GetCompiledTargetCPU: string; begin Result:=lowerCase({$I %FPCTARGETCPU%}); end; function GetDefaultCompilerFilename(const TargetCPU: string; Cross: boolean): string; begin if Cross then {$ifdef darwin} Result:='ppc' // the mach-o format supports "fat" binaries whereby // a single executable contains machine code for several architectures {$else} Result:='ppcross' {$endif} else Result:='ppc'; if TargetCPU='' then Result:='fpc' else if SysUtils.CompareText(TargetCPU,'i386')=0 then Result:=Result+'386' else if SysUtils.CompareText(TargetCPU,'m68k')=0 then Result:=Result+'86k' else if SysUtils.CompareText(TargetCPU,'alpha')=0 then Result:=Result+'apx' else if SysUtils.CompareText(TargetCPU,'powerpc')=0 then Result:=Result+'ppc' else if SysUtils.CompareText(TargetCPU,'powerpc64')=0 then Result:=Result+'ppc64' else if SysUtils.CompareText(TargetCPU,'arm')=0 then Result:=Result+'arm' else if SysUtils.CompareText(TargetCPU,'avr')=0 then Result:=Result+'avr' else if SysUtils.CompareText(TargetCPU,'sparc')=0 then Result:=Result+'sparc' else if SysUtils.CompareText(TargetCPU,'x86_64')=0 then Result:=Result+'x64' else if SysUtils.CompareText(TargetCPU,'ia64')=0 then Result:=Result+'ia64' else if SysUtils.CompareText(TargetCPU,'aarch64')=0 then Result:=Result+'aarch64' else if SysUtils.CompareText(TargetCPU,'xtensa')=0 then Result:=Result+'xtensa' else Result:='fpc'; Result:=Result+ExeExt; end; procedure GetTargetProcessors(const TargetCPU: string; aList: TStrings); procedure Arm; begin aList.Add('ARMV3'); aList.Add('ARMV4'); aList.Add('ARMV4T'); aList.Add('ARMV5'); aList.Add('ARMV5T'); aList.Add('ARMV5TE'); aList.Add('ARMV5TEJ'); aList.Add('ARMV6'); aList.Add('ARMV6K'); aList.Add('ARMV6T2'); aList.Add('ARMV6Z'); aList.Add('ARMV6M'); aList.Add('ARMV7'); aList.Add('ARMV7A'); aList.Add('ARMV7R'); aList.Add('ARMV7M'); aList.Add('ARMV7EM'); aList.Add('CORTEXM3'); end; procedure Intel_i386; begin aList.Add('80386'); aList.Add('Pentium'); aList.Add('Pentium2'); aList.Add('Pentium3'); aList.Add('Pentium4'); aList.Add('PentiumM'); end; procedure Intel_x86_64; begin aList.Add('ATHLON64'); end; procedure PowerPC; begin aList.Add('604'); aList.Add('750'); aList.Add('7400'); aList.Add('970'); end; procedure PowerPC64; begin //aList.Add('power4'); aList.Add('970'); //aList.Add('power5'); //aList.Add('power5+'); //aList.Add('power6'); //aList.Add('power6x'); //aList.Add('power7'); //aList.Add('power8'); end; procedure Sparc; begin aList.Add('SPARC V7'); aList.Add('SPARC V8'); aList.Add('SPARC V9'); end; procedure Mips; begin aList.Add('mips1'); aList.Add('mips2'); aList.Add('mips3'); aList.Add('mips4'); aList.Add('mips5'); aList.Add('mips32'); aList.Add('mips32r2'); end; procedure AVR; begin aList.Add('AVRTINY'); aList.Add('AVR1'); aList.Add('AVR2'); aList.Add('AVR25'); aList.Add('AVR3'); aList.Add('AVR31'); aList.Add('AVR35'); aList.Add('AVR4'); aList.Add('AVR5'); aList.Add('AVR51'); aList.Add('AVR6'); aList.Add('AVRXMEGA3'); end; procedure M68k; begin aList.Add('68000'); aList.Add('68020'); aList.Add('68040'); aList.Add('68060'); aList.Add('ISAA'); aList.Add('ISAA+'); aList.Add('ISAB'); aList.Add('ISAC'); aList.Add('CFV4'); end; procedure Xtensa; begin aList.Add('lx106'); aList.Add('lx6'); end; begin case TargetCPU of 'arm' : Arm; 'avr' : AVR; 'i386' : Intel_i386; 'm68k' : M68k; 'powerpc' : PowerPC; 'powerpc64': PowerPC64; 'sparc' : Sparc; 'x86_64' : Intel_x86_64; 'mipsel','mips' : Mips; 'jvm' : ; 'aarch64' : ; 'xtensa' : Xtensa; end; end; function GetFPCTargetOS(TargetOS: string): string; begin Result:=lowercase(TargetOS); end; function GetFPCTargetCPU(TargetCPU: string): string; begin Result:=LowerCase(TargetCPU); end; function IsPas2jsTargetOS(TargetOS: string): boolean; begin Result:=(CompareText(TargetOS,'browser')=0) or (CompareText(TargetOS,'nodejs')=0); end; function IsPas2jsTargetCPU(TargetCPU: string): boolean; begin Result:=PosI('ecmascript',TargetCPU)>0; end; function IsCTExecutable(AFilename: string; out ErrorMsg: string): boolean; begin Result:=false; AFilename:=ResolveDots(AFilename); if AFilename='' then begin ErrorMsg:='missing file name'; exit; end; if not FilenameIsAbsolute(AFilename) then begin ErrorMsg:='file missing path'; exit; end; if not FileExistsCached(AFilename) then begin ErrorMsg:='file not found'; exit; end; if DirPathExistsCached(AFilename) then begin ErrorMsg:='file is a directory'; exit; end; if not FileIsExecutableCached(AFilename) then begin ErrorMsg:='file is not executable'; exit; end; ErrorMsg:=''; Result:=true; end; function GuessPascalCompilerFromExeName(Filename: string): TPascalCompiler; var ShortFilename: String; begin ShortFilename:=ExtractFileNameOnly(Filename); // *pas2js* if PosI('pas2js',ShortFilename)>0 then exit(pcPas2js); // dcc*.exe if LazStartsText('dcc',ShortFilename) and ( (ExeExt='') or FilenameExtIs(Filename,ExeExt) ) then exit(pcDelphi); Result:=pcFPC; end; function IsCompilerExecutable(AFilename: string; out ErrorMsg: string; out Kind: TPascalCompiler; Run: boolean): boolean; var ShortFilename, Line: String; Params: TStringList; Lines: TStringList; i: Integer; begin Result:=False; if not IsCTExecutable(AFilename,ErrorMsg) then exit; Kind:=pcFPC; // allow scripts like fpc.sh and fpc.bat ShortFilename:=ExtractFileNameOnly(AFilename); //debugln(['IsCompilerExecutable Short=',ShortFilename]); // check ppc*.exe if CompareText(LeftStr(ShortFilename,3),'ppc')=0 then exit(true); // check pas2js* if CompareText(LeftStr(ShortFilename,6),'pas2js')=0 then begin Kind:=pcPas2js; exit(true); end; // dcc*.exe if (CompareFilenames(LeftStr(ShortFilename,3),'dcc')=0) and ( (ExeExt='') or FilenameExtIs(AFilename,ExeExt) ) then begin Kind:=pcDelphi; exit(true); end; if Run then begin // run it and check for magics debugln(['Note: (lazarus) [IsCompilerExecutable] run "',AFilename,'"']); Params:=TStringList.Create; Lines:=nil; try Params.Add('-va'); Lines:=RunTool(AFilename,Params); if Lines<>nil then begin for i:=0 to Lines.Count-1 do begin Line:=Lines[i]; if Pos('fpc.cfg',Line)>0 then begin Kind:=pcFPC; exit(true); end; if Pos('pas2js.cfg',Line)>0 then begin Kind:=pcPas2js; exit(true); end; end; ErrorMsg:='Compiler -va does neither search for fpc.cfg nor pas2js.cfg. This is neither fpc nor pas2js.'; exit; end; finally Params.Free; Lines.Free; end; end; // check fpc // Note: fpc.exe is just a wrapper, it can call pas2js if CompareFilenames(LeftStr(ShortFilename,3),'fpc')=0 then exit(true); ErrorMsg:='fpc executable should start with fpc or ppc'; end; function IsFPCExecutable(AFilename: string; out ErrorMsg: string; Run: boolean ): boolean; var ShortFilename: String; Kind: TPascalCompiler; begin if Run then begin Result:=IsCompilerExecutable(AFilename,ErrorMsg,Kind,true) and (Kind=pcFPC); exit; end; Result:=IsCTExecutable(AFilename,ErrorMsg); if not Result then exit; // allow scripts like fpc*.sh and fpc*.bat ShortFilename:=ExtractFileNameOnly(AFilename); //debugln(['IsFPCExecutable Short=',ShortFilename]); if LazStartsText('fpc',ShortFilename) then exit(true); // allow ppcxxx.exe if (LazStartsText('ppc',ShortFilename)) and ( (ExeExt='') or FilenameExtIs(AFilename,ExeExt) ) then exit(true); ErrorMsg:='fpc executable should start with fpc or ppc'; end; function IsPas2JSExecutable(AFilename: string; out ErrorMsg: string; Run: boolean): boolean; var ShortFilename: String; Kind: TPascalCompiler; begin if Run then begin Result:=IsCompilerExecutable(AFilename,ErrorMsg,Kind,true) and (Kind=pcPas2js); exit; end; Result:=IsCTExecutable(AFilename,ErrorMsg); if not Result then exit; // allow scripts like *pas2js* ShortFilename:=ExtractFileNameOnly(AFilename); if PosI('pas2js',ShortFilename)>0 then exit(true); ErrorMsg:='pas2js executable should start with pas2js'; end; function CreateDefinesInDirectories(const SourcePaths, FlagName: string ): TDefineTemplate; var StartPos: Integer; EndPos: LongInt; CurDirectory: String; DirsTempl: TDefineTemplate; DirTempl: TDefineTemplate; SetFlagTempl: TDefineTemplate; begin // create a block template for the directories DirsTempl:=TDefineTemplate.Create(FlagName, 'Block of directories to set '+FlagName, '','',da_Block); // create a define flag for every directory StartPos:=1; while StartPos<=length(SourcePaths) do begin EndPos:=StartPos; while (EndPos<=length(SourcePaths)) and (SourcePaths[EndPos]<>';') do inc(EndPos); if EndPos>StartPos then begin CurDirectory:=copy(SourcePaths,StartPos,EndPos-StartPos); DirTempl:=TDefineTemplate.Create('FlagDirectory','FlagDirectory', '',CurDirectory,da_Directory); SetFlagTempl:=TDefineTemplate.Create(FlagName,FlagName, FlagName,'1',da_Define); DirTempl.AddChild(SetFlagTempl); DirsTempl.AddChild(DirTempl); end; StartPos:=EndPos+1; end; Result:=DirsTempl; end; procedure InitDefaultFPCSourceRules; begin DefaultFPCSourceRules:=TFPCSourceRules.Create; with DefaultFPCSourceRules do begin // put into an include file for easy edit via an editor {$I fpcsrcrules.inc} end; end; { TDefineTemplate } procedure TDefineTemplate.MarkFlags( const MustFlags, NotFlags: TDefineTemplateFlags; WithSiblings, WithChilds: boolean); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin ANode.FMarked:=ANode.FMarked or (((ANode.Flags*MustFlags)=MustFlags) and (ANode.Flags*NotFlags=[])); if (ANode.FirstChild<>nil) and WithChilds then ANode.FirstChild.MarkFlags(MustFlags,NotFlags,true,true); if not WithSiblings then break; ANode:=ANode.Next; end; end; procedure TDefineTemplate.MarkOwnedBy(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags; WithSiblings, WithChilds: boolean); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin ANode.FMarked:=ANode.FMarked or ((ANode.Owner=TheOwner) and ((ANode.Flags*MustFlags)=MustFlags) and (ANode.Flags*NotFlags=[])); if (ANode.FirstChild<>nil) and WithChilds then ANode.FirstChild.MarkOwnedBy(TheOwner,MustFlags,NotFlags,true,true); if not WithSiblings then break; ANode:=ANode.Next; end; end; procedure TDefineTemplate.MarkNodes(WithSiblings, WithChilds: boolean); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin ANode.FMarked:=true; if (ANode.FirstChild<>nil) and WithChilds then ANode.FirstChild.MarkNodes(true,true); if not WithSiblings then break; ANode:=ANode.Next; end; end; procedure TDefineTemplate.ReverseMarks(WithSiblings, WithChilds: boolean); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin ANode.FMarked:=not ANode.FMarked; if (ANode.FirstChild<>nil) and WithChilds then ANode.FirstChild.MarkNodes(true,true); if not WithSiblings then break; ANode:=ANode.Next; end; end; procedure TDefineTemplate.InheritMarks(WithSiblings, WithChilds, Down, Up: boolean); var ANode: TDefineTemplate; ChildNode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin if WithChilds then begin ChildNode:=ANode.FirstChild; while ChildNode<>nil do begin if Down and ANode.FMarked then ChildNode.FMarked:=true; ChildNode.InheritMarks(false,true,Down,Up); if Up and ChildNode.FMarked then ANode.FMarked:=true; ChildNode:=ChildNode.Next; end; end; if not WithSiblings then break; ANode:=ANode.Next; end; end; procedure TDefineTemplate.UnmarkNodes(WithSiblings, WithChilds: boolean); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin ANode.FMarked:=false; if (ANode.FirstChild<>nil) and WithChilds then ANode.FirstChild.UnmarkNodes(true,true); if not WithSiblings then break; ANode:=ANode.Next; end; end; procedure TDefineTemplate.RemoveMarked(WithSiblings: boolean; var FirstDefTemplate: TDefineTemplate); var ANode, NextNode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin NextNode:=ANode.Next; if ANode.FirstChild<>nil then begin ANode.FirstChild.RemoveMarked(true,FirstDefTemplate); end; if ANode.FMarked and (ANode.FirstChild=nil) then begin if ANode=FirstDefTemplate then FirstDefTemplate:=ANode.Next; ANode.Unbind; ANode.Free; end; if not WithSiblings then break; ANode:=NextNode; end; end; procedure TDefineTemplate.RemoveOwner(TheOwner: TObject; WithSiblings: boolean); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin if ANode.FFirstChild<>nil then ANode.FFirstChild.RemoveOwner(TheOwner,true); if ANode.Owner=TheOwner then ANode.Owner:=nil; if not WithSiblings then break; ANode:=ANode.Next; end; end; procedure TDefineTemplate.RemoveLeaves(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags; WithSiblings: boolean; var FirstDefTemplate: TDefineTemplate); var ANode, NextNode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin NextNode:=ANode.Next; if ANode.FirstChild<>nil then ANode.FirstChild.RemoveLeaves(TheOwner,MustFlags,NotFlags,true, FirstDefTemplate); if ANode.FirstChild=nil then begin // this is a leaf if ((ANode.Owner=TheOwner) and ((ANode.Flags*MustFlags)=MustFlags) and (ANode.Flags*NotFlags=[])) then begin if ANode=FirstDefTemplate then FirstDefTemplate:=ANode.Next; ANode.Unbind; ANode.Free; end; end; if not WithSiblings then break; ANode:=NextNode; end; end; procedure TDefineTemplate.AddChild(ADefineTemplate: TDefineTemplate); // add as last child begin if ADefineTemplate=nil then exit; if ADefineTemplate.Parent<>nil then raise Exception.Create('TDefineTemplate.AddChild'); if LastChild=nil then begin while ADefineTemplate<>nil do begin ADefineTemplate.fParent:=Self; if ADefineTemplate.Prior=nil then FFirstChild:=ADefineTemplate; if ADefineTemplate.Next=nil then FLastChild:=ADefineTemplate; inc(FChildCount); ADefineTemplate:=ADefineTemplate.Next; end; end else begin ADefineTemplate.InsertBehind(LastChild); end; end; procedure TDefineTemplate.ReplaceChild(ADefineTemplate: TDefineTemplate); var OldTempl: TDefineTemplate; begin OldTempl:=FindChildByName(ADefineTemplate.Name); if OldTempl<>nil then begin ADefineTemplate.InsertInFront(OldTempl); OldTempl.UnBind; OldTempl.Free; end else AddChild(ADefineTemplate); end; function TDefineTemplate.DeleteChild(const AName: string): boolean; var OldTempl: TDefineTemplate; begin OldTempl:=FindChildByName(AName); if OldTempl<>nil then begin Result:=true; OldTempl.Unbind; OldTempl.Free; end else Result:=false; end; procedure TDefineTemplate.InsertBehind(APrior: TDefineTemplate); // insert this and all next siblings behind APrior var ANode, LastSibling, NewParent: TDefineTemplate; begin if APrior=nil then exit; NewParent:=APrior.Parent; if Parent<>nil then begin ANode:=Self; while ANode<>nil do begin if ANode=APrior then raise Exception.Create('internal error: ' +'TDefineTemplate.InsertBehind: APrior=ANode'); dec(Parent.FChildCount); ANode.FParent:=nil; ANode:=ANode.Next; end; end; LastSibling:=Self; while LastSibling.Next<>nil do LastSibling:=LastSibling.Next; FParent:=NewParent; if Parent<>nil then begin ANode:=Self; while (ANode<>nil) do begin ANode.FParent:=Parent; inc(Parent.FChildCount); ANode:=ANode.Next; end; if Parent.LastChild=APrior then Parent.FLastChild:=LastSibling; end; FPrior:=APrior; LastSibling.FNext:=APrior.Next; APrior.FNext:=Self; if LastSibling.Next<>nil then LastSibling.Next.FPrior:=LastSibling; end; procedure TDefineTemplate.InsertInFront(ANext: TDefineTemplate); // insert this and all next siblings in front of ANext var ANode, LastSibling: TDefineTemplate; begin if ANext=nil then exit; if FParent<>nil then begin ANode:=Self; while ANode<>nil do begin if ANode=ANext then raise Exception.Create('internal error: ' +'TDefineTemplate.InsertInFront: ANext=ANode'); dec(FParent.FChildCount); ANode.FParent:=nil; ANode:=ANode.Next; end; end; LastSibling:=Self; while LastSibling.Next<>nil do LastSibling:=LastSibling.Next; FParent:=ANext.Parent; if Parent<>nil then begin ANode:=Self; while ANode<>nil do begin ANode.FParent:=Parent; inc(Parent.FChildCount); ANode:=ANode.Next; end; if Parent.FirstChild=ANext then Parent.FFirstChild:=Self; end; FPrior:=ANext.Prior; if Prior<>nil then Prior.FNext:=Self; LastSibling.FNext:=ANext; ANext.FPrior:=LastSibling; end; procedure TDefineTemplate.MoveToLast(Child: TDefineTemplate); var Node: TDefineTemplate; begin if Child.Next=nil then exit; Node:=Child.Next; while Node.Next<>nil do Node:=Node.Next; Child.Unbind; Child.InsertBehind(Node); end; procedure TDefineTemplate.Assign(ADefineTemplate: TDefineTemplate; WithSubNodes, WithNextSiblings, ClearOldSiblings: boolean); var ChildTemplate, CopyTemplate, NextTemplate: TDefineTemplate; begin Clear(ClearOldSiblings); if ADefineTemplate=nil then exit; AssignValues(ADefineTemplate); if WithSubNodes then begin ChildTemplate:=ADefineTemplate.FirstChild; if ChildTemplate<>nil then begin CopyTemplate:=TDefineTemplate.Create; AddChild(CopyTemplate); CopyTemplate.Assign(ChildTemplate,true,true,false); end; end; if WithNextSiblings then begin NextTemplate:=ADefineTemplate.Next; if NextTemplate<>nil then begin CopyTemplate:=TDefineTemplate.Create; CopyTemplate.InsertBehind(Self); CopyTemplate.Assign(NextTemplate,WithSubNodes,true,false); end; end; end; procedure TDefineTemplate.AssignValues(ADefineTemplate: TDefineTemplate); begin Name:=ADefineTemplate.Name; Description:=ADefineTemplate.Description; Variable:=ADefineTemplate.Variable; Value:=ADefineTemplate.Value; Action:=ADefineTemplate.Action; Flags:=ADefineTemplate.Flags; MergeNameInFront:=ADefineTemplate.MergeNameInFront; MergeNameBehind:=ADefineTemplate.MergeNameBehind; Owner:=ADefineTemplate.Owner; end; procedure TDefineTemplate.Unbind; begin if FPrior<>nil then FPrior.FNext:=FNext; if FNext<>nil then FNext.FPrior:=FPrior; if FParent<>nil then begin if FParent.FFirstChild=Self then FParent.FFirstChild:=FNext; if FParent.FLastChild=Self then FParent.FLastChild:=FPrior; dec(FParent.FChildCount); end; FNext:=nil; FPrior:=nil; FParent:=nil; end; procedure TDefineTemplate.Clear(WithSiblings: boolean); begin while FFirstChild<>nil do FFirstChild.Free; if WithSiblings then while FNext<>nil do FNext.Free; Name:=''; Description:=''; Value:=''; Variable:=''; Flags:=[]; end; constructor TDefineTemplate.Create; begin inherited Create; end; constructor TDefineTemplate.Create(const AName, ADescription, AVariable, AValue: string; AnAction: TDefineAction); begin inherited Create; Name:=AName; Description:=ADescription; Variable:=AVariable; Value:=AValue; Action:=AnAction; end; function TDefineTemplate.CreateCopy(OnlyMarked: boolean; WithSiblings: boolean; WithChilds: boolean): TDefineTemplate; var LastNewNode, NewNode, ANode: TDefineTemplate; begin Result:=nil; LastNewNode:=nil; ANode:=Self; while ANode<>nil do begin if (not OnlyMarked) or (ANode.FMarked) then begin // copy node NewNode:=TDefineTemplate.Create; NewNode.Assign(ANode,false,false,false); if LastNewNode<>nil then NewNode.InsertBehind(LastNewNode) else Result:=NewNode; LastNewNode:=NewNode; // copy children if WithChilds and (ANode.FirstChild<>nil) then begin NewNode:=ANode.FirstChild.CreateCopy(OnlyMarked,true,true); if NewNode<>nil then LastNewNode.AddChild(NewNode); end; end; if not WithSiblings then break; ANode:=ANode.Next; end; end; function TDefineTemplate.CreateMergeCopy: TDefineTemplate; begin CreateMergeInfo(false,false); Result:=TDefineTemplate.Create; Result.Assign(Self,true,false,false); end; function TDefineTemplate.FindRoot: TDefineTemplate; begin Result:=Self; repeat if Result.Parent<>nil then Result:=Result.Parent else if Result.Prior<>nil then Result:=Result.Prior else break; until false; end; destructor TDefineTemplate.Destroy; begin Clear(false); Unbind; inherited Destroy; end; function TDefineTemplate.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string; ClearOldSiblings, WithMergeInfo: boolean): boolean; var IndexedPath: string; i, LvlCount: integer; DefTempl, LastDefTempl: TDefineTemplate; NewChild: TDefineTemplate; begin Clear(ClearOldSiblings); LvlCount:=XMLConfig.GetValue(Path+'Count/Value',0); DefTempl:=nil; for i:=1 to LvlCount do begin if i=1 then begin DefTempl:=Self; LastDefTempl:=Prior; end else begin LastDefTempl:=DefTempl; DefTempl:=TDefineTemplate.Create; DefTempl.InsertBehind(LastDefTempl); end; IndexedPath:=Path+'Node'+IntToStr(i)+'/'; DefTempl.LoadValuesFromXMLConfig(XMLConfig,IndexedPath,WithMergeInfo); // load children if XMLConfig.GetValue(IndexedPath+'Count/Value',0)>0 then begin NewChild:=TDefineTemplate.Create; DefTempl.AddChild(NewChild); if not NewChild.LoadFromXMLConfig(XMLConfig,IndexedPath, false,WithMergeInfo) then begin Result:=false; exit; end; end; end; Result:=true; end; procedure TDefineTemplate.LoadValuesFromXMLConfig(XMLConfig: TXMLConfig; const Path: string; WithMergeInfo: boolean); var f: TDefineTemplateFlag; begin Name:=XMLConfig.GetValue(Path+'Name/Value','no name'); Description:=XMLConfig.GetValue(Path+'Description/Value',''); Value:=XMLConfig.GetValue(Path+'Value/Value',''); Variable:=XMLConfig.GetValue(Path+'Variable/Value',''); Action:=DefineActionNameToAction( XMLConfig.GetValue(Path+'Action/Value','')); Flags:=[]; for f:=Low(TDefineTemplateFlag) to High(TDefineTemplateFlag) do begin if (f<>dtfAutoGenerated) and (XMLConfig.GetValue(Path+'Flags/'+DefineTemplateFlagNames[f],false)) then Include(Flags,f); end; if WithMergeInfo then begin MergeNameInFront:=XMLConfig.GetValue(Path+'MergeNameInFront/Value',''); MergeNameBehind:=XMLConfig.GetValue(Path+'MergeNameInFront/Value',''); end else begin MergeNameInFront:=''; MergeNameBehind:=''; end; end; procedure TDefineTemplate.SaveValuesToXMLConfig(XMLConfig: TXMLConfig; const Path: string; WithMergeInfo: boolean); var f: TDefineTemplateFlag; begin XMLConfig.SetDeleteValue(Path+'Name/Value',Name,''); XMLConfig.SetDeleteValue(Path+'Description/Value',Description,''); XMLConfig.SetDeleteValue(Path+'Value/Value',Value,''); XMLConfig.SetDeleteValue(Path+'Variable/Value',Variable,''); XMLConfig.SetDeleteValue(Path+'Action/Value', DefineActionNames[Action], DefineActionNames[da_None]); for f:=Low(TDefineTemplateFlag) to High(TDefineTemplateFlag) do begin if (f<>dtfAutoGenerated) then XMLConfig.SetDeleteValue( Path+'Flags/'+DefineTemplateFlagNames[f] ,f in Flags,false); end; if WithMergeInfo then begin XMLConfig.SetDeleteValue(Path+'MergeNameInFront/Value', MergeNameInFront,''); XMLConfig.SetDeleteValue(Path+'MergeNameBehind/Value', MergeNameBehind,''); end else begin XMLConfig.SetDeleteValue(Path+'MergeNameInFront/Value','',''); XMLConfig.SetDeleteValue(Path+'MergeNameBehind/Value','',''); end; end; procedure TDefineTemplate.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string; WithSiblings, OnlyMarked, WithMergeInfo, UpdateMergeInfo: boolean); var IndexedPath: string; Index, LvlCount: integer; DefTempl: TDefineTemplate; begin if UpdateMergeInfo then CreateMergeInfo(WithSiblings,OnlyMarked); DefTempl:=Self; LvlCount:=0; while DefTempl<>nil do begin inc(LvlCount); DefTempl:=DefTempl.Next; end; DefTempl:=Self; Index:=0; repeat if (DefTempl.FMarked) or (not OnlyMarked) then begin // save node inc(Index); IndexedPath:=Path+'Node'+IntToStr(Index)+'/'; DefTempl.SaveValuesToXMLConfig(XMLConfig,IndexedPath,WithMergeInfo); // save children if DefTempl.FFirstChild<>nil then DefTempl.FirstChild.SaveToXMLConfig(XMLConfig,IndexedPath, true,OnlyMarked, WithMergeInfo,false) else XMLConfig.SetDeleteValue(IndexedPath+'Count/Value',0,0); end; if not WithSiblings then break; DefTempl:=DefTempl.Next; until DefTempl=nil; XMLConfig.SetDeleteValue(Path+'Count/Value',Index,0); end; procedure TDefineTemplate.CreateMergeInfo(WithSiblings, OnlyMarked: boolean); var DefTempl: TDefineTemplate; begin DefTempl:=Self; repeat if (DefTempl.FMarked) or (not OnlyMarked) then begin if DefTempl.Prior<>nil then DefTempl.MergeNameInFront:=DefTempl.Prior.Name else DefTempl.MergeNameInFront:=''; if DefTempl.Next<>nil then DefTempl.MergeNameBehind:=DefTempl.Next.Name else DefTempl.MergeNameBehind:=''; // update children if DefTempl.FFirstChild<>nil then DefTempl.FirstChild.CreateMergeInfo(true,OnlyMarked); end; if not WithSiblings then break; DefTempl:=DefTempl.Next; until DefTempl=nil; end; class procedure TDefineTemplate.MergeXMLConfig(ParentDefTempl: TDefineTemplate; var FirstSibling, LastSibling: TDefineTemplate; XMLConfig: TXMLConfig; const Path, NewNamePrefix: string); var SrcNode: TDefineTemplate; begin SrcNode:=TDefineTemplate.Create; SrcNode.LoadFromXMLConfig(XMLConfig,Path,false,true); MergeTemplates(ParentDefTempl,FirstSibling,LastSibling,SrcNode,true, NewNamePrefix); SrcNode.Clear(true); SrcNode.Free; end; class procedure TDefineTemplate.MergeTemplates(ParentDefTempl: TDefineTemplate; var FirstSibling, LastSibling: TDefineTemplate; SourceTemplate: TDefineTemplate; WithSiblings: boolean; const NewNamePrefix: string); // merge SourceTemplate. This will keep SourceTemplate untouched var NewNode, PosNode: TDefineTemplate; Inserted: boolean; SrcNode: TDefineTemplate; begin SrcNode:=SourceTemplate; while SrcNode<>nil do begin // merge all source nodes NewNode:=SrcNode.CreateCopy(false,false,false); Inserted:=false; if NewNode.Name<>'' then begin // node has a name -> test if already exists PosNode:=FirstSibling; while (PosNode<>nil) and (CompareText(PosNode.Name,NewNode.Name)<>0) do PosNode:=PosNode.Next; if PosNode<>nil then begin // node with same name already exists -> check if it is a copy if NewNode.IsEqual(PosNode,false,false) then begin // node already exists NewNode.Free; NewNode:=PosNode; end else begin // node has same name, but different values // -> rename node NewNode.Name:=NewNode.FindUniqueName(NewNamePrefix+NewNode.Name); // insert behind PosNode NewNode.InsertBehind(PosNode); end; Inserted:=true; end; end; if not Inserted then begin // node name is unique or empty -> insert node if NewNode.MergeNameInFront<>'' then begin // last time, node was inserted behind MergeNameInFront // -> search MergeNameInFront PosNode:=LastSibling; while (PosNode<>nil) and (CompareText(PosNode.Name,NewNode.MergeNameInFront)<>0) do PosNode:=PosNode.Prior; if PosNode<>nil then begin // MergeNameInFront found -> insert behind NewNode.InsertBehind(PosNode); Inserted:=true; end; end; if not Inserted then begin if NewNode.MergeNameBehind<>'' then begin // last time, node was inserted in front of MergeNameBehind // -> search MergeNameBehind PosNode:=FirstSibling; while (PosNode<>nil) and (CompareText(PosNode.Name,NewNode.MergeNameBehind)<>0) do PosNode:=PosNode.Next; if PosNode<>nil then begin // MergeNameBehind found -> insert in front NewNode.InsertInFront(PosNode); Inserted:=true; end; end; end; if not Inserted then begin // no merge position found -> add as last if LastSibling<>nil then begin NewNode.InsertBehind(LastSibling); end else if ParentDefTempl<>nil then begin ParentDefTempl.AddChild(NewNode); end; end; end; // NewNode is now inserted -> update FirstSibling and LastSibling if FirstSibling=nil then begin FirstSibling:=NewNode; LastSibling:=NewNode; end; while FirstSibling.Prior<>nil do FirstSibling:=FirstSibling.Prior; while LastSibling.Next<>nil do LastSibling:=LastSibling.Next; // merge children MergeTemplates(NewNode,NewNode.FFirstChild,NewNode.FLastChild, SrcNode.FirstChild,true,NewNamePrefix); if not WithSiblings then break; SrcNode:=SrcNode.Next; end; end; procedure TDefineTemplate.ConsistencyCheck; var RealChildCount: integer; DefTempl: TDefineTemplate; begin RealChildCount:=0; DefTempl:=FFirstChild; if DefTempl<>nil then begin if DefTempl.Prior<>nil then begin // not first child RaiseCatchableException(''); end; while DefTempl<>nil do begin if DefTempl.Parent<>Self then begin DebugLn(' C: DefTempl.Parent<>Self: ',Name,',',DefTempl.Name); RaiseCatchableException(''); end; if (DefTempl.Next<>nil) and (DefTempl.Next.Prior<>DefTempl) then RaiseCatchableException(''); if (DefTempl.Prior<>nil) and (DefTempl.Prior.Next<>DefTempl) then RaiseCatchableException(''); DefTempl.ConsistencyCheck; DefTempl:=DefTempl.Next; inc(RealChildCount); end; end; if (Parent<>nil) then begin if (Prior=nil) and (Parent.FirstChild<>Self) then RaiseCatchableException(''); if (Next=nil) and (Parent.LastChild<>Self) then RaiseCatchableException(''); end; if RealChildCount<>FChildCount then RaiseCatchableException(''); end; procedure TDefineTemplate.CalcMemSize(Stats: TCTMemStats); var Child: TDefineTemplate; begin Stats.Add('TDefineTemplate Instance Count',1); Stats.Add('TDefineTemplate', PtrUInt(InstanceSize) +MemSizeString(FMergeNameBehind) +MemSizeString(FMergeNameInFront) +MemSizeString(Name) +MemSizeString(Description) +MemSizeString(Variable) +MemSizeString(Value) +MemSizeString(Value) ); Child:=FFirstChild; while Child<>nil do begin Child.CalcMemSize(Stats); Child:=Child.Next; end; end; procedure TDefineTemplate.SetDefineOwner(NewOwner: TObject; WithSiblings: boolean); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin ANode.Owner:=NewOwner; if ANode.FFirstChild<>nil then ANode.FFirstChild.SetDefineOwner(NewOwner,true); if not WithSiblings then exit; ANode:=ANode.Next; end; end; procedure TDefineTemplate.SetFlags(AddFlags, SubFlags: TDefineTemplateFlags; WithSiblings: boolean); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin ANode.Flags:=ANode.Flags+AddFlags-SubFlags; if ANode.FFirstChild<>nil then ANode.FFirstChild.SetFlags(AddFlags,SubFlags,true); if not WithSiblings then exit; ANode:=ANode.Next; end; end; procedure TDefineTemplate.WriteDebugReport(OnlyMarked: boolean); procedure WriteNode(ANode: TDefineTemplate; const Prefix: string); var ActionStr: string; begin if ANode=nil then exit; if (not OnlyMarked) or (ANode.Marked) then begin ActionStr:=DefineActionNames[ANode.Action]; DebugLn(Prefix+'Self='+DbgS(ANode), ' Name="'+ANode.Name,'"', ' Next='+DbgS(ANode.Next), ' Prior='+DbgS(ANode.Prior), ' Action='+ActionStr, ' Flags=['+DefineTemplateFlagsToString(ANode.Flags),']', ' Marked='+dbgs(ANode.Marked) ); DebugLn(Prefix+' + Description="',ANode.Description,'"'); DebugLn(Prefix+' + Variable="',ANode.Variable,'"'); DebugLn(Prefix+' + Value="',ANode.Value,'"'); end; WriteNode(ANode.FirstChild,Prefix+' '); WriteNode(ANode.Next,Prefix); end; begin WriteNode(Self,' '); end; function TDefineTemplate.GetNext: TDefineTemplate; begin if FirstChild<>nil then exit(FirstChild); Result:=GetNextSkipChildren; end; function TDefineTemplate.GetNextSkipChildren: TDefineTemplate; begin Result:=Self; while (Result<>nil) do begin if Result.Next<>nil then begin Result:=Result.Next; exit; end; Result:=Result.Parent; end; end; function TDefineTemplate.HasDefines(OnlyMarked, WithSiblings: boolean): boolean; var CurTempl: TDefineTemplate; begin Result:=true; CurTempl:=Self; while CurTempl<>nil do begin if ((not OnlyMarked) or (CurTempl.FMarked)) and (CurTempl.Action in DefineActionDefines) then exit; // go to next if CurTempl.FFirstChild<>nil then CurTempl:=CurTempl.FFirstChild else if (CurTempl.FNext<>nil) and (WithSiblings or (CurTempl.Parent<>Parent)) then CurTempl:=CurTempl.FNext else begin // search uncle repeat CurTempl:=CurTempl.Parent; if (CurTempl=Parent) or ((CurTempl.Parent=Parent) and not WithSiblings) then begin Result:=false; exit; end; until (CurTempl.FNext<>nil); CurTempl:=CurTempl.FNext; end; end; Result:=false; end; function TDefineTemplate.IsEqual(ADefineTemplate: TDefineTemplate; CheckSubNodes, CheckNextSiblings: boolean): boolean; var SrcNode, DestNode: TDefineTemplate; begin Result:=(ADefineTemplate<>nil) and (Name=ADefineTemplate.Name) and (Description=ADefineTemplate.Description) and (Variable=ADefineTemplate.Variable) and (Value=ADefineTemplate.Value) and (Action=ADefineTemplate.Action) and (Flags=ADefineTemplate.Flags) and (Owner=ADefineTemplate.Owner); if not Result then begin exit; end; if CheckSubNodes then begin if (ChildCount<>ADefineTemplate.ChildCount) then begin Result:=false; exit; end; SrcNode:=FirstChild; DestNode:=ADefineTemplate.FirstChild; if SrcNode<>nil then begin Result:=SrcNode.IsEqual(DestNode,CheckSubNodes,true); if not Result then exit; end; end; if CheckNextSiblings then begin SrcNode:=Next; DestNode:=ADefineTemplate.Next; while (SrcNode<>nil) and (DestNode<>nil) do begin Result:=SrcNode.IsEqual(DestNode,CheckSubNodes,false); if not Result then exit; SrcNode:=SrcNode.Next; DestNode:=DestNode.Next; end; Result:=(SrcNode=nil) and (DestNode=nil); if not Result then begin //DebugLn('TDefineTemplate.IsEqual DIFF 3 ',Name,' ', // ADefineTemplate.Name,' ',dbgs(ChildCount),' ',dbgs(ADefineTemplate.ChildCount)); end; end; end; function TDefineTemplate.IsAutoGenerated: boolean; begin Result:=SelfOrParentContainsFlag(dtfAutoGenerated); end; procedure TDefineTemplate.RemoveFlags(TheFlags: TDefineTemplateFlags); var ANode: TDefineTemplate; begin ANode:=Self; while ANode<>nil do begin Flags:=Flags-TheFlags; if FirstChild<>nil then FirstChild.RemoveFlags(TheFlags); ANode:=ANode.Next; end; end; function TDefineTemplate.Level: integer; var ANode: TDefineTemplate; begin Result:=-1; ANode:=Self; while ANode<>nil do begin inc(Result); ANode:=ANode.Parent; end; end; function TDefineTemplate.GetFirstSibling: TDefineTemplate; begin Result:=Self; while Result.Prior<>nil do Result:=Result.Prior; end; function TDefineTemplate.SelfOrParentContainsFlag( AFlag: TDefineTemplateFlag): boolean; var Node: TDefineTemplate; begin Node:=Self; while (Node<>nil) do begin if AFlag in Node.Flags then begin Result:=true; exit; end; Node:=Node.Parent; end; Result:=false; end; function TDefineTemplate.FindChildByName(const AName: string): TDefineTemplate; begin if FirstChild<>nil then begin Result:=FirstChild.FindByName(AName,false,true) end else Result:=nil; end; function TDefineTemplate.FindByName(const AName: string; WithSubChilds, WithNextSiblings: boolean): TDefineTemplate; var ANode: TDefineTemplate; begin if CompareText(AName,Name)=0 then begin Result:=Self; end else begin if WithSubChilds and (FirstChild<>nil) then Result:=FirstChild.FindByName(AName,true,true) else Result:=nil; if (Result=nil) and WithNextSiblings then begin ANode:=Next; while (ANode<>nil) do begin Result:=ANode.FindByName(AName,WithSubChilds,false); if Result<>nil then break; ANode:=ANode.Next; end; end; end; end; function TDefineTemplate.FindUniqueName(const Prefix: string): string; var Root: TDefineTemplate; i: integer; begin Root:=FindRoot; i:=0; repeat inc(i); Result:=Prefix+IntToStr(i); until Root.FindByName(Result,true,true)=nil; end; { TDirectoryDefines } constructor TDirectoryDefines.Create; begin inherited Create; Values:=TExpressionEvaluator.Create; Path:=''; end; destructor TDirectoryDefines.Destroy; begin Values.Free; inherited Destroy; end; procedure TDirectoryDefines.CalcMemSize(Stats: TCTMemStats); begin Stats.Add('TDirectoryDefines',PtrUInt(InstanceSize) +MemSizeString(Path)); if Values<>nil then Stats.Add('TDirectoryDefines.Values',Values.CalcMemSize(false,nil)); end; { TDefineTree } procedure TDefineTree.Clear; begin if FFirstDefineTemplate<>nil then begin FFirstDefineTemplate.Clear(true); FFirstDefineTemplate.Free; FFirstDefineTemplate:=nil; end; ClearCache; end; function TDefineTree.IsEqual(SrcDefineTree: TDefineTree): boolean; begin Result:=false; if SrcDefineTree=nil then exit; if (FFirstDefineTemplate=nil) xor (SrcDefineTree.FFirstDefineTemplate=nil) then exit; if (FFirstDefineTemplate<>nil) and (not FFirstDefineTemplate.IsEqual( SrcDefineTree.FFirstDefineTemplate,true,true)) then exit; Result:=true; end; procedure TDefineTree.Assign(SrcDefineTree: TDefineTree); begin if IsEqual(SrcDefineTree) then exit; Clear; if SrcDefineTree.FFirstDefineTemplate<>nil then begin FFirstDefineTemplate:=TDefineTemplate.Create; FFirstDefineTemplate.Assign(SrcDefineTree.FFirstDefineTemplate, true,true,true); end; end; procedure TDefineTree.AssignNonAutoCreated(SrcDefineTree: TDefineTree); var SrcNonAutoCreated: TDefineTemplate; begin MarkNonAutoCreated; RemoveMarked; SrcNonAutoCreated:=SrcDefineTree.ExtractNonAutoCreated; if SrcNonAutoCreated=nil then exit; //DebugLn('TDefineTree.AssignNonAutoCreated A Front=',SrcNonAutoCreated.MergeNameInFront,' Behind=',SrcNonAutoCreated.MergeNameBehind); MergeTemplates(SrcNonAutoCreated,''); SrcNonAutoCreated.Clear(true); SrcNonAutoCreated.Free; FFirstDefineTemplate.CreateMergeInfo(true,false); //DebugLn('TDefineTree.AssignNonAutoCreated B Front=',FFirstDefineTemplate.MergeNameInFront,' Behind=',FFirstDefineTemplate.MergeNameBehind); end; procedure TDefineTree.ClearCache; begin if (FCache.Count=0) and (FVirtualDirCache=nil) then exit; DoClearCache; end; constructor TDefineTree.Create; begin inherited Create; IncreaseChangeStep; FFirstDefineTemplate:=nil; FCache:=TAVLTree.Create(@CompareDirectoryDefines); FDefineStrings:=TStringTree.Create; FMacroFunctions:=TKeyWordFunctionList.Create('TDefineTree.Create.MacroFunctions'); FMacroFunctions.AddExtended('Ext',nil,@MacroFuncExtractFileExt); FMacroFunctions.AddExtended('PATH',nil,@MacroFuncExtractFilePath); FMacroFunctions.AddExtended('NAME',nil,@MacroFuncExtractFileName); FMacroFunctions.AddExtended('NAMEONLY',nil,@MacroFuncExtractFileNameOnly); FMacroVariables:=TKeyWordFunctionList.Create('TDefineTree.Create.MacroVariables'); end; destructor TDefineTree.Destroy; begin Clear; FMacroVariables.Free; FMacroFunctions.Free; FCache.Free; FreeAndNil(FDefineStrings); inherited Destroy; end; function TDefineTree.GetLastRootTemplate: TDefineTemplate; begin Result:=FFirstDefineTemplate; if Result=nil then exit; while Result.Next<>nil do Result:=Result.Next; end; function TDefineTree.FindDirectoryInCache(const Path: string): TDirectoryDefines; var cmp: integer; ANode: TAVLTreeNode; begin ANode:=FCache.Root; while (ANode<>nil) do begin cmp:=CompareFilenames(Path,TDirectoryDefines(ANode.Data).Path); if cmp<0 then ANode:=ANode.Left else if cmp>0 then ANode:=ANode.Right else break; end; if ANode<>nil then Result:=TDirectoryDefines(ANode.Data) else Result:=nil; end; function TDefineTree.GetDirDefinesForDirectory(const Path: string; WithVirtualDir: boolean): TDirectoryDefines; var ExpPath: String; begin //DebugLn('[TDefineTree.GetDirDefinesForDirectory] "',Path,'"'); if (Path<>'') or (not WithVirtualDir) then begin DoPrepareTree; ExpPath:=AppendPathDelim(TrimFilename(Path)); Result:=FindDirectoryInCache(ExpPath); if Result=nil then begin Result:=TDirectoryDefines.Create; Result.Path:=ExpPath; //DebugLn('[TDefineTree.GetDirDefinesForDirectory] B ',ExpPath,' '); if Calculate(Result) then begin //DebugLn('[TDefineTree.GetDirDefinesForDirectory] C success'); RemoveDoubles(Result); FCache.Add(Result); end else begin Result.Free; Result:=nil; end; end; end else begin Result:=GetDirDefinesForVirtualDirectory; end; end; function TDefineTree.GetDirDefinesForVirtualDirectory: TDirectoryDefines; begin DoPrepareTree; if FVirtualDirCache=nil then begin {$IFDEF VerboseDefineCache} DebugLn('################ TDefineTree.GetDirDefinesForVirtualDirectory'); {$ENDIF} FVirtualDirCache:=TDirectoryDefines.Create; FVirtualDirCache.Path:=VirtualDirectory; if Calculate(FVirtualDirCache) then begin //DebugLn('TDefineTree.GetDirDefinesForVirtualDirectory '); RemoveDoubles(FVirtualDirCache); end else begin FVirtualDirCache.Free; FVirtualDirCache:=nil; end; end; Result:=FVirtualDirCache; end; function TDefineTree.MacroFuncExtractFileExt(Data: Pointer): boolean; var FuncData: PReadFunctionData; begin FuncData:=PReadFunctionData(Data); FuncData^.Result:=ExtractFileExt(FuncData^.Param); Result:=true; end; function TDefineTree.MacroFuncExtractFilePath(Data: Pointer): boolean; var FuncData: PReadFunctionData; begin FuncData:=PReadFunctionData(Data); FuncData^.Result:=ExtractFilePath(FuncData^.Param); Result:=true; end; function TDefineTree.MacroFuncExtractFileName(Data: Pointer): boolean; var FuncData: PReadFunctionData; begin FuncData:=PReadFunctionData(Data); FuncData^.Result:=ExtractFileName(FuncData^.Param); Result:=true; end; function TDefineTree.MacroFuncExtractFileNameOnly(Data: Pointer): boolean; var FuncData: PReadFunctionData; begin FuncData:=PReadFunctionData(Data); FuncData^.Result:=ExtractFileNameOnly(FuncData^.Param); Result:=true; end; procedure TDefineTree.DoClearCache; begin {$IFDEF VerboseDefineCache} DebugLn('TDefineTree.DoClearCache A +++++++++'); {$ENDIF} if FCache<>nil then FCache.FreeAndClear; if FVirtualDirCache<>nil then begin FVirtualDirCache.Free; FVirtualDirCache:=nil; end; IncreaseChangeStep; FDefineStrings.Clear; end; procedure TDefineTree.DoPrepareTree; begin if Assigned(OnPrepareTree) then OnPrepareTree(Self); end; procedure TDefineTree.RemoveMarked; begin if FFirstDefineTemplate=nil then exit; FFirstDefineTemplate.RemoveMarked(true,FFirstDefineTemplate); ClearCache; end; procedure TDefineTree.MarkNonAutoCreated; begin if FFirstDefineTemplate=nil then exit; with FFirstDefineTemplate do begin // clear marks UnmarkNodes(true,true); // mark each non autocreated node MarkFlags([],[dtfAutoGenerated],true,true); // mark every parent with a marked child InheritMarks(true,true,false,true); end; end; function TDefineTree.GetUnitPathForDirectory(const Directory: string): string; var Evaluator: TExpressionEvaluator; begin Evaluator:=GetDefinesForDirectory(Directory,true); if Evaluator<>nil then begin Result:=Evaluator.Variables[UnitPathMacroName]; end else begin Result:=''; end; end; function TDefineTree.GetIncludePathForDirectory(const Directory: string ): string; var Evaluator: TExpressionEvaluator; begin Evaluator:=GetDefinesForDirectory(Directory,true); if Evaluator<>nil then begin Result:=Evaluator.Variables[IncludePathMacroName]; end else begin Result:=''; end; end; function TDefineTree.GetSrcPathForDirectory(const Directory: string): string; var Evaluator: TExpressionEvaluator; begin Evaluator:=GetDefinesForDirectory(Directory,true); if Evaluator<>nil then begin Result:=Evaluator.Variables[SrcPathMacroName]; end else begin Result:=''; end; end; function TDefineTree.GetPPUSrcPathForDirectory(const Directory: string ): string; var Evaluator: TExpressionEvaluator; begin Evaluator:=GetDefinesForDirectory(Directory,true); if Evaluator<>nil then begin Result:=Evaluator.Variables[PPUSrcPathMacroName]; end else begin Result:=''; end; end; function TDefineTree.GetDCUSrcPathForDirectory(const Directory: string): string; var Evaluator: TExpressionEvaluator; begin Evaluator:=GetDefinesForDirectory(Directory,true); if Evaluator<>nil then begin Result:=Evaluator.Variables[DCUSrcPathMacroName]; end else begin Result:=''; end; end; function TDefineTree.GetCompiledSrcPathForDirectory(const Directory: string ): string; var Evaluator: TExpressionEvaluator; begin Evaluator:=GetDefinesForDirectory(Directory,true); if Evaluator<>nil then begin Result:=Evaluator.Variables[CompiledSrcPathMacroName]; end else begin Result:=''; end; end; function TDefineTree.GetDefinesForDirectory( const Path: string; WithVirtualDir: boolean): TExpressionEvaluator; var DirDef: TDirectoryDefines; begin DirDef:=GetDirDefinesForDirectory(Path,WithVirtualDir); if DirDef<>nil then Result:=DirDef.Values else Result:=nil; end; function TDefineTree.GetDefinesForVirtualDirectory: TExpressionEvaluator; var DirDef: TDirectoryDefines; begin DirDef:=GetDirDefinesForVirtualDirectory; if DirDef<>nil then Result:=DirDef.Values else Result:=nil; end; procedure TDefineTree.ReadValue(const DirDef: TDirectoryDefines; const PreValue, CurDefinePath: string; out NewValue: string); var Buffer: PChar; BufferPos: integer; BufferSize: integer; ValuePos: integer; function SearchBracketClose(const s: string; Position:integer): integer; var BracketClose:char; sLen: Integer; begin if s[Position]='(' then BracketClose:=')' else BracketClose:='{'; inc(Position); sLen:=length(s); while (Position<=sLen) and (s[Position]<>BracketClose) do begin if s[Position]=SpecialChar then inc(Position) else if (s[Position] in ['(','{']) then Position:=SearchBracketClose(s,Position); inc(Position); end; Result:=Position; end; function ExecuteMacroFunction(const FuncName, Params: string): string; var FuncData: TReadFunctionData; begin FuncData.Param:=Params; FuncData.Result:=''; FMacroFunctions.DoDataFunction(PChar(Pointer(FuncName)),length(FuncName), @FuncData); Result:=FuncData.Result; end; function ExecuteMacroVariable(var MacroVariable: string): boolean; var FuncData: TReadFunctionData; begin FuncData.Param:=MacroVariable; FuncData.Result:=''; Result:=FMacroVariables.DoDataFunction( PChar(Pointer(MacroVariable)),length(MacroVariable),@FuncData); if Result then MacroVariable:=FuncData.Result; end; procedure GrowBuffer(MinSize: integer); var NewSize: Integer; begin if MinSize<=BufferSize then exit; NewSize:=MinSize*2+100; ReAllocMem(Buffer,NewSize); BufferSize:=NewSize; end; procedure CopyStringToBuffer(const Src: string); begin if Src='' then exit; Move(Src[1],Buffer[BufferPos],length(Src)); inc(BufferPos,length(Src)); end; procedure CopyFromValueToBuffer(Len: integer); begin if Len=0 then exit; Move(NewValue[ValuePos],Buffer[BufferPos],Len); inc(BufferPos,Len); inc(ValuePos,Len); end; function Substitute(const CurValue: string; ValueLen: integer; MacroStart: integer; var MacroEnd: integer): boolean; var MacroFuncNameEnd: Integer; MacroFuncNameLen: Integer; MacroStr: String; MacroFuncName: String; NewMacroLen: Integer; MacroParam: string; OldMacroLen: Integer; Handled: Boolean; MacroVarName: String; begin Result:=false; MacroFuncNameEnd:=MacroEnd; MacroFuncNameLen:=MacroFuncNameEnd-MacroStart-1; MacroEnd:=SearchBracketClose(CurValue,MacroFuncNameEnd)+1; if MacroEnd>ValueLen+1 then exit; OldMacroLen:=MacroEnd-MacroStart; // Macro found if MacroFuncNameLen>0 then begin MacroFuncName:=copy(CurValue,MacroStart+1,MacroFuncNameLen); // Macro function -> substitute macro parameter first ReadValue(DirDef,copy(CurValue,MacroFuncNameEnd+1 ,MacroEnd-MacroFuncNameEnd-2),CurDefinePath,MacroParam); // execute the macro function //debugln('Substitute MacroFuncName="',MacroFuncName,'" MacroParam="',MacroParam,'"'); MacroStr:=ExecuteMacroFunction(MacroFuncName,MacroParam); end else begin // Macro variable MacroVarName:=copy(CurValue,MacroStart+2,MacroEnd-MacroStart-3); MacroStr:=MacroVarName; //DebugLn('**** MacroVarName=',MacroVarName,' ',DirDef.Values.Variables[MacroVarName]); //DebugLn('DirDef.Values=',DirDef.Values.AsString); if MacroVarName=DefinePathMacroName then begin MacroStr:=CurDefinePath; end else if DirDef.Values.IsDefined(MacroVarName) then begin MacroStr:=DirDef.Values.Variables[MacroVarName]; end else begin Handled:=false; if Assigned(FOnReadValue) then begin MacroParam:=MacroVarName; MacroStr:=''; FOnReadValue(Self,MacroParam,MacroStr,Handled); end; if not Handled then begin MacroStr:=MacroVarName; Handled:=ExecuteMacroVariable(MacroStr); end; if not Handled then begin MacroStr:=''; end; end; end; NewMacroLen:=length(MacroStr); GrowBuffer(BufferPos+NewMacroLen-OldMacroLen+ValueLen-ValuePos+1); // copy text between this macro and last macro CopyFromValueToBuffer(MacroStart-ValuePos); // copy macro value to buffer CopyStringToBuffer(MacroStr); ValuePos:=MacroEnd; Result:=true; end; procedure SetNewValue; var RestLen: Integer; begin if Buffer=nil then exit; // write rest to buffer RestLen:=length(NewValue)-ValuePos+1; if RestLen>0 then begin GrowBuffer(BufferPos+RestLen); Move(NewValue[ValuePos],Buffer[BufferPos],RestLen); inc(BufferPos,RestLen); end; // copy the buffer into NewValue //DebugLn(' [ReadValue] Old="',copy(NewValue,1,100),'"'); SetLength(NewValue,BufferPos); if BufferPos>0 then Move(Buffer^,NewValue[1],BufferPos); //DebugLn(' [ReadValue] New="',copy(NewValue,1,100),'"'); // clean up FreeMem(Buffer); Buffer:=nil; end; var MacroStart,MacroEnd: integer; ValueLen: Integer; begin // DebugLn(' [ReadValue] A "',copy(PreValue,1,100),'"'); NewValue:=PreValue; if NewValue='' then exit; MacroStart:=1; ValueLen:=length(NewValue); Buffer:=nil; BufferSize:=0; BufferPos:=0; // position in buffer ValuePos:=1; // same position in value while MacroStart<=ValueLen do begin // search for macro while (MacroStart<=ValueLen) and (NewValue[MacroStart]<>'$') do begin if (NewValue[MacroStart]=SpecialChar) then inc(MacroStart); inc(MacroStart); end; if MacroStart>ValueLen then break; // read macro function name MacroEnd:=MacroStart+1; while (MacroEnd<=ValueLen) and (NewValue[MacroEnd] in ['0'..'9','A'..'Z','a'..'z','_']) do inc(MacroEnd); // read macro name / parameters if (MacroEndnil then SetNewValue; end; procedure TDefineTree.MarkTemplatesOwnedBy(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags); begin if FFirstDefineTemplate=nil then exit; with FFirstDefineTemplate do begin // unmark all nodes UnmarkNodes(true,true); // mark each node in filter MarkOwnedBy(TheOwner,MustFlags,NotFlags,true,true); // mark every parent, that has a marked child InheritMarks(true,true,false,true); end; end; procedure TDefineTree.RemoveTemplatesOwnedBy(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags); begin if FFirstDefineTemplate=nil then exit; FFirstDefineTemplate.RemoveLeaves(TheOwner,MustFlags,NotFlags,true, FFirstDefineTemplate); FFirstDefineTemplate.RemoveOwner(TheOwner,true); ClearCache; end; function TDefineTree.ExtractTemplatesOwnedBy(TheOwner: TObject; const MustFlags, NotFlags: TDefineTemplateFlags): TDefineTemplate; begin Result:=nil; if FFirstDefineTemplate=nil then exit; MarkTemplatesOwnedBy(TheOwner,MustFlags,NotFlags); with FFirstDefineTemplate do begin // store some information, so that merging the nodes will result in old order CreateMergeInfo(true,false); // extract marked nodes Result:=CreateCopy(true,true,true); end; end; function TDefineTree.ExtractNonAutoCreated: TDefineTemplate; begin Result:=nil; if FFirstDefineTemplate=nil then exit; MarkNonAutoCreated; with FFirstDefineTemplate do begin // store some information, so that merging the nodes will result in old order CreateMergeInfo(true,false); // extract marked nodes Result:=CreateCopy(true,true,true); end; end; procedure TDefineTree.MergeTemplates(SourceTemplate: TDefineTemplate; const NewNamePrefix: string); var LastDefTempl: TDefineTemplate; begin LastDefTempl:=GetLastRootTemplate; TDefineTemplate.MergeTemplates(nil,FFirstDefineTemplate,LastDefTempl, SourceTemplate,true,NewNamePrefix); ClearCache; end; function TDefineTree.Calculate(DirDef: TDirectoryDefines): boolean; // calculates the values for a single directory // returns false on error var TempValue: string; begin {$IFDEF VerboseDefineCache} DebugLn('[TDefineTree.Calculate] ++++++ "',DirDef.Path,'"'); {$ENDIF} Result:=true; FErrorTemplate:=nil; FDirDef:=DirDef; FExpandedDirectory:=DirDef.Path; if (FExpandedDirectory=VirtualDirectory) and Assigned(OnGetVirtualDirectoryAlias) then OnGetVirtualDirectoryAlias(Self,FExpandedDirectory); if (FExpandedDirectory<>VirtualDirectory) then begin ReadValue(DirDef,FExpandedDirectory,'',TempValue); FExpandedDirectory:=TempValue; end; DirDef.Values.Clear; // compute the result of all matching DefineTemplates CalculateTemplate(FFirstDefineTemplate,''); if (FExpandedDirectory=VirtualDirectory) and (Assigned(OnGetVirtualDirectoryDefines)) then OnGetVirtualDirectoryDefines(Self,DirDef); Result:=(ErrorTemplate=nil); end; procedure TDefineTree.CalculateTemplate(DefTempl: TDefineTemplate; const CurPath: string); procedure CalculateIfChildren; begin // execute children CalculateTemplate(DefTempl.FirstChild,CurPath); // jump to end of else templates while (DefTempl.Next<>nil) and (DefTempl.Next.Action in [da_Else,da_ElseIf]) do begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',false); DefTempl:=DefTempl.Next; end; end; var EvalResult, SubPath, TempValue, VarName: string; begin while DefTempl<>nil do begin //DebugLn(' [CalculateTemplate] CurPath="',CurPath,'" DefTempl.Name="',DefTempl.Name,'"'); case DefTempl.Action of da_Block: // calculate children begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',true); CalculateTemplate(DefTempl.FirstChild,CurPath); end; da_Define: // Define for a single Directory (not SubDirs) begin if FilenameIsMatching(CurPath,FExpandedDirectory,true) then begin ReadValue(FDirDef,DefTempl.Value,CurPath,TempValue); if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,true,TempValue,false,'',true); ReadValue(FDirDef,DefTempl.Variable,CurPath,VarName); FDirDef.Values.Variables[VarName]:=TempValue; end else begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',false); end; end; da_DefineRecurse: // Define for current and sub directories begin ReadValue(FDirDef,DefTempl.Value,CurPath,TempValue); if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,true,TempValue,false,'',true); ReadValue(FDirDef,DefTempl.Variable,CurPath,VarName); FDirDef.Values.Variables[VarName]:=TempValue; end; da_Undefine: // Undefine for a single Directory (not SubDirs) if FilenameIsMatching(CurPath,FExpandedDirectory,true) then begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',true); ReadValue(FDirDef,DefTempl.Variable,CurPath,VarName); FDirDef.Values.Undefine(VarName); end else begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',false); end; da_UndefineRecurse: // Undefine for current and sub directories begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',true); ReadValue(FDirDef,DefTempl.Variable,CurPath,VarName); FDirDef.Values.Undefine(VarName); end; da_UndefineAll: // Undefine every value for current and sub directories begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',true); FDirDef.Values.Clear; end; da_If, da_ElseIf: begin // test expression in value ReadValue(FDirDef,DefTempl.Value,CurPath,TempValue); EvalResult:=FDirDef.Values.Eval(TempValue,true); if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,true,TempValue,true,EvalResult,EvalResult='1'); //debugln('da_If,da_ElseIf: DefTempl.Value="',DbgStr(DefTempl.Value),'" CurPath="',CurPath,'" TempValue="',TempValue,'" EvalResult=',EvalResult); if FDirDef.Values.ErrorPosition>=0 then begin FErrorDescription:=Format(ctsSyntaxErrorInExpr,[TempValue]); FErrorTemplate:=DefTempl; //debugln(['CalculateTemplate "',FErrorDescription,'"']); end else if EvalResult='1' then CalculateIfChildren; end; da_IfDef,da_IfNDef: // test if variable is defined begin //DebugLn('da_IfDef A Name=',DefTempl.Name, // ' Variable=',DefTempl.Variable, // ' Is=',dbgs(FDirDef.Values.IsDefined(DefTempl.Variable)), // ' CurPath="',CurPath,'"', // ' Values.Count=',dbgs(FDirDef.Values.Count)); ReadValue(FDirDef,DefTempl.Variable,CurPath,VarName); if FDirDef.Values.IsDefined(VarName)=(DefTempl.Action=da_IfDef) then begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',true); CalculateIfChildren; end else begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',false); end; end; da_Else: // execute children begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,false,'',false,'',true); CalculateTemplate(DefTempl.FirstChild,CurPath); end; da_Directory: begin // template for a sub directory ReadValue(FDirDef,DefTempl.Value,CurPath,TempValue); // Note: CurPath can be '' SubPath:=AppendPathDelim(CurPath)+TempValue; // test if FExpandedDirectory is part of SubPath if (SubPath<>'') and FilenameIsMatching(SubPath,FExpandedDirectory,false) then begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,true,SubPath,false,'',true); CalculateTemplate(DefTempl.FirstChild,SubPath); end else begin if Assigned(OnCalculate) then OnCalculate(Self,DefTempl,true,SubPath,false,'',false); end; end; end; if ErrorTemplate<>nil then exit; if DefTempl<>nil then DefTempl:=DefTempl.Next; end; end; procedure TDefineTree.IncreaseChangeStep; begin CTIncreaseChangeStamp(FChangeStep); if DirectoryCachePool<>nil then DirectoryCachePool.IncreaseConfigTimeStamp; end; procedure TDefineTree.SetDirectoryCachePool(const AValue: TCTDirectoryCachePool); begin if FDirectoryCachePool=AValue then exit; FDirectoryCachePool:=AValue; end; procedure TDefineTree.RemoveDoubles(Defines: TDirectoryDefines); // use only one copy of each ansistring begin if Defines=nil then exit; Defines.Values.RemoveDoubles(@FDefineStrings.ReplaceString); end; procedure TDefineTree.Add(ADefineTemplate: TDefineTemplate); // add as last var LastDefTempl: TDefineTemplate; begin if ADefineTemplate=nil then exit; if RootTemplate=nil then RootTemplate:=ADefineTemplate else begin // add as last LastDefTempl:=RootTemplate; while LastDefTempl.Next<>nil do LastDefTempl:=LastDefTempl.Next; ADefineTemplate.InsertBehind(LastDefTempl); end; ClearCache; end; procedure TDefineTree.AddFirst(ADefineTemplate: TDefineTemplate); // add as first begin if ADefineTemplate=nil then exit; if RootTemplate=nil then RootTemplate:=ADefineTemplate else begin RootTemplate.InsertBehind(ADefineTemplate); RootTemplate:=ADefineTemplate; end; ClearCache; end; procedure TDefineTree.MoveToLast(ADefineTemplate: TDefineTemplate); begin if (ADefineTemplate.Next=nil) and (ADefineTemplate.Parent=nil) then exit; ADefineTemplate.Unbind; if FFirstDefineTemplate=ADefineTemplate then FFirstDefineTemplate:=nil; Add(ADefineTemplate); end; function TDefineTree.FindDefineTemplateByName( const AName: string; OnlyRoots: boolean): TDefineTemplate; begin Result:=RootTemplate; if RootTemplate<>nil then Result:=RootTemplate.FindByName(AName,not OnlyRoots,true) else Result:=nil; end; procedure TDefineTree.ReplaceRootSameName(const Name: string; ADefineTemplate: TDefineTemplate); // if there is a DefineTemplate with the same name then replace it // else add as last var OldDefineTemplate: TDefineTemplate; begin if (Name='') then exit; OldDefineTemplate:=FindDefineTemplateByName(Name,true); if OldDefineTemplate<>nil then begin if not OldDefineTemplate.IsEqual(ADefineTemplate,true,false) then begin ClearCache; end; if ADefineTemplate<>nil then ADefineTemplate.InsertBehind(OldDefineTemplate); if OldDefineTemplate=FFirstDefineTemplate then FFirstDefineTemplate:=FFirstDefineTemplate.Next; OldDefineTemplate.Unbind; OldDefineTemplate.Free; end else Add(ADefineTemplate); end; procedure TDefineTree.RemoveRootDefineTemplateByName(const AName: string); var ADefTempl: TDefineTemplate; begin ADefTempl:=FindDefineTemplateByName(AName,true); if ADefTempl<>nil then RemoveDefineTemplate(ADefTempl); end; procedure TDefineTree.RemoveDefineTemplate(ADefTempl: TDefineTemplate); var HadDefines: Boolean; begin if ADefTempl=FFirstDefineTemplate then FFirstDefineTemplate:=FFirstDefineTemplate.Next; HadDefines:=ADefTempl.HasDefines(false,false); ADefTempl.Unbind; ADefTempl.Free; if HadDefines then ClearCache; end; procedure TDefineTree.ReplaceChild(ParentTemplate, NewDefineTemplate: TDefineTemplate; const ChildName: string); // if there is a DefineTemplate with the same name then replace it // else add as last var OldDefineTemplate: TDefineTemplate; begin if (ChildName='') or (ParentTemplate=nil) then exit; OldDefineTemplate:=ParentTemplate.FindChildByName(ChildName); if OldDefineTemplate<>nil then begin if not OldDefineTemplate.IsEqual(NewDefineTemplate,true,false) then ClearCache; if NewDefineTemplate<>nil then NewDefineTemplate.InsertBehind(OldDefineTemplate); if OldDefineTemplate=FFirstDefineTemplate then FFirstDefineTemplate:=FFirstDefineTemplate.Next; OldDefineTemplate.Unbind; OldDefineTemplate.Free; end else begin ClearCache; ParentTemplate.AddChild(NewDefineTemplate); end; end; procedure TDefineTree.AddChild(ParentTemplate, NewDefineTemplate: TDefineTemplate); begin ClearCache; ParentTemplate.AddChild(NewDefineTemplate); end; procedure TDefineTree.ReplaceRootSameName(ADefineTemplate: TDefineTemplate); begin if (ADefineTemplate=nil) then exit; ReplaceRootSameName(ADefineTemplate.Name,ADefineTemplate); end; procedure TDefineTree.ReplaceRootSameNameAddFirst( ADefineTemplate: TDefineTemplate); var OldDefineTemplate: TDefineTemplate; begin if ADefineTemplate=nil then exit; OldDefineTemplate:=FindDefineTemplateByName(ADefineTemplate.Name,true); if OldDefineTemplate<>nil then begin if not OldDefineTemplate.IsEqual(ADefineTemplate,true,false) then begin ClearCache; end; ADefineTemplate.InsertBehind(OldDefineTemplate); if OldDefineTemplate=FFirstDefineTemplate then FFirstDefineTemplate:=FFirstDefineTemplate.Next; OldDefineTemplate.Unbind; OldDefineTemplate.Free; end else AddFirst(ADefineTemplate); end; procedure TDefineTree.MergeDefineTemplates(SourceTemplate: TDefineTemplate; const NewNamePrefix: string); var LastDefTempl: TDefineTemplate; begin if SourceTemplate=nil then exit; // import new defines LastDefTempl:=GetLastRootTemplate; TDefineTemplate.MergeTemplates(nil,FFirstDefineTemplate,LastDefTempl, SourceTemplate,true,NewNamePrefix); ClearCache; end; procedure TDefineTree.ConsistencyCheck; begin if FFirstDefineTemplate<>nil then FFirstDefineTemplate.ConsistencyCheck; FCache.ConsistencyCheck; end; procedure TDefineTree.CalcMemSize(Stats: TCTMemStats); var Node: TAVLTreeNode; begin Stats.Add('TDefineTree',PtrUInt(InstanceSize) +MemSizeString(FErrorDescription) ); if FMacroFunctions<>nil then Stats.Add('TDefineTree.FMacroFunctions',FMacroFunctions.CalcMemSize); if FMacroVariables<>nil then Stats.Add('TDefineTree.FMacroVariables',FMacroVariables.CalcMemSize); if FFirstDefineTemplate<>nil then FFirstDefineTemplate.CalcMemSize(Stats); if FVirtualDirCache<>nil then FVirtualDirCache.CalcMemSize(Stats); if FDefineStrings<>nil then Stats.Add('TDefineTree.FDefineStrings',FDefineStrings.CalcMemSize); if FCache<>nil then begin Stats.Add('TDefineTree.FCache.Count',FCache.Count); Node:=FCache.FindLowest; while Node<>nil do begin TDirectoryDefines(Node.Data).CalcMemSize(Stats); Node:=FCache.FindSuccessor(Node); end; end; end; procedure TDefineTree.WriteDebugReport; begin DebugLn('TDefineTree.WriteDebugReport'); if FFirstDefineTemplate<>nil then FFirstDefineTemplate.WriteDebugReport(false) else DebugLn(' No templates defined'); DebugLn(FCache.ReportAsString); DebugLn(''); ConsistencyCheck; end; { TDefinePool } constructor TDefinePool.Create; begin inherited Create; FItems:=TFPList.Create; end; destructor TDefinePool.Destroy; begin Clear; FItems.Free; inherited Destroy; end; procedure TDefinePool.Clear; var i: integer; begin for i:=0 to Count-1 do begin Items[i].Clear(true); Items[i].Free; end; FItems.Clear; end; function TDefinePool.GetItems(Index: integer): TDefineTemplate; begin Result:=TDefineTemplate(FItems[Index]); end; procedure TDefinePool.SetEnglishErrorMsgFilename(const AValue: string); begin if FEnglishErrorMsgFilename=AValue then exit; FEnglishErrorMsgFilename:=AValue; end; function TDefinePool.CheckAbort(ProgressID, MaxIndex: integer; const Msg: string): boolean; begin Result:=false; if Assigned(OnProgress) then OnProgress(Self,ProgressID,MaxIndex,Msg,Result); end; procedure TDefinePool.Add(ADefineTemplate: TDefineTemplate); begin if ADefineTemplate<>nil then FItems.Add(ADefineTemplate); end; procedure TDefinePool.Insert(Index: integer; ADefineTemplate: TDefineTemplate); begin FItems.Insert(Index,ADefineTemplate); end; procedure TDefinePool.Delete(Index: integer); begin Items[Index].Clear(true); Items[Index].Free; FItems.Delete(Index); end; procedure TDefinePool.Move(SrcIndex, DestIndex: integer); begin FItems.Move(SrcIndex,DestIndex); end; function TDefinePool.Count: integer; begin Result:=FItems.Count; end; function TDefinePool.CreateFPCTemplate( const CompilerPath, CompilerOptions, TestPascalFile: string; out UnitSearchPath, TargetOS, aTargetCPU: string; Owner: TObject): TDefineTemplate; // create symbol definitions for the freepascal compiler // To get reliable values the compiler itself is asked for var LastDefTempl: TDefineTemplate; procedure AddTemplate(NewDefTempl: TDefineTemplate); begin if NewDefTempl=nil then exit; if LastDefTempl<>nil then NewDefTempl.InsertBehind(LastDefTempl); LastDefTempl:=NewDefTempl; end; function FindSymbol(const SymbolName: string): TDefineTemplate; begin Result:=LastDefTempl; while (Result<>nil) and (Comparetext(Result.Variable,SymbolName)<>0) do Result:=Result.Prior; end; procedure DefineSymbol(const SymbolName, SymbolValue: string; const Description: string = ''); var NewDefTempl: TDefineTemplate; Desc: String; begin NewDefTempl:=FindSymbol(SymbolName); if NewDefTempl=nil then begin if Description<>'' then Desc:=Description else Desc:=ctsDefaultFPCSymbol; NewDefTempl:=TDefineTemplate.Create('Define '+SymbolName, Desc,SymbolName,SymbolValue,da_DefineRecurse); AddTemplate(NewDefTempl); end else begin NewDefTempl.Value:=SymbolValue; end; end; procedure UndefineSymbol(const SymbolName: string); var ADefTempl: TDefineTemplate; begin ADefTempl:=FindSymbol(SymbolName); if ADefTempl=nil then exit; if LastDefTempl=ADefTempl then LastDefTempl:=ADefTempl.Prior; ADefTempl.Unbind; ADefTempl.Free; end; procedure ProcessOutputLine(var Line: string); var SymbolName, SymbolValue, UpLine, NewPath: string; i, len, curpos: integer; begin len := length(Line); if len <= 6 then Exit; // shortest match CurPos := 1; // strip timestamp e.g. [0.306] if Line[CurPos] = '[' then begin repeat inc(CurPos); if CurPos > len then Exit; until line[CurPos] = ']'; Inc(CurPos, 2); // skip space too if len - CurPos < 6 then Exit; // shortest match end; UpLine:=UpperCaseStr(Line); //DebugLn(['ProcessOutputLine ',Line]); case UpLine[CurPos] of 'M': if StrLComp(@UpLine[CurPos], 'MACRO ', 6) = 0 then begin // no macro Inc(CurPos, 6); if (StrLComp(@UpLine[CurPos], 'DEFINED: ', 9) = 0) then begin Inc(CurPos, 9); SymbolName:=copy(UpLine, CurPos, len); DefineSymbol(SymbolName,''); Exit; end; if (StrLComp(@UpLine[CurPos], 'UNDEFINED: ', 11) = 0) then begin Inc(CurPos, 11); SymbolName:=copy(UpLine,CurPos,len); UndefineSymbol(SymbolName); Exit; end; // MACRO something... i := CurPos; while (i <= len) and (Line[i]<>' ') do inc(i); SymbolName:=copy(UpLine,CurPos,i-CurPos); CurPos := i + 1; // skip space if StrLComp(@UpLine[CurPos], 'SET TO ', 7) = 0 then begin Inc(CurPos, 7); SymbolValue:=copy(Line, CurPos, len); DefineSymbol(SymbolName, SymbolValue); end; end; 'U': if (StrLComp(@UpLine[CurPos], 'USING UNIT PATH: ', 17) = 0) then begin Inc(CurPos, 17); NewPath:=copy(Line,CurPos,len); if not FilenameIsAbsolute(NewPath) then NewPath:=ExpandFileNameUTF8(NewPath); {$IFDEF VerboseFPCSrcScan} DebugLn('Using unit path: "',NewPath,'"'); {$ENDIF} UnitSearchPath:=UnitSearchPath+NewPath+';'; end; end; end; var i, OutLen, LineStart: integer; TheProcess: TProcessUTF8; OutputLine, Buf: String; NewDefTempl: TDefineTemplate; SrcOS: string; SrcOS2: String; Step: String; Params: TStringList; begin Result:=nil; //DebugLn('TDefinePool.CreateFPCTemplate PPC386Path="',CompilerPath,'" FPCOptions="',CompilerOptions,'"'); if TestPascalFile='' then begin DebugLn(['Warning: [TDefinePool.CreateFPCTemplate] TestPascalFile empty']); end; UnitSearchPath:=''; TargetOS:=''; SrcOS:=''; aTargetCPU:=''; if (CompilerPath='') or (not FileIsExecutable(CompilerPath)) then exit; LastDefTempl:=nil; // find all initial compiler macros and all unit paths // -> ask compiler with the -va switch SetLength(Buf,1024); Step:='Init'; try Params:=TStringList.Create; TheProcess := TProcessUTF8.Create(nil); try TheProcess.Executable:=CompilerPath; Params.Add('-va'); if (PosI('pas2js',ExtractFileName(CompilerPath))<1) and FileExistsCached(EnglishErrorMsgFilename) then Params.Add('-Fr'+EnglishErrorMsgFilename); if CompilerOptions<>'' then SplitCmdLineParams(CompilerOptions,Params,true); Params.Add(TestPascalFile); //DebugLn('TDefinePool.CreateFPCTemplate Params="',MergeCmdLineParams(Params),'"'); TheProcess.Parameters:=Params; TheProcess.Options:= [poUsePipes, poStdErrToOutPut]; TheProcess.ShowWindow := swoHide; Step:='Running '+MergeCmdLineParams(Params); TheProcess.Execute; OutputLine:=''; repeat if (TheProcess.Output<>nil) then begin OutLen:=TheProcess.Output.Read(Buf[1],length(Buf)); end else OutLen:=0; LineStart:=1; i:=1; while i<=OutLen do begin if Buf[i] in [#10,#13] then begin OutputLine:=OutputLine+copy(Buf,LineStart,i-LineStart); ProcessOutputLine(OutputLine); OutputLine:=''; if (iBuf[i+1]) then inc(i); LineStart:=i+1; end; inc(i); end; OutputLine:=copy(Buf,LineStart,OutLen-LineStart+1); until OutLen=0; TheProcess.WaitOnExit; finally //DebugLn('TDefinePool.CreateFPCTemplate Run with -va: OutputLine="',OutputLine,'"'); TheProcess.Free; Params.Free; end; DefineSymbol(FPCUnitPathMacroName,UnitSearchPath,'FPC default unit search path'); //DebugLn('TDefinePool.CreateFPCTemplate First done UnitSearchPath="',UnitSearchPath,'"'); // ask for target operating system -> ask compiler with switch -iTO Params:=TStringList.Create; TheProcess := TProcessUTF8.Create(nil); try TheProcess.Executable:=CompilerPath; if CompilerOptions<>'' then SplitCmdLineParams(CompilerOptions,Params,true); Params.Add('-iTO'); TheProcess.Parameters:=Params; TheProcess.Options:= [poUsePipes, poStdErrToOutPut]; TheProcess.ShowWindow := swoHide; Step:='Running '+MergeCmdLineParams(Params); TheProcess.Execute; if (TheProcess.Output<>nil) then OutLen:=TheProcess.Output.Read(Buf[1],length(Buf)) else OutLen:=0; i:=1; while i<=OutLen do begin if Buf[i] in [#10,#13] then begin // define #TargetOS TargetOS:=copy(Buf,1,i-1); NewDefTempl:=TDefineTemplate.Create('Define TargetOS', ctsDefaultFPCTargetOperatingSystem, ExternalMacroStart+'TargetOS',TargetOS,da_DefineRecurse); AddTemplate(NewDefTempl); // define #SrcOS SrcOS:=GetDefaultSrcOSForTargetOS(TargetOS); if SrcOS='' then SrcOS:=TargetOS; NewDefTempl:=TDefineTemplate.Create('Define SrcOS', ctsDefaultFPCSourceOperatingSystem, ExternalMacroStart+'SrcOS',SrcOS,da_DefineRecurse); AddTemplate(NewDefTempl); // define #SrcOS2 SrcOS2:=GetDefaultSrcOS2ForTargetOS(TargetOS); if SrcOS2='' then SrcOS2:=TargetOS; NewDefTempl:=TDefineTemplate.Create('Define SrcOS2', ctsDefaultFPCSource2OperatingSystem, ExternalMacroStart+'SrcOS2',SrcOS2,da_DefineRecurse); AddTemplate(NewDefTempl); break; end; inc(i); end; TheProcess.WaitOnExit; //DebugLn('TDefinePool.CreateFPCTemplate target OS done'); finally //DebugLn('TDefinePool.CreateFPCTemplate Run with -iTO: OutputLine="',OutputLine,'"'); TheProcess.Free; Params.Free; end; // ask for target processor -> ask compiler with switch -iTP Params:=TStringList.Create; TheProcess := TProcessUTF8.Create(nil); try TheProcess.Executable:=CompilerPath; if CompilerOptions<>'' then SplitCmdLineParams(CompilerOptions,Params,true); Params.Add('-iTP'); TheProcess.Parameters:=Params; TheProcess.Options:= [poUsePipes, poStdErrToOutPut]; TheProcess.ShowWindow := swoHide; Step:='Running '+MergeCmdLineParams(Params); TheProcess.Execute; if TheProcess.Output<>nil then OutLen:=TheProcess.Output.Read(Buf[1],length(Buf)) else OutLen:=0; i:=1; while i<=OutLen do begin if Buf[i] in [#10,#13] then begin aTargetCPU:=copy(Buf,1,i-1); NewDefTempl:=TDefineTemplate.Create('Define TargetCPU', ctsDefaultFPCTargetProcessor, TargetCPUMacroName,aTargetCPU, da_DefineRecurse); AddTemplate(NewDefTempl); break; end; inc(i); end; TheProcess.WaitOnExit; //DebugLn('TDefinePool.CreateFPCTemplate target CPU done'); finally //DebugLn('TDefinePool.CreateFPCTemplate Run with -iTP: OutputLine="',OutputLine,'"'); TheProcess.Free; end; // add if (LastDefTempl<>nil) then begin Result:=TDefineTemplate.Create(StdDefTemplFPC, ctsFreePascalCompilerInitialMacros,'','',da_Block); Result.AddChild(LastDefTempl.GetFirstSibling); Result.SetFlags([dtfAutoGenerated],[],false); //DebugLn('TDefinePool.CreateFPCTemplate FPC defines done'); end; except on E: Exception do begin DebugLn('Error: TDefinePool.CreateFPCTemplate (',Step,'): ',E.Message); end; end; if Result<>nil then Result.SetDefineOwner(Owner,true); end; function TDefinePool.GetFPCVerFromFPCTemplate(Template: TDefineTemplate; out FPCVersion, FPCRelease, FPCPatch: integer): boolean; var p: Integer; function ReadInt(const VarName: string; out AnInteger: integer): boolean; var StartPos: Integer; begin StartPos:=p; AnInteger:=0; while (p<=length(VarName)) and (VarName[p] in ['0'..'9']) do begin AnInteger:=AnInteger*10+(ord(VarName[p])-ord('0')); if AnInteger>=100 then begin Result:=false; exit; end; inc(p); end; Result:=StartPos3) and (VarName[1] in ['V','v']) and (VarName[2] in ['E','e']) and (VarName[3] in ['R','r']) and (VarName[4] in ['0'..'9']) then begin p:=4; if not ReadInt(VarName,NewVersion) then exit; inc(Result); if (p>=length(VarName)) or (VarName[p]<>'_') then exit; inc(p); if not ReadInt(VarName,NewRelease) then exit; inc(Result); if (p>=length(VarName)) or (VarName[p]<>'_') then exit; inc(p); if not ReadInt(VarName,NewPatch) then exit; inc(Result); end; end; var Def: TDefineTemplate; VarName: String; BestCount: integer; NewCount: LongInt; NewVersion: integer; NewRelease: integer; NewPatch: integer; begin Result:=false; FPCVersion:=0; FPCRelease:=0; FPCPatch:=0; BestCount:=0; Def:=Template; while Def<>nil do begin if Def.Action in [da_Define,da_DefineRecurse] then begin VarName:=Def.Variable; NewCount:=ReadVersion(VarName,NewVersion,NewRelease,NewPatch); if NewCount>BestCount then begin BestCount:=NewCount; FPCVersion:=NewVersion; if NewCount>1 then FPCRelease:=NewRelease; if NewCount>2 then FPCPatch:=NewPatch; if NewCount=3 then exit; end; end; Def:=Def.Next; end; end; function TDefinePool.CreateDelphiSrcPath(DelphiVersion: integer; const PathPrefix: string): string; begin case DelphiVersion of 1..5: Result:=PathPrefix+'Source/Rtl/Win;' +PathPrefix+'Source/Rtl/Sys;' +PathPrefix+'Source/Rtl/Corba;' +PathPrefix+'Source/Vcl;'; else // 6 and above Result:=PathPrefix+'Source/Rtl/Win;' +PathPrefix+'Source/Rtl/Sys;' +PathPrefix+'Source/Rtl/Common;' +PathPrefix+'Source/Rtl/Corba40;' +PathPrefix+'Source/Vcl;'; end; end; function TDefinePool.CreateLazarusSrcTemplate( const LazarusSrcDir, WidgetType, ExtraOptions: string; Owner: TObject): TDefineTemplate; function D(const Filename: string): string; begin Result:=GetForcedPathDelims(Filename); end; var MainDir, DirTempl, SubDirTempl, IfTemplate, SubTempl: TDefineTemplate; TargetOS, SrcOS, SrcPath: string; i: Integer; CurCPU, CurOS, CurWidgetSet: string; ToolsInstallDirTempl: TDefineTemplate; AllWidgetSets: String; begin Result:=nil; if (LazarusSrcDir='') or (WidgetType='') then exit; TargetOS:='$('+ExternalMacroStart+'TargetOS)'; SrcOS:='$('+ExternalMacroStart+'SrcOS)'; SrcPath:='$('+ExternalMacroStart+'SrcPath)'; AllWidgetSets:=''; for i:=Low(Lazarus_CPU_OS_Widget_Combinations) to High(Lazarus_CPU_OS_Widget_Combinations) do begin SplitLazarusCPUOSWidgetCombo(Lazarus_CPU_OS_Widget_Combinations[i], CurCPU,CurOS,CurWidgetSet); if not HasDelimitedItem(AllWidgetSets,';',CurWidgetSet) then begin if AllWidgetSets<>'' then AllWidgetSets:=AllWidgetSets+';'; AllWidgetSets:=AllWidgetSets+CurWidgetSet; end; end; // MainDir:=TDefineTemplate.Create( StdDefTemplLazarusSrcDir, ctsDefsForLazarusSources,'',LazarusSrcDir, da_Directory); // clear src path MainDir.AddChild(TDefineTemplate.Create('Clear SrcPath','Clear SrcPath', ExternalMacroStart+'SrcPath','',da_DefineRecurse)); // if SrcOS<>win IfTemplate:=TDefineTemplate.Create('IF '''+SrcOS+'''<>''win''', ctsIfTargetOSIsNotWin32,'',''''+SrcOS+'''<>''win''',da_If); // then define #SrcPath := #SrcPath;lcl/nonwin32 IfTemplate.AddChild(TDefineTemplate.Create('win32api for non win', Format(ctsAddsDirToSourcePath,[d(LazarusSrcDir+'/lcl/nonwin32')]), ExternalMacroStart+'SrcPath', d(LazarusSrcDir+'/lcl/nonwin32;')+SrcPath,da_DefineRecurse)); MainDir.AddChild(IfTemplate); // define 'LCL' MainDir.AddChild(TDefineTemplate.Create('define LCL', ctsDefineLCL,'LCL',WidgetType,da_DefineRecurse)); // define LCLwidgetset, e.g. LCLcarbon, LCLgtk, LCLgtk2 MainDir.AddChild(TDefineTemplate.Create('Define LCLwidgettype', ctsDefineLCLWidgetset, 'LCL$(#LCLWidgetType)','',da_DefineRecurse)); // /ide DirTempl:=TDefineTemplate.Create('ide',ctsIDEDirectory, '','ide',da_Directory); DirTempl.AddChild(TDefineTemplate.Create('IDE path addition', Format(ctsAddsDirToSourcePath,['designer, debugger, synedit, ...']), ExternalMacroStart+'SrcPath', d(LazarusSrcDir+'/ide;' +LazarusSrcDir+'/ide/frames;' +LazarusSrcDir+'/designer;' +LazarusSrcDir+'/debugger;' +LazarusSrcDir+'/debugger/frames;' +LazarusSrcDir+'/converter;' +LazarusSrcDir+'/packager;' +LazarusSrcDir+'/packager/registration;' +LazarusSrcDir+'/packager/frames;' +LazarusSrcDir+'/components/buildintf;' +LazarusSrcDir+'/components/ideintf;' +LazarusSrcDir+'/components/lazutils;' +LazarusSrcDir+'/components/lazcontrols;' +LazarusSrcDir+'/components/synedit;' +LazarusSrcDir+'/components/codetools;' +LazarusSrcDir+'/components/lazdebuggergdbmi;' +LazarusSrcDir+'/components/debuggerintf;' +LazarusSrcDir+'/lcl;' +LazarusSrcDir+'/lcl/interfaces;' +LazarusSrcDir+'/lcl/interfaces/'+WidgetType+';' +LazarusSrcDir+'/components/custom;' +SrcPath) ,da_DefineRecurse)); // include path addition DirTempl.AddChild(TDefineTemplate.Create('includepath addition', Format(ctsSetsIncPathTo,['include, include/TargetOS, include/SrcOS']), IncludePathMacroName, d(LazarusSrcDir+'/ide/include;' +LazarusSrcDir+'/ide/include/'+TargetOS+';' +LazarusSrcDir+'/ide/include/'+SrcOS), da_DefineRecurse)); MainDir.AddChild(DirTempl); // /designer DirTempl:=TDefineTemplate.Create('Designer',ctsDesignerDirectory, '','designer',da_Directory); DirTempl.AddChild(TDefineTemplate.Create('components path addition', Format(ctsAddsDirToSourcePath,['synedit']), SrcPathMacroName, d('../components/lazutils' +';../components/codetools' +';../lcl' +';../lcl/interfaces' +';../lcl/interfaces/'+WidgetType +';../components/buildintf' +';../components/ideintf' +';../components/synedit' +';../components/codetools' +';../components/lazcontrols' +';../components/custom') +';'+SrcPath ,da_Define)); DirTempl.AddChild(TDefineTemplate.Create('main path addition', Format(ctsAddsDirToSourcePath,[ctsLazarusMainDirectory]), SrcPathMacroName, d('../ide;../packager;')+SrcPath ,da_Define)); DirTempl.AddChild(TDefineTemplate.Create('includepath addition', Format(ctsIncludeDirectoriesPlusDirs,['include']), IncludePathMacroName, d('../ide/include;../ide/include/'+TargetOS), da_Define)); // /designer/units MainDir.AddChild(DirTempl); // /images // /debugger DirTempl:=TDefineTemplate.Create('Debugger',ctsDebuggerDirectory, '','debugger',da_Directory); DirTempl.AddChild(TDefineTemplate.Create('LCL path addition', Format(ctsAddsDirToSourcePath,['lcl, components']), ExternalMacroStart+'SrcPath', d(LazarusSrcDir+'/debugger;' +LazarusSrcDir+'/debugger/frames;' +LazarusSrcDir+'/ide;' +LazarusSrcDir+'/components/buildintf;' +LazarusSrcDir+'/components/ideintf;' +LazarusSrcDir+'/components/lazutils;' +LazarusSrcDir+'/components/codetools;' +LazarusSrcDir+'/components/lazdebuggergdbmi;' +LazarusSrcDir+'/components/debuggerintf;' +LazarusSrcDir+'/lcl;' +LazarusSrcDir+'/lcl/interfaces;' +LazarusSrcDir+'/lcl/interfaces/'+WidgetType+';') +SrcPath ,da_DefineRecurse)); MainDir.AddChild(DirTempl); // /converter DirTempl:=TDefineTemplate.Create('Converter',ctsDebuggerDirectory, '','converter',da_Directory); DirTempl.AddChild(TDefineTemplate.Create('LCL path addition', Format(ctsAddsDirToSourcePath,['lcl, components']), ExternalMacroStart+'SrcPath', d('../ide' +';../components/buildintf' +';../components/ideintf' +';../components/lazutils' +';../components/codetools' +';../components/synedit' +';../components/lazcontrols' +';../packager' +';../debugger' +';../designer' +';../lcl' +';../lcl/interfaces' +';../lcl/interfaces/'+WidgetType) +';'+SrcPath ,da_Define)); MainDir.AddChild(DirTempl); // /packager DirTempl:=TDefineTemplate.Create('Packager',ctsDesignerDirectory, '','packager',da_Directory); DirTempl.AddChild(TDefineTemplate.Create('src path addition', Format(ctsAddsDirToSourcePath,['lcl synedit codetools lazcontrols ideintf buildintf']), SrcPathMacroName, d(LazarusSrcDir+'/lcl' +';'+LazarusSrcDir+'/lcl/interfaces' +';'+LazarusSrcDir+'/lcl/interfaces/'+WidgetType +';'+LazarusSrcDir+'/ide' +';'+LazarusSrcDir+'/components/buildintf' +';'+LazarusSrcDir+'/components/ideintf' +';'+LazarusSrcDir+'/components/synedit' +';'+LazarusSrcDir+'/components/lazcontrols' +';'+LazarusSrcDir+'/components/lazutils' +';'+LazarusSrcDir+'/components/codetools' +';'+LazarusSrcDir+'/packager/frames' +';'+LazarusSrcDir+'/packager/registration' +';'+SrcPath) ,da_DefineRecurse)); DirTempl.AddChild(TDefineTemplate.Create('includepath addition', Format(ctsIncludeDirectoriesPlusDirs,['include']), IncludePathMacroName, d('../ide/include;../ide/include/'+TargetOS), da_Define)); // /packager/frames SubDirTempl:=TDefineTemplate.Create('Frames', 'Frames','','frames',da_Directory); DirTempl.AddChild(SubDirTempl); SubDirTempl.AddChild(TDefineTemplate.Create('src path addition', Format(ctsAddsDirToSourcePath,['ide']), SrcPathMacroName, d(LazarusSrcDir+'/ide;'+LazarusSrcDir+'/packager;'+SrcPath) ,da_Define)); // /packager/registration SubDirTempl:=TDefineTemplate.Create('Registration', ctsPackagerRegistrationDirectory,'','registration',da_Directory); DirTempl.AddChild(SubDirTempl); // /packager/units SubDirTempl:=TDefineTemplate.Create('Packager Units', ctsPackagerUnitsDirectory,'','units',da_Directory); SubDirTempl.AddChild(TDefineTemplate.Create('CompiledSrcPath', ctsCompiledSrcPath,CompiledSrcPathMacroName, LazarusSrcDir+d('/packager/registration'), da_DefineRecurse)); DirTempl.AddChild(SubDirTempl); MainDir.AddChild(DirTempl); // /examples DirTempl:=TDefineTemplate.Create('Examples', Format(ctsNamedDirectory,['Examples']), '','examples',da_Directory); DirTempl.AddChild(TDefineTemplate.Create('LCL path addition', Format(ctsAddsDirToSourcePath,['lcl']), ExternalMacroStart+'SrcPath', d('../lcl' +';../lcl/interfaces/'+WidgetType+';'+SrcPath) ,da_Define)); MainDir.AddChild(DirTempl); // /components DirTempl:=TDefineTemplate.Create('Components',ctsComponentsDirectory, '','components',da_Directory); // /components/custom SubDirTempl:=TDefineTemplate.Create('Custom Components', ctsCustomComponentsDirectory, '','custom',da_Directory); SubDirTempl.AddChild(TDefineTemplate.Create('lazarus standard components', Format(ctsAddsDirToSourcePath,['synedit']), ExternalMacroStart+'SrcPath', d('../synedit;') +SrcPath ,da_DefineRecurse)); DirTempl.AddChild(SubDirTempl); MainDir.AddChild(DirTempl); // /tools DirTempl:=TDefineTemplate.Create('Tools', ctsToolsDirectory,'','tools',da_Directory); DirTempl.AddChild(TDefineTemplate.Create('LCL path addition', Format(ctsAddsDirToSourcePath,['lcl']), ExternalMacroStart+'SrcPath', d('../lcl;../lcl/interfaces/'+WidgetType +';../components/codetools') +';'+SrcPath ,da_Define)); // /tools/install ToolsInstallDirTempl:=TDefineTemplate.Create('Install', ctsInstallDirectory,'','install',da_Directory); DirTempl.AddChild(ToolsInstallDirTempl); ToolsInstallDirTempl.AddChild(TDefineTemplate.Create('LCL path addition', Format(ctsAddsDirToSourcePath,['lcl']), ExternalMacroStart+'SrcPath', d('../../lcl;../../lcl/interfaces/'+WidgetType +';../../components/codetools') +';'+SrcPath ,da_Define)); MainDir.AddChild(DirTempl); // extra options SubTempl:=CreateFPCCommandLineDefines(StdDefTemplLazarusBuildOpts, ExtraOptions,true,Owner); MainDir.AddChild(SubTempl); // put it all into a block if MainDir<>nil then begin Result:=TDefineTemplate.Create(StdDefTemplLazarusSources, ctsLazarusSources,'','',da_Block); Result.AddChild(MainDir); end; Result.SetDefineOwner(Owner,true); Result.SetFlags([dtfAutoGenerated],[],false); end; function TDefinePool.CreateLCLProjectTemplate( const LazarusSrcDir, WidgetType, ProjectDir: string; Owner: TObject): TDefineTemplate; var DirTempl: TDefineTemplate; begin Result:=nil; if (LazarusSrcDir='') or (WidgetType='') or (ProjectDir='') then exit; DirTempl:=TDefineTemplate.Create('ProjectDir',ctsAnLCLProject, '',ProjectDir,da_Directory); DirTempl.AddChild(TDefineTemplate.Create('LCL', Format(ctsAddsDirToSourcePath,['lcl']), ExternalMacroStart+'SrcPath', LazarusSrcDir+PathDelim+'lcl;' +LazarusSrcDir+PathDelim+'lcl'+PathDelim+'interfaces' +PathDelim+WidgetType +';$('+ExternalMacroStart+'SrcPath)' ,da_DefineRecurse)); Result:=TDefineTemplate.Create(StdDefTemplLCLProject, 'LCL Project','','',da_Block); Result.AddChild(DirTempl); Result.SetDefineOwner(Owner,true); Result.SetFlags([dtfAutoGenerated],[],false); end; function TDefinePool.CreateDelphiCompilerDefinesTemplate( DelphiVersion: integer; Owner: TObject): TDefineTemplate; var DefTempl: TDefineTemplate; VerMacro: String; begin DefTempl:=TDefineTemplate.Create('Delphi'+IntToStr(DelphiVersion) +' Compiler Defines', Format(ctsOtherCompilerDefines,['Delphi'+IntToStr(DelphiVersion)]), '','',da_Block); DefTempl.AddChild(TDefineTemplate.Create('Reset', ctsResetAllDefines, '','',da_UndefineAll)); DefTempl.AddChild(TDefineTemplate.Create('Define macro DELPHI', Format(ctsDefineMacroName,['DELPHI']), 'DELPHI','',da_DefineRecurse)); DefTempl.AddChild(TDefineTemplate.Create('Define macro FPC_DELPHI', Format(ctsDefineMacroName,['FPC_DELPHI']), 'FPC_DELPHI','',da_DefineRecurse)); DefTempl.AddChild(TDefineTemplate.Create('Define macro MSWINDOWS', Format(ctsDefineMacroName,['MSWINDOWS']), 'MSWINDOWS','',da_DefineRecurse)); // version case DelphiVersion of 3: VerMacro:='VER_110'; 4: VerMacro:='VER_125'; 5: VerMacro:='VER_130'; 6: VerMacro:='VER_140'; else // else define Delphi 7 VerMacro:='VER_150'; end; DefTempl.AddChild(TDefineTemplate.Create('Define macro '+VerMacro, Format(ctsDefineMacroName,[VerMacro]), VerMacro,'',da_DefineRecurse)); DefTempl.AddChild(TDefineTemplate.Create( Format(ctsDefineMacroName,[ExternalMacroStart+'Compiler']), 'Define '+ExternalMacroStart+'Compiler variable', ExternalMacroStart+'Compiler','DELPHI',da_DefineRecurse)); Result:=DefTempl; Result.SetDefineOwner(Owner,true); end; function TDefinePool.CreateDelphiDirectoryTemplate( const DelphiDirectory: string; DelphiVersion: integer; Owner: TObject): TDefineTemplate; var MainDirTempl: TDefineTemplate; begin MainDirTempl:=TDefineTemplate.Create('Delphi'+IntToStr(DelphiVersion) +' Directory', Format(ctsNamedDirectory,['Delphi'+IntToStr(DelphiVersion)]), '',DelphiDirectory,da_Directory); MainDirTempl.AddChild(CreateDelphiCompilerDefinesTemplate(DelphiVersion,Owner)); MainDirTempl.AddChild(TDefineTemplate.Create('SrcPath', Format(ctsSetsSrcPathTo,['RTL, VCL']), ExternalMacroStart+'SrcPath', GetForcedPathDelims( CreateDelphiSrcPath(DelphiVersion,DefinePathMacro+'/')+'$(#SrcPath)'), da_DefineRecurse)); Result:=MainDirTempl; Result.SetDefineOwner(Owner,true); end; function TDefinePool.CreateDelphiProjectTemplate( const ProjectDir, DelphiDirectory: string; DelphiVersion: integer; Owner: TObject): TDefineTemplate; var MainDirTempl: TDefineTemplate; begin MainDirTempl:=TDefineTemplate.Create('Delphi'+IntToStr(DelphiVersion)+' Project', Format(ctsNamedProject,['Delphi'+IntToStr(DelphiVersion)]), '',ProjectDir,da_Directory); MainDirTempl.AddChild( CreateDelphiCompilerDefinesTemplate(DelphiVersion,Owner)); MainDirTempl.AddChild(TDefineTemplate.Create( 'Define '+ExternalMacroStart+'DelphiDir', Format(ctsDefineMacroName,[ExternalMacroStart+'DelphiDir']), ExternalMacroStart+'DelphiDir',DelphiDirectory,da_DefineRecurse)); MainDirTempl.AddChild(TDefineTemplate.Create('SrcPath', Format(ctsAddsDirToSourcePath,['Delphi RTL+VCL']), ExternalMacroStart+'SrcPath', GetForcedPathDelims(CreateDelphiSrcPath(DelphiVersion,'$(#DelphiDir)/') +'$(#SrcPath)'), da_DefineRecurse)); Result:=MainDirTempl; Result.SetDefineOwner(Owner,true); end; function TDefinePool.CreateKylixCompilerDefinesTemplate(KylixVersion: integer; Owner: TObject): TDefineTemplate; var DefTempl: TDefineTemplate; begin DefTempl:=TDefineTemplate.Create('Kylix'+IntToStr(KylixVersion) +' Compiler Defines', Format(ctsOtherCompilerDefines,['Kylix'+IntToStr(KylixVersion)]), '','',da_Block); DefTempl.AddChild(TDefineTemplate.Create('Reset', ctsResetAllDefines, '','',da_UndefineAll)); DefTempl.AddChild(TDefineTemplate.Create('Define macro KYLIX', Format(ctsDefineMacroName,['KYLIX']), 'KYLIX','',da_DefineRecurse)); DefTempl.AddChild(TDefineTemplate.Create('Define macro FPC_DELPHI', Format(ctsDefineMacroName,['FPC_DELPHI']), 'FPC_DELPHI','',da_DefineRecurse)); DefTempl.AddChild(TDefineTemplate.Create('Define macro LINUX', Format(ctsDefineMacroName,['LINUX']), 'LINUX','',da_DefineRecurse)); DefTempl.AddChild(TDefineTemplate.Create('Define macro CPU386', Format(ctsDefineMacroName,['CPU386']), 'CPU386','',da_DefineRecurse)); // version case KylixVersion of 1: DefTempl.AddChild(TDefineTemplate.Create('Define macro VER_125', Format(ctsDefineMacroName,['VER_125']), 'VER_125','',da_DefineRecurse)); 2: DefTempl.AddChild(TDefineTemplate.Create('Define macro VER_130', Format(ctsDefineMacroName,['VER_130']), 'VER_130','',da_DefineRecurse)); else // else define Kylix 3 DefTempl.AddChild(TDefineTemplate.Create('Define macro VER_140', Format(ctsDefineMacroName,['VER_140']), 'VER_140','',da_DefineRecurse)); end; DefTempl.AddChild(TDefineTemplate.Create( Format(ctsDefineMacroName,[ExternalMacroStart+'Compiler']), 'Define '+ExternalMacroStart+'Compiler variable', ExternalMacroStart+'Compiler','DELPHI',da_DefineRecurse)); Result:=DefTempl; Result.SetDefineOwner(Owner,true); end; function TDefinePool.CreateKylixSrcPath(KylixVersion: integer; const PathPrefix: string): string; begin Result:=PathPrefix+'source/rtl/linux;' +PathPrefix+'source/rtl/sys;' +PathPrefix+'source/rtl/common;' +PathPrefix+'source/rtl/corba40;' +PathPrefix+'source/rtle;' +PathPrefix+'source/rtl/clx'; end; function TDefinePool.CreateKylixDirectoryTemplate(const KylixDirectory: string; KylixVersion: integer; Owner: TObject): TDefineTemplate; var MainDirTempl: TDefineTemplate; begin MainDirTempl:=TDefineTemplate.Create('Kylix'+IntToStr(KylixVersion) +' Directory', Format(ctsNamedDirectory,['Kylix'+IntToStr(KylixVersion)]), '',KylixDirectory,da_Directory); MainDirTempl.AddChild(CreateKylixCompilerDefinesTemplate(KylixVersion,Owner)); MainDirTempl.AddChild(TDefineTemplate.Create('SrcPath', Format(ctsSetsSrcPathTo,['RTL, CLX']), ExternalMacroStart+'SrcPath', GetForcedPathDelims(CreateKylixSrcPath(KylixVersion,DefinePathMacro+'/') +'$(#SrcPath)'), da_DefineRecurse)); Result:=MainDirTempl; Result.SetDefineOwner(Owner,true); end; function TDefinePool.CreateKylixProjectTemplate(const ProjectDir, KylixDirectory: string; KylixVersion: integer; Owner: TObject ): TDefineTemplate; var MainDirTempl: TDefineTemplate; begin MainDirTempl:=TDefineTemplate.Create('Kylix'+IntToStr(KylixVersion)+' Project', Format(ctsNamedProject,['Kylix'+IntToStr(KylixVersion)]), '',ProjectDir,da_Directory); MainDirTempl.AddChild( CreateDelphiCompilerDefinesTemplate(KylixVersion,Owner)); MainDirTempl.AddChild(TDefineTemplate.Create( 'Define '+ExternalMacroStart+'KylixDir', Format(ctsDefineMacroName,[ExternalMacroStart+'KylixDir']), ExternalMacroStart+'KylixDir',KylixDirectory,da_DefineRecurse)); MainDirTempl.AddChild(TDefineTemplate.Create('SrcPath', Format(ctsAddsDirToSourcePath,['Kylix RTL+VCL']), ExternalMacroStart+'SrcPath', GetForcedPathDelims(CreateKylixSrcPath(KylixVersion,'$(#KylixDir)/') +'$(#SrcPath)'), da_DefineRecurse)); Result:=MainDirTempl; Result.SetDefineOwner(Owner,true); end; function TDefinePool.CreateFPCCommandLineDefines(const Name, CmdLine: string; RecursiveDefines: boolean; Owner: TObject; AlwaysCreate: boolean; AddPaths: boolean): TDefineTemplate; procedure CreateMainTemplate; begin if Result=nil then Result:=TDefineTemplate.Create(Name,ctsCommandLineParameters,'','', da_Block); end; procedure AddDefine(const AName, ADescription, AVariable, AValue: string; AnAction: TDefineAction); var NewTempl: TDefineTemplate; begin if AName='' then exit; NewTempl:=TDefineTemplate.Create(AName, ADescription, AVariable, AValue, AnAction); CreateMainTemplate; Result.AddChild(NewTempl); end; procedure AddDefine(const AName, ADescription, AVariable, AValue: string); var NewAction: TDefineAction; begin //debugln(['AddDefine Name="',AName,'" Var="',AVariable,'" Value="',AValue,'"']); if RecursiveDefines then NewAction:=da_DefineRecurse else NewAction:=da_Define; AddDefine(AName,ADescription,AVariable,AValue,NewAction); end; procedure AddDefine(const AParam: string); var Identifier: String; AValue: String; begin Identifier:=GetIdentifier(PChar(AParam)); if Identifier='' then exit; AValue:=''; if length(Identifier) nil then tpl:=Result.FindChildByName(Name) else tpl:=nil; if tpl = nil then begin if RecursiveDefines then NewAction:=da_DefineRecurse else NewAction:=da_Define; CreateMainTemplate; tpl:=TDefineTemplate.Create(Name, Descr, Opt, OptValue, NewAction); Result.AddChild(tpl); end else begin tpl.Value:=OptValue; tpl.Description:=Descr; end; end; procedure DefineOpt(const Opt: char; Enabled: boolean); const Values: array[boolean] of string = ('OFF', 'ON'); begin DefineOpt(CompilerSwitchesNames[Opt], Values[Enabled]); end; function FindControllerUnit(const AControllerName: string): string; type TControllerType = record controllertypestr, controllerunitstr: string[20]; end; const ControllerTypes: array[0..608+1306] of TControllerType = ((controllertypestr:''; controllerunitstr:''), (controllertypestr:'LPC810M021FN8'; controllerunitstr:'LPC8xx'), (controllertypestr:'LPC811M001FDH16'; controllerunitstr:'LPC8xx'), (controllertypestr:'LPC812M101FDH16'; controllerunitstr:'LPC8xx'), (controllertypestr:'LPC812M101FD20'; controllerunitstr:'LPC8xx'), (controllertypestr:'LPC812M101FDH20'; controllerunitstr:'LPC8xx'), (controllertypestr:'LPC1110FD20'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1111FDH20_002'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1111FHN33_101'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1111FHN33_102'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1111FHN33_103'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1111FHN33_201'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1111FHN33_202'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1111FHN33_203'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FD20_102'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FDH20_102'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FDH28_102'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHN33_101'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHN33_102'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHN33_103'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHN33_201'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHN24_202'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHN33_202'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHN33_203'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHI33_202'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1112FHI33_203'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FHN33_201'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FHN33_202'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FHN33_203'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FHN33_301'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FHN33_302'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FHN33_303'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FBD48_301'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FBD48_302'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1113FBD48_303'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FDH28_102'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FN28_102'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHN33_201'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHN33_202'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHN33_203'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHN33_301'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHN33_302'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHN33_303'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHN33_333'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHI33_302'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FHI33_303'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FBD48_301'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FBD48_302'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FBD48_303'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FBD48_323'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1114FBD48_333'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1115FBD48_303'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC11C12FBD48_301'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC11C14FBD48_301'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC11C22FBD48_301'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC11C24FBD48_301'; controllerunitstr:'LPC11XX'), (controllertypestr:'LPC11D14FBD100_302';controllerunitstr:'LPC11XX'), (controllertypestr:'LPC1224FBD48_101'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1224FBD48_121'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1224FBD64_101'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1224FBD64_121'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1225FBD48_301'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1225FBD48_321'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1225FBD64_301'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1225FBD64_321'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1226FBD48_301'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1226FBD64_301'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1227FBD48_301'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC1227FBD64_301'; controllerunitstr:'LPC122X'), (controllertypestr:'LPC12D27FBD100_301';controllerunitstr:'LPC122X'), (controllertypestr:'LPC1311FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1311FHN33_01'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1313FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1313FHN33_01'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1313FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1313FBD48_01'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1315FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1315FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1316FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1316FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1317FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1317FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1317FBD64'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1342FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1342FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1343FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1343FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1345FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1345FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1346FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1346FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1347FHN33'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1347FBD48'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC1347FBD64'; controllerunitstr:'LPC13XX'), (controllertypestr:'LPC2114'; controllerunitstr:'LPC21x4'), (controllertypestr:'LPC2124'; controllerunitstr:'LPC21x4'), (controllertypestr:'LPC2194'; controllerunitstr:'LPC21x4'), (controllertypestr:'LPC1754'; controllerunitstr:'LPC1754'), (controllertypestr:'LPC1756'; controllerunitstr:'LPC1756'), (controllertypestr:'LPC1758'; controllerunitstr:'LPC1758'), (controllertypestr:'LPC1764'; controllerunitstr:'LPC1764'), (controllertypestr:'LPC1766'; controllerunitstr:'LPC1766'), (controllertypestr:'LPC1768'; controllerunitstr:'LPC1768'), (controllertypestr:'AT91SAM7S256'; controllerunitstr:'AT91SAM7x256'), (controllertypestr:'AT91SAM7SE256'; controllerunitstr:'AT91SAM7x256'), (controllertypestr:'AT91SAM7X256'; controllerunitstr:'AT91SAM7x256'), (controllertypestr:'AT91SAM7XC256'; controllerunitstr:'AT91SAM7x256'), (controllertypestr:'STM32F100X4'; controllerunitstr:'STM32F10X_LD'), (controllertypestr:'STM32F100X6'; controllerunitstr:'STM32F10X_LD'), (controllertypestr:'STM32F100X8'; controllerunitstr:'STM32F10X_MD'), (controllertypestr:'STM32F100XB'; controllerunitstr:'STM32F10X_MD'), (controllertypestr:'STM32F100XC'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F100XD'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F100XE'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F101X4'; controllerunitstr:'STM32F10X_LD'), (controllertypestr:'STM32F101X6'; controllerunitstr:'STM32F10X_LD'), (controllertypestr:'STM32F101X8'; controllerunitstr:'STM32F10X_MD'), (controllertypestr:'STM32F101XB'; controllerunitstr:'STM32F10X_MD'), (controllertypestr:'STM32F101XC'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F101XD'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F101XE'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F101XF'; controllerunitstr:'STM32F10X_XL'), (controllertypestr:'STM32F101XG'; controllerunitstr:'STM32F10X_XL'), (controllertypestr:'STM32F102X4'; controllerunitstr:'STM32F10X_LD'), (controllertypestr:'STM32F102X6'; controllerunitstr:'STM32F10X_LD'), (controllertypestr:'STM32F102X8'; controllerunitstr:'STM32F10X_MD'), (controllertypestr:'STM32F102XB'; controllerunitstr:'STM32F10X_MD'), (controllertypestr:'STM32F103X4'; controllerunitstr:'STM32F10X_LD'), (controllertypestr:'STM32F103X6'; controllerunitstr:'STM32F10X_LD'), (controllertypestr:'STM32F103X8'; controllerunitstr:'STM32F10X_MD'), (controllertypestr:'STM32F103XB'; controllerunitstr:'STM32F10X_MD'), (controllertypestr:'STM32F103XC'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F103XD'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F103XE'; controllerunitstr:'STM32F10X_HD'), (controllertypestr:'STM32F103XF'; controllerunitstr:'STM32F10X_XL'), (controllertypestr:'STM32F103XG'; controllerunitstr:'STM32F10X_XL'), (controllertypestr:'STM32F105X8'; controllerunitstr:'STM32F10X_CL'), (controllertypestr:'STM32F105XB'; controllerunitstr:'STM32F10X_CL'), (controllertypestr:'STM32F105XC'; controllerunitstr:'STM32F10X_CL'), (controllertypestr:'STM32F107X8'; controllerunitstr:'STM32F10X_CONN'), (controllertypestr:'STM32F107XB'; controllerunitstr:'STM32F10X_CONN'), (controllertypestr:'STM32F107XC'; controllerunitstr:'STM32F10X_CONN'), (controllertypestr:'STM32F030C6'; controllerunitstr:'STM32F030X6'), (controllertypestr:'STM32F030C8'; controllerunitstr:'STM32F030X8'), (controllertypestr:'STM32F030CC'; controllerunitstr:'STM32F030XC'), (controllertypestr:'STM32F030F4'; controllerunitstr:'STM32F030X6'), (controllertypestr:'STM32F030K6'; controllerunitstr:'STM32F030X6'), (controllertypestr:'STM32F030R8'; controllerunitstr:'STM32F030X8'), (controllertypestr:'STM32F030RC'; controllerunitstr:'STM32F030XC'), (controllertypestr:'STM32F031C4'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F031C6'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F031E6'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F031F4'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F031F6'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F031G4'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F031G6'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F031K4'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F031K6'; controllerunitstr:'STM32F031X6'), (controllertypestr:'STM32F038C6'; controllerunitstr:'STM32F038XX'), (controllertypestr:'STM32F038E6'; controllerunitstr:'STM32F038XX'), (controllertypestr:'STM32F038F6'; controllerunitstr:'STM32F038XX'), (controllertypestr:'STM32F038G6'; controllerunitstr:'STM32F038XX'), (controllertypestr:'STM32F038K6'; controllerunitstr:'STM32F038XX'), (controllertypestr:'STM32F042C4'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F042C6'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F042F4'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F042F6'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F042G4'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F042G6'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F042K4'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F042K6'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F042T6'; controllerunitstr:'STM32F042X6'), (controllertypestr:'STM32F048C6'; controllerunitstr:'STM32F048XX'), (controllertypestr:'STM32F048G6'; controllerunitstr:'STM32F048XX'), (controllertypestr:'STM32F048T6'; controllerunitstr:'STM32F048XX'), (controllertypestr:'STM32F051C4'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051C6'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051C8'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051K4'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051K6'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051K8'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051R4'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051R6'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051R8'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F051T8'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F058C8'; controllerunitstr:'STM32F058XX'), (controllertypestr:'STM32F058R8'; controllerunitstr:'STM32F058XX'), (controllertypestr:'STM32F058T8'; controllerunitstr:'STM32F058XX'), (controllertypestr:'STM32F070C6'; controllerunitstr:'STM32F070X6'), (controllertypestr:'STM32F070CB'; controllerunitstr:'STM32F070XB'), (controllertypestr:'STM32F070F6'; controllerunitstr:'STM32F070X6'), (controllertypestr:'STM32F070RB'; controllerunitstr:'STM32F070XB'), (controllertypestr:'STM32F071C8'; controllerunitstr:'STM32F071XB'), (controllertypestr:'STM32F071CB'; controllerunitstr:'STM32F071XB'), (controllertypestr:'STM32F071RB'; controllerunitstr:'STM32F071XB'), (controllertypestr:'STM32F071V8'; controllerunitstr:'STM32F071XB'), (controllertypestr:'STM32F071VB'; controllerunitstr:'STM32F071XB'), (controllertypestr:'STM32F072C8'; controllerunitstr:'STM32F072XB'), (controllertypestr:'STM32F072CB'; controllerunitstr:'STM32F072XB'), (controllertypestr:'STM32F072R8'; controllerunitstr:'STM32F072XB'), (controllertypestr:'STM32F072RB'; controllerunitstr:'STM32F072XB'), (controllertypestr:'STM32F072V8'; controllerunitstr:'STM32F072XB'), (controllertypestr:'STM32F072VB'; controllerunitstr:'STM32F072XB'), (controllertypestr:'STM32F078CB'; controllerunitstr:'STM32F078XX'), (controllertypestr:'STM32F078RB'; controllerunitstr:'STM32F078XX'), (controllertypestr:'STM32F078VB'; controllerunitstr:'STM32F078XX'), (controllertypestr:'STM32F091CB'; controllerunitstr:'STM32F091XC'), (controllertypestr:'STM32F091CC'; controllerunitstr:'STM32F091XC'), (controllertypestr:'STM32F091RB'; controllerunitstr:'STM32F091XC'), (controllertypestr:'STM32F091RC'; controllerunitstr:'STM32F091XC'), (controllertypestr:'STM32F091VB'; controllerunitstr:'STM32F091XC'), (controllertypestr:'STM32F091VC'; controllerunitstr:'STM32F091XC'), (controllertypestr:'STM32F098CC'; controllerunitstr:'STM32F098XX'), (controllertypestr:'STM32F098RC'; controllerunitstr:'STM32F098XX'), (controllertypestr:'STM32F098VC'; controllerunitstr:'STM32F098XX'), (controllertypestr:'NUCLEOF030R8'; controllerunitstr:'STM32F030X8'), (controllertypestr:'NUCLEOF031K6'; controllerunitstr:'STM32F031X6'), (controllertypestr:'NUCLEOF042K6'; controllerunitstr:'STM32F042X6'), (controllertypestr:'NUCLEOF070RB'; controllerunitstr:'STM32F070XB'), (controllertypestr:'NUCLEOF072RB'; controllerunitstr:'STM32F072XB'), (controllertypestr:'NUCLEOF091RC'; controllerunitstr:'STM32F091XC'), (controllertypestr:'STM32F0308DISCOVERY';controllerunitstr:'STM32F030X8'), (controllertypestr:'STM32F072BDISCOVERY';controllerunitstr:'STM32F072XB'), (controllertypestr:'STM32F0DISCOVERY'; controllerunitstr:'STM32F051X8'), (controllertypestr:'STM32F100C4'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100C6'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100C8'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100CB'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100R4'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100R6'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100R8'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100RB'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100RC'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F100RD'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F100RE'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F100V8'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100VB'; controllerunitstr:'STM32F100XB'), (controllertypestr:'STM32F100VC'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F100VD'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F100VE'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F100ZC'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F100ZD'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F100ZE'; controllerunitstr:'STM32F100XE'), (controllertypestr:'STM32F101C4'; controllerunitstr:'STM32F101X6'), (controllertypestr:'STM32F101C6'; controllerunitstr:'STM32F101X6'), (controllertypestr:'STM32F101C8'; controllerunitstr:'STM32F101XB'), (controllertypestr:'STM32F101CB'; controllerunitstr:'STM32F101XB'), (controllertypestr:'STM32F101R4'; controllerunitstr:'STM32F101X6'), (controllertypestr:'STM32F101R6'; controllerunitstr:'STM32F101X6'), (controllertypestr:'STM32F101R8'; controllerunitstr:'STM32F101XB'), (controllertypestr:'STM32F101RB'; controllerunitstr:'STM32F101XB'), (controllertypestr:'STM32F101RC'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101RD'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101RE'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101RF'; controllerunitstr:'STM32F101XG'), (controllertypestr:'STM32F101RG'; controllerunitstr:'STM32F101XG'), (controllertypestr:'STM32F101T4'; controllerunitstr:'STM32F101X6'), (controllertypestr:'STM32F101T6'; controllerunitstr:'STM32F101X6'), (controllertypestr:'STM32F101T8'; controllerunitstr:'STM32F101XB'), (controllertypestr:'STM32F101TB'; controllerunitstr:'STM32F101XB'), (controllertypestr:'STM32F101V8'; controllerunitstr:'STM32F101XB'), (controllertypestr:'STM32F101VB'; controllerunitstr:'STM32F101XB'), (controllertypestr:'STM32F101VC'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101VD'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101VE'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101VF'; controllerunitstr:'STM32F101XG'), (controllertypestr:'STM32F101VG'; controllerunitstr:'STM32F101XG'), (controllertypestr:'STM32F101ZC'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101ZD'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101ZE'; controllerunitstr:'STM32F101XE'), (controllertypestr:'STM32F101ZF'; controllerunitstr:'STM32F101XG'), (controllertypestr:'STM32F101ZG'; controllerunitstr:'STM32F101XG'), (controllertypestr:'STM32F102C4'; controllerunitstr:'STM32F102X6'), (controllertypestr:'STM32F102C6'; controllerunitstr:'STM32F102X6'), (controllertypestr:'STM32F102C8'; controllerunitstr:'STM32F102XB'), (controllertypestr:'STM32F102CB'; controllerunitstr:'STM32F102XB'), (controllertypestr:'STM32F102R4'; controllerunitstr:'STM32F102X6'), (controllertypestr:'STM32F102R6'; controllerunitstr:'STM32F102X6'), (controllertypestr:'STM32F102R8'; controllerunitstr:'STM32F102XB'), (controllertypestr:'STM32F102RB'; controllerunitstr:'STM32F102XB'), (controllertypestr:'STM32F103C4'; controllerunitstr:'STM32F103X6'), (controllertypestr:'STM32F103C6'; controllerunitstr:'STM32F103X6'), (controllertypestr:'STM32F103C8'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F103CB'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F103R4'; controllerunitstr:'STM32F103X6'), (controllertypestr:'STM32F103R6'; controllerunitstr:'STM32F103X6'), (controllertypestr:'STM32F103R8'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F103RB'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F103RC'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103RD'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103RE'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103RF'; controllerunitstr:'STM32F103XG'), (controllertypestr:'STM32F103RG'; controllerunitstr:'STM32F103XG'), (controllertypestr:'STM32F103T4'; controllerunitstr:'STM32F103X6'), (controllertypestr:'STM32F103T6'; controllerunitstr:'STM32F103X6'), (controllertypestr:'STM32F103T8'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F103TB'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F103V8'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F103VB'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F103VC'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103VD'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103VE'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103VF'; controllerunitstr:'STM32F103XG'), (controllertypestr:'STM32F103VG'; controllerunitstr:'STM32F103XG'), (controllertypestr:'STM32F103ZC'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103ZD'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103ZE'; controllerunitstr:'STM32F103XE'), (controllertypestr:'STM32F103ZF'; controllerunitstr:'STM32F103XG'), (controllertypestr:'STM32F103ZG'; controllerunitstr:'STM32F103XG'), (controllertypestr:'STM32F105R8'; controllerunitstr:'STM32F105XC'), (controllertypestr:'STM32F105RB'; controllerunitstr:'STM32F105XC'), (controllertypestr:'STM32F105RC'; controllerunitstr:'STM32F105XC'), (controllertypestr:'STM32F105V8'; controllerunitstr:'STM32F105XC'), (controllertypestr:'STM32F105VB'; controllerunitstr:'STM32F105XC'), (controllertypestr:'STM32F105VC'; controllerunitstr:'STM32F105XC'), (controllertypestr:'STM32F107RB'; controllerunitstr:'STM32F107XC'), (controllertypestr:'STM32F107RC'; controllerunitstr:'STM32F107XC'), (controllertypestr:'STM32F107VB'; controllerunitstr:'STM32F107XC'), (controllertypestr:'STM32F107VC'; controllerunitstr:'STM32F107XC'), (controllertypestr:'NUCLEOF103RB'; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32VLDISCOVERY'; controllerunitstr:'STM32F100XB'), (controllertypestr:'BLUEPILL' ; controllerunitstr:'STM32F103XB'), (controllertypestr:'STM32F205RB'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205RC'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205RE'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205RF'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205RG'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205VB'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205VC'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205VE'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205VF'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205VG'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205ZC'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205ZE'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205ZF'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F205ZG'; controllerunitstr:'STM32F205XX'), (controllertypestr:'STM32F207IC'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207IE'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207IF'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207IG'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207VC'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207VE'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207VF'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207VG'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207ZC'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207ZE'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207ZF'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F207ZG'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F215RE'; controllerunitstr:'STM32F215XX'), (controllertypestr:'STM32F215RG'; controllerunitstr:'STM32F215XX'), (controllertypestr:'STM32F215VE'; controllerunitstr:'STM32F215XX'), (controllertypestr:'STM32F215VG'; controllerunitstr:'STM32F215XX'), (controllertypestr:'STM32F215ZE'; controllerunitstr:'STM32F215XX'), (controllertypestr:'STM32F215ZG'; controllerunitstr:'STM32F215XX'), (controllertypestr:'STM32F217IE'; controllerunitstr:'STM32F217XX'), (controllertypestr:'STM32F217IG'; controllerunitstr:'STM32F217XX'), (controllertypestr:'STM32F217VE'; controllerunitstr:'STM32F217XX'), (controllertypestr:'STM32F217VG'; controllerunitstr:'STM32F217XX'), (controllertypestr:'STM32F217ZE'; controllerunitstr:'STM32F217XX'), (controllertypestr:'STM32F217ZG'; controllerunitstr:'STM32F217XX'), (controllertypestr:'NUCLEOF207ZG'; controllerunitstr:'STM32F207XX'), (controllertypestr:'STM32F301C6'; controllerunitstr:'STM32F301X8'), (controllertypestr:'STM32F301C8'; controllerunitstr:'STM32F301X8'), (controllertypestr:'STM32F301K6'; controllerunitstr:'STM32F301X8'), (controllertypestr:'STM32F301K8'; controllerunitstr:'STM32F301X8'), (controllertypestr:'STM32F301R6'; controllerunitstr:'STM32F301X8'), (controllertypestr:'STM32F301R8'; controllerunitstr:'STM32F301X8'), (controllertypestr:'STM32F302C6'; controllerunitstr:'STM32F302X8'), (controllertypestr:'STM32F302C8'; controllerunitstr:'STM32F302X8'), (controllertypestr:'STM32F302CB'; controllerunitstr:'STM32F302XC'), (controllertypestr:'STM32F302CC'; controllerunitstr:'STM32F302XC'), (controllertypestr:'STM32F302K6'; controllerunitstr:'STM32F302X8'), (controllertypestr:'STM32F302K8'; controllerunitstr:'STM32F302X8'), (controllertypestr:'STM32F302R6'; controllerunitstr:'STM32F302X8'), (controllertypestr:'STM32F302R8'; controllerunitstr:'STM32F302X8'), (controllertypestr:'STM32F302RB'; controllerunitstr:'STM32F302XC'), (controllertypestr:'STM32F302RC'; controllerunitstr:'STM32F302XC'), (controllertypestr:'STM32F302RD'; controllerunitstr:'STM32F302XE'), (controllertypestr:'STM32F302RE'; controllerunitstr:'STM32F302XE'), (controllertypestr:'STM32F302VB'; controllerunitstr:'STM32F302XC'), (controllertypestr:'STM32F302VC'; controllerunitstr:'STM32F302XC'), (controllertypestr:'STM32F302VD'; controllerunitstr:'STM32F302XE'), (controllertypestr:'STM32F302VE'; controllerunitstr:'STM32F302XE'), (controllertypestr:'STM32F302ZD'; controllerunitstr:'STM32F302XE'), (controllertypestr:'STM32F302ZE'; controllerunitstr:'STM32F302XE'), (controllertypestr:'STM32F303C6'; controllerunitstr:'STM32F303X8'), (controllertypestr:'STM32F303C8'; controllerunitstr:'STM32F303X8'), (controllertypestr:'STM32F303CB'; controllerunitstr:'STM32F303XC'), (controllertypestr:'STM32F303CC'; controllerunitstr:'STM32F303XC'), (controllertypestr:'STM32F303K6'; controllerunitstr:'STM32F303X8'), (controllertypestr:'STM32F303K8'; controllerunitstr:'STM32F303X8'), (controllertypestr:'STM32F303R6'; controllerunitstr:'STM32F303X8'), (controllertypestr:'STM32F303R8'; controllerunitstr:'STM32F303X8'), (controllertypestr:'STM32F303RB'; controllerunitstr:'STM32F303XC'), (controllertypestr:'STM32F303RC'; controllerunitstr:'STM32F303XC'), (controllertypestr:'STM32F303RD'; controllerunitstr:'STM32F303XE'), (controllertypestr:'STM32F303RE'; controllerunitstr:'STM32F303XE'), (controllertypestr:'STM32F303VB'; controllerunitstr:'STM32F303XC'), (controllertypestr:'STM32F303VC'; controllerunitstr:'STM32F303XC'), (controllertypestr:'STM32F303VD'; controllerunitstr:'STM32F303XE'), (controllertypestr:'STM32F303VE'; controllerunitstr:'STM32F303XE'), (controllertypestr:'STM32F303ZD'; controllerunitstr:'STM32F303XE'), (controllertypestr:'STM32F303ZE'; controllerunitstr:'STM32F303XE'), (controllertypestr:'STM32F318C8'; controllerunitstr:'STM32F318XX'), (controllertypestr:'STM32F318K8'; controllerunitstr:'STM32F318XX'), (controllertypestr:'STM32F328C8'; controllerunitstr:'STM32F328XX'), (controllertypestr:'STM32F334C4'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F334C6'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F334C8'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F334K4'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F334K6'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F334K8'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F334R6'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F334R8'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F358CC'; controllerunitstr:'STM32F358XX'), (controllertypestr:'STM32F358RC'; controllerunitstr:'STM32F358XX'), (controllertypestr:'STM32F358VC'; controllerunitstr:'STM32F358XX'), (controllertypestr:'STM32F373C8'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F373CB'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F373CC'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F373R8'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F373RB'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F373RC'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F373V8'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F373VB'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F373VC'; controllerunitstr:'STM32F373XC'), (controllertypestr:'STM32F378CC'; controllerunitstr:'STM32F378XX'), (controllertypestr:'STM32F378RC'; controllerunitstr:'STM32F378XX'), (controllertypestr:'STM32F378VC'; controllerunitstr:'STM32F378XX'), (controllertypestr:'STM32F398VE'; controllerunitstr:'STM32F398XX'), (controllertypestr:'NUCLEOF302R8'; controllerunitstr:'STM32F302X8'), (controllertypestr:'NUCLEOF303K8'; controllerunitstr:'STM32F303X8'), (controllertypestr:'NUCLEOF303RE'; controllerunitstr:'STM32F303XE'), (controllertypestr:'NUCLEOF303ZE'; controllerunitstr:'STM32F303XE'), (controllertypestr:'NUCLEOF334R8'; controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F3348DISCOVERY';controllerunitstr:'STM32F334X8'), (controllertypestr:'STM32F3DISCOVERY'; controllerunitstr:'STM32F303XC'), (controllertypestr:'STM32F401CB'; controllerunitstr:'STM32F401XC'), (controllertypestr:'STM32F401CC'; controllerunitstr:'STM32F401XC'), (controllertypestr:'STM32F401CD'; controllerunitstr:'STM32F401XE'), (controllertypestr:'STM32F401CE'; controllerunitstr:'STM32F401XE'), (controllertypestr:'STM32F401RB'; controllerunitstr:'STM32F401XC'), (controllertypestr:'STM32F401RC'; controllerunitstr:'STM32F401XC'), (controllertypestr:'STM32F401RD'; controllerunitstr:'STM32F401XE'), (controllertypestr:'STM32F401RE'; controllerunitstr:'STM32F401XE'), (controllertypestr:'STM32F401VB'; controllerunitstr:'STM32F401XC'), (controllertypestr:'STM32F401VC'; controllerunitstr:'STM32F401XC'), (controllertypestr:'STM32F401VD'; controllerunitstr:'STM32F401XE'), (controllertypestr:'STM32F401VE'; controllerunitstr:'STM32F401XE'), (controllertypestr:'STM32F405OE'; controllerunitstr:'STM32F405XX'), (controllertypestr:'STM32F405OG'; controllerunitstr:'STM32F405XX'), (controllertypestr:'STM32F405RG'; controllerunitstr:'STM32F405XX'), (controllertypestr:'STM32F405VG'; controllerunitstr:'STM32F405XX'), (controllertypestr:'STM32F405ZG'; controllerunitstr:'STM32F405XX'), (controllertypestr:'STM32F407IE'; controllerunitstr:'STM32F407XX'), (controllertypestr:'STM32F407IG'; controllerunitstr:'STM32F407XX'), (controllertypestr:'STM32F407VE'; controllerunitstr:'STM32F407XX'), (controllertypestr:'STM32F407VG'; controllerunitstr:'STM32F407XX'), (controllertypestr:'STM32F407ZE'; controllerunitstr:'STM32F407XX'), (controllertypestr:'STM32F407ZG'; controllerunitstr:'STM32F407XX'), (controllertypestr:'STM32F410C8'; controllerunitstr:'STM32F410CX'), (controllertypestr:'STM32F410CB'; controllerunitstr:'STM32F410CX'), (controllertypestr:'STM32F410R8'; controllerunitstr:'STM32F410RX'), (controllertypestr:'STM32F410RB'; controllerunitstr:'STM32F410RX'), (controllertypestr:'STM32F410T8'; controllerunitstr:'STM32F410TX'), (controllertypestr:'STM32F410TB'; controllerunitstr:'STM32F410TX'), (controllertypestr:'STM32F411CC'; controllerunitstr:'STM32F411XE'), (controllertypestr:'STM32F411CE'; controllerunitstr:'STM32F411XE'), (controllertypestr:'STM32F411RC'; controllerunitstr:'STM32F411XE'), (controllertypestr:'STM32F411RE'; controllerunitstr:'STM32F411XE'), (controllertypestr:'STM32F411VC'; controllerunitstr:'STM32F411XE'), (controllertypestr:'STM32F411VE'; controllerunitstr:'STM32F411XE'), (controllertypestr:'STM32F412CE'; controllerunitstr:'STM32F412CX'), (controllertypestr:'STM32F412CG'; controllerunitstr:'STM32F412CX'), (controllertypestr:'STM32F412RE'; controllerunitstr:'STM32F412RX'), (controllertypestr:'STM32F412REP'; controllerunitstr:'STM32F412RX'), (controllertypestr:'STM32F412RG'; controllerunitstr:'STM32F412RX'), (controllertypestr:'STM32F412RGP'; controllerunitstr:'STM32F412RX'), (controllertypestr:'STM32F412VE'; controllerunitstr:'STM32F412VX'), (controllertypestr:'STM32F412VG'; controllerunitstr:'STM32F412VX'), (controllertypestr:'STM32F412ZE'; controllerunitstr:'STM32F412ZX'), (controllertypestr:'STM32F412ZG'; controllerunitstr:'STM32F412ZX'), (controllertypestr:'STM32F413CG'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413CH'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413MG'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413MH'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413RG'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413RH'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413VG'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413VH'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413ZG'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F413ZH'; controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F415OG'; controllerunitstr:'STM32F415XX'), (controllertypestr:'STM32F415RG'; controllerunitstr:'STM32F415XX'), (controllertypestr:'STM32F415VG'; controllerunitstr:'STM32F415XX'), (controllertypestr:'STM32F415ZG'; controllerunitstr:'STM32F415XX'), (controllertypestr:'STM32F417IE'; controllerunitstr:'STM32F417XX'), (controllertypestr:'STM32F417IG'; controllerunitstr:'STM32F417XX'), (controllertypestr:'STM32F417VE'; controllerunitstr:'STM32F417XX'), (controllertypestr:'STM32F417VG'; controllerunitstr:'STM32F417XX'), (controllertypestr:'STM32F417ZE'; controllerunitstr:'STM32F417XX'), (controllertypestr:'STM32F417ZG'; controllerunitstr:'STM32F417XX'), (controllertypestr:'STM32F423CH'; controllerunitstr:'STM32F423XX'), (controllertypestr:'STM32F423MH'; controllerunitstr:'STM32F423XX'), (controllertypestr:'STM32F423RH'; controllerunitstr:'STM32F423XX'), (controllertypestr:'STM32F423VH'; controllerunitstr:'STM32F423XX'), (controllertypestr:'STM32F423ZH'; controllerunitstr:'STM32F423XX'), (controllertypestr:'STM32F427AG'; controllerunitstr:'STM32F427XX'), (controllertypestr:'STM32F427AI'; controllerunitstr:'STM32F427XX'), (controllertypestr:'STM32F427IG'; controllerunitstr:'STM32F427XX'), (controllertypestr:'STM32F427II'; controllerunitstr:'STM32F427XX'), (controllertypestr:'STM32F427VG'; controllerunitstr:'STM32F427XX'), (controllertypestr:'STM32F427VI'; controllerunitstr:'STM32F427XX'), (controllertypestr:'STM32F427ZG'; controllerunitstr:'STM32F427XX'), (controllertypestr:'STM32F427ZI'; controllerunitstr:'STM32F427XX'), (controllertypestr:'STM32F429AG'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429AI'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429BE'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429BG'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429BI'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429IE'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429IG'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429II'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429NE'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429NG'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429NI'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429VE'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429VG'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429VI'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429ZE'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429ZG'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F429ZI'; controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F437AI'; controllerunitstr:'STM32F437XX'), (controllertypestr:'STM32F437IG'; controllerunitstr:'STM32F437XX'), (controllertypestr:'STM32F437II'; controllerunitstr:'STM32F437XX'), (controllertypestr:'STM32F437VG'; controllerunitstr:'STM32F437XX'), (controllertypestr:'STM32F437VI'; controllerunitstr:'STM32F437XX'), (controllertypestr:'STM32F437ZG'; controllerunitstr:'STM32F437XX'), (controllertypestr:'STM32F437ZI'; controllerunitstr:'STM32F437XX'), (controllertypestr:'STM32F439AI'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439BG'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439BI'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439IG'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439II'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439NG'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439NI'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439VG'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439VI'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439ZG'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F439ZI'; controllerunitstr:'STM32F439XX'), (controllertypestr:'STM32F446MC'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F446ME'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F446RC'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F446RE'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F446VC'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F446VE'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F446ZC'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F446ZE'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F469AE'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469AG'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469AI'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469BE'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469BG'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469BI'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469IE'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469IG'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469II'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469NE'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469NG'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469NI'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469VE'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469VG'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469VI'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469ZE'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469ZG'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F469ZI'; controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F479AG'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479AI'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479BG'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479BI'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479IG'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479II'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479NG'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479NI'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479VG'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479VI'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479ZG'; controllerunitstr:'STM32F479XX'), (controllertypestr:'STM32F479ZI'; controllerunitstr:'STM32F479XX'), (controllertypestr:'NUCLEOF401RE'; controllerunitstr:'STM32F401XE'), (controllertypestr:'NUCLEOF410RB'; controllerunitstr:'STM32F410RX'), (controllertypestr:'NUCLEOF411RE'; controllerunitstr:'STM32F411XE'), (controllertypestr:'NUCLEOF412ZG'; controllerunitstr:'STM32F412ZX'), (controllertypestr:'NUCLEOF413ZH'; controllerunitstr:'STM32F413XX'), (controllertypestr:'NUCLEOF429ZI'; controllerunitstr:'STM32F429XX'), (controllertypestr:'NUCLEOF439ZI'; controllerunitstr:'STM32F439XX'), (controllertypestr:'NUCLEOF446RE'; controllerunitstr:'STM32F446XX'), (controllertypestr:'NUCLEOF446ZE'; controllerunitstr:'STM32F446XX'), (controllertypestr:'STM32F401CDISCOVERY';controllerunitstr:'STM32F401XC'), (controllertypestr:'STM32F407GDISCOVERY';controllerunitstr:'STM32F407XX'), (controllertypestr:'STM32F411EDISCOVERY';controllerunitstr:'STM32F411XE'), (controllertypestr:'STM32F412GDISCOVERY';controllerunitstr:'STM32F412ZX'), (controllertypestr:'STM32F413HDISCOVERY';controllerunitstr:'STM32F413XX'), (controllertypestr:'STM32F429IDISCOVERY';controllerunitstr:'STM32F429XX'), (controllertypestr:'STM32F469IDISCOVERY';controllerunitstr:'STM32F469XX'), (controllertypestr:'STM32F722IC'; controllerunitstr:'STM32F722XX'), (controllertypestr:'STM32F722IE'; controllerunitstr:'STM32F722XX'), (controllertypestr:'STM32F722RC'; controllerunitstr:'STM32F722XX'), (controllertypestr:'STM32F722RE'; controllerunitstr:'STM32F722XX'), (controllertypestr:'STM32F722VC'; controllerunitstr:'STM32F722XX'), (controllertypestr:'STM32F722VE'; controllerunitstr:'STM32F722XX'), (controllertypestr:'STM32F722ZC'; controllerunitstr:'STM32F722XX'), (controllertypestr:'STM32F722ZE'; controllerunitstr:'STM32F722XX'), (controllertypestr:'STM32F723IC'; controllerunitstr:'STM32F723XX'), (controllertypestr:'STM32F723IE'; controllerunitstr:'STM32F723XX'), (controllertypestr:'STM32F723VC'; controllerunitstr:'STM32F723XX'), (controllertypestr:'STM32F723VE'; controllerunitstr:'STM32F723XX'), (controllertypestr:'STM32F723ZC'; controllerunitstr:'STM32F723XX'), (controllertypestr:'STM32F723ZE'; controllerunitstr:'STM32F723XX'), (controllertypestr:'STM32F730I8'; controllerunitstr:'STM32F730XX'), (controllertypestr:'STM32F730R8'; controllerunitstr:'STM32F730XX'), (controllertypestr:'STM32F730V8'; controllerunitstr:'STM32F730XX'), (controllertypestr:'STM32F730Z8'; controllerunitstr:'STM32F730XX'), (controllertypestr:'STM32F732IE'; controllerunitstr:'STM32F732XX'), (controllertypestr:'STM32F732RE'; controllerunitstr:'STM32F732XX'), (controllertypestr:'STM32F732VE'; controllerunitstr:'STM32F732XX'), (controllertypestr:'STM32F732ZE'; controllerunitstr:'STM32F732XX'), (controllertypestr:'STM32F733IE'; controllerunitstr:'STM32F733XX'), (controllertypestr:'STM32F733VE'; controllerunitstr:'STM32F733XX'), (controllertypestr:'STM32F733ZE'; controllerunitstr:'STM32F733XX'), (controllertypestr:'STM32F745IE'; controllerunitstr:'STM32F745XX'), (controllertypestr:'STM32F745IG'; controllerunitstr:'STM32F745XX'), (controllertypestr:'STM32F745VE'; controllerunitstr:'STM32F745XX'), (controllertypestr:'STM32F745VG'; controllerunitstr:'STM32F745XX'), (controllertypestr:'STM32F745ZE'; controllerunitstr:'STM32F745XX'), (controllertypestr:'STM32F745ZG'; controllerunitstr:'STM32F745XX'), (controllertypestr:'STM32F746BE'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746BG'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746IE'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746IG'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746NE'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746NG'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746VE'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746VG'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746ZE'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F746ZG'; controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F750N8'; controllerunitstr:'STM32F750XX'), (controllertypestr:'STM32F750V8'; controllerunitstr:'STM32F750XX'), (controllertypestr:'STM32F750Z8'; controllerunitstr:'STM32F750XX'), (controllertypestr:'STM32F756BG'; controllerunitstr:'STM32F756XX'), (controllertypestr:'STM32F756IG'; controllerunitstr:'STM32F756XX'), (controllertypestr:'STM32F756NG'; controllerunitstr:'STM32F756XX'), (controllertypestr:'STM32F756VG'; controllerunitstr:'STM32F756XX'), (controllertypestr:'STM32F756ZG'; controllerunitstr:'STM32F756XX'), (controllertypestr:'STM32F765BG'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765BI'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765IG'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765II'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765NG'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765NI'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765VG'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765VI'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765ZG'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F765ZI'; controllerunitstr:'STM32F765XX'), (controllertypestr:'STM32F767BG'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767BI'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767IG'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767II'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767NG'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767NI'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767VG'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767VI'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767ZG'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F767ZI'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F768AI'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F769AG'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F769AI'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F769BG'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F769BI'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F769IG'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F769II'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F769NG'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F769NI'; controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32F777BI'; controllerunitstr:'STM32F777XX'), (controllertypestr:'STM32F777II'; controllerunitstr:'STM32F777XX'), (controllertypestr:'STM32F777NI'; controllerunitstr:'STM32F777XX'), (controllertypestr:'STM32F777VI'; controllerunitstr:'STM32F777XX'), (controllertypestr:'STM32F777ZI'; controllerunitstr:'STM32F777XX'), (controllertypestr:'STM32F778AI'; controllerunitstr:'STM32F779XX'), (controllertypestr:'STM32F779AI'; controllerunitstr:'STM32F779XX'), (controllertypestr:'STM32F779BI'; controllerunitstr:'STM32F779XX'), (controllertypestr:'STM32F779II'; controllerunitstr:'STM32F779XX'), (controllertypestr:'STM32F779NI'; controllerunitstr:'STM32F779XX'), (controllertypestr:'NUCLEOF722ZE'; controllerunitstr:'STM32F722XX'), (controllertypestr:'NUCLEOF746ZG'; controllerunitstr:'STM32F746XX'), (controllertypestr:'NUCLEOF767ZI'; controllerunitstr:'STM32F767XX'), (controllertypestr:'STM32F723EDISCOVERY';controllerunitstr:'STM32F723XX'), (controllertypestr:'STM32F7308DK'; controllerunitstr:'STM32F730XX'), (controllertypestr:'STM32F746GDISCOVERY';controllerunitstr:'STM32F746XX'), (controllertypestr:'STM32F7508DK'; controllerunitstr:'STM32F750XX'), (controllertypestr:'STM32F769IDISCOVERY';controllerunitstr:'STM32F769XX'), (controllertypestr:'STM32G030C6'; controllerunitstr:'STM32G030XX'), (controllertypestr:'STM32G030C8'; controllerunitstr:'STM32G030XX'), (controllertypestr:'STM32G030F6'; controllerunitstr:'STM32G030XX'), (controllertypestr:'STM32G030J6'; controllerunitstr:'STM32G030XX'), (controllertypestr:'STM32G030K6'; controllerunitstr:'STM32G030XX'), (controllertypestr:'STM32G030K8'; controllerunitstr:'STM32G030XX'), (controllertypestr:'STM32G031C4'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031C6'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031C8'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031F4'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031F6'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031F8'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031G4'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031G6'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031G8'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031J4'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031J6'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031K4'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031K6'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031K8'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G031Y8'; controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G041C6'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041C8'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041F6'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041F8'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041G6'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041G8'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041J6'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041K6'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041K8'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G041Y8'; controllerunitstr:'STM32G041XX'), (controllertypestr:'STM32G070CB'; controllerunitstr:'STM32G070XX'), (controllertypestr:'STM32G070KB'; controllerunitstr:'STM32G070XX'), (controllertypestr:'STM32G070RB'; controllerunitstr:'STM32G070XX'), (controllertypestr:'STM32G071C6'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071C8'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071CB'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071EB'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071G6'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071G8'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071G8N'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071GB'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071GBN'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071K6'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071K8'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071K8N'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071KB'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071KBN'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071R6'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071R8'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G071RB'; controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G081CB'; controllerunitstr:'STM32G081XX'), (controllertypestr:'STM32G081EB'; controllerunitstr:'STM32G081XX'), (controllertypestr:'STM32G081GB'; controllerunitstr:'STM32G081XX'), (controllertypestr:'STM32G081GBN'; controllerunitstr:'STM32G081XX'), (controllertypestr:'STM32G081KB'; controllerunitstr:'STM32G081XX'), (controllertypestr:'STM32G081KBN'; controllerunitstr:'STM32G081XX'), (controllertypestr:'STM32G081RB'; controllerunitstr:'STM32G081XX'), (controllertypestr:'STM32G0B0CE'; controllerunitstr:'STM32G0B0XX'), (controllertypestr:'STM32G0B0KE'; controllerunitstr:'STM32G0B0XX'), (controllertypestr:'STM32G0B0RE'; controllerunitstr:'STM32G0B0XX'), (controllertypestr:'STM32G0B0VE'; controllerunitstr:'STM32G0B0XX'), (controllertypestr:'STM32G0B1CC'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1CE'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1KC'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1KCN'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1KE'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1KEN'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1MC'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1ME'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1RC'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1RE'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1VC'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0B1VE'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0C1CC'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1CE'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1KC'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1KCN'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1KE'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1KEN'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1MC'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1ME'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1RC'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1RE'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1VC'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'STM32G0C1VE'; controllerunitstr:'STM32G0C1XX'), (controllertypestr:'NUCLEOG031K8'; controllerunitstr:'STM32G031XX'), (controllertypestr:'NUCLEOG070RB'; controllerunitstr:'STM32G070XX'), (controllertypestr:'NUCLEOG071RB'; controllerunitstr:'STM32G071XX'), (controllertypestr:'NUCLEOG0B1RE'; controllerunitstr:'STM32G0B1XX'), (controllertypestr:'STM32G0316DISCOVERY';controllerunitstr:'STM32G031XX'), (controllertypestr:'STM32G071BDISCOVERY';controllerunitstr:'STM32G071XX'), (controllertypestr:'STM32G431C6'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431C8'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431CB'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431K6'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431K8'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431KB'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431M6'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431M8'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431MB'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431R6'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431R8'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431RB'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431V6'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431V8'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G431VB'; controllerunitstr:'STM32G431XX'), (controllertypestr:'STM32G441CB'; controllerunitstr:'STM32G441XX'), (controllertypestr:'STM32G441KB'; controllerunitstr:'STM32G441XX'), (controllertypestr:'STM32G441MB'; controllerunitstr:'STM32G441XX'), (controllertypestr:'STM32G441RB'; controllerunitstr:'STM32G441XX'), (controllertypestr:'STM32G441VB'; controllerunitstr:'STM32G441XX'), (controllertypestr:'STM32G471CC'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471CE'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471MC'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471ME'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471QC'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471QE'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471RC'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471RE'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471VC'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G471VE'; controllerunitstr:'STM32G471XX'), (controllertypestr:'STM32G473CB'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473CC'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473CE'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473MB'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473MC'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473ME'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473PB'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473PC'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473PE'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473QB'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473QC'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473QE'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473RB'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473RC'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473RE'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473VB'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473VC'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G473VE'; controllerunitstr:'STM32G473XX'), (controllertypestr:'STM32G474CB'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474CC'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474CE'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474MB'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474MC'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474ME'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474PB'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474PC'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474PE'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474QB'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474QC'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474QE'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474RB'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474RC'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474RE'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474VB'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474VC'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G474VE'; controllerunitstr:'STM32G474XX'), (controllertypestr:'STM32G483CE'; controllerunitstr:'STM32G483XX'), (controllertypestr:'STM32G483ME'; controllerunitstr:'STM32G483XX'), (controllertypestr:'STM32G483PE'; controllerunitstr:'STM32G483XX'), (controllertypestr:'STM32G483QE'; controllerunitstr:'STM32G483XX'), (controllertypestr:'STM32G483RE'; controllerunitstr:'STM32G483XX'), (controllertypestr:'STM32G483VE'; controllerunitstr:'STM32G483XX'), (controllertypestr:'STM32G484CE'; controllerunitstr:'STM32G484XX'), (controllertypestr:'STM32G484ME'; controllerunitstr:'STM32G484XX'), (controllertypestr:'STM32G484PE'; controllerunitstr:'STM32G484XX'), (controllertypestr:'STM32G484QE'; controllerunitstr:'STM32G484XX'), (controllertypestr:'STM32G484RE'; controllerunitstr:'STM32G484XX'), (controllertypestr:'STM32G484VE'; controllerunitstr:'STM32G484XX'), (controllertypestr:'STM32G491CC'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491CE'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491KC'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491KE'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491MC'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491MCSX'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491ME'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491MESX'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491RC'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491RE'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491VC'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G491VE'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32G4A1CE'; controllerunitstr:'STM32G4A1XX'), (controllertypestr:'STM32G4A1KE'; controllerunitstr:'STM32G4A1XX'), (controllertypestr:'STM32G4A1ME'; controllerunitstr:'STM32G4A1XX'), (controllertypestr:'STM32G4A1MESX'; controllerunitstr:'STM32G4A1XX'), (controllertypestr:'STM32G4A1RE'; controllerunitstr:'STM32G4A1XX'), (controllertypestr:'STM32G4A1VE'; controllerunitstr:'STM32G4A1XX'), (controllertypestr:'BG474EDPOW1'; controllerunitstr:'STM32G474XX'), (controllertypestr:'NUCLEOG431KB'; controllerunitstr:'STM32G431XX'), (controllertypestr:'NUCLEOG431RB'; controllerunitstr:'STM32G431XX'), (controllertypestr:'NUCLEOG474RE'; controllerunitstr:'STM32G474XX'), (controllertypestr:'NUCLEOG491RE'; controllerunitstr:'STM32G491XX'), (controllertypestr:'STM32H723VE'; controllerunitstr:'STM32H723XX'), (controllertypestr:'STM32H723VG'; controllerunitstr:'STM32H723XX'), (controllertypestr:'STM32H723ZE'; controllerunitstr:'STM32H723XX'), (controllertypestr:'STM32H723ZG'; controllerunitstr:'STM32H723XX'), (controllertypestr:'STM32H725AE'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725AG'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725IE'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725IG'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725RE'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725RG'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725VE'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725VG'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725ZE'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H725ZG'; controllerunitstr:'STM32H725XX'), (controllertypestr:'STM32H730ABQ'; controllerunitstr:'STM32H730XX'), (controllertypestr:'STM32H730IBQ'; controllerunitstr:'STM32H730XX'), (controllertypestr:'STM32H730VB'; controllerunitstr:'STM32H730XX'), (controllertypestr:'STM32H730ZB'; controllerunitstr:'STM32H730XX'), (controllertypestr:'STM32H733VG'; controllerunitstr:'STM32H733XX'), (controllertypestr:'STM32H733ZG'; controllerunitstr:'STM32H733XX'), (controllertypestr:'STM32H735AG'; controllerunitstr:'STM32H735XX'), (controllertypestr:'STM32H735IG'; controllerunitstr:'STM32H735XX'), (controllertypestr:'STM32H735RG'; controllerunitstr:'STM32H735XX'), (controllertypestr:'STM32H735VG'; controllerunitstr:'STM32H735XX'), (controllertypestr:'STM32H735ZG'; controllerunitstr:'STM32H735XX'), (controllertypestr:'STM32H742AG'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742AI'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742BG'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742BI'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742IG'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742II'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742VG'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742VI'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742XG'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742XI'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742ZG'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H742ZI'; controllerunitstr:'STM32H742XX'), (controllertypestr:'STM32H743AG'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743AI'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743BG'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743BI'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743IG'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743II'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743VG'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743VI'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743XG'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743XI'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743ZG'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H743ZI'; controllerunitstr:'STM32H743XX'), (controllertypestr:'STM32H745BG'; controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H745BI'; controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H745IG'; controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H745II'; controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H745XG'; controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H745XI'; controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H745ZG'; controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H745ZI'; controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H747AG'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H747AI'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H747BG'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H747BI'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H747IG'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H747II'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H747XG'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H747XI'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H747ZI'; controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H750IB'; controllerunitstr:'STM32H750XX'), (controllertypestr:'STM32H750VB'; controllerunitstr:'STM32H750XX'), (controllertypestr:'STM32H750XB'; controllerunitstr:'STM32H750XX'), (controllertypestr:'STM32H750ZB'; controllerunitstr:'STM32H750XX'), (controllertypestr:'STM32H753AI'; controllerunitstr:'STM32H753XX'), (controllertypestr:'STM32H753BI'; controllerunitstr:'STM32H753XX'), (controllertypestr:'STM32H753II'; controllerunitstr:'STM32H753XX'), (controllertypestr:'STM32H753VI'; controllerunitstr:'STM32H753XX'), (controllertypestr:'STM32H753XI'; controllerunitstr:'STM32H753XX'), (controllertypestr:'STM32H753ZI'; controllerunitstr:'STM32H753XX'), (controllertypestr:'STM32H755BI'; controllerunitstr:'STM32H755XX'), (controllertypestr:'STM32H755II'; controllerunitstr:'STM32H755XX'), (controllertypestr:'STM32H755XI'; controllerunitstr:'STM32H755XX'), (controllertypestr:'STM32H755ZI'; controllerunitstr:'STM32H755XX'), (controllertypestr:'STM32H757AI'; controllerunitstr:'STM32H757XX'), (controllertypestr:'STM32H757BI'; controllerunitstr:'STM32H757XX'), (controllertypestr:'STM32H757II'; controllerunitstr:'STM32H757XX'), (controllertypestr:'STM32H757XI'; controllerunitstr:'STM32H757XX'), (controllertypestr:'STM32H757ZI'; controllerunitstr:'STM32H757XX'), (controllertypestr:'STM32H7A3AGQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3AIQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3IG'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3IGQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3II'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3IIQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3LGQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3LIQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3NG'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3NI'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3QIQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3RG'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3RI'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3VG'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3VGQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3VI'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3VIQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3ZG'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3ZGQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3ZI'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7A3ZIQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H7B0ABQ'; controllerunitstr:'STM32H7B0XXQ'), (controllertypestr:'STM32H7B0IB'; controllerunitstr:'STM32H7B0XX'), (controllertypestr:'STM32H7B0IBQ'; controllerunitstr:'STM32H7B0XXQ'), (controllertypestr:'STM32H7B0RB'; controllerunitstr:'STM32H7B0XX'), (controllertypestr:'STM32H7B0VB'; controllerunitstr:'STM32H7B0XX'), (controllertypestr:'STM32H7B0ZB'; controllerunitstr:'STM32H7B0XX'), (controllertypestr:'STM32H7B3AIQ'; controllerunitstr:'STM32H7B3XXQ'), (controllertypestr:'STM32H7B3II'; controllerunitstr:'STM32H7B3XX'), (controllertypestr:'STM32H7B3IIQ'; controllerunitstr:'STM32H7B3XXQ'), (controllertypestr:'STM32H7B3LIQ'; controllerunitstr:'STM32H7B3XXQ'), (controllertypestr:'STM32H7B3NI'; controllerunitstr:'STM32H7B3XX'), (controllertypestr:'STM32H7B3QIQ'; controllerunitstr:'STM32H7B3XXQ'), (controllertypestr:'STM32H7B3RI'; controllerunitstr:'STM32H7B3XX'), (controllertypestr:'STM32H7B3VI'; controllerunitstr:'STM32H7B3XX'), (controllertypestr:'STM32H7B3VIQ'; controllerunitstr:'STM32H7B3XXQ'), (controllertypestr:'STM32H7B3ZI'; controllerunitstr:'STM32H7B3XX'), (controllertypestr:'STM32H7B3ZIQ'; controllerunitstr:'STM32H7B3XXQ'), (controllertypestr:'NUCLEOH723ZG'; controllerunitstr:'STM32H723XX'), (controllertypestr:'NUCLEOH743ZI'; controllerunitstr:'STM32H743XX'), (controllertypestr:'NUCLEOH743ZI2'; controllerunitstr:'STM32H743XX'), (controllertypestr:'NUCLEOH745ZIQ'; controllerunitstr:'STM32H745XX'), (controllertypestr:'NUCLEOH753ZI'; controllerunitstr:'STM32H753XX'), (controllertypestr:'NUCLEOH755ZIQ'; controllerunitstr:'STM32H755XX'), (controllertypestr:'NUCLEOH7A3ZIQ'; controllerunitstr:'STM32H7A3XX'), (controllertypestr:'STM32H735GDK'; controllerunitstr:'STM32H735XX'), (controllertypestr:'STM32H745IDISCOVERY';controllerunitstr:'STM32H745XX'), (controllertypestr:'STM32H747IDISCOVERY';controllerunitstr:'STM32H747XX'), (controllertypestr:'STM32H750BDK'; controllerunitstr:'STM32H750XX'), (controllertypestr:'STM32H7B3IDK'; controllerunitstr:'STM32H7B3XXQ'), (controllertypestr:'STM32L010C6'; controllerunitstr:'STM32L010X6'), (controllertypestr:'STM32L010F4'; controllerunitstr:'STM32L010X4'), (controllertypestr:'STM32L010K4'; controllerunitstr:'STM32L010X4'), (controllertypestr:'STM32L010K8'; controllerunitstr:'STM32L010X8'), (controllertypestr:'STM32L010R8'; controllerunitstr:'STM32L010X8'), (controllertypestr:'STM32L010RB'; controllerunitstr:'STM32L010XB'), (controllertypestr:'STM32L011D3'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011D4'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011E3'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011E4'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011F3'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011F4'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011G3'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011G4'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011K3'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L011K4'; controllerunitstr:'STM32L011XX'), (controllertypestr:'STM32L021D4'; controllerunitstr:'STM32L021XX'), (controllertypestr:'STM32L021F4'; controllerunitstr:'STM32L021XX'), (controllertypestr:'STM32L021G4'; controllerunitstr:'STM32L021XX'), (controllertypestr:'STM32L021K4'; controllerunitstr:'STM32L021XX'), (controllertypestr:'STM32L031C4'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031C6'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031E4'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031E6'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031F4'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031F6'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031G4'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031G6'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031G6S'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031K4'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L031K6'; controllerunitstr:'STM32L031XX'), (controllertypestr:'STM32L041C4'; controllerunitstr:'STM32L041XX'), (controllertypestr:'STM32L041C6'; controllerunitstr:'STM32L041XX'), (controllertypestr:'STM32L041E6'; controllerunitstr:'STM32L041XX'), (controllertypestr:'STM32L041F6'; controllerunitstr:'STM32L041XX'), (controllertypestr:'STM32L041G6'; controllerunitstr:'STM32L041XX'), (controllertypestr:'STM32L041G6S'; controllerunitstr:'STM32L041XX'), (controllertypestr:'STM32L041K6'; controllerunitstr:'STM32L041XX'), (controllertypestr:'STM32L051C6'; controllerunitstr:'STM32L051XX'), (controllertypestr:'STM32L051C8'; controllerunitstr:'STM32L051XX'), (controllertypestr:'STM32L051K6'; controllerunitstr:'STM32L051XX'), (controllertypestr:'STM32L051K8'; controllerunitstr:'STM32L051XX'), (controllertypestr:'STM32L051R6'; controllerunitstr:'STM32L051XX'), (controllertypestr:'STM32L051R8'; controllerunitstr:'STM32L051XX'), (controllertypestr:'STM32L051T6'; controllerunitstr:'STM32L051XX'), (controllertypestr:'STM32L051T8'; controllerunitstr:'STM32L051XX'), (controllertypestr:'STM32L052C6'; controllerunitstr:'STM32L052XX'), (controllertypestr:'STM32L052C8'; controllerunitstr:'STM32L052XX'), (controllertypestr:'STM32L052K6'; controllerunitstr:'STM32L052XX'), (controllertypestr:'STM32L052K8'; controllerunitstr:'STM32L052XX'), (controllertypestr:'STM32L052R6'; controllerunitstr:'STM32L052XX'), (controllertypestr:'STM32L052R8'; controllerunitstr:'STM32L052XX'), (controllertypestr:'STM32L052T6'; controllerunitstr:'STM32L052XX'), (controllertypestr:'STM32L052T8'; controllerunitstr:'STM32L052XX'), (controllertypestr:'STM32L053C6'; controllerunitstr:'STM32L053XX'), (controllertypestr:'STM32L053C8'; controllerunitstr:'STM32L053XX'), (controllertypestr:'STM32L053R6'; controllerunitstr:'STM32L053XX'), (controllertypestr:'STM32L053R8'; controllerunitstr:'STM32L053XX'), (controllertypestr:'STM32L062C8'; controllerunitstr:'STM32L062XX'), (controllertypestr:'STM32L062K8'; controllerunitstr:'STM32L062XX'), (controllertypestr:'STM32L063C8'; controllerunitstr:'STM32L063XX'), (controllertypestr:'STM32L063R8'; controllerunitstr:'STM32L063XX'), (controllertypestr:'STM32L071C8'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071CB'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071CZ'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071K8'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071KB'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071KZ'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071RB'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071RZ'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071V8'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071VB'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L071VZ'; controllerunitstr:'STM32L071XX'), (controllertypestr:'STM32L072CB'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L072CZ'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L072KB'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L072KZ'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L072RB'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L072RZ'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L072V8'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L072VB'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L072VZ'; controllerunitstr:'STM32L072XX'), (controllertypestr:'STM32L073CB'; controllerunitstr:'STM32L073XX'), (controllertypestr:'STM32L073CZ'; controllerunitstr:'STM32L073XX'), (controllertypestr:'STM32L073RB'; controllerunitstr:'STM32L073XX'), (controllertypestr:'STM32L073RZ'; controllerunitstr:'STM32L073XX'), (controllertypestr:'STM32L073V8'; controllerunitstr:'STM32L073XX'), (controllertypestr:'STM32L073VB'; controllerunitstr:'STM32L073XX'), (controllertypestr:'STM32L073VZ'; controllerunitstr:'STM32L073XX'), (controllertypestr:'STM32L081CB'; controllerunitstr:'STM32L081XX'), (controllertypestr:'STM32L081CZ'; controllerunitstr:'STM32L081XX'), (controllertypestr:'STM32L081KZ'; controllerunitstr:'STM32L081XX'), (controllertypestr:'STM32L082CZ'; controllerunitstr:'STM32L082XX'), (controllertypestr:'STM32L082KB'; controllerunitstr:'STM32L082XX'), (controllertypestr:'STM32L082KZ'; controllerunitstr:'STM32L082XX'), (controllertypestr:'STM32L083CB'; controllerunitstr:'STM32L083XX'), (controllertypestr:'STM32L083CZ'; controllerunitstr:'STM32L083XX'), (controllertypestr:'STM32L083RB'; controllerunitstr:'STM32L083XX'), (controllertypestr:'STM32L083RZ'; controllerunitstr:'STM32L083XX'), (controllertypestr:'STM32L083V8'; controllerunitstr:'STM32L083XX'), (controllertypestr:'STM32L083VB'; controllerunitstr:'STM32L083XX'), (controllertypestr:'STM32L083VZ'; controllerunitstr:'STM32L083XX'), (controllertypestr:'BL072ZLRWAN1'; controllerunitstr:'STM32L072XX'), (controllertypestr:'NUCLEOL010RB'; controllerunitstr:'STM32L010XB'), (controllertypestr:'NUCLEOL011K4'; controllerunitstr:'STM32L011XX'), (controllertypestr:'NUCLEOL031K6'; controllerunitstr:'STM32L031XX'), (controllertypestr:'NUCLEOL053R8'; controllerunitstr:'STM32L053XX'), (controllertypestr:'NUCLEOL073RZ'; controllerunitstr:'STM32L073XX'), (controllertypestr:'STM32L0538DISCOVERY';controllerunitstr:'STM32L053XX'), (controllertypestr:'STM32L100C6'; controllerunitstr:'STM32L100XB'), (controllertypestr:'STM32L100C6A'; controllerunitstr:'STM32L100XB'), (controllertypestr:'STM32L100R8'; controllerunitstr:'STM32L100XB'), (controllertypestr:'STM32L100R8A'; controllerunitstr:'STM32L100XB'), (controllertypestr:'STM32L100RB'; controllerunitstr:'STM32L100XB'), (controllertypestr:'STM32L100RBA'; controllerunitstr:'STM32L100XBA'), (controllertypestr:'STM32L100RC'; controllerunitstr:'STM32L100XC'), (controllertypestr:'STM32L151C6'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151C6A'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151C8'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151C8A'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151CB'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151CBA'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151CC'; controllerunitstr:'STM32L151XC'), (controllertypestr:'STM32L151QC'; controllerunitstr:'STM32L151XC'), (controllertypestr:'STM32L151QD'; controllerunitstr:'STM32L151XD'), (controllertypestr:'STM32L151QE'; controllerunitstr:'STM32L151XE'), (controllertypestr:'STM32L151R6'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151R6A'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151R8'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151R8A'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151RB'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151RBA'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151RC'; controllerunitstr:'STM32L151XC'), (controllertypestr:'STM32L151RCA'; controllerunitstr:'STM32L151XCA'), (controllertypestr:'STM32L151RD'; controllerunitstr:'STM32L151XD'), (controllertypestr:'STM32L151RE'; controllerunitstr:'STM32L151XE'), (controllertypestr:'STM32L151UC'; controllerunitstr:'STM32L151XC'), (controllertypestr:'STM32L151V8'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151V8A'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151VB'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151VBA'; controllerunitstr:'STM32L151XB'), (controllertypestr:'STM32L151VC'; controllerunitstr:'STM32L151XC'), (controllertypestr:'STM32L151VCA'; controllerunitstr:'STM32L151XCA'), (controllertypestr:'STM32L151VD'; controllerunitstr:'STM32L151XD'), (controllertypestr:'STM32L151VDX'; controllerunitstr:'STM32L151XDX'), (controllertypestr:'STM32L151VE'; controllerunitstr:'STM32L151XE'), (controllertypestr:'STM32L151ZC'; controllerunitstr:'STM32L151XC'), (controllertypestr:'STM32L151ZD'; controllerunitstr:'STM32L151XD'), (controllertypestr:'STM32L151ZE'; controllerunitstr:'STM32L151XE'), (controllertypestr:'STM32L152C6'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152C6A'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152C8'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152C8A'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152CB'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152CBA'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152CC'; controllerunitstr:'STM32L152XC'), (controllertypestr:'STM32L152QC'; controllerunitstr:'STM32L152XC'), (controllertypestr:'STM32L152QD'; controllerunitstr:'STM32L152XD'), (controllertypestr:'STM32L152QE'; controllerunitstr:'STM32L152XE'), (controllertypestr:'STM32L152R6'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152R6A'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152R8'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152R8A'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152RB'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152RBA'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152RC'; controllerunitstr:'STM32L152XC'), (controllertypestr:'STM32L152RCA'; controllerunitstr:'STM32L152XCA'), (controllertypestr:'STM32L152RD'; controllerunitstr:'STM32L152XD'), (controllertypestr:'STM32L152RE'; controllerunitstr:'STM32L152XE'), (controllertypestr:'STM32L152UC'; controllerunitstr:'STM32L152XC'), (controllertypestr:'STM32L152V8'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152V8A'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152VB'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152VBA'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L152VC'; controllerunitstr:'STM32L152XC'), (controllertypestr:'STM32L152VCA'; controllerunitstr:'STM32L152XCA'), (controllertypestr:'STM32L152VD'; controllerunitstr:'STM32L152XD'), (controllertypestr:'STM32L152VDX'; controllerunitstr:'STM32L152XD'), (controllertypestr:'STM32L152VE'; controllerunitstr:'STM32L152XE'), (controllertypestr:'STM32L152ZC'; controllerunitstr:'STM32L152XC'), (controllertypestr:'STM32L152ZD'; controllerunitstr:'STM32L152XD'), (controllertypestr:'STM32L152ZE'; controllerunitstr:'STM32L152XE'), (controllertypestr:'STM32L162QC'; controllerunitstr:'STM32L162XC'), (controllertypestr:'STM32L162QD'; controllerunitstr:'STM32L162XD'), (controllertypestr:'STM32L162RC'; controllerunitstr:'STM32L162XC'), (controllertypestr:'STM32L162RCA'; controllerunitstr:'STM32L162XC'), (controllertypestr:'STM32L162RD'; controllerunitstr:'STM32L162XD'), (controllertypestr:'STM32L162RE'; controllerunitstr:'STM32L162XE'), (controllertypestr:'STM32L162VC'; controllerunitstr:'STM32L162XC'), (controllertypestr:'STM32L162VCA'; controllerunitstr:'STM32L162XC'), (controllertypestr:'STM32L162VD'; controllerunitstr:'STM32L162XD'), (controllertypestr:'STM32L162VDX'; controllerunitstr:'STM32L162XD'), (controllertypestr:'STM32L162VE'; controllerunitstr:'STM32L162XE'), (controllertypestr:'STM32L162ZC'; controllerunitstr:'STM32L162XC'), (controllertypestr:'STM32L162ZD'; controllerunitstr:'STM32L162XD'), (controllertypestr:'STM32L162ZE'; controllerunitstr:'STM32L162XE'), (controllertypestr:'NUCLEOL152RE'; controllerunitstr:'STM32L152XE'), (controllertypestr:'STM32L100CDISCOVERY';controllerunitstr:'STM32L100XC'), (controllertypestr:'STM32L152CDISCOVERY';controllerunitstr:'STM32L152XC'), (controllertypestr:'STM32LDISCOVERY'; controllerunitstr:'STM32L152XB'), (controllertypestr:'STM32L412C8'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412CB'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412CBP'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412K8'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412KB'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412R8'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412RB'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412RBP'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412T8'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412TB'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L412TBP'; controllerunitstr:'STM32L412XX'), (controllertypestr:'STM32L422CB'; controllerunitstr:'STM32L422XX'), (controllertypestr:'STM32L422KB'; controllerunitstr:'STM32L422XX'), (controllertypestr:'STM32L422RB'; controllerunitstr:'STM32L422XX'), (controllertypestr:'STM32L422TB'; controllerunitstr:'STM32L422XX'), (controllertypestr:'STM32L431CB'; controllerunitstr:'STM32L431XX'), (controllertypestr:'STM32L431CC'; controllerunitstr:'STM32L431XX'), (controllertypestr:'STM32L431KB'; controllerunitstr:'STM32L431XX'), (controllertypestr:'STM32L431KC'; controllerunitstr:'STM32L431XX'), (controllertypestr:'STM32L431RB'; controllerunitstr:'STM32L431XX'), (controllertypestr:'STM32L431RC'; controllerunitstr:'STM32L431XX'), (controllertypestr:'STM32L431VC'; controllerunitstr:'STM32L431XX'), (controllertypestr:'STM32L432KB'; controllerunitstr:'STM32L432XX'), (controllertypestr:'STM32L432KC'; controllerunitstr:'STM32L432XX'), (controllertypestr:'STM32L433CB'; controllerunitstr:'STM32L433XX'), (controllertypestr:'STM32L433CC'; controllerunitstr:'STM32L433XX'), (controllertypestr:'STM32L433RB'; controllerunitstr:'STM32L433XX'), (controllertypestr:'STM32L433RC'; controllerunitstr:'STM32L433XX'), (controllertypestr:'STM32L433RCP'; controllerunitstr:'STM32L433XX'), (controllertypestr:'STM32L433VC'; controllerunitstr:'STM32L433XX'), (controllertypestr:'STM32L442KC'; controllerunitstr:'STM32L442XX'), (controllertypestr:'STM32L443CC'; controllerunitstr:'STM32L443XX'), (controllertypestr:'STM32L443RC'; controllerunitstr:'STM32L443XX'), (controllertypestr:'STM32L443VC'; controllerunitstr:'STM32L443XX'), (controllertypestr:'STM32L451CC'; controllerunitstr:'STM32L451XX'), (controllertypestr:'STM32L451CE'; controllerunitstr:'STM32L451XX'), (controllertypestr:'STM32L451RC'; controllerunitstr:'STM32L451XX'), (controllertypestr:'STM32L451RE'; controllerunitstr:'STM32L451XX'), (controllertypestr:'STM32L451VC'; controllerunitstr:'STM32L451XX'), (controllertypestr:'STM32L451VE'; controllerunitstr:'STM32L451XX'), (controllertypestr:'STM32L452CC'; controllerunitstr:'STM32L452XX'), (controllertypestr:'STM32L452CE'; controllerunitstr:'STM32L452XX'), (controllertypestr:'STM32L452RC'; controllerunitstr:'STM32L452XX'), (controllertypestr:'STM32L452RE'; controllerunitstr:'STM32L452XX'), (controllertypestr:'STM32L452REP'; controllerunitstr:'STM32L452XX'), (controllertypestr:'STM32L452VC'; controllerunitstr:'STM32L452XX'), (controllertypestr:'STM32L452VE'; controllerunitstr:'STM32L452XX'), (controllertypestr:'STM32L462CE'; controllerunitstr:'STM32L462XX'), (controllertypestr:'STM32L462RE'; controllerunitstr:'STM32L462XX'), (controllertypestr:'STM32L462VE'; controllerunitstr:'STM32L462XX'), (controllertypestr:'STM32L471QE'; controllerunitstr:'STM32L471XX'), (controllertypestr:'STM32L471QG'; controllerunitstr:'STM32L471XX'), (controllertypestr:'STM32L471RE'; controllerunitstr:'STM32L471XX'), (controllertypestr:'STM32L471RG'; controllerunitstr:'STM32L471XX'), (controllertypestr:'STM32L471VE'; controllerunitstr:'STM32L471XX'), (controllertypestr:'STM32L471VG'; controllerunitstr:'STM32L471XX'), (controllertypestr:'STM32L471ZE'; controllerunitstr:'STM32L471XX'), (controllertypestr:'STM32L471ZG'; controllerunitstr:'STM32L471XX'), (controllertypestr:'STM32L475RC'; controllerunitstr:'STM32L475XX'), (controllertypestr:'STM32L475RE'; controllerunitstr:'STM32L475XX'), (controllertypestr:'STM32L475RG'; controllerunitstr:'STM32L475XX'), (controllertypestr:'STM32L475VC'; controllerunitstr:'STM32L475XX'), (controllertypestr:'STM32L475VE'; controllerunitstr:'STM32L475XX'), (controllertypestr:'STM32L475VG'; controllerunitstr:'STM32L475XX'), (controllertypestr:'STM32L476JE'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476JG'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476JGP'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476ME'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476MG'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476QE'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476QG'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476RC'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476RE'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476RG'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476VC'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476VE'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476VG'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476ZE'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476ZG'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L476ZGP'; controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L485JC'; controllerunitstr:'STM32L485XX'), (controllertypestr:'STM32L485JE'; controllerunitstr:'STM32L485XX'), (controllertypestr:'STM32L486JG'; controllerunitstr:'STM32L486XX'), (controllertypestr:'STM32L486QG'; controllerunitstr:'STM32L486XX'), (controllertypestr:'STM32L486RG'; controllerunitstr:'STM32L486XX'), (controllertypestr:'STM32L486VG'; controllerunitstr:'STM32L486XX'), (controllertypestr:'STM32L486ZG'; controllerunitstr:'STM32L486XX'), (controllertypestr:'STM32L496AE'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496AG'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496AGP'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496QE'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496QG'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496QGP'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496RE'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496RG'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496RGP'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496VE'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496VG'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496VGP'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496WGP'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496ZE'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496ZG'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L496ZGP'; controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L4A6AG'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6AGP'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6QG'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6QGP'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6RG'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6RGP'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6VG'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6VGP'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6ZG'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4A6ZGP'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'STM32L4P5AE'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5AG'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5AGP'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5CE'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5CG'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5CGP'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5QE'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5QG'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5QGP'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5RE'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5RG'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5RGP'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5VE'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5VG'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5VGP'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5ZE'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5ZG'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4P5ZGP'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4Q5AG'; controllerunitstr:'STM32L4Q5XX'), (controllertypestr:'STM32L4Q5CG'; controllerunitstr:'STM32L4Q5XX'), (controllertypestr:'STM32L4Q5QG'; controllerunitstr:'STM32L4Q5XX'), (controllertypestr:'STM32L4Q5RG'; controllerunitstr:'STM32L4Q5XX'), (controllertypestr:'STM32L4Q5VG'; controllerunitstr:'STM32L4Q5XX'), (controllertypestr:'STM32L4Q5ZG'; controllerunitstr:'STM32L4Q5XX'), (controllertypestr:'STM32L4R5AG'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R5AI'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R5QG'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R5QI'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R5VG'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R5VI'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R5ZG'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R5ZI'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R5ZIP'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L4R7AI'; controllerunitstr:'STM32L4R7XX'), (controllertypestr:'STM32L4R7VI'; controllerunitstr:'STM32L4R7XX'), (controllertypestr:'STM32L4R7ZI'; controllerunitstr:'STM32L4R7XX'), (controllertypestr:'STM32L4R9AG'; controllerunitstr:'STM32L4R9XX'), (controllertypestr:'STM32L4R9AI'; controllerunitstr:'STM32L4R9XX'), (controllertypestr:'STM32L4R9VG'; controllerunitstr:'STM32L4R9XX'), (controllertypestr:'STM32L4R9VI'; controllerunitstr:'STM32L4R9XX'), (controllertypestr:'STM32L4R9ZG'; controllerunitstr:'STM32L4R9XX'), (controllertypestr:'STM32L4R9ZI'; controllerunitstr:'STM32L4R9XX'), (controllertypestr:'STM32L4R9ZIP'; controllerunitstr:'STM32L4R9XX'), (controllertypestr:'STM32L4S5AI'; controllerunitstr:'STM32L4S5XX'), (controllertypestr:'STM32L4S5QI'; controllerunitstr:'STM32L4S5XX'), (controllertypestr:'STM32L4S5VI'; controllerunitstr:'STM32L4S5XX'), (controllertypestr:'STM32L4S5ZI'; controllerunitstr:'STM32L4S5XX'), (controllertypestr:'STM32L4S7AI'; controllerunitstr:'STM32L4S7XX'), (controllertypestr:'STM32L4S7VI'; controllerunitstr:'STM32L4S7XX'), (controllertypestr:'STM32L4S7ZI'; controllerunitstr:'STM32L4S7XX'), (controllertypestr:'STM32L4S9AI'; controllerunitstr:'STM32L4S9XX'), (controllertypestr:'STM32L4S9VI'; controllerunitstr:'STM32L4S9XX'), (controllertypestr:'STM32L4S9ZI'; controllerunitstr:'STM32L4S9XX'), (controllertypestr:'BL462ECELL1'; controllerunitstr:'STM32L462XX'), (controllertypestr:'BL475EIOT01A1'; controllerunitstr:'STM32L475XX'), (controllertypestr:'BL475EIOT01A2'; controllerunitstr:'STM32L475XX'), (controllertypestr:'BL4S5IIOT01A'; controllerunitstr:'STM32L4S5XX'), (controllertypestr:'NUCLEOL412KB'; controllerunitstr:'STM32L412XX'), (controllertypestr:'NUCLEOL412RBP'; controllerunitstr:'STM32L412XX'), (controllertypestr:'NUCLEOL432KC'; controllerunitstr:'STM32L432XX'), (controllertypestr:'NUCLEOL433RCP'; controllerunitstr:'STM32L433XX'), (controllertypestr:'NUCLEOL452RE'; controllerunitstr:'STM32L452XX'), (controllertypestr:'NUCLEOL452REP'; controllerunitstr:'STM32L452XX'), (controllertypestr:'NUCLEOL476RG'; controllerunitstr:'STM32L476XX'), (controllertypestr:'NUCLEOL496ZG'; controllerunitstr:'STM32L496XX'), (controllertypestr:'NUCLEOL496ZGP'; controllerunitstr:'STM32L496XX'), (controllertypestr:'NUCLEOL4A6ZG'; controllerunitstr:'STM32L4A6XX'), (controllertypestr:'NUCLEOL4P5ZG'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'NUCLEOL4R5ZI'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'NUCLEOL4R5ZIP'; controllerunitstr:'STM32L4R5XX'), (controllertypestr:'STM32L476GDISCOVERY';controllerunitstr:'STM32L476XX'), (controllertypestr:'STM32L496GDISCOVERY';controllerunitstr:'STM32L496XX'), (controllertypestr:'STM32L4P5GDK'; controllerunitstr:'STM32L4P5XX'), (controllertypestr:'STM32L4R9IDISCOVERY';controllerunitstr:'STM32L4R9XX'), (controllertypestr:'STM32WB30CEA'; controllerunitstr:'STM32WB30XX'), (controllertypestr:'STM32WB35CCA'; controllerunitstr:'STM32WB35XX'), (controllertypestr:'STM32WB35CEA'; controllerunitstr:'STM32WB35XX'), (controllertypestr:'STM32WB50CG'; controllerunitstr:'STM32WB50XX'), (controllertypestr:'STM32WB55CC'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55CE'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55CG'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55RC'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55RE'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55RG'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55VC'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55VE'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55VG'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB55VY'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'STM32WB5MMG'; controllerunitstr:'STM32WB5MXX'), (controllertypestr:'NUCLEOWB55' ; controllerunitstr:'STM32WB55XX'), (controllertypestr:'NUCLEOWB55RG'; controllerunitstr:'STM32WB55XX'), (controllertypestr:'NUCLEOWB55USBDONGLE';controllerunitstr:'STM32WB55XX'), (controllertypestr:'LM3S1110'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1133'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1138'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1150'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1162'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1165'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1166'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2110'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2139'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6100'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6110'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1601'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1608'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1620'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1635'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1636'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1637'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1651'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2601'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2608'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2620'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2637'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2651'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6610'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6611'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6618'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6633'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6637'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S8630'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1911'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1918'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1937'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1958'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1960'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1968'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S1969'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2911'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2918'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2919'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2939'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2948'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2950'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S2965'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6911'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6918'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6938'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6950'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6952'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S6965'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S8930'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S8933'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S8938'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S8962'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S8970'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S8971'; controllerunitstr:'LM3FURY'), (controllertypestr:'LM3S5951'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S5956'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S1B21'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S2B93'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S5B91'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S9B81'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S9B90'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S9B92'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S9B95'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S9B96'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM3S5D51'; controllerunitstr:'LM3TEMPEST'), (controllertypestr:'LM4F120H5'; controllerunitstr:'LM4F120'), (controllertypestr:'SC32442B'; controllerunitstr:'SC32442b'), (controllertypestr:'XMC4500X1024'; controllerunitstr:'XMC4500'), (controllertypestr:'XMC4500X768'; controllerunitstr:'XMC4500'), (controllertypestr:'XMC4502X768'; controllerunitstr:'XMC4502'), (controllertypestr:'XMC4504X512'; controllerunitstr:'XMC4504'), (controllertypestr:'ALLWINNER_A20'; controllerunitstr:'ALLWINNER_A20'), (controllertypestr:'MK20DX128VFM5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX128VFT5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX128VLF5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX128VLH5'; controllerunitstr:'MK20D5'), (controllertypestr:'TEENSY30' ; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX128VMP5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX32VFM5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX32VFT5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX32VLF5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX32VLH5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX32VMP5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX64VFM5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX64VFT5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX64VLF5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX64VLH5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX64VMP5'; controllerunitstr:'MK20D5'), (controllertypestr:'MK20DX128VLH7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX128VLK7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX128VLL7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX128VMC7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX256VLH7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX256VLK7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX256VLL7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX256VMC7'; controllerunitstr:'MK20D7'), (controllertypestr:'TEENSY31'; controllerunitstr:'MK20D7'), (controllertypestr:'TEENSY32'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX64VLH7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX64VLK7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK20DX64VMC7'; controllerunitstr:'MK20D7'), (controllertypestr:'MK22FN512CAP12'; controllerunitstr:'MK22F51212'), (controllertypestr:'MK22FN512CBP12'; controllerunitstr:'MK22F51212'), (controllertypestr:'MK22FN512VDC12'; controllerunitstr:'MK22F51212'), (controllertypestr:'MK22FN512VLH12'; controllerunitstr:'MK22F51212'), (controllertypestr:'MK22FN512VLL12'; controllerunitstr:'MK22F51212'), (controllertypestr:'MK22FN512VMP12'; controllerunitstr:'MK22F51212'), (controllertypestr:'FREEDOM_K22F'; controllerunitstr:'MK22F51212'), (controllertypestr:'MK64FN1M0VDC12'; controllerunitstr:'MK64F12'), (controllertypestr:'MK64FN1M0VLL12'; controllerunitstr:'MK64F12'), (controllertypestr:'FREEDOM_K64F'; controllerunitstr:'MK64F12'), (controllertypestr:'MK64FN1M0VLQ12'; controllerunitstr:'MK64F12'), (controllertypestr:'MK64FN1M0VMD12'; controllerunitstr:'MK64F12'), (controllertypestr:'MK64FX512VDC12'; controllerunitstr:'MK64F12'), (controllertypestr:'MK64FX512VLL12'; controllerunitstr:'MK64F12'), (controllertypestr:'MK64FX512VLQ12'; controllerunitstr:'MK64F12'), (controllertypestr:'MK64FX512VMD12'; controllerunitstr:'MK64F12'), (controllertypestr:'SAMD10C13A' ;controllerunitstr:'SAMD10C13A'), (controllertypestr:'SAMD10C14A' ;controllerunitstr:'SAMD10C14A'), (controllertypestr:'SAMD10D13A' ;controllerunitstr:'SAMD10D13A'), (controllertypestr:'SAMD10D14A' ;controllerunitstr:'SAMD10D14A'), (controllertypestr:'SAMD11C13A' ;controllerunitstr:'SAMD11C13A'), (controllertypestr:'SAMD11C14A' ;controllerunitstr:'SAMD11C14A'), (controllertypestr:'SAMD11D14AM' ;controllerunitstr:'SAMD11D14AM'), (controllertypestr:'SAMD11D14AS' ;controllerunitstr:'SAMD11D14AS'), (controllertypestr:'SAMD20E14' ;controllerunitstr:'SAMD20E14'), (controllertypestr:'SAMD20E15' ;controllerunitstr:'SAMD20E15'), (controllertypestr:'SAMD20E16' ;controllerunitstr:'SAMD20E16'), (controllertypestr:'SAMD20E17' ;controllerunitstr:'SAMD20E17'), (controllertypestr:'SAMD20E18' ;controllerunitstr:'SAMD20E18'), (controllertypestr:'SAMD20G14' ;controllerunitstr:'SAMD20G14'), (controllertypestr:'SAMD20G15' ;controllerunitstr:'SAMD20G15'), (controllertypestr:'SAMD20G16' ;controllerunitstr:'SAMD20G16'), (controllertypestr:'SAMD20G17' ;controllerunitstr:'SAMD20G17'), (controllertypestr:'SAMD20G18' ;controllerunitstr:'SAMD20G18'), (controllertypestr:'SAMD20J14' ;controllerunitstr:'SAMD20J14'), (controllertypestr:'SAMD20J15' ;controllerunitstr:'SAMD20J15'), (controllertypestr:'SAMD20J16' ;controllerunitstr:'SAMD20J16'), (controllertypestr:'SAMD20J17' ;controllerunitstr:'SAMD20J17'), (controllertypestr:'SAMD20J18' ;controllerunitstr:'SAMD20J18'), (controllertypestr:'SAMC20E15A' ;controllerunitstr:'SAMC20E15A'), (controllertypestr:'SAMC20E16A' ;controllerunitstr:'SAMC20E16A'), (controllertypestr:'SAMC20E17A' ;controllerunitstr:'SAMC20E17A'), (controllertypestr:'SAMC20E18A' ;controllerunitstr:'SAMC20E18A'), (controllertypestr:'SAMC20G15A' ;controllerunitstr:'SAMC20G15A'), (controllertypestr:'SAMC20G16A' ;controllerunitstr:'SAMC20G16A'), (controllertypestr:'SAMC20G17A' ;controllerunitstr:'SAMC20G17A'), (controllertypestr:'SAMC20G18A' ;controllerunitstr:'SAMC20G18A'), (controllertypestr:'SAMC20J15A' ;controllerunitstr:'SAMC20J15A'), (controllertypestr:'SAMC20J16A' ;controllerunitstr:'SAMC20J16A'), (controllertypestr:'SAMC20J17A' ;controllerunitstr:'SAMC20J17A'), (controllertypestr:'SAMC20J17AU' ;controllerunitstr:'SAMC20J17AU'), (controllertypestr:'SAMC20J18A' ;controllerunitstr:'SAMC20J18A'), (controllertypestr:'SAMC20J18AU' ;controllerunitstr:'SAMC20J18AU'), (controllertypestr:'SAMC20N17A' ;controllerunitstr:'SAMC20N17A'), (controllertypestr:'SAMC20N18A' ;controllerunitstr:'SAMC20N18A'), (controllertypestr:'SAMC21E15A' ;controllerunitstr:'SAMC21E15A'), (controllertypestr:'SAMC21E16A' ;controllerunitstr:'SAMC21E16A'), (controllertypestr:'SAMC21E17A' ;controllerunitstr:'SAMC21E17A'), (controllertypestr:'SAMC21E18A' ;controllerunitstr:'SAMC21E18A'), (controllertypestr:'SAMC21G15A' ;controllerunitstr:'SAMC21G15A'), (controllertypestr:'SAMC21G16A' ;controllerunitstr:'SAMC21G16A'), (controllertypestr:'SAMC21G17A' ;controllerunitstr:'SAMC21G17A'), (controllertypestr:'SAMC21G18A' ;controllerunitstr:'SAMC21G18A'), (controllertypestr:'SAMC21J15A' ;controllerunitstr:'SAMC21J15A'), (controllertypestr:'SAMC21J16A' ;controllerunitstr:'SAMC21J16A'), (controllertypestr:'SAMC21J17A' ;controllerunitstr:'SAMC21J17A'), (controllertypestr:'SAMC21J17AU' ;controllerunitstr:'SAMC21J17AU'), (controllertypestr:'SAMC21J18A' ;controllerunitstr:'SAMC21J18A'), (controllertypestr:'SAMC21J18AU' ;controllerunitstr:'SAMC21J18AU'), (controllertypestr:'SAMC21N17A' ;controllerunitstr:'SAMC21N17A'), (controllertypestr:'SAMC21N18A' ;controllerunitstr:'SAMC21N18A'), (controllertypestr:'SAMD21E15A' ;controllerunitstr:'SAMD21E15A'), (controllertypestr:'SAMD21E15B' ;controllerunitstr:'SAMD21E15B'), (controllertypestr:'SAMD21E15BU' ;controllerunitstr:'SAMD21E15BU'), (controllertypestr:'SAMD21E15L' ;controllerunitstr:'SAMD21E15L'), (controllertypestr:'SAMD21E16A' ;controllerunitstr:'SAMD21E16A'), (controllertypestr:'SAMD21E16B' ;controllerunitstr:'SAMD21E16B'), (controllertypestr:'SAMD21E16BU' ;controllerunitstr:'SAMD21E16BU'), (controllertypestr:'SAMD21E16L' ;controllerunitstr:'SAMD21E16L'), (controllertypestr:'SAMD21E17A' ;controllerunitstr:'SAMD21E17A'), (controllertypestr:'SAMD21E18A' ;controllerunitstr:'SAMD21E18A'), (controllertypestr:'SAMD21G15A' ;controllerunitstr:'SAMD21G15A'), (controllertypestr:'SAMD21G15B' ;controllerunitstr:'SAMD21G15B'), (controllertypestr:'SAMD21G15L' ;controllerunitstr:'SAMD21G15L'), (controllertypestr:'SAMD21G16A' ;controllerunitstr:'SAMD21G16A'), (controllertypestr:'SAMD21G16B' ;controllerunitstr:'SAMD21G16B'), (controllertypestr:'SAMD21G16L' ;controllerunitstr:'SAMD21G16L'), (controllertypestr:'SAMD21G17A' ;controllerunitstr:'SAMD21G17A'), (controllertypestr:'SAMD21G17AU' ;controllerunitstr:'SAMD21G17AU'), (controllertypestr:'SAMD21G18A' ;controllerunitstr:'SAMD21G18A'), (controllertypestr:'SAMD21G18AU' ;controllerunitstr:'SAMD21G18AU'), (controllertypestr:'SAMD21J15A' ;controllerunitstr:'SAMD21J15A'), (controllertypestr:'SAMD21J15B' ;controllerunitstr:'SAMD21J15B'), (controllertypestr:'SAMD21J16A' ;controllerunitstr:'SAMD21J16A'), (controllertypestr:'SAMD21J16B' ;controllerunitstr:'SAMD21J16B'), (controllertypestr:'SAMD21J17A' ;controllerunitstr:'SAMD21J17A'), (controllertypestr:'SAMD21J18A' ;controllerunitstr:'SAMD21J18A'), (controllertypestr:'SAMC21XPRO';controllerunitstr:'SAMC21J18A'), (controllertypestr:'SAMD10XMINI';controllerunitstr:'SAMD10D14A'), (controllertypestr:'SAMD20XPRO';controllerunitstr:'SAMD20J18'), (controllertypestr:'ARDUINOZERO';controllerunitstr:'SAMD21G18AU'), (controllertypestr:'SAMD21XPRO';controllerunitstr:'SAMD21J18A'), (controllertypestr:'ATSAM3X8E'; controllerunitstr:'SAM3X8E'), (controllertypestr:'ARDUINO_DUE'; controllerunitstr:'SAM3X8E'), (controllertypestr:'FLIP_N_CLICK'; controllerunitstr:'SAM3X8E'), (controllertypestr:'XIAO' ; controllerunitstr:'SAMD21G18A'), (controllertypestr:'FEATHER_M0'; controllerunitstr:'SAMD21G18A'), (controllertypestr:'ITSYBITSY_M0'; controllerunitstr:'SAMD21G18A'), (controllertypestr:'METRO_M0'; controllerunitstr:'SAMD21G18A'), (controllertypestr:'TRINKET_M0'; controllerunitstr:'SAMD21E18A'), (controllertypestr:'WIO_TERMINAL'; controllerunitstr:'SAMD51P19A'), (controllertypestr:'FEATHER_M4'; controllerunitstr:'SAMD51J19A'), (controllertypestr:'ITSYBITSY_M4'; controllerunitstr:'SAMD51G19A'), (controllertypestr:'METRO_M4'; controllerunitstr:'SAMD51J19A'), (controllertypestr:'NRF51422_XXAA'; controllerunitstr:'NRF51'), (controllertypestr:'NRF51422_XXAB'; controllerunitstr:'NRF51'), (controllertypestr:'NRF51422_XXAC'; controllerunitstr:'NRF51'), (controllertypestr:'NRF51822_XXAA'; controllerunitstr:'NRF51'), (controllertypestr:'NRF51822_XXAB'; controllerunitstr:'NRF51'), (controllertypestr:'NRF51822_XXAC'; controllerunitstr:'NRF51'), (controllertypestr:'NRF52832_XXAA'; controllerunitstr:'NRF52'), (controllertypestr:'NRF52840_XXAA'; controllerunitstr:'NRF52'), (controllertypestr:'RASPI2'; controllerunitstr:'RASPI2'), (controllertypestr:'RP2040'; controllerunitstr:'RP2040'), (controllertypestr:'RASPI_PICO'; controllerunitstr:'RP2040'), (controllertypestr:'FEATHER_RP2040'; controllerunitstr:'RP2040'), (controllertypestr:'ITZYBITZY_RP2040'; controllerunitstr:'RP2040'), (controllertypestr:'TINY_2040'; controllerunitstr:'RP2040'), (controllertypestr:'QTPY_RP2040'; controllerunitstr:'RP2040'), (controllertypestr:'THUMB2_BARE'; controllerunitstr:'THUMB2_BARE'), (controllertypestr:'PIC32MX110F016B'; controllerunitstr:'PIC32MX1xxFxxxB'), (controllertypestr:'PIC32MX110F016C'; controllerunitstr:'PIC32MX1xxFxxxC'), (controllertypestr:'PIC32MX110F016D'; controllerunitstr:'PIC32MX1xxFxxxD'), (controllertypestr:'PIC32MX120F032B'; controllerunitstr:'PIC32MX1xxFxxxB'), (controllertypestr:'PIC32MX120F032C'; controllerunitstr:'PIC32MX1xxFxxxC'), (controllertypestr:'PIC32MX120F032D'; controllerunitstr:'PIC32MX1xxFxxxD'), (controllertypestr:'PIC32MX130F064B'; controllerunitstr:'PIC32MX1xxFxxxB'), (controllertypestr:'PIC32MX130F064C'; controllerunitstr:'PIC32MX1xxFxxxC'), (controllertypestr:'PIC32MX130F064D'; controllerunitstr:'PIC32MX1xxFxxxD'), (controllertypestr:'PIC32MX150F128B'; controllerunitstr:'PIC32MX1xxFxxxB'), (controllertypestr:'PIC32MX150F128C'; controllerunitstr:'PIC32MX1xxFxxxC'), (controllertypestr:'PIC32MX150F128D'; controllerunitstr:'PIC32MX1xxFxxxD'), (controllertypestr:'PIC32MX210F016B'; controllerunitstr:'PIC32MX2xxFxxxB'), (controllertypestr:'PIC32MX210F016C'; controllerunitstr:'PIC32MX2xxFxxxC'), (controllertypestr:'PIC32MX210F016D'; controllerunitstr:'PIC32MX2xxFxxxD'), (controllertypestr:'PIC32MX220F032B'; controllerunitstr:'PIC32MX2xxFxxxB'), (controllertypestr:'PIC32MX220F032C'; controllerunitstr:'PIC32MX2xxFxxxC'), (controllertypestr:'PIC32MX220F032D'; controllerunitstr:'PIC32MX2xxFxxxD'), (controllertypestr:'PIC32MX230F064B'; controllerunitstr:'PIC32MX2xxFxxxB'), (controllertypestr:'PIC32MX230F064C'; controllerunitstr:'PIC32MX2xxFxxxC'), (controllertypestr:'PIC32MX230F064D'; controllerunitstr:'PIC32MX2xxFxxxD'), (controllertypestr:'PIC32MX250F128B'; controllerunitstr:'PIC32MX2xxFxxxB'), (controllertypestr:'PIC32MX250F128C'; controllerunitstr:'PIC32MX2xxFxxxC'), (controllertypestr:'PIC32MX250F128D'; controllerunitstr:'PIC32MX2xxFxxxD'), (controllertypestr:'PIC32MX775F256H'; controllerunitstr:'PIC32MX7x5FxxxH'), (controllertypestr:'PIC32MX775F256L'; controllerunitstr:'PIC32MX7x5FxxxL'), (controllertypestr:'PIC32MX775F512H'; controllerunitstr:'PIC32MX7x5FxxxH'), (controllertypestr:'PIC32MX775F512L'; controllerunitstr:'PIC32MX7x5FxxxL'), (controllertypestr:'PIC32MX795F512H'; controllerunitstr:'PIC32MX7x5FxxxH'), (controllertypestr:'PIC32MX795F512L'; controllerunitstr:'PIC32MX7x5FxxxL'), // AVR controllers (controllertypestr:'AT90CAN32'; controllerunitstr:'AT90CAN32'), (controllertypestr:'AT90CAN64'; controllerunitstr:'AT90CAN64'), (controllertypestr:'AT90CAN128'; controllerunitstr:'AT90CAN128'), (controllertypestr:'AT90PWM1'; controllerunitstr:'AT90PWM1'), (controllertypestr:'AT90PWM2B'; controllerunitstr:'AT90PWM2B'), (controllertypestr:'AT90PWM3B'; controllerunitstr:'AT90PWM3B'), (controllertypestr:'AT90PWM81'; controllerunitstr:'AT90PWM81'), (controllertypestr:'AT90PWM161'; controllerunitstr:'AT90PWM161'), (controllertypestr:'AT90PWM216'; controllerunitstr:'AT90PWM216'), (controllertypestr:'AT90PWM316'; controllerunitstr:'AT90PWM316'), (controllertypestr:'AT90USB82'; controllerunitstr:'AT90USB82'), (controllertypestr:'AT90USB162'; controllerunitstr:'AT90USB162'), (controllertypestr:'AT90USB646'; controllerunitstr:'AT90USB646'), (controllertypestr:'AT90USB647'; controllerunitstr:'AT90USB647'), (controllertypestr:'AT90USB1286'; controllerunitstr:'AT90USB1286'), (controllertypestr:'AT90USB1287'; controllerunitstr:'AT90USB1287'), (controllertypestr:'ATA6285'; controllerunitstr:'ATA6285'), (controllertypestr:'ATA6286'; controllerunitstr:'ATA6286'), (controllertypestr:'ATMEGA8'; controllerunitstr:'ATMEGA8'), (controllertypestr:'ATMEGA8A'; controllerunitstr:'ATMEGA8A'), (controllertypestr:'ATMEGA8HVA'; controllerunitstr:'ATMEGA8HVA'), (controllertypestr:'ATMEGA8U2'; controllerunitstr:'ATMEGA8U2'), (controllertypestr:'ATMEGA16'; controllerunitstr:'ATMEGA16'), (controllertypestr:'ATMEGA16A'; controllerunitstr:'ATMEGA16A'), (controllertypestr:'ATMEGA16HVA'; controllerunitstr:'ATMEGA16HVA'), (controllertypestr:'ATMEGA16HVB'; controllerunitstr:'ATMEGA16HVB'), (controllertypestr:'ATMEGA16HVBREVB'; controllerunitstr:'ATMEGA16HVBREVB'), (controllertypestr:'ATMEGA16M1'; controllerunitstr:'ATMEGA16M1'), (controllertypestr:'ATMEGA16U2'; controllerunitstr:'ATMEGA16U2'), (controllertypestr:'ATMEGA16U4'; controllerunitstr:'ATMEGA16U4'), (controllertypestr:'ATMEGA32'; controllerunitstr:'ATMEGA32'), (controllertypestr:'ATMEGA32A'; controllerunitstr:'ATMEGA32A'), (controllertypestr:'ATMEGA32C1'; controllerunitstr:'ATMEGA32C1'), (controllertypestr:'ATMEGA32HVB'; controllerunitstr:'ATMEGA32HVB'), (controllertypestr:'ATMEGA32HVBREVB'; controllerunitstr:'ATMEGA32HVBREVB'), (controllertypestr:'ATMEGA32M1'; controllerunitstr:'ATMEGA32M1'), (controllertypestr:'ATMEGA32U2'; controllerunitstr:'ATMEGA32U2'), (controllertypestr:'ATMEGA32U4'; controllerunitstr:'ATMEGA32U4'), (controllertypestr:'ATMEGA48'; controllerunitstr:'ATMEGA48'), (controllertypestr:'ATMEGA48A'; controllerunitstr:'ATMEGA48A'), (controllertypestr:'ATMEGA48P'; controllerunitstr:'ATMEGA48P'), (controllertypestr:'ATMEGA48PA'; controllerunitstr:'ATMEGA48PA'), (controllertypestr:'ATMEGA48PB'; controllerunitstr:'ATMEGA48PB'), (controllertypestr:'ATMEGA64'; controllerunitstr:'ATMEGA64'), (controllertypestr:'ATMEGA64A'; controllerunitstr:'ATMEGA64A'), (controllertypestr:'ATMEGA64C1'; controllerunitstr:'ATMEGA64C1'), (controllertypestr:'ATMEGA64HVE2'; controllerunitstr:'ATMEGA64HVE2'), (controllertypestr:'ATMEGA64M1'; controllerunitstr:'ATMEGA64M1'), (controllertypestr:'ATMEGA64RFR2'; controllerunitstr:'ATMEGA64RFR2'), (controllertypestr:'ATMEGA88'; controllerunitstr:'ATMEGA88'), (controllertypestr:'ATMEGA88A'; controllerunitstr:'ATMEGA88A'), (controllertypestr:'ATMEGA88P'; controllerunitstr:'ATMEGA88P'), (controllertypestr:'ATMEGA88PA'; controllerunitstr:'ATMEGA88PA'), (controllertypestr:'ATMEGA88PB'; controllerunitstr:'ATMEGA88PB'), (controllertypestr:'ATMEGA128'; controllerunitstr:'ATMEGA128'), (controllertypestr:'ATMEGA128A'; controllerunitstr:'ATMEGA128A'), (controllertypestr:'ATMEGA128RFA1'; controllerunitstr:'ATMEGA128RFA1'), (controllertypestr:'ATMEGA128RFR2'; controllerunitstr:'ATMEGA128RFR2'), (controllertypestr:'ATMEGA162'; controllerunitstr:'ATMEGA162'), (controllertypestr:'ATMEGA164A'; controllerunitstr:'ATMEGA164A'), (controllertypestr:'ATMEGA164P'; controllerunitstr:'ATMEGA164P'), (controllertypestr:'ATMEGA164PA'; controllerunitstr:'ATMEGA164PA'), (controllertypestr:'ATMEGA165A'; controllerunitstr:'ATMEGA165A'), (controllertypestr:'ATMEGA165P'; controllerunitstr:'ATMEGA165P'), (controllertypestr:'ATMEGA165PA'; controllerunitstr:'ATMEGA165PA'), (controllertypestr:'ATMEGA168'; controllerunitstr:'ATMEGA168'), (controllertypestr:'ATMEGA168A'; controllerunitstr:'ATMEGA168A'), (controllertypestr:'ATMEGA168P'; controllerunitstr:'ATMEGA168P'), (controllertypestr:'ATMEGA168PA'; controllerunitstr:'ATMEGA168PA'), (controllertypestr:'ATMEGA168PB'; controllerunitstr:'ATMEGA168PB'), (controllertypestr:'ATMEGA169A'; controllerunitstr:'ATMEGA169A'), (controllertypestr:'ATMEGA169P'; controllerunitstr:'ATMEGA169P'), (controllertypestr:'ATMEGA169PA'; controllerunitstr:'ATMEGA169PA'), (controllertypestr:'ATMEGA256RFR2'; controllerunitstr:'ATMEGA256RFR2'), (controllertypestr:'ATMEGA324A'; controllerunitstr:'ATMEGA324A'), (controllertypestr:'ATMEGA324P'; controllerunitstr:'ATMEGA324P'), (controllertypestr:'ATMEGA324PA'; controllerunitstr:'ATMEGA324PA'), (controllertypestr:'ATMEGA324PB'; controllerunitstr:'ATMEGA324PB'), (controllertypestr:'ATMEGA325'; controllerunitstr:'ATMEGA325'), (controllertypestr:'ATMEGA325A'; controllerunitstr:'ATMEGA325A'), (controllertypestr:'ATMEGA325P'; controllerunitstr:'ATMEGA325P'), (controllertypestr:'ATMEGA325PA'; controllerunitstr:'ATMEGA325PA'), (controllertypestr:'ATMEGA328'; controllerunitstr:'ATMEGA328'), (controllertypestr:'ATMEGA328P'; controllerunitstr:'ATMEGA328P'), (controllertypestr:'ATMEGA328PB'; controllerunitstr:'ATMEGA328PB'), (controllertypestr:'ATMEGA329'; controllerunitstr:'ATMEGA329'), (controllertypestr:'ATMEGA329A'; controllerunitstr:'ATMEGA329A'), (controllertypestr:'ATMEGA329P'; controllerunitstr:'ATMEGA329P'), (controllertypestr:'ATMEGA329PA'; controllerunitstr:'ATMEGA329PA'), (controllertypestr:'ATMEGA406'; controllerunitstr:'ATMEGA406'), (controllertypestr:'ATMEGA640'; controllerunitstr:'ATMEGA640'), (controllertypestr:'ATMEGA644'; controllerunitstr:'ATMEGA644'), (controllertypestr:'ATMEGA644A'; controllerunitstr:'ATMEGA644A'), (controllertypestr:'ATMEGA644P'; controllerunitstr:'ATMEGA644P'), (controllertypestr:'ATMEGA644PA'; controllerunitstr:'ATMEGA644PA'), (controllertypestr:'ATMEGA644RFR2'; controllerunitstr:'ATMEGA644RFR2'), (controllertypestr:'ATMEGA645'; controllerunitstr:'ATMEGA645'), (controllertypestr:'ATMEGA645A'; controllerunitstr:'ATMEGA645A'), (controllertypestr:'ATMEGA645P'; controllerunitstr:'ATMEGA645P'), (controllertypestr:'ATMEGA649'; controllerunitstr:'ATMEGA649'), (controllertypestr:'ATMEGA649A'; controllerunitstr:'ATMEGA649A'), (controllertypestr:'ATMEGA649P'; controllerunitstr:'ATMEGA649P'), (controllertypestr:'ATMEGA808'; controllerunitstr:'ATMEGA808'), (controllertypestr:'ATMEGA809'; controllerunitstr:'ATMEGA809'), (controllertypestr:'ATMEGA1280'; controllerunitstr:'ATMEGA1280'), (controllertypestr:'ATMEGA1281'; controllerunitstr:'ATMEGA1281'), (controllertypestr:'ATMEGA1284'; controllerunitstr:'ATMEGA1284'), (controllertypestr:'ATMEGA1284P'; controllerunitstr:'ATMEGA1284P'), (controllertypestr:'ATMEGA1284RFR2'; controllerunitstr:'ATMEGA1284RFR2'), (controllertypestr:'ATMEGA1608'; controllerunitstr:'ATMEGA1608'), (controllertypestr:'ATMEGA1609'; controllerunitstr:'ATMEGA1609'), (controllertypestr:'ATMEGA2560'; controllerunitstr:'ATMEGA2560'), (controllertypestr:'ATMEGA2561'; controllerunitstr:'ATMEGA2561'), (controllertypestr:'ATMEGA2564RFR2'; controllerunitstr:'ATMEGA2564RFR2'), (controllertypestr:'ATMEGA3208'; controllerunitstr:'ATMEGA3208'), (controllertypestr:'ATMEGA3209'; controllerunitstr:'ATMEGA3209'), (controllertypestr:'ATMEGA3250'; controllerunitstr:'ATMEGA3250'), (controllertypestr:'ATMEGA3250A'; controllerunitstr:'ATMEGA3250A'), (controllertypestr:'ATMEGA3250P'; controllerunitstr:'ATMEGA3250P'), (controllertypestr:'ATMEGA3250PA'; controllerunitstr:'ATMEGA3250PA'), (controllertypestr:'ATMEGA3290'; controllerunitstr:'ATMEGA3290'), (controllertypestr:'ATMEGA3290A'; controllerunitstr:'ATMEGA3290A'), (controllertypestr:'ATMEGA3290P'; controllerunitstr:'ATMEGA3290P'), (controllertypestr:'ATMEGA3290PA'; controllerunitstr:'ATMEGA3290PA'), (controllertypestr:'ATMEGA4808'; controllerunitstr:'ATMEGA4808'), (controllertypestr:'ATMEGA4809'; controllerunitstr:'ATMEGA4809'), (controllertypestr:'ATMEGA6450'; controllerunitstr:'ATMEGA6450'), (controllertypestr:'ATMEGA6450A'; controllerunitstr:'ATMEGA6450A'), (controllertypestr:'ATMEGA6450P'; controllerunitstr:'ATMEGA6450P'), (controllertypestr:'ATMEGA6490'; controllerunitstr:'ATMEGA6490'), (controllertypestr:'ATMEGA6490A'; controllerunitstr:'ATMEGA6490A'), (controllertypestr:'ATMEGA6490P'; controllerunitstr:'ATMEGA6490P'), (controllertypestr:'ATMEGA8515'; controllerunitstr:'ATMEGA8515'), (controllertypestr:'ATMEGA8535'; controllerunitstr:'ATMEGA8535'), (controllertypestr:'ATTINY4'; controllerunitstr:'ATTINY4'), (controllertypestr:'ATTINY5'; controllerunitstr:'ATTINY5'), (controllertypestr:'ATTINY9'; controllerunitstr:'ATTINY9'), (controllertypestr:'ATTINY10'; controllerunitstr:'ATTINY10'), (controllertypestr:'ATTINY11'; controllerunitstr:'ATTINY11'), (controllertypestr:'ATTINY12'; controllerunitstr:'ATTINY12'), (controllertypestr:'ATTINY13'; controllerunitstr:'ATTINY13'), (controllertypestr:'ATTINY13A'; controllerunitstr:'ATTINY13A'), (controllertypestr:'ATTINY15'; controllerunitstr:'ATTINY15'), (controllertypestr:'ATTINY20'; controllerunitstr:'ATTINY20'), (controllertypestr:'ATTINY24'; controllerunitstr:'ATTINY24'), (controllertypestr:'ATTINY24A'; controllerunitstr:'ATTINY24A'), (controllertypestr:'ATTINY25'; controllerunitstr:'ATTINY25'), (controllertypestr:'ATTINY26'; controllerunitstr:'ATTINY26'), (controllertypestr:'ATTINY28'; controllerunitstr:'ATTINY28'), (controllertypestr:'ATTINY40'; controllerunitstr:'ATTINY40'), (controllertypestr:'ATTINY43U'; controllerunitstr:'ATTINY43U'), (controllertypestr:'ATTINY44'; controllerunitstr:'ATTINY44'), (controllertypestr:'ATTINY44A'; controllerunitstr:'ATTINY44A'), (controllertypestr:'ATTINY45'; controllerunitstr:'ATTINY45'), (controllertypestr:'ATTINY48'; controllerunitstr:'ATTINY48'), (controllertypestr:'ATTINY84'; controllerunitstr:'ATTINY84'), (controllertypestr:'ATTINY84A'; controllerunitstr:'ATTINY84A'), (controllertypestr:'ATTINY85'; controllerunitstr:'ATTINY85'), (controllertypestr:'ATTINY87'; controllerunitstr:'ATTINY87'), (controllertypestr:'ATTINY88'; controllerunitstr:'ATTINY88'), (controllertypestr:'ATTINY102'; controllerunitstr:'ATTINY102'), (controllertypestr:'ATTINY104'; controllerunitstr:'ATTINY104'), (controllertypestr:'ATTINY167'; controllerunitstr:'ATTINY167'), (controllertypestr:'ATTINY202'; controllerunitstr:'ATTINY202'), (controllertypestr:'ATTINY204'; controllerunitstr:'ATTINY204'), (controllertypestr:'ATTINY212'; controllerunitstr:'ATTINY212'), (controllertypestr:'ATTINY214'; controllerunitstr:'ATTINY214'), (controllertypestr:'ATTINY261'; controllerunitstr:'ATTINY261'), (controllertypestr:'ATTINY261A'; controllerunitstr:'ATTINY261A'), (controllertypestr:'ATTINY402'; controllerunitstr:'ATTINY402'), (controllertypestr:'ATTINY404'; controllerunitstr:'ATTINY404'), (controllertypestr:'ATTINY406'; controllerunitstr:'ATTINY406'), (controllertypestr:'ATTINY412'; controllerunitstr:'ATTINY412'), (controllertypestr:'ATTINY414'; controllerunitstr:'ATTINY414'), (controllertypestr:'ATTINY416'; controllerunitstr:'ATTINY416'), (controllertypestr:'ATTINY416AUTO'; controllerunitstr:'ATTINY416AUTO'), (controllertypestr:'ATTINY417'; controllerunitstr:'ATTINY417'), (controllertypestr:'ATTINY441'; controllerunitstr:'ATTINY441'), (controllertypestr:'ATTINY461'; controllerunitstr:'ATTINY461'), (controllertypestr:'ATTINY461A'; controllerunitstr:'ATTINY461A'), (controllertypestr:'ATTINY804'; controllerunitstr:'ATTINY804'), (controllertypestr:'ATTINY806'; controllerunitstr:'ATTINY806'), (controllertypestr:'ATTINY807'; controllerunitstr:'ATTINY807'), (controllertypestr:'ATTINY814'; controllerunitstr:'ATTINY814'), (controllertypestr:'ATTINY816'; controllerunitstr:'ATTINY816'), (controllertypestr:'ATTINY817'; controllerunitstr:'ATTINY817'), (controllertypestr:'ATTINY828'; controllerunitstr:'ATTINY828'), (controllertypestr:'ATTINY841'; controllerunitstr:'ATTINY841'), (controllertypestr:'ATTINY861'; controllerunitstr:'ATTINY861'), (controllertypestr:'ATTINY861A'; controllerunitstr:'ATTINY861A'), (controllertypestr:'ATTINY1604'; controllerunitstr:'ATTINY1604'), (controllertypestr:'ATTINY1606'; controllerunitstr:'ATTINY1606'), (controllertypestr:'ATTINY1607'; controllerunitstr:'ATTINY1607'), (controllertypestr:'ATTINY1614'; controllerunitstr:'ATTINY1614'), (controllertypestr:'ATTINY1616'; controllerunitstr:'ATTINY1616'), (controllertypestr:'ATTINY1617'; controllerunitstr:'ATTINY1617'), (controllertypestr:'ATTINY1624'; controllerunitstr:'ATTINY1624'), (controllertypestr:'ATTINY1626'; controllerunitstr:'ATTINY1626'), (controllertypestr:'ATTINY1627'; controllerunitstr:'ATTINY1627'), (controllertypestr:'ATTINY1634'; controllerunitstr:'ATTINY1634'), (controllertypestr:'ATTINY2313'; controllerunitstr:'ATTINY2313'), (controllertypestr:'ATTINY2313A'; controllerunitstr:'ATTINY2313A'), (controllertypestr:'ATTINY3214'; controllerunitstr:'ATTINY3214'), (controllertypestr:'ATTINY3216'; controllerunitstr:'ATTINY3216'), (controllertypestr:'ATTINY3217'; controllerunitstr:'ATTINY3217'), (controllertypestr:'ATTINY4313'; controllerunitstr:'ATTINY4313'), // AVR controller board aliases (controllertypestr:'ARDUINOLEONARDO'; controllerunitstr:'ATMEGA32U4'), (controllertypestr:'ARDUINOMEGA'; controllerunitstr:'ATMEGA2560'), (controllertypestr:'ARDUINOMICRO'; controllerunitstr:'ATMEGA32U4'), (controllertypestr:'ARDUINONANO'; controllerunitstr:'ATMEGA328P'), (controllertypestr:'ARDUINONANOEVERY'; controllerunitstr:'ATMEGA4809'), (controllertypestr:'ARDUINOUNO'; controllerunitstr:'ATMEGA328P'), (controllertypestr:'ATMEGA256RFR2XPRO'; controllerunitstr:'ATMEGA256RFR2'), (controllertypestr:'ATMEGA324PBXPRO'; controllerunitstr:'ATMEGA324PB'), (controllertypestr:'ATMEGA1284PXPLAINED'; controllerunitstr:'ATMEGA1284P'), (controllertypestr:'ATMEGA4809XPRO'; controllerunitstr:'ATMEGA4809'), (controllertypestr:'ATTINY817XPRO'; controllerunitstr:'ATTINY817'), (controllertypestr:'ATTINY3217XPRO'; controllerunitstr:'ATTINY3217'), // xtensa controllers (controllertypestr:'ESP8266'; controllerunitstr:'ESP8266'), (controllertypestr:'ESP32'; controllerunitstr:'ESP32')); var i: integer; str: String; begin str:=UpperCase(AControllerName); for i := low(ControllerTypes) to high(ControllerTypes) do if ControllerTypes[i].controllertypestr=str then exit(ControllerTypes[i].controllerunitstr); result:=''; end; var s: string; CompilerMode: String; m: Integer; UnitPath: String; IncPath: String; Params: TStrings; i: Integer; Param, Namespaces: String; p: PChar; MacMinVer: single; begin Result:=nil; if AlwaysCreate then CreateMainTemplate; CompilerMode:=''; UnitPath:=''; IncPath:=''; Namespaces:=''; Params:=TStringList.Create; try SplitCmdLineParams(CmdLine,Params); for i:=0 to Params.Count-1 do begin Param:=Params[i]; if Length(Param) < 2 then continue; p:=PChar(Param); if p^<>'-' then continue; // a parameter case p[1] of 'F': case p[2] of 'i': IncPath+=';'+copy(Param,4,length(Param)); 'u': UnitPath+=';'+copy(Param,4,length(Param)); 'N': Namespaces+=';'+copy(Param,4,length(Param)); end; 'd': begin // define AddDefine(copy(Param,3,255)); end; 'u': begin // undefine AddUndefine(copy(Param,3,255)); end; 'S': begin // syntax inc(p,2); while p^ <> #0 do begin case p^ of '2': CompilerMode:='ObjFPC'; 'd': CompilerMode:='Delphi'; 'o': CompilerMode:='TP'; 'p': CompilerMode:='GPC'; 'a': DefineOpt('C', p[1] <> '-'); // Assertions 'h': DefineOpt('H', p[1] <> '-'); // ansistrings end; inc(p); end; end; 'M': begin // syntax CompilerMode:=copy(Param,3,255); end; 'N': case p[2] of 'S': Namespaces+=';'+copy(Param,4,length(Param)) end; 'W': case p[2] of 'p': begin s:=FindControllerUnit(copy(Param,4,255)); // controller unit if s<>'' then AddDefine('Define '+MacroControllerUnit, ctsDefine+MacroControllerUnit,MacroControllerUnit, s); end; 'M': begin val(copy(Param,4,255),MacMinVer,m); if m=0 then AddDefine(MacOSMinSDKVersionMacro,MacOSMinSDKVersionMacro, MacOSMinSDKVersionMacro,IntToStr(Round(MacMinVer*100))); end; end; 'g': begin // Debug info Inc(p, 2); case p^ of #0: DefineOpt('D', True); '-': DefineOpt('D', False); else begin while not (p^ in [#0, 'o']) do begin if p^ = 'w' then begin DefineOpt('D', True); break; end; Inc(p); end; end; end; end; 'C': begin // Code generator options Inc(p, 2); while p^ <> #0 do begin case p^ of 'i': DefineOpt('I', p[1] <> '-'); 'r': DefineOpt('R', p[1] <> '-'); 'o': DefineOpt('Q', p[1] <> '-'); end; Inc(p); end; end; end; end; finally Params.Free; end; if CompilerMode<>'' then begin for m:=low(FPCSyntaxModes) to high(FPCSyntaxModes) do AddDefineUndefine('FPC_'+FPCSyntaxModes[m],SysUtils.CompareText(CompilerMode,FPCSyntaxModes[m])=0); end; if AddPaths then begin if UnitPath<>'' then AddDefine('UnitPath','UnitPath addition',UnitPathMacroName,UnitPathMacro+';'+UnitPath); if IncPath<>'' then AddDefine('IncPath','IncPath addition',IncludePathMacroName,IncludePathMacro+';'+IncPath); end; if Namespaces<>'' then AddDefine('Namespaces','Namespaces addition',NamespacesMacroName,NamespacesMacro+';'+Namespaces); Result.SetDefineOwner(Owner,true); end; procedure TDefinePool.ConsistencyCheck; var i: integer; begin for i:=0 to Count-1 do Items[i].ConsistencyCheck; end; procedure TDefinePool.WriteDebugReport; var i: integer; begin DebugLn('TDefinePool.WriteDebugReport'); for i:=0 to Count-1 do Items[i].WriteDebugReport(false); ConsistencyCheck; end; procedure TDefinePool.CalcMemSize(Stats: TCTMemStats); var i: Integer; begin Stats.Add('TDefinePool',PtrUInt(InstanceSize) +MemSizeString(FEnglishErrorMsgFilename)); if FItems<>nil then begin Stats.Add('TDefinePool.Count',Count); for i:=0 to Count-1 do Items[i].CalcMemSize(Stats); end; end; { TFPCSourceRules } function TFPCSourceRules.GetItems(Index: integer): TFPCSourceRule; begin Result:=TFPCSourceRule(FItems[Index]); end; procedure TFPCSourceRules.SetTargets(const AValue: string); begin if FTargets=AValue then exit; FTargets:=LowerCase(AValue); end; constructor TFPCSourceRules.Create; begin FItems:=TFPList.Create; end; destructor TFPCSourceRules.Destroy; begin Clear; FreeAndNil(FItems); inherited Destroy; end; procedure TFPCSourceRules.Clear; var i: Integer; begin if FItems.Count=0 then exit; for i:=0 to FItems.Count-1 do TObject(FItems[i]).Free; FItems.Clear; IncreaseChangeStamp; end; function TFPCSourceRules.IsEqual(Rules: TFPCSourceRules): boolean; var i: Integer; begin Result:=false; if Count<>Rules.Count then exit; for i:=0 to Count-1 do if not Items[i].IsEqual(Rules[i]) then exit; Result:=true; end; procedure TFPCSourceRules.Assign(Rules: TFPCSourceRules); var i: Integer; SrcRule: TFPCSourceRule; Rule: TFPCSourceRule; begin if IsEqual(Rules) then exit; Clear; for i:=0 to Rules.Count-1 do begin SrcRule:=Rules[i]; Rule:=Add(SrcRule.Filename); Rule.Assign(SrcRule); //debugln(['TFPCSourceRules.Assign ',i,' ',Rule.Targets,' ',Rule.Filename]); end; IncreaseChangeStamp; end; function TFPCSourceRules.Clone: TFPCSourceRules; begin Result:=TFPCSourceRules.Create; Result.Assign(Self); end; function TFPCSourceRules.Count: integer; begin Result:=FItems.Count; end; function TFPCSourceRules.Add(const Filename: string): TFPCSourceRule; begin Result:=TFPCSourceRule.Create; Result.Score:=Score; Result.Targets:=Targets; //DebugLn(['TFPCSourceRules.Add Targets="',Result.Targets,'" Priority=',Result.Score]); Result.Filename:=lowercase(GetForcedPathDelims(Filename)); FItems.Add(Result); IncreaseChangeStamp; end; function TFPCSourceRules.GetDefaultTargets(TargetOS, TargetCPU: string): string; var SrcOS: String; SrcOS2: String; SrcCPU: String; begin if TargetOS='' then TargetOS:=GetCompiledTargetOS; if TargetCPU='' then TargetCPU:=GetCompiledTargetCPU; Result:=TargetOS+','+TargetCPU; SrcOS:=GetDefaultSrcOSForTargetOS(TargetOS); SrcOS2:=GetDefaultSrcOS2ForTargetOS(TargetOS); SrcCPU:=GetDefaultSrcCPUForTargetCPU(TargetCPU); if SrcOS<>'' then Result:=Result+','+SrcOS; if SrcOS2<>'' then Result:=Result+','+SrcOS2; if SrcCPU<>'' then Result:=Result+','+SrcCPU; end; procedure TFPCSourceRules.GetRulesForTargets(Targets: string; var RulesSortedForFilenameStart: TAVLTree); var i: Integer; begin if RulesSortedForFilenameStart=nil then RulesSortedForFilenameStart:=TAVLTree.Create(@CompareFPCSourceRulesViaFilename); for i:=0 to Count-1 do if Items[i].FitsTargets(Targets) then RulesSortedForFilenameStart.Add(Items[i]); end; function TFPCSourceRules.GetScore(Filename: string; RulesSortedForFilenameStart: TAVLTree): integer; var Node: TAVLTreeNode; Rule: TFPCSourceRule; cmp: LongInt; Cnt: Integer; begin Result:=0; if Filename='' then exit; Filename:=LowerCase(Filename); {Node:=RulesSortedForFilenameStart.FindLowest; while Node<>nil do begin Rule:=TFPCSourceRule(Node.Data); DebugLn(['TFPCSourceRules.GetScore Rule: ',Rule.Score,' ',Rule.Filename]); Node:=RulesSortedForFilenameStart.FindSuccessor(Node); end;} // find first rule for Filename Node:=RulesSortedForFilenameStart.Root; while true do begin Rule:=TFPCSourceRule(Node.Data); cmp:=CompareFilenames(Filename,Rule.Filename); //DebugLn(['TFPCSourceRules.GetScore Rule.Filename=',Rule.Filename,' Filename=',Filename,' cmp=',cmp]); if cmp=0 then break; if cmp<0 then begin if Node.Left<>nil then Node:=Node.Left else break; end else begin if Node.Right<>nil then Node:=Node.Right else break; end; end; { The rules are sorted for the file name. Shorter file names comes before longer ones. packages/httpd20/examples packages/httpd22 packages/httpd22/examples A filename packages/httpd22/examples matches packages/httpd22 and packages/httpd22/examples If a file name has no exact match the binary search for packages/httpd22/e can either point to packages/httpd22 or packages/httpd22/examples } // run through all fitting rules (the Filename is >= Rule.Filename) Cnt:=0; while Node<>nil do begin inc(Cnt); Rule:=TFPCSourceRule(Node.Data); if Rule.FitsFilename(Filename) then inc(Result,Rule.Score) else if Cnt>1 then break; Node:=RulesSortedForFilenameStart.FindPrecessor(Node); end; end; procedure TFPCSourceRules.IncreaseChangeStamp; begin if FChangeStampRule.Filename) or (Score<>Rule.Score) or (Targets<>Rule.Targets) then exit; Result:=true; end; procedure TFPCSourceRule.Assign(Rule: TFPCSourceRule); begin Filename:=Rule.Filename; Score:=Rule.Score; Targets:=Rule.Targets; end; { TPCTargetConfigCache } constructor TPCTargetConfigCache.Create(AOwner: TComponent); begin CTIncreaseChangeStamp(FChangeStamp); // set to not 0 inherited Create(AOwner); ConfigFiles:=TPCConfigFileStateList.Create; if Owner is TPCTargetConfigCaches then Caches:=TPCTargetConfigCaches(Owner); end; destructor TPCTargetConfigCache.Destroy; begin Clear; FreeAndNil(ConfigFiles); inherited Destroy; end; procedure TPCTargetConfigCache.Clear; begin // keep keys Kind:=pcFPC; CompilerDate:=0; RealCompiler:=''; RealCompilerDate:=0; RealTargetCPU:=''; RealTargetOS:=''; RealTargetCPUCompiler:=''; FullVersion:=''; HasPPUs:=false; ConfigFiles.Clear; ErrorMsg:=''; ErrorTranslatedMsg:=''; FreeAndNil(Defines); FreeAndNil(Undefines); FreeAndNil(UnitPaths); FreeAndNil(IncludePaths); FreeAndNil(UnitScopes); FreeAndNil(Units); FreeAndNil(Includes); FreeAndNil(UnitToFPM); FreeAndNil(FPMNameToFPM); // this frees the FPMs end; function TPCTargetConfigCache.Equals(Item: TPCTargetConfigCache; CompareKey: boolean): boolean; function CompareStrings(List1, List2: TStrings): boolean; var List1Empty: Boolean; List2Empty: Boolean; begin Result:=false; List1Empty:=(List1=nil) or (List1.Count=0); List2Empty:=(List2=nil) or (List2.Count=0); if (List1Empty<>List2Empty) then exit; if (not List1Empty) and (not List1.Equals(List2)) then exit; Result:=true; end; function CompareStringTrees(Tree1, Tree2: TStringToStringTree): boolean; var Tree1Empty: Boolean; Tree2Empty: Boolean; begin Result:=false; Tree1Empty:=(Tree1=nil) or (Tree1.Tree.Count=0); Tree2Empty:=(Tree2=nil) or (Tree2.Tree.Count=0); if (Tree1Empty<>Tree2Empty) then exit; if (not Tree1Empty) and (not Tree1.Equals(Tree2)) then exit; Result:=true; end; var Node1, Node2: TAVLTreeNode; S2PItem1, S2PItem2: PStringToPointerTreeItem; begin Result:=false; if CompareKey then begin if (TargetOS<>Item.TargetOS) or (TargetCPU<>Item.TargetCPU) or (Compiler<>Item.Compiler) or (CompilerOptions<>Item.CompilerOptions) then exit; end; if (Kind<>Item.Kind) or (CompilerDate<>Item.CompilerDate) or (RealCompiler<>Item.RealCompiler) or (RealCompilerDate<>Item.RealCompilerDate) or (RealTargetOS<>Item.RealTargetOS) or (RealTargetCPU<>Item.RealTargetCPU) or (RealTargetCPUCompiler<>Item.RealTargetCPUCompiler) or (FullVersion<>Item.FullVersion) or (HasPPUs<>Item.HasPPUs) or (not ConfigFiles.Equals(Item.ConfigFiles,true)) then exit; if not CompareStringTrees(Defines,Item.Defines) then exit; if not CompareStringTrees(Undefines,Item.Undefines) then exit; if not CompareStrings(UnitPaths,Item.UnitPaths) then exit; if not CompareStrings(IncludePaths,Item.IncludePaths) then exit; if not CompareStrings(UnitScopes,Item.UnitScopes) then exit; if not CompareStringTrees(Units,Item.Units) then exit; if not CompareStringTrees(Includes,Item.Includes) then exit; if UnitToFPM<>nil then begin if Item.UnitToFPM=nil then exit; if UnitToFPM.Count<>Item.UnitToFPM.Count then exit; Node1:=UnitToFPM.Tree.FindLowest; Node2:=Item.UnitToFPM.Tree.FindLowest; while Node1<>nil do begin S2PItem1:=PStringToPointerTreeItem(Node1.Data); S2PItem2:=PStringToPointerTreeItem(Node2.Data); if S2PItem1^.Name<>S2PItem2^.Name then exit; if TPCFPMFileState(S2PItem1^.Value).Name<>TPCFPMFileState(S2PItem2^.Value).Name then exit; Node1:=Node1.Successor; Node2:=Node2.Successor; end; end; if FPMNameToFPM<>nil then begin if Item.FPMNameToFPM=nil then exit; if FPMNameToFPM.Count<>Item.FPMNameToFPM.Count then exit; Node1:=FPMNameToFPM.Tree.FindLowest; Node2:=Item.FPMNameToFPM.Tree.FindLowest; while Node1<>nil do begin S2PItem1:=PStringToPointerTreeItem(Node1.Data); S2PItem2:=PStringToPointerTreeItem(Node2.Data); if S2PItem1^.Name<>S2PItem2^.Name then exit; if not TPCFPMFileState(S2PItem1^.Value).Equals(TPCFPMFileState(S2PItem2^.Value),true) then exit; Node1:=Node1.Successor; Node2:=Node2.Successor; end; end; Result:=true; end; procedure TPCTargetConfigCache.Assign(Source: TPersistent); var Item: TPCTargetConfigCache; Node: TAVLTreeNode; FPM: TPCFPMFileState; S2PItem: PStringToPointerTreeItem; procedure AssignStringTree(var Dest: TStringToStringTree; const Src: TStringToStringTree); begin if Src<>nil then begin if Dest=nil then Dest:=TStringToStringTree.Create(false); Dest.Assign(Src); end else begin FreeAndNil(Dest); end; end; procedure AssignStringList(var Dest: TStrings; const Src: TStrings); begin if Src<>nil then begin if Dest=nil then Dest:=TStringList.Create; Dest.Assign(Src); end else begin FreeAndNil(Dest); end; end; begin if Source is TPCTargetConfigCache then begin Item:=TPCTargetConfigCache(Source); // keys TargetOS:=Item.TargetOS; TargetCPU:=Item.TargetCPU; Compiler:=Item.Compiler; CompilerOptions:=Item.CompilerOptions; // values Kind:=Item.Kind; CompilerDate:=Item.CompilerDate; RealCompiler:=Item.RealCompiler; RealCompilerDate:=Item.RealCompilerDate; RealTargetOS:=Item.RealTargetOS; RealTargetCPU:=Item.RealTargetCPU; RealTargetCPUCompiler:=Item.RealTargetCPUCompiler; FullVersion:=Item.FullVersion; HasPPUs:=Item.HasPPUs; ConfigFiles.Assign(Item.ConfigFiles); AssignStringTree(Defines,Item.Defines); AssignStringTree(Undefines,Item.Undefines); AssignStringList(UnitPaths,Item.UnitPaths); AssignStringList(IncludePaths,Item.IncludePaths); AssignStringList(UnitScopes,Item.UnitScopes); AssignStringTree(Units,Item.Units); AssignStringTree(Includes,Item.Includes); FreeAndNil(UnitToFPM); FreeAndNil(FPMNameToFPM); if (Item.FPMNameToFPM<>nil) and (Item.UnitToFPM=nil) then begin FPMNameToFPM:=TStringToPointerTree.Create(false); FPMNameToFPM.FreeValues:=true; UnitToFPM:=TStringToPointerTree.Create(false); // clone TPCFPMFileState objects Node:=Item.FPMNameToFPM.Tree.FindLowest; while Node<>nil do begin S2PItem:=PStringToPointerTreeItem(Node.Data); FPM:=TPCFPMFileState.Create; FPM.Name:=S2PItem^.Name; FPM.Assign(TPCFPMFileState(S2PItem^.Value)); FPMNameToFPM[FPM.Name]:=FPM; Node:=Node.Successor; end; // clone UnitToFPM Node:=Item.UnitToFPM.Tree.FindLowest; while Node<>nil do begin S2PItem:=PStringToPointerTreeItem(Node.Data); FPM:=TPCFPMFileState(FPMNameToFPM[TPCFPMFileState(S2PItem^.Value).Name]); UnitToFPM[S2PItem^.Name]:=FPM; Node:=Node.Successor; end; end; ErrorMsg:=Item.ErrorMsg; ErrorTranslatedMsg:=Item.ErrorTranslatedMsg; end else inherited Assign(Source); end; procedure TPCTargetConfigCache.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure LoadPathsFor(out ADest: TStrings; const ASubPath: string); var i: Integer; List: TStringList; BaseDir, s: String; begin // Paths: format: semicolon separated compressed list List:=TStringList.Create; try s:=XMLConfig.GetValue(Path+ASubPath+'Value',''); List.Delimiter:=';'; List.StrictDelimiter:=true; List.DelimitedText:=s; ADest:=Decompress1FileList(List); BaseDir:=TrimFilename(AppendPathDelim(XMLConfig.GetValue(Path+ASubPath+'BaseDir',''))); if BaseDir<>'' then for i:=0 to ADest.Count-1 do ADest[i]:=ChompPathDelim(TrimFilename(BaseDir+ADest[i])) else for i:=ADest.Count-1 downto 0 do if ADest[i]='' then ADest.Delete(i) else ADest[i]:=ChompPathDelim(TrimFilename(ADest[i])); // do not sort, order is important (e.g. for httpd.ppu) finally List.Free; end; end; procedure LoadSemicolonList(out UnitScopes: TStrings; const ASubPath: string); var s, Scope: String; p: Integer; begin UnitScopes:=TStringList.Create; s:=XMLConfig.GetValue(Path+ASubPath,''); p:=1; while p<=length(s) do begin Scope:=GetNextDelimitedItem(s,';',p); if Scope<>'' then UnitScopes.Add(Scope); end; end; procedure LoadFilesFor(var ADest: TStringToStringTree; const ASubPath: string); var i: Integer; List: TStringList; File_Name, CurPath, s, Filename: String; FileList: TStringList; begin // files: format: ASubPath+Values semicolon separated list of compressed filename if ADest=nil then ADest:=TStringToStringTree.Create(false); List:=TStringList.Create; FileList:=nil; try CurPath:=Path+ASubPath+'Value'; s:=XMLConfig.GetValue(CurPath,''); List.Delimiter:=';'; List.StrictDelimiter:=true; List.DelimitedText:=s; FileList:=Decompress1FileList(List); for i:=0 to FileList.Count-1 do begin Filename:=TrimFilename(FileList[i]); File_Name:=ExtractFileNameOnly(Filename); if (File_Name='') or not IsDottedIdentifier(File_Name) then begin DebugLn(['Warning: [TPCTargetConfigCache.LoadFromXMLConfig] invalid filename "',File_Name,'" in "',XMLConfig.Filename,'" at "',CurPath,'"']); continue; end; ADest[File_Name]:=Filename; end; finally List.Free; FileList.Free; end; end; var Cnt: integer; SubPath: String; DefineName, DefineValue: String; s, CurUnitName, CurFPMName: String; i: Integer; p: Integer; StartPos: Integer; FPM: TPCFPMFileState; begin Clear; Kind:=StrToPascalCompiler(XMLConfig.GetValue(Path+'Kind',PascalCompilerNames[pcFPC])); TargetOS:=XMLConfig.GetValue(Path+'TargetOS',''); TargetCPU:=XMLConfig.GetValue(Path+'TargetCPU',''); Compiler:=XMLConfig.GetValue(Path+'Compiler/File',''); CompilerOptions:=XMLConfig.GetValue(Path+'Compiler/Options',''); CompilerDate:=XMLConfig.GetValue(Path+'Compiler/Date',0); RealCompiler:=XMLConfig.GetValue(Path+'RealCompiler/File',''); RealCompilerDate:=XMLConfig.GetValue(Path+'RealCompiler/Date',0); RealTargetOS:=XMLConfig.GetValue(Path+'RealCompiler/OS',''); RealTargetCPU:=XMLConfig.GetValue(Path+'RealCompiler/CPU',''); RealTargetCPUCompiler:=XMLConfig.GetValue(Path+'RealCompiler/InPath',''); FullVersion:=XMLConfig.GetValue(Path+'RealCompiler/FullVersion',''); HasPPUs:=XMLConfig.GetValue(Path+'HasPPUs',true); ConfigFiles.LoadFromXMLConfig(XMLConfig,Path+'Configs/'); // defines: format: Define/Name,Value Cnt:=XMLConfig.GetValue(Path+'Defines/Count',0); for i:=1 to Cnt do begin SubPath:=Path+'Defines/Macro'+IntToStr(i)+'/'; DefineName:=UpperCaseStr(XMLConfig.GetValue(SubPath+'Name','')); if not IsValidIdent(DefineName) then begin DebugLn(['Warning: [TPCTargetConfigCache.LoadFromXMLConfig] invalid define name ',DefineName]); continue; end; DefineValue:=XMLConfig.GetValue(SubPath+'Value',''); if Defines=nil then Defines:=TStringToStringTree.Create(false); Defines[DefineName]:=DefineValue; end; // undefines: format: Undefines/Value and comma separated list of names s:=XMLConfig.GetValue(Path+'Undefines/Values',''); if s<>'' then begin p:=1; while (p<=length(s)) do begin StartPos:=1; while (p<=length(s)) and (s[p]<>';') do inc(p); DefineName:=copy(s,StartPos,p-StartPos); if IsValidIdent(DefineName) then begin if Undefines=nil then Undefines:=TStringToStringTree.Create(false); Undefines[DefineName]:=''; end; inc(p); end; end; // Paths LoadPathsFor(UnitPaths,'UnitPaths/'); LoadPathsFor(IncludePaths,'IncludePaths/'); // Unit scopes LoadSemicolonList(UnitScopes, 'UnitScopes'); // Files LoadFilesFor(Units,'Units/'); LoadFilesFor(Includes,'Includes/'); // read FPMNameToFPM before UnitToFPM! Cnt:=XMLConfig.GetValue(Path+'FPMs/Count',0); if Cnt>0 then begin FPMNameToFPM:=TStringToPointerTree.Create(false); FPMNameToFPM.FreeValues:=true; UnitToFPM:=TStringToPointerTree.Create(false); for i:=1 to Cnt do begin SubPath:=Path+'FPMs/Item'+IntToStr(i)+'/'; FPM:=TPCFPMFileState.Create; FPM.Name:=XMLConfig.GetValue(SubPath+'Name',''); if FPM.Name='' then FPM.Free else FPM.LoadFromXMLConfig(XMLConfig,SubPath); FPMNameToFPM[FPM.Name]:=FPM; end; end; // UnitToFPM Cnt:=XMLConfig.GetValue(Path+'UnitToFPM/Count',0); if UnitToFPM<>nil then begin for i:=1 to Cnt do begin SubPath:=Path+'UnitToFPM/Item'+IntToStr(i)+'/'; CurUnitName:=XMLConfig.GetValue(SubPath+'Unit',''); if CurUnitName='' then continue; CurFPMName:=XMLConfig.GetValue(SubPath+'FPM',''); if CurFPMName='' then continue; FPM:=TPCFPMFileState(FPMNameToFPM[CurFPMName]); if FPM=nil then exit; UnitToFPM[CurUnitName]:=FPM; end; end; end; procedure TPCTargetConfigCache.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); procedure SavePathsFor(const ASource: TStrings; const ASubPath: string); var List: TStringList; RelativeUnitPaths: TStringList; BaseDir, s: string; begin // Paths: write as semicolon separated compressed list s:=''; BaseDir:=''; if ASource<>nil then begin List:=nil; RelativeUnitPaths:=nil; try RelativeUnitPaths:=MakeRelativeFileList(ASource,BaseDir); List:=Compress1FileList(RelativeUnitPaths); // do not sort, order is important (e.g. for httpd.ppu) List.Delimiter:=';'; List.StrictDelimiter:=true; s:=List.DelimitedText; finally RelativeUnitPaths.Free; List.Free; end; end; XMLConfig.SetDeleteValue(Path+ASubPath+'BaseDir',BaseDir,''); XMLConfig.SetDeleteValue(Path+ASubPath+'Value',s,''); end; procedure SaveSemicolonList(List: TStrings; const ASubPath: string); var i: Integer; s: String; begin s:=''; if List<>nil then for i:=0 to List.Count-1 do s:=s+';'+List[i]; delete(s,1,1); XMLConfig.SetDeleteValue(Path+ASubPath,s,''); end; procedure SaveFilesFor(const ASource: TStringToStringTree; const ASubPath: string); var List: TStringList; FileList: TStringList; Filename, s: String; Node: TAVLTreeNode; Item: PStringToStringItem; begin // Files: ASubPath+Values semicolon separated list of compressed filenames // Files contains thousands of file names. This needs compression. s:=''; List:=nil; FileList:=TStringList.Create; try if ASource<>nil then begin // Create a string list of filenames Node:=ASource.Tree.FindLowest; while Node<>nil do begin Item:=PStringToStringItem(Node.Data); Filename:=Item^.Value; FileList.Add(Filename); Node:=ASource.Tree.FindSuccessor(Node); end; // Sort the strings. FileList.CaseSensitive:=true; FileList.Sort; // Compress the file names List:=Compress1FileList(FileList); // and write the semicolon separated list List.Delimiter:=';'; List.StrictDelimiter:=true; s:=List.DelimitedText; end; finally List.Free; FileList.Free; end; XMLConfig.SetDeleteValue(Path+ASubPath+'Value',s,''); end; var Node: TAVLTreeNode; Item: PStringToStringItem; Cnt, i: Integer; SubPath: String; s: String; S2PItem: PStringToPointerTreeItem; FPM: TPCFPMFileState; begin XMLConfig.SetDeleteValue(Path+'Kind',PascalCompilerNames[Kind],PascalCompilerNames[pcFPC]); XMLConfig.SetDeleteValue(Path+'TargetOS',TargetOS,''); XMLConfig.SetDeleteValue(Path+'TargetCPU',TargetCPU,''); XMLConfig.SetDeleteValue(Path+'Compiler/File',Compiler,''); XMLConfig.SetDeleteValue(Path+'Compiler/Options',CompilerOptions,''); XMLConfig.SetDeleteValue(Path+'Compiler/Date',CompilerDate,0); XMLConfig.SetDeleteValue(Path+'RealCompiler/File',RealCompiler,''); XMLConfig.SetDeleteValue(Path+'RealCompiler/Date',RealCompilerDate,0); XMLConfig.SetDeleteValue(Path+'RealCompiler/OS',RealTargetOS,''); XMLConfig.SetDeleteValue(Path+'RealCompiler/CPU',RealTargetCPU,''); XMLConfig.SetDeleteValue(Path+'RealCompiler/InPath',RealTargetCPUCompiler,''); XMLConfig.SetDeleteValue(Path+'RealCompiler/FullVersion',FullVersion,''); XMLConfig.SetDeleteValue(Path+'HasPPUs',HasPPUs,true); ConfigFiles.SaveToXMLConfig(XMLConfig,Path+'Configs/'); // Defines: write as Define/Name,Value Cnt:=0; if Defines<>nil then begin Node:=Defines.Tree.FindLowest; while Node<>nil do begin Item:=PStringToStringItem(Node.Data); if IsValidIdent(Item^.Name) then begin inc(Cnt); SubPath:=Path+'Defines/Macro'+IntToStr(Cnt)+'/'; XMLConfig.SetDeleteValue(SubPath+'Name',Item^.Name,''); XMLConfig.SetDeleteValue(SubPath+'Value',Item^.Value,''); end; Node:=Defines.Tree.FindSuccessor(Node); end; end; XMLConfig.SetDeleteValue(Path+'Defines/Count',Cnt,0); // Undefines: write as Undefines/Value and comma separated list of names Cnt:=0; s:=''; if Undefines<>nil then begin Node:=Undefines.Tree.FindLowest; while Node<>nil do begin Item:=PStringToStringItem(Node.Data); inc(Cnt); if s<>'' then s:=s+','; s:=s+Item^.Name; Node:=Undefines.Tree.FindSuccessor(Node); end; end; XMLConfig.SetDeleteValue(Path+'Undefines/Values',s,''); // Paths SavePathsFor(UnitPaths, 'UnitPaths/'); SavePathsFor(IncludePaths, 'IncludePaths/'); // Unit scopes SaveSemicolonList(UnitScopes, 'UnitScopes'); // Files SaveFilesFor(Units, 'Units/'); SaveFilesFor(Includes, 'Includes/'); // UnitToFPM if UnitToFPM<>nil then begin // write as UnitToFPM/Item/Unit,FPM i:=0; Node:=UnitToFPM.Tree.FindLowest; while Node<>nil do begin inc(i); SubPath:=Path+'UnitToFPM/Item'+IntToStr(i)+'/'; S2PItem:=PStringToPointerTreeItem(Node.Data); XMLConfig.SetValue(SubPath+'Unit',S2PItem^.Name); FPM:=TPCFPMFileState(S2PItem^.Value); XMLConfig.SetValue(SubPath+'FPM',FPM.Name); Node:=Node.Successor; end; XMLConfig.SetDeleteValue(Path+'UnitToFPM/Count',i,0); end; // FPMNameToFPM if FPMNameToFPM<>nil then begin // write as FPMs/Item/ i:=0; Node:=FPMNameToFPM.Tree.FindLowest; while Node<>nil do begin inc(i); SubPath:=Path+'FPMs/Item'+IntToStr(i)+'/'; S2PItem:=PStringToPointerTreeItem(Node.Data); FPM:=TPCFPMFileState(S2PItem^.Value); FPM.SaveToXMLConfig(XMLConfig,SubPath); Node:=Node.Successor; end; XMLConfig.SetDeleteValue(Path+'FPMs/Count',i,0); end; end; procedure TPCTargetConfigCache.LoadFromFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.Create(Filename); try LoadFromXMLConfig(XMLConfig,'FPCConfig/'); finally XMLConfig.Free; end; end; procedure TPCTargetConfigCache.SaveToFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.CreateClean(Filename); try SaveToXMLConfig(XMLConfig,'FPCConfig/'); finally XMLConfig.Free; end; end; function TPCTargetConfigCache.NeedsUpdate: boolean; var i: Integer; Cfg: TPCConfigFileState; AFilename: String; begin Result:=true; if (not FileExistsCached(Compiler)) then begin if CTConsoleVerbosity>0 then debugln(['Hint: [TPCTargetConfigCache.NeedsUpdate] TargetOS="',TargetOS,'" TargetCPU="',TargetCPU,'" Options="',CompilerOptions,'" compiler file missing "',Compiler,'"']); exit; end; if (FileAgeCached(Compiler)<>CompilerDate) then begin if CTConsoleVerbosity>0 then debugln(['Hint: [TPCTargetConfigCache.NeedsUpdate] TargetOS="',TargetOS,'" TargetCPU="',TargetCPU,'" Options="',CompilerOptions,'" compiler file changed "',Compiler,'" FileAge=',FileAgeCached(Compiler),' StoredAge=',CompilerDate]); exit; end; if (RealCompiler<>'') and (CompareFilenames(RealCompiler,Compiler)<>0) then begin if (not FileExistsCached(RealCompiler)) or (FileAgeCached(RealCompiler)<>RealCompilerDate) then begin if CTConsoleVerbosity>0 then debugln(['Hint: [TPCTargetConfigCache.NeedsUpdate] TargetOS="',TargetOS,'" TargetCPU="',TargetCPU,'" Options="',CompilerOptions,'" real compiler file changed "',RealCompiler,'"']); exit; end; end; // fpc searches via PATH for the real compiler, resolves any symlink // and that is the RealCompiler AFilename:=FindDefaultTargetCPUCompiler(TargetCPU,true); if RealTargetCPUCompiler<>AFilename then begin if CTConsoleVerbosity>0 then debugln(['Hint: [TPCTargetConfigCache.NeedsUpdate] TargetOS="',TargetOS,'" TargetCPU="',TargetCPU,'" Options="',CompilerOptions,'" real compiler in PATH changed from "',RealTargetCPUCompiler,'" to "',AFilename,'"']); exit; end; for i:=0 to ConfigFiles.Count-1 do begin Cfg:=ConfigFiles[i]; if (Cfg.Filename='') or (not FilenameIsAbsolute(Cfg.Filename)) then continue; if FileExistsCached(Cfg.Filename)<>Cfg.FileExists then begin if CTConsoleVerbosity>0 then debugln(['Hint: [TPCTargetConfigCache.NeedsUpdate] TargetOS="',TargetOS,'" TargetCPU="',TargetCPU,'" Options="',CompilerOptions,'" config fileexists changed "',Cfg.Filename,'"']); exit; end; if Cfg.FileExists and (FileAgeCached(Cfg.Filename)<>Cfg.FileDate) then begin if CTConsoleVerbosity>0 then debugln(['Hint: [TPCTargetConfigCache.NeedsUpdate] TargetOS="',TargetOS,'" TargetCPU="',TargetCPU,'" Options="',CompilerOptions,'" config file changed "',Cfg.Filename,'"']); exit; end; end; Result:=false; end; function TPCTargetConfigCache.GetFPCInfoCmdLineOptions(ExtraOptions: string ): string; begin Result:=CompilerOptions; if TargetCPU<>'' then Result:=Result+' -P'+LowerCase(TargetCPU); if TargetOS<>'' then Result:=Result+' -T'+LowerCase(TargetOS); if ExtraOptions<>'' then Result:=Result+' '+ExtraOptions; Result:=Trim(Result); end; procedure TPCTargetConfigCache.IncreaseChangeStamp; begin CTIncreaseChangeStamp(FChangeStamp); if Caches<>nil then Caches.IncreaseChangeStamp; end; function TPCTargetConfigCache.Update(TestFilename: string; ExtraOptions: string; const OnProgress: TDefinePoolProgress): boolean; procedure PreparePaths(APaths: TStrings); var i: Integer; begin if APaths<>nil then for i:=0 to APaths.Count-1 do APaths[i]:=ChompPathDelim(TrimFilename(APaths[i])); end; var i: Integer; OldOptions: TPCTargetConfigCache; CfgFiles: TStrings; Filename: string; CfgFileExists: Boolean; CfgFileDate: Integer; Info: String; Infos: TFPCInfoStrings; InfoTypes: TFPCInfoTypes; BaseDir: String; FullFilename, KindErrorMsg: String; begin OldOptions:=TPCTargetConfigCache.Create(nil); CfgFiles:=nil; try // remember old state to find out if something changed OldOptions.Assign(Self); Clear; if CTConsoleVerbosity>0 then debugln(['Hint: [TPCTargetConfigCache.NeedsUpdate] ',Compiler,' TargetOS=',TargetOS,' TargetCPU=',TargetCPU,' CompilerOptions=',CompilerOptions,' ExtraOptions=',ExtraOptions,' PATH=',GetEnvironmentVariableUTF8('PATH')]); CompilerDate:=-1; if FileExistsCached(Compiler) then begin CompilerDate:=FileAgeCached(Compiler); ExtraOptions:=GetFPCInfoCmdLineOptions(ExtraOptions);// add -TTargetOS and -PTargetCPU BaseDir:=''; // check if this is a FPC compatible compiler and get version, OS and CPU // Note: fpc.exe calls the real compiler depending on -T and -P InfoTypes:=[fpciTargetOS,fpciTargetProcessor,fpciFullVersion]; Info:=RunFPCInfo(Compiler,InfoTypes,ExtraOptions); if ParseFPCInfo(Info,InfoTypes,Infos) then begin // fpc or pas2js RealTargetOS:=Infos[fpciTargetOS]; RealTargetCPU:=Infos[fpciTargetProcessor]; FullVersion:=Infos[fpciFullVersion]; if FullVersion='' then debugln(['Warning: [TPCTargetConfigCache.Update] cannot determine compiler version: Compiler="'+Compiler+'" Options="'+ExtraOptions+'"']); end else begin RealTargetOS:=TargetOS; if RealTargetOS='' then RealTargetOS:=GetCompiledTargetOS; RealTargetCPU:=TargetCPU; if RealTargetCPU='' then RealTargetCPU:=GetCompiledTargetCPU; end; if FullVersion<>'' then begin // run fpc/pas2js and parse output if (Pos('-Fr',ExtraOptions)<1) and (Pos('-Fr',Caches.ExtraOptions)>0) then ExtraOptions:=Trim(ExtraOptions+' '+Caches.ExtraOptions); RunFPCVerbose(Compiler,TestFilename,CfgFiles,RealCompiler,UnitPaths, IncludePaths,UnitScopes,Defines,Undefines,ExtraOptions); //debugln(['TPCTargetConfigCache.Update UnitPaths="',UnitPaths.Text,'"']); //debugln(['TPCTargetConfigCache.Update UnitScopes="',UnitScopes.Text,'"']); //debugln(['TPCTargetConfigCache.Update IncludePaths="',IncludePaths.Text,'"']); end; if Defines<>nil then begin if Defines.Contains('PAS2JS') and Defines.Contains('PAS2JS_FULLVERSION') then Kind:=pcPas2js else if Defines.Contains('FPC') and Defines.Contains('FPC_FULLVERSION') then Kind:=pcFPC else begin IsCompilerExecutable(Compiler,KindErrorMsg,Kind,false); if KindErrorMsg<>'' then debugln(['Warning: [TPCTargetConfigCache.Update] cannot determine type of compiler: Compiler="'+Compiler+'" Options="'+ExtraOptions+'"']); end; end; if Kind=pcFPC then begin RealTargetCPUCompiler:=FindDefaultTargetCPUCompiler(TargetCPU,true); if RealCompiler='' then RealCompiler:=RealTargetCPUCompiler; end; PreparePaths(UnitPaths); PreparePaths(IncludePaths); // store the real compiler file and date if (RealCompiler<>'') and FileExistsCached(RealCompiler) then RealCompilerDate:=FileAgeCached(RealCompiler) else if Kind=pcFPC then begin if CTConsoleVerbosity>=-1 then debugln(['Warning: [TPCTargetConfigCache.Update] cannot find real compiler for this platform: Compiler="'+Compiler+'" Options="'+ExtraOptions+'" RealCompiler="',RealCompiler,'"']); end; // store the list of tried and read cfg files if CfgFiles<>nil then for i:=0 to CfgFiles.Count-1 do begin Filename:=CfgFiles[i]; if Filename='' then continue; CfgFileExists:=Filename[1]='+'; Filename:=copy(Filename,2,length(Filename)); FullFilename:=ExpandFileNameUTF8(TrimFileName(Filename),BaseDir); if CfgFileExists<>FileExistsCached(FullFilename) then begin debugln(['Warning: [TPCTargetConfigCache.Update] '+ExtractFileName(Compiler)+' found cfg a file, the IDE did not: "',Filename,'"']); CfgFileExists:=not CfgFileExists; end; CfgFileDate:=0; if CfgFileExists then CfgFileDate:=FileAgeCached(Filename); ConfigFiles.Add(Filename,CfgFileExists,CfgFileDate); end; // gather all units and include files in search paths GatherUnitsInSearchPaths(UnitPaths,IncludePaths,OnProgress,Units,Includes); GatherUnitsInFPMSources(Units,UnitToFPM,FPMNameToFPM,OnProgress); //if Kind=pcPas2js then begin // debugln(['TPCTargetConfigCache.Update Units:']); // for e in Units do // debugln([' ',E^.Name,' ',E^.Value]); //end; if (UnitPaths<>nil) and (UnitPaths.Count=0) then begin if CTConsoleVerbosity>=-1 then debugln(['Warning: [TPCTargetConfigCache.Update] no unit paths: ',Compiler,' ',ExtraOptions]); end; // check if the system ppu exists HasPPUs:=(Kind=pcFPC) and (Units<>nil) and FilenameExtIs(Units['system'],'ppu',true); // check compiler version define if (CTConsoleVerbosity>=-1) and (Defines<>nil) then begin case Kind of pcFPC: if not Defines.Contains('FPC_FULLVERSION') then debugln(['Warning: [TPCTargetConfigCache.Update] invalid fpc: Compiler="'+Compiler+'" Options="'+ExtraOptions+'" RealCompiler="',RealCompiler,'" missing FPC_FULLVERSION']); pcDelphi: ; pcPas2js: if not Defines.Contains('PAS2JS_FULLVERSION') then debugln(['Warning: [TPCTargetConfigCache.Update] invalid pas2js: Compiler="'+Compiler+'" Options="'+ExtraOptions+'" missing PAS2JS_FULLVERSION']); end; end; end; // check for changes if not Equals(OldOptions) then begin IncreaseChangeStamp; if CTConsoleVerbosity>=0 then debugln(['Hint: [TPCTargetConfigCache.Update] has changed']); end; Result:=true; finally CfgFiles.Free; OldOptions.Free; end; end; function TPCTargetConfigCache.FindDefaultTargetCPUCompiler(aTargetCPU: string; ResolveLinks: boolean): string; function Search(const ShortFileName: string): string; var ExtPath: String; begin // fpc.exe first searches in -Xp ExtPath:=GetLastFPCParameter(CompilerOptions,'-Xp'); if (ExtPath<>'') and (ExtPath<>'.') then begin if not FilenameIsAbsolute(ExtPath) then // If -Xp is relative then it is relative to the working directory ExtPath:=TrimFilename(AppendPathDelim(GetCurrentDirUTF8)+ExtPath); Result:=AppendPathDelim(ExtPath)+ShortFileName; if FileExistsCached(Result) then exit; end; // then fpc.exe searches in its own directory if Compiler<>'' then begin Result:=ExtractFilePath(Compiler); if FilenameIsAbsolute(Result) then begin Result+=ShortFileName; if FileExistsCached(Result) then exit; end; end; // finally fpc.exe searches in PATH Result:=SearchFileInPath(ShortFileName,GetCurrentDirUTF8, GetEnvironmentVariableUTF8('PATH'),PathSeparator,ctsfcDefault); if (Result<>'') or (Compiler='') then exit; end; var CompiledTargetCPU: String; Cross: Boolean; Postfix: String; begin Result:=''; if Kind<>pcFPC then exit; CompiledTargetCPU:=GetCompiledTargetCPU; if aTargetCPU='' then aTargetCPU:=CompiledTargetCPU; Cross:=not SameText(aTargetCPU,CompiledTargetCPU); // The -V parameter searches for ppcx64-postfix instead of ppcx64 Postfix:=GetLastFPCParameter(CompilerOptions,'-V'); if Postfix<>'' then Postfix:='-'+Postfix; Result:=Search(GetDefaultCompilerFilename(aTargetCPU,Cross)+Postfix); if (Result='') and Cross then begin Result:=Search(GetDefaultCompilerFilename(aTargetCPU,false)+Postfix); if Result='' then exit; end; if ResolveLinks then begin Result:=GetPhysicalFilenameCached(Result,false); end; end; function TPCTargetConfigCache.GetUnitPaths: string; begin if UnitPaths=nil then exit(''); UnitPaths.Delimiter:=';'; UnitPaths.StrictDelimiter:=true; Result:=UnitPaths.DelimitedText; end; function TPCTargetConfigCache.GetFPCVerNumbers(out FPCVersion, FPCRelease, FPCPatch: integer): boolean; var v: string; begin // get default FPC version v:={$I %FPCVERSION%}; Result:=SplitFPCVersion(v,FPCVersion,FPCRelease,FPCPatch); if Defines<>nil then begin // use defines FPCVersion:=StrToIntDef(Defines['FPC_VERSION'],FPCVersion); FPCRelease:=StrToIntDef(Defines['FPC_RELEASE'],FPCRelease); FPCPatch:=StrToIntDef(Defines['FPC_PATCH'],FPCPatch); end; end; function TPCTargetConfigCache.GetFPCVer: string; var FPCVersion: integer; FPCRelease: integer; FPCPatch: integer; begin if GetFPCVerNumbers(FPCVersion,FPCRelease,FPCPatch) then Result:=IntToStr(FPCVersion)+'.'+IntToStr(FPCRelease)+'.'+IntToStr(FPCPatch) else Result:=''; end; function TPCTargetConfigCache.GetFPC_FULLVERSION: integer; begin if Defines<>nil then Result:=StrToIntDef(Defines['FPC_FULLVERSION'],0) else Result:=0; if Result=0 then Result:=GetCompiledFPCVersion; end; function TPCTargetConfigCache.IndexOfUsedCfgFile: integer; begin if ConfigFiles=nil then exit(-1); Result:=0; while (ResultfItems.Count then exit; Node1:=fItems.FindLowest; Node2:=Caches.fItems.FindLowest; while Node1<>nil do begin Item1:=TPCTargetConfigCache(Node1.Data); Item2:=TPCTargetConfigCache(Node2.Data); if not Item1.Equals(Item2) then exit; Node1:=fItems.FindSuccessor(Node1); Node2:=Caches.fItems.FindSuccessor(Node2); end; Result:=true; end; procedure TPCTargetConfigCaches.Assign(Source: TPersistent); var Caches: TPCTargetConfigCaches; Node: TAVLTreeNode; SrcItem: TPCTargetConfigCache; NewItem: TPCTargetConfigCache; begin if Source is TPCTargetConfigCaches then begin Caches:=TPCTargetConfigCaches(Source); if Equals(Caches) then exit; // no change, keep ChangeStamp Clear; Node:=Caches.fItems.FindLowest; while Node<>nil do begin SrcItem:=TPCTargetConfigCache(Node.Data); NewItem:=TPCTargetConfigCache.Create(Self); NewItem.Assign(SrcItem); fItems.Add(NewItem); Node:=Caches.fItems.FindSuccessor(Node); end; IncreaseChangeStamp; end else inherited Assign(Source); end; procedure TPCTargetConfigCaches.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); var Cnt: integer; i: Integer; Item: TPCTargetConfigCache; begin Clear; Cnt:=XMLConfig.GetValue(Path+'Count',0); for i:=1 to Cnt do begin Item:=TPCTargetConfigCache.Create(Self); Item.LoadFromXMLConfig(XMLConfig,Path+'Item'+IntToStr(i)+'/'); if (Item.Compiler<>'') then fItems.Add(Item) else Item.Free; end; IncreaseChangeStamp; end; procedure TPCTargetConfigCaches.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); var Node: TAVLTreeNode; Item: TPCTargetConfigCache; i: Integer; begin Node:=fItems.FindLowest; i:=0; while Node<>nil do begin Item:=TPCTargetConfigCache(Node.Data); inc(i); Item.SaveToXMLConfig(XMLConfig,Path+'Item'+IntToStr(i)+'/'); Node:=fItems.FindSuccessor(Node); end; XMLConfig.SetDeleteValue(Path+'Count',i,0); end; procedure TPCTargetConfigCaches.LoadFromFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.Create(Filename); try LoadFromXMLConfig(XMLConfig,'FPCConfigs/'); finally XMLConfig.Free; end; end; procedure TPCTargetConfigCaches.SaveToFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.CreateClean(Filename); try SaveToXMLConfig(XMLConfig,'FPCConfigs/'); finally XMLConfig.Free; end; end; procedure TPCTargetConfigCaches.IncreaseChangeStamp; begin CTIncreaseChangeStamp(FChangeStamp); end; function TPCTargetConfigCaches.Find(CompilerFilename, CompilerOptions, TargetOS, TargetCPU: string; CreateIfNotExists: boolean ): TPCTargetConfigCache; var Node: TAVLTreeNode; Cmp: TPCTargetConfigCache; begin Cmp:=TPCTargetConfigCache.Create(Self); try Cmp.Compiler:=CompilerFilename; Cmp.CompilerOptions:=CompilerOptions; Cmp.TargetOS:=TargetOS; Cmp.TargetCPU:=TargetCPU; Node:=fItems.Find(cmp); if Node<>nil then begin Result:=TPCTargetConfigCache(Node.Data); end else if CreateIfNotExists then begin Result:=cmp; cmp:=nil; fItems.Add(Result); end else begin Result:=nil; end; finally Cmp.Free; end; end; procedure TPCTargetConfigCaches.GetDefaultCompilerTarget( const CompilerFilename, CompilerOptions: string; out TargetOS, TargetCPU: string); var Cfg: TPCTargetConfigCache; begin Cfg:=Find(CompilerFilename,CompilerOptions,'','',true); if Cfg=nil then begin TargetOS:=''; TargetCPU:=''; end else begin if Cfg.NeedsUpdate then Cfg.Update(TestFilename); TargetOS:=Cfg.RealTargetOS; TargetCPU:=Cfg.RealTargetCPU; end; end; function TPCTargetConfigCaches.GetListing: string; var Node: TAVLTreeNode; CfgCache: TPCTargetConfigCache; i: Integer; begin Result:='TPCTargetConfigCaches.GetListing Count='+dbgs(fItems.Count)+LineEnding; i:=0; Node:=fItems.FindLowest; while Node<>nil do begin inc(i); CfgCache:=TPCTargetConfigCache(Node.Data); Result+=' '+dbgs(i)+':' +' TargetOS="'+CfgCache.TargetOS+'"' +' TargetCPU="'+CfgCache.TargetCPU+'"' +' Compiler="'+CfgCache.Compiler+'"' +' CompilerOptions="'+CfgCache.CompilerOptions+'"' +LineEnding; Node:=fItems.FindSuccessor(Node); end; end; { TPCConfigFileStateList } function TPCConfigFileStateList.GetItems(Index: integer): TPCConfigFileState; begin Result:=TPCConfigFileState(fItems[Index]); end; constructor TPCConfigFileStateList.Create; begin fItems:=TFPList.Create; end; destructor TPCConfigFileStateList.Destroy; begin Clear; FreeAndNil(fItems); inherited Destroy; end; procedure TPCConfigFileStateList.Clear; var i: Integer; begin for i:=0 to fItems.Count-1 do TObject(fItems[i]).Free; fItems.Clear; end; procedure TPCConfigFileStateList.Assign(List: TPCConfigFileStateList); var i: Integer; Item: TPCConfigFileState; begin Clear; for i:=0 to List.Count-1 do begin Item:=List[i]; Add(Item.Filename,Item.FileExists,Item.FileDate); end; end; function TPCConfigFileStateList.Equals(List: TPCConfigFileStateList; CheckDates: boolean): boolean; var i: Integer; begin Result:=false; if Count<>List.Count then exit; for i:=0 to Count-1 do if not Items[i].Equals(List[i],CheckDates) then exit; Result:=true; end; function TPCConfigFileStateList.Add(aFilename: string; aFileExists: boolean; aFileDate: longint): TPCConfigFileState; begin Result:=TPCConfigFileState.Create(aFilename,aFileExists,aFileDate); fItems.Add(Result); end; function TPCConfigFileStateList.Count: integer; begin Result:=fItems.Count; end; procedure TPCConfigFileStateList.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); var Cnt: integer; Item: TPCConfigFileState; i: Integer; begin Cnt:=XMLConfig.GetValue(Path+'Count',0); for i:=1 to Cnt do begin Item:=TPCConfigFileState.Create('',false,0); Item.LoadFromXMLConfig(XMLConfig,Path+'Item'+IntToStr(i)+'/'); fItems.Add(Item); end; end; procedure TPCConfigFileStateList.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); var i: Integer; begin for i:=1 to Count do Items[i-1].SaveToXMLConfig(XMLConfig,Path+'Item'+IntToStr(i)+'/'); XMLConfig.SetDeleteValue(Path+'Count',Count,0); end; { TPCConfigFileState } constructor TPCConfigFileState.Create(const aFilename: string; aFileExists: boolean; aFileDate: longint); begin Filename:=aFilename; FileExists:=aFileExists; FileDate:=aFileDate; end; function TPCConfigFileState.Equals(Other: TPCConfigFileState; CheckDate: boolean): boolean; begin Result:=false; if (Filename<>Other.Filename) or (FileExists<>Other.FileExists) then exit; if CheckDate and FileExists and (FileDate<>Other.FileDate) then exit; Result:=true; end; procedure TPCConfigFileState.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); begin Filename:=XMLConfig.GetValue(Path+'Filename',''); FileExists:=XMLConfig.GetValue(Path+'Exists',false); FileDate:=XMLConfig.GetValue(Path+'Date',0); end; procedure TPCConfigFileState.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); begin XMLConfig.SetDeleteValue(Path+'Filename',Filename,''); XMLConfig.SetDeleteValue(Path+'Exists',FileExists,false); XMLConfig.SetDeleteValue(Path+'Date',FileDate,0); end; { TFPCSourceCacheItem } constructor TFPCSourceCache.Create(AOwner: TComponent); begin inherited Create(AOwner); Files:=TStringList.Create; Valid:=false; CTIncreaseChangeStamp(FChangeStamp); // set to not 0 if Owner is TFPCSourceCaches then Caches:=TFPCSourceCaches(Owner); end; destructor TFPCSourceCache.Destroy; begin FreeAndNil(Files); inherited Destroy; end; procedure TFPCSourceCache.Clear; begin FreeAndNil(Files); Valid:=false; end; procedure TFPCSourceCache.Assign(Source: TPersistent); var Cache: TFPCSourceCache; begin if Source is TFPCSourceCache then begin Cache:=TFPCSourceCache(Source); Directory:=Cache.Directory; Files.Assign(Cache.Files); Valid:=Cache.Valid; end else inherited Assign(Source); end; function TFPCSourceCache.Equals(Cache: TFPCSourceCache): boolean; begin Result:=false; if Valid<>Cache.Valid then exit; if Directory<>Cache.Directory then exit; if not Files.Equals(Cache.Files) then exit; Result:=true; end; procedure TFPCSourceCache.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); var List: TStringList; begin Clear; List:=nil; try Valid:=XMLConfig.GetValue(Path+'Valid',true); Directory:=XMLConfig.GetValue(Path+'Directory',''); List:=TStringList.Create; List.StrictDelimiter:=true; List.Delimiter:=';'; List.DelimitedText:=XMLConfig.GetValue(Path+'Files',''); FreeAndNil(Files); Files:=Decompress1FileList(List); finally if Files=nil then Files:=TStringList.Create; List.Free; end; end; procedure TFPCSourceCache.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); var List: TStringList; s: String; begin List:=nil; try XMLConfig.SetDeleteValue(Path+'Valid',Valid,true); XMLConfig.SetDeleteValue(Path+'Directory',Directory,''); if Files<>nil then begin List:=Compress1FileList(Files); List.StrictDelimiter:=true; List.Delimiter:=';'; s:=List.DelimitedText; end else s:=''; XMLConfig.SetDeleteValue(Path+'Files',s,''); finally List.Free; end; end; procedure TFPCSourceCache.LoadFromFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.Create(Filename); try LoadFromXMLConfig(XMLConfig,'FPCSourceDirectory/'); finally XMLConfig.Free; end; end; procedure TFPCSourceCache.SaveToFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.CreateClean(Filename); try SaveToXMLConfig(XMLConfig,'FPCSourceDirectory/'); finally XMLConfig.Free; end; end; procedure TFPCSourceCache.Update(const OnProgress: TDefinePoolProgress); var NewFiles: TStringList; begin Valid:=false; if Directory<>'' then NewFiles:=GatherFilesInFPCSources(Directory,OnProgress) else NewFiles:=TStringList.Create; Update(NewFiles); end; procedure TFPCSourceCache.Update(var NewFiles: TStringList); var OldFiles: TStringList; OldValid: Boolean; begin OldFiles:=Files; OldValid:=Valid; try Files:=NewFiles; NewFiles:=nil; Valid:=true; if (Valid<>OldValid) or ((Files=nil)<>(OldFiles=nil)) or ((Files<>nil) and (Files.Text<>OldFiles.Text)) then begin IncreaseChangeStamp; if CTConsoleVerbosity>0 then debugln(['Hint: [TFPCSourceCache.Update] ',Directory,' has changed.']); end; finally OldFiles.Free; end; end; procedure TFPCSourceCache.IncreaseChangeStamp; begin CTIncreaseChangeStamp(FChangeStamp); if Caches<>nil then Caches.IncreaseChangeStamp; end; { TFPCSourceCache } constructor TFPCSourceCaches.Create(AOwner: TComponent); begin CTIncreaseChangeStamp(FChangeStamp); // set to not 0 inherited Create(AOwner); fItems:=TAVLTree.Create(@CompareFPCSourceCacheItems); end; destructor TFPCSourceCaches.Destroy; begin Clear; FreeAndNil(fItems); inherited Destroy; end; procedure TFPCSourceCaches.Clear; begin if fItems.Count=0 then exit; fItems.FreeAndClear; IncreaseChangeStamp; end; procedure TFPCSourceCaches.Assign(Source: TPersistent); var Caches: TFPCSourceCaches; SrcItem: TFPCSourceCache; NewItem: TFPCSourceCache; Node: TAVLTreeNode; begin if Source is TFPCSourceCaches then begin Caches:=TFPCSourceCaches(Source); if Equals(Caches) then exit; // keep ChangeStamp if equal Clear; Node:=Caches.fItems.FindLowest; while Node<>nil do begin SrcItem:=TFPCSourceCache(Node.Data); NewItem:=TFPCSourceCache.Create(Self); NewItem.Assign(SrcItem); fItems.Add(NewItem); Node:=Caches.fItems.FindSuccessor(Node); end; IncreaseChangeStamp; end else inherited Assign(Source); end; function TFPCSourceCaches.Equals(Caches: TFPCSourceCaches): boolean; var Node1, Node2: TAVLTreeNode; Item1: TFPCSourceCache; Item2: TFPCSourceCache; begin Result:=false; if Caches.fItems.Count<>fItems.Count then exit; Node1:=fItems.FindLowest; Node2:=Caches.fItems.FindLowest; while Node1<>nil do begin Item1:=TFPCSourceCache(Node1.Data); Item2:=TFPCSourceCache(Node2.Data); if not Item1.Equals(Item2) then exit; Node1:=fItems.FindSuccessor(Node1); Node2:=Caches.fItems.FindSuccessor(Node2); end; Result:=true; end; procedure TFPCSourceCaches.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); var Cnt: integer; i: Integer; Item: TFPCSourceCache; begin Clear; Cnt:=XMLConfig.GetValue(Path+'Count',0); for i:=1 to Cnt do begin Item:=TFPCSourceCache.Create(Self); Item.LoadFromXMLConfig(XMLConfig,Path+'Item'+IntToStr(i)+'/'); if (Item.Directory='') or (fItems.Find(Item)<>nil) then Item.Free else fItems.Add(Item); end; end; procedure TFPCSourceCaches.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); var Node: TAVLTreeNode; Item: TFPCSourceCache; Cnt: Integer; begin Cnt:=0; Node:=fItems.FindLowest; while Node<>nil do begin Item:=TFPCSourceCache(Node.Data); if Item.Directory<>'' then begin inc(Cnt); Item.SaveToXMLConfig(XMLConfig,Path+'Item'+IntToStr(Cnt)+'/'); end; Node:=fItems.FindSuccessor(Node); end; XMLConfig.SetDeleteValue(Path+'Count',Cnt,0); end; procedure TFPCSourceCaches.LoadFromFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.Create(Filename); try LoadFromXMLConfig(XMLConfig,'FPCSourceDirectories/'); finally XMLConfig.Free; end; end; procedure TFPCSourceCaches.SaveToFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.CreateClean(Filename); try SaveToXMLConfig(XMLConfig,'FPCSourceDirectories/'); finally XMLConfig.Free; end; end; procedure TFPCSourceCaches.IncreaseChangeStamp; begin CTIncreaseChangeStamp(FChangeStamp); end; function TFPCSourceCaches.Find(Directory: string; CreateIfNotExists: boolean): TFPCSourceCache; var Node: TAVLTreeNode; begin Directory:=ChompPathDelim(TrimFilename(Directory)); Node:=fItems.FindKey(PChar(Directory),@CompareDirectoryWithFPCSourceCacheItem); if Node<>nil then begin Result:=TFPCSourceCache(Node.Data); end else if CreateIfNotExists then begin Result:=TFPCSourceCache.Create(Self); Result.Directory:=Directory; fItems.Add(Result); end else begin Result:=nil; end; end; { TCompilerDefinesCache } procedure TCompilerDefinesCache.SetConfigCaches(const AValue: TPCTargetConfigCaches); begin if FConfigCaches=AValue then exit; FConfigCaches:=AValue; FConfigCachesSaveStamp:=Low(FConfigCachesSaveStamp); end; function TCompilerDefinesCache.GetExtraOptions: string; begin Result:=ConfigCaches.ExtraOptions; end; function TCompilerDefinesCache.GetTestFilename: string; begin Result:=ConfigCaches.TestFilename; end; procedure TCompilerDefinesCache.SetExtraOptions(AValue: string); begin ConfigCaches.ExtraOptions:=AValue; end; procedure TCompilerDefinesCache.SetSourceCaches(const AValue: TFPCSourceCaches); begin if FSourceCaches=AValue then exit; FSourceCaches:=AValue; FSourceCachesSaveStamp:=low(FSourceCachesSaveStamp); end; procedure TCompilerDefinesCache.ClearUnitToSrcCaches; var i: Integer; begin for i:=0 to fUnitToSrcCaches.Count-1 do TObject(fUnitToSrcCaches[i]).Free; fUnitToSrcCaches.Clear; end; procedure TCompilerDefinesCache.SetTestFilename(AValue: string); begin ConfigCaches.TestFilename:=AValue; end; constructor TCompilerDefinesCache.Create(AOwner: TComponent); begin inherited Create(AOwner); ConfigCaches:=TPCTargetConfigCaches.Create(nil); SourceCaches:=TFPCSourceCaches.Create(nil); fUnitToSrcCaches:=TFPList.Create; end; destructor TCompilerDefinesCache.Destroy; begin ClearUnitToSrcCaches; FreeAndNil(FConfigCaches); FreeAndNil(FSourceCaches); FreeAndNil(fUnitToSrcCaches); inherited Destroy; end; procedure TCompilerDefinesCache.Clear; begin ClearUnitToSrcCaches; if ConfigCaches<>nil then ConfigCaches.Clear; if SourceCaches<>nil then SourceCaches.Clear; end; procedure TCompilerDefinesCache.LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string); begin if ConfigCaches<>nil then begin ConfigCaches.LoadFromXMLConfig(XMLConfig,Path+'FPCConfigs/'); FConfigCachesSaveStamp:=ConfigCaches.ChangeStamp; end; if SourceCaches<>nil then begin SourceCaches.LoadFromXMLConfig(XMLConfig,Path+'FPCSources/'); FSourceCachesSaveStamp:=SourceCaches.ChangeStamp; end; end; procedure TCompilerDefinesCache.SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); begin //debugln(['TCompilerDefinesCache.SaveToXMLConfig ']); if ConfigCaches<>nil then begin ConfigCaches.SaveToXMLConfig(XMLConfig,Path+'FPCConfigs/'); FConfigCachesSaveStamp:=ConfigCaches.ChangeStamp; end; if SourceCaches<>nil then begin SourceCaches.SaveToXMLConfig(XMLConfig,Path+'FPCSources/'); FSourceCachesSaveStamp:=SourceCaches.ChangeStamp; end; end; procedure TCompilerDefinesCache.LoadFromFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.Create(Filename); try LoadFromXMLConfig(XMLConfig,''); finally XMLConfig.Free; end; end; procedure TCompilerDefinesCache.SaveToFile(Filename: string); var XMLConfig: TXMLConfig; begin XMLConfig:=TXMLConfig.CreateClean(Filename); try SaveToXMLConfig(XMLConfig,''); finally XMLConfig.Free; end; end; function TCompilerDefinesCache.NeedsSave: boolean; begin Result:=true; if (ConfigCaches<>nil) and (ConfigCaches.ChangeStamp<>FConfigCachesSaveStamp) then exit; if (SourceCaches<>nil) and (SourceCaches.ChangeStamp<>FSourceCachesSaveStamp) then exit; Result:=false; end; function TCompilerDefinesCache.GetFPCVersion(const CompilerFilename, TargetOS, TargetCPU: string; UseCompiledVersionAsDefault: boolean): string; var Kind: TPascalCompiler; begin Result:=GetPCVersion(CompilerFilename,TargetOS,TargetCPU,UseCompiledVersionAsDefault,Kind); if Kind=pcFPC then ; end; function TCompilerDefinesCache.GetPCVersion(const CompilerFilename, TargetOS, TargetCPU: string; UseCompiledVersionAsDefault: boolean; out Kind: TPascalCompiler): string; var CfgCache: TPCTargetConfigCache; ErrorMsg: string; begin Kind:=pcFPC; if UseCompiledVersionAsDefault then Result:={$I %FPCVersion%} else Result:=''; if not IsCTExecutable(CompilerFilename,ErrorMsg) then exit; CfgCache:=ConfigCaches.Find(CompilerFilename,ExtraOptions,TargetOS,TargetCPU,true); if CfgCache.NeedsUpdate and not CfgCache.Update(TestFilename,ExtraOptions) then exit; Kind:=CfgCache.Kind; if CfgCache.FullVersion='' then exit; Result:=CfgCache.FullVersion; end; function TCompilerDefinesCache.FindUnitSet(const CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir: string; CreateIfNotExists: boolean ): TFPCUnitSetCache; var i: Integer; begin for i:=0 to fUnitToSrcCaches.Count-1 do begin Result:=TFPCUnitSetCache(fUnitToSrcCaches[i]); if (CompareFilenames(Result.CompilerFilename,CompilerFilename)=0) and (SysUtils.CompareText(Result.TargetOS,TargetOS)=0) and (SysUtils.CompareText(Result.TargetCPU,TargetCPU)=0) and (CompareFilenames(Result.FPCSourceDirectory,FPCSrcDir)=0) and (Result.CompilerOptions=Options) then exit; end; if CreateIfNotExists then begin Result:=TFPCUnitSetCache.Create(Self); Result.CompilerFilename:=CompilerFilename; Result.CompilerOptions:=Options; Result.TargetOS:=TargetOS; Result.TargetCPU:=TargetCPU; Result.FPCSourceDirectory:=FPCSrcDir; fUnitToSrcCaches.Add(Result); end else Result:=nil; end; function TCompilerDefinesCache.FindUnitSetWithID(const UnitSetID: string; out Changed: boolean; CreateIfNotExists: boolean): TFPCUnitSetCache; var CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir: string; ChangeStamp: integer; begin ParseUnitSetID(UnitSetID,CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir, ChangeStamp); //debugln(['TCompilerDefinesCache.FindUnitToSrcCache UnitSetID="',dbgstr(UnitSetID),'" CompilerFilename="',CompilerFilename,'" TargetOS="',TargetOS,'" TargetCPU="',TargetCPU,'" Options="',Options,'" FPCSrcDir="',FPCSrcDir,'" ChangeStamp=',ChangeStamp,' exists=',FindUnitToSrcCache(CompilerFilename, TargetOS, TargetCPU,Options, FPCSrcDir,false)<>nil]); Result:=FindUnitSet(CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir, false); if Result<>nil then begin Changed:=ChangeStamp<>Result.ChangeStamp; end else if CreateIfNotExists then begin Changed:=true; Result:=FindUnitSet(CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir, true); end else Changed:=false; end; function TCompilerDefinesCache.GetUnitSetID(CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir: string; ChangeStamp: integer): string; begin Result:='CompilerFilename='+CompilerFilename+LineEnding +'TargetOS='+TargetOS+LineEnding +'TargetCPU='+TargetCPU+LineEnding +'Options='+Options+LineEnding +'FPCSrcDir='+FPCSrcDir+LineEnding +'Stamp='+IntToStr(ChangeStamp); end; procedure TCompilerDefinesCache.ParseUnitSetID(const ID: string; out CompilerFilename, TargetOS, TargetCPU, Options, FPCSrcDir: string; out ChangeStamp: integer); var NameStartPos: PChar; function NameFits(p: PChar): boolean; var p1: PChar; begin p1:=NameStartPos; while (FPUpChars[p1^]=FPUpChars[p^]) and (p^<>#0) do begin inc(p1); inc(p); end; Result:=p1^='='; end; var ValueStartPos: PChar; ValueEndPos: PChar; Value: String; begin CompilerFilename:=''; TargetCPU:=''; TargetOS:=''; Options:=''; FPCSrcDir:=''; ChangeStamp:=0; if ID='' then exit; // read the lines with name=value NameStartPos:=PChar(ID); while NameStartPos^<>#0 do begin while (NameStartPos^ in [#10,#13]) do inc(NameStartPos); ValueStartPos:=NameStartPos; while not (ValueStartPos^ in ['=',#10,#13,#0]) do inc(ValueStartPos); if ValueStartPos^<>'=' then exit; inc(ValueStartPos); ValueEndPos:=ValueStartPos; while not (ValueEndPos^ in [#10,#13,#0]) do inc(ValueEndPos); Value:=copy(ID,ValueStartPos-PChar(ID)+1,ValueEndPos-ValueStartPos); //debugln(['TCompilerDefinesCache.ParseUnitSetID Name=',copy(ID,NameStartPos-PChar(ID)+1,ValueStartPos-NameStartPos-1),' Value="',Value,'"']); case NameStartPos^ of 'c','C': if NameFits('CompilerFilename') then CompilerFilename:=Value; 'f','F': if NameFits('FPCSrcDir') then FPCSrcDir:=Value; 'o','O': if NameFits('Options') then Options:=Value; 's','S': if NameFits('Stamp') then ChangeStamp:=StrToIntDef(Value,0); 't','T': if NameFits('TargetOS') then TargetOS:=Value else if NameFits('TargetCPU') then TargetCPU:=Value; end; NameStartPos:=ValueEndPos; end; end; { TFPCUnitSetCache } procedure TFPCUnitSetCache.SetCompilerFilename(const AValue: string); var NewFilename: String; begin NewFilename:=ResolveDots(AValue); if FCompilerFilename=NewFilename then exit; FCompilerFilename:=NewFilename; ClearConfigCache; end; procedure TFPCUnitSetCache.SetCompilerOptions(const AValue: string); begin if FCompilerOptions=AValue then exit; FCompilerOptions:=AValue; ClearConfigCache; end; procedure TFPCUnitSetCache.SetFPCSourceDirectory(const AValue: string); var NewValue: String; begin NewValue:=TrimAndExpandDirectory(AValue); if FFPCSourceDirectory=NewValue then exit; FFPCSourceDirectory:=NewValue; ClearSourceCache; end; procedure TFPCUnitSetCache.SetTargetCPU(const AValue: string); begin if FTargetCPU=AValue then exit; FTargetCPU:=AValue; ClearConfigCache; end; procedure TFPCUnitSetCache.SetTargetOS(const AValue: string); begin if FTargetOS=AValue then exit; FTargetOS:=AValue; ClearConfigCache; end; procedure TFPCUnitSetCache.ClearConfigCache; begin FConfigCache:=nil; fFlags:=fFlags+[fuscfUnitTreeNeedsUpdate,fuscfSrcRulesNeedUpdate]; end; procedure TFPCUnitSetCache.ClearSourceCache; begin fSourceCache:=nil; Include(fFlags,fuscfUnitTreeNeedsUpdate); end; procedure TFPCUnitSetCache.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if Operation=opRemove then begin if FConfigCache=AComponent then ClearConfigCache; if fSourceCache=AComponent then ClearSourceCache; end; end; constructor TFPCUnitSetCache.Create(TheOwner: TComponent); begin inherited Create(TheOwner); CTIncreaseChangeStamp(FChangeStamp); // set ot not 0 FCaches:=TheOwner as TCompilerDefinesCache; fUnitToSourceTree:=TStringToStringTree.Create(false); fSrcDuplicates:=TStringToStringTree.Create(false); fSourceRules:=TFPCSourceRules.Create; fFlags:=[fuscfUnitTreeNeedsUpdate,fuscfSrcRulesNeedUpdate]; fUnitStampOfFPC:=CTInvalidChangeStamp; fUnitStampOfFiles:=CTInvalidChangeStamp; fUnitStampOfRules:=CTInvalidChangeStamp; end; destructor TFPCUnitSetCache.Destroy; begin FreeAndNil(fSourceRules); FreeAndNil(fUnitToSourceTree); FreeAndNil(fSrcDuplicates); inherited Destroy; end; procedure TFPCUnitSetCache.Clear; begin end; procedure TFPCUnitSetCache.Init; begin GetUnitToSourceTree(True); end; function TFPCUnitSetCache.GetConfigCache(AutoUpdate: boolean ): TPCTargetConfigCache; begin if CompilerFilename='' then raise Exception.Create('TFPCUnitToSrcCache.GetConfigCache missing CompilerFilename'); if Caches.TestFilename='' then raise Exception.Create('TFPCUnitToSrcCache.GetConfigCache missing TestFilename'); if FConfigCache=nil then begin FConfigCache:=Caches.ConfigCaches.Find(CompilerFilename,CompilerOptions, TargetOS,TargetCPU,true); FConfigCache.FreeNotification(Self); end; //debugln(['TFPCUnitSetCache.GetConfigCache CompilerOptions="',CompilerOptions,'" FConfigCache.CompilerOptions="',FConfigCache.CompilerOptions,'"']); if AutoUpdate and FConfigCache.NeedsUpdate then FConfigCache.Update(Caches.TestFilename,Caches.ExtraOptions); Result:=FConfigCache; end; function TFPCUnitSetCache.GetSourceCache(AutoUpdate: boolean ): TFPCSourceCache; begin if fSourceCache=nil then begin fSourceCache:=Caches.SourceCaches.Find(FPCSourceDirectory,true); fSourceCache.FreeNotification(Self); end; if AutoUpdate and (not fSourceCache.Valid) then fSourceCache.Update(nil); Result:=fSourceCache; end; function TFPCUnitSetCache.GetSourceRules(AutoUpdate: boolean ): TFPCSourceRules; var Cfg: TPCTargetConfigCache; NewRules: TFPCSourceRules; begin Cfg:=GetConfigCache(AutoUpdate); if (fuscfSrcRulesNeedUpdate in fFlags) or (fRulesStampOfConfig<>Cfg.ChangeStamp) then begin Exclude(fFlags,fuscfSrcRulesNeedUpdate); if Cfg.Kind=pcFPC then begin NewRules:=DefaultFPCSourceRules.Clone; try if Cfg.Units<>nil then AdjustFPCSrcRulesForPPUPaths(Cfg.Units,NewRules); fSourceRules.Assign(NewRules); // increases ChangeStamp if something changed finally NewRules.Free; end; end else begin fSourceRules.Clear; end; fRulesStampOfConfig:=Cfg.ChangeStamp; end; Result:=fSourceRules; end; function TFPCUnitSetCache.GetUnitToSourceTree(AutoUpdate: boolean ): TStringToStringTree; var Src: TFPCSourceCache; SrcRules: TFPCSourceRules; NewUnitToSourceTree: TStringToStringTree; NewSrcDuplicates: TStringToStringTree; ConfigCache: TPCTargetConfigCache; begin Src:=GetSourceCache(AutoUpdate); SrcRules:=GetSourceRules(AutoUpdate); ConfigCache:=GetConfigCache(false); // Note: update already done by GetSourceRules(AutoUpdate) if ConfigCache.Kind=pcFPC then begin if (fuscfUnitTreeNeedsUpdate in fFlags) or (fUnitStampOfFPC<>ConfigCache.ChangeStamp) or (fUnitStampOfFiles<>Src.ChangeStamp) or (fUnitStampOfRules<>SrcRules.ChangeStamp) then begin Exclude(fFlags,fuscfUnitTreeNeedsUpdate); NewSrcDuplicates:=nil; NewUnitToSourceTree:=nil; try NewSrcDuplicates:=TStringToStringTree.Create(false); NewUnitToSourceTree:=GatherUnitsInFPCSources(Src.Files, ConfigCache.RealTargetOS,ConfigCache.RealTargetCPU, NewSrcDuplicates,SrcRules); if NewUnitToSourceTree=nil then NewUnitToSourceTree:=TStringToStringTree.Create(false); // ToDo: add/replace sources in PPU search paths if not fUnitToSourceTree.Equals(NewUnitToSourceTree) then begin fUnitToSourceTree.Assign(NewUnitToSourceTree); IncreaseChangeStamp; end; if not fSrcDuplicates.Equals(NewSrcDuplicates) then begin fSrcDuplicates.Assign(NewSrcDuplicates); IncreaseChangeStamp; end; fUnitStampOfFPC:=ConfigCache.ChangeStamp; fUnitStampOfFiles:=Src.ChangeStamp; fUnitStampOfRules:=SrcRules.ChangeStamp; finally NewUnitToSourceTree.Free; NewSrcDuplicates.Free; end; end; end else begin fUnitToSourceTree.Clear; fSrcDuplicates.Clear; Exclude(fFlags,fuscfUnitTreeNeedsUpdate); fUnitStampOfFPC:=ConfigCache.ChangeStamp; fUnitStampOfFiles:=Src.ChangeStamp; fUnitStampOfRules:=SrcRules.ChangeStamp; end; Result:=fUnitToSourceTree; end; function TFPCUnitSetCache.GetSourceDuplicates(AutoUpdate: boolean ): TStringToStringTree; begin GetUnitToSourceTree(AutoUpdate); Result:=fSrcDuplicates; end; function TFPCUnitSetCache.GetUnitSrcFile(const AnUnitName: string; SrcSearchRequiresPPU: boolean; SkipPPUCheckIfTargetIsSourceOnly: boolean): string; { Searches the unit in the FPC search path and sources. SrcSearchRequiresPPU: only search the sources if there is a ppu in the search path } var Tree: TStringToStringTree; ConfigCache: TPCTargetConfigCache; UnitInFPCPath: String; begin Result:=''; {$IFDEF ShowTriedUnits} debugln(['TFPCUnitSetCache.GetUnitSrcFile Unit="',AnUnitName,'" SrcSearchRequiresPPU=',SrcSearchRequiresPPU,' SkipPPUCheckIfTargetIsSourceOnly=',SkipPPUCheckIfTargetIsSourceOnly]); {$ENDIF} Tree:=GetUnitToSourceTree(false); ConfigCache:=GetConfigCache(false); if (ConfigCache.Units<>nil) then begin UnitInFPCPath:=ConfigCache.Units[AnUnitName]; //if Pos('lazmkunit',AnUnitName)>0 then debugln(['TFPCUnitSetCache.GetUnitSrcFile UnitInFPCPath=',UnitInFPCPath]); if FilenameExtIs(UnitInFPCPath,'ppu',true) then begin // there is a ppu end else if UnitInFPCPath<>'' then begin // there is a pp or pas in the FPC search path {$IFDEF ShowTriedUnits} debugln(['TFPCUnitSetCache.GetUnitSrcFile Unit="',AnUnitName,'" source in FPC search path: "',Result,'"']); {$ENDIF} Result:=UnitInFPCPath; exit; end else begin // unit has no ppu in the FPC ppu search path if SrcSearchRequiresPPU then begin if ConfigCache.HasPPUs then begin // but there are other ppu files {$IFDEF ShowTriedUnits} debugln(['TFPCUnitSetCache.GetUnitSrcFile Unit="',AnUnitName,'" unit has no ppu file in FPC path, but there are other ppu']); {$ENDIF} exit; end else begin // no ppu exists at all // => the fpc is not installed properly for this target {$IFDEF ShowTriedUnits} debugln(['TFPCUnitSetCache.GetUnitSrcFile Unit="',AnUnitName,'" there are no ppu files for this target']); {$ENDIF} if (not SkipPPUCheckIfTargetIsSourceOnly) then exit; // => search directly in the sources // this allows cross editing even if FPC is not installed for this target end; end; end; end; // search the sources if Tree<>nil then begin Result:=Tree[AnUnitName]; if (Result<>'') and (not FilenameIsAbsolute(Result)) then Result:=FPCSourceDirectory+Result; {$IFDEF ShowTriedUnits} debugln(['TFPCUnitSetCache.GetUnitSrcFile Unit="',AnUnitName,'" Result=',Result]); {$ENDIF} end; end; function TFPCUnitSetCache.GetCompiledUnitFile(const AUnitName: string): string; var ConfigCache: TPCTargetConfigCache; begin Result:=''; ConfigCache:=GetConfigCache(false); if ConfigCache.Units=nil then exit; Result:=ConfigCache.Units[AUnitName]; if Result='' then exit; if not FilenameExtIs(Result,'ppu',true) then Result:=''; end; class function TFPCUnitSetCache.GetInvalidChangeStamp: integer; begin Result:=CTInvalidChangeStamp; end; procedure TFPCUnitSetCache.IncreaseChangeStamp; begin CTIncreaseChangeStamp(FChangeStamp); end; function TFPCUnitSetCache.GetUnitSetID: string; begin Result:=Caches.GetUnitSetID(CompilerFilename,TargetOS,TargetCPU, CompilerOptions,FPCSourceDirectory,ChangeStamp); end; function TFPCUnitSetCache.GetFirstFPCCfg: string; var Cfg: TPCTargetConfigCache; i: Integer; Files: TPCConfigFileStateList; begin Result:=''; Cfg:=GetConfigCache(false); if Cfg=nil then exit; Files:=Cfg.ConfigFiles; if Files=nil then exit; for i:=0 to Files.Count-1 do begin if Files[i].FileExists then begin Result:=Files[i].Filename; exit; end; end; end; function TFPCUnitSetCache.GetUnitScopes: string; var Cfg: TPCTargetConfigCache; Scopes: TStrings; Scope: String; i: Integer; begin Result:=''; Cfg:=GetConfigCache(false); if Cfg=nil then exit; Scopes:=Cfg.UnitScopes; if Scopes=nil then exit; for i:=0 to Scopes.Count-1 do begin Scope:=Scopes[i]; if Scope='' then continue; Result:=Result+';'+Scope; end; Delete(Result,1,1); end; function TFPCUnitSetCache.GetCompilerKind: TPascalCompiler; var Cfg: TPCTargetConfigCache; begin Cfg:=GetConfigCache(false); if Cfg=nil then exit(pcFPC); Result:=Cfg.Kind; end; initialization InitDefaultFPCSourceRules; finalization FreeAndNil(DefaultFPCSourceRules); end.