lazarus/components/codetools/definetemplates.pas
2021-03-07 11:39:46 +00:00

11853 lines
458 KiB
ObjectPascal

{
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 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<version> -Xp<path>
// 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<target>.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<language file>
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<language file>
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<targetos>
fpcpP, // -P<targetprocessor>
fpcpV, // -V<postfix>
fpcpXp // -Xp<directory>
);
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 (i<OutLen) and (Buf[i+1] in [#10,#13]) and (Buf[i]<>Buf[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/<FPCVer>/units/<FPCTarget>/<name>/
if there is lib/fpc/<FPCVer>/fpmkinst/><FPCTarget>/<name>.fpm
and search line SourcePath=<directory>
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/<FPCTarget>/<pkgname>/<unitname>.ppu
// and if there is /something/fpmkinst/<FPCTarget>/<pkgname>.fpm
p:=length(Filename);
if not SearchPriorPathDelim(p,Filename) then exit;
// <pkgname>
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;
// <fpctarget>
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 Lvl<MaxLevel then
Traverse(Dir+Filename+PathDelim,Tree,Lvl+1);
end else if FilenameIsPascalUnit(Filename) then begin
AnUnitName:=ExtractFileNameOnly(Filename);
if not Tree.Contains(AnUnitName) then
Tree[AnUnitName]:=Dir+Filename;
end;
until FindNextUTF8(Info)<>0;
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<Score then begin
// found a better unit
if (DebugUnitName<>'') 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<MakefileFPC.Count do begin
Line:=MakefileFPC[i];
if Line='' then begin
end else if (Line[1]='[') then begin
// start of section
p:=System.Pos(']',Line);
if p<1 then p:=length(Line);
List.Add(Line);
end else if (Line[1] in ['a'..'z','A'..'Z','0'..'9','_']) then begin
// start of name=value pair
NameValue:=Line;
repeat
p:=length(NameValue);
while (p>=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<something>
// 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 (MacroEnd<ValueLen) and (NewValue[MacroEnd] in ['(','{']) then
begin
if not Substitute(NewValue,ValueLen,MacroStart,MacroEnd) then break;
end;
MacroStart:=MacroEnd;
end;
if Buffer<>nil 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 (i<OutLen) and (Buf[i+1] in [#10,#13]) and (Buf[i]<>Buf[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:=StartPos<p;
end;
function ReadVersion(const VarName: string;
out NewVersion, NewRelease, NewPatch: integer): integer;
begin
Result:=0;
if (length(VarName)>3) 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;
// <LazarusSrcDir>
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));
// <LazarusSrcDir>/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);
// <LazarusSrcDir>/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));
// <LazarusSrcDir>/designer/units
MainDir.AddChild(DirTempl);
// <LazarusSrcDir>/images
// <LazarusSrcDir>/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);
// <LazarusSrcDir>/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);
// <LazarusSrcDir>/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));
// <LazarusSrcDir>/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));
// <LazarusSrcDir>/packager/registration
SubDirTempl:=TDefineTemplate.Create('Registration',
ctsPackagerRegistrationDirectory,'','registration',da_Directory);
DirTempl.AddChild(SubDirTempl);
// <LazarusSrcDir>/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);
// <LazarusSrcDir>/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);
// <LazarusSrcDir>/components
DirTempl:=TDefineTemplate.Create('Components',ctsComponentsDirectory,
'','components',da_Directory);
// <LazarusSrcDir>/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);
// <LazarusSrcDir>/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));
// <LazarusSrcDir>/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)<length(AParam) then begin
if copy(AParam,length(Identifier)+1,2)=':=' then
AValue:=copy(AParam,length(Identifier)+3,length(AParam));
end;
AddDefine('Define '+Identifier,ctsDefine+AParam,Identifier,AValue);
end;
procedure AddUndefine(const AParam: string);
var
NewAction: TDefineAction;
Identifier: String;
begin
if RecursiveDefines then
NewAction:=da_UndefineRecurse
else
NewAction:=da_Undefine;
Identifier:=GetIdentifier(PChar(AParam));
AddDefine('Undefine '+Identifier,ctsUndefine+AParam,Identifier,'',NewAction);
end;
procedure AddDefineUndefine(const AName: string; Define: boolean);
begin
if Define then
AddDefine(AName)
else
AddUndefine(AName);
end;
procedure DefineOpt(const Opt, Value: string);
var
tpl: TDefineTemplate;
Name, Descr, OptValue: string;
NewAction: TDefineAction;
begin
Name:='Option $' + Opt;
Descr:=Format('{$%s %s}', [Opt, Value]);
if Value = 'ON' then
OptValue:='1'
else
OptValue:='0';
if Result <> 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 FChangeStamp<High(FChangeStamp) then
inc(FChangeStamp)
else
FChangeStamp:=Low(FChangeStamp);
end;
{ TFPCSourceRule }
function TFPCSourceRule.FitsTargets(const FilterTargets: string): boolean;
var
FilterStartPos: PChar;
TargetPos: PChar;
FilterPos: PChar;
begin
//DebugLn(['TFPCSourceRule.FitsTargets FilterTargets="',FilterTargets,'" Targets="',Targets,'"']);
if Targets='*' then exit(true);
if (Targets='') or (FilterTargets='') then exit(false);
FilterStartPos:=PChar(FilterTargets);
while true do begin
while (FilterStartPos^=',') do inc(FilterStartPos);
if FilterStartPos^=#0 then exit(false);
TargetPos:=PChar(Targets);
repeat
while (TargetPos^=',') do inc(TargetPos);
if TargetPos^=#0 then break;
FilterPos:=FilterStartPos;
while (FilterPos^=TargetPos^) and (not (FilterPos^ in [#0,','])) do begin
inc(TargetPos);
inc(FilterPos);
end;
if (TargetPos^ in [#0,',']) then begin
// the target fits
exit(true);
end;
// try next target
while not (TargetPos^ in [#0,',']) do inc(TargetPos);
until TargetPos^=#0;
// next target filter
while not (FilterStartPos^ in [#0,',']) do inc(FilterStartPos);
end;
Result:=false;
end;
function TFPCSourceRule.FitsFilename(const aFilename: string): boolean;
begin
Result:=(length(Filename)<=length(aFilename))
and CompareMem(Pointer(Filename),Pointer(aFilename),length(Filename));
end;
function TFPCSourceRule.IsEqual(Rule: TFPCSourceRule): boolean;
begin
Result:=false;
if (Filename<>Rule.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<Number>/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<Number>/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<i>/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>/
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<path>
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<postfix> 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 (Result<ConfigFiles.Count) and (not ConfigFiles[Result].FileExists) do
inc(Result);
if Result=ConfigFiles.Count then Result:=-1;
end;
{ TPCTargetConfigCaches }
constructor TPCTargetConfigCaches.Create(AOwner: TComponent);
begin
CTIncreaseChangeStamp(FChangeStamp); // set to not 0
inherited Create(AOwner);
fItems:=TAVLTree.Create(@CompareFPCTargetConfigCacheItems);
end;
destructor TPCTargetConfigCaches.Destroy;
begin
Clear;
FreeAndNil(fItems);
inherited Destroy;
end;
procedure TPCTargetConfigCaches.Clear;
begin
if fItems.Count=0 then exit;
fItems.FreeAndClear;
IncreaseChangeStamp;
end;
function TPCTargetConfigCaches.Equals(Caches: TPCTargetConfigCaches): boolean;
var
Node1, Node2: TAVLTreeNode;
Item1: TPCTargetConfigCache;
Item2: TPCTargetConfigCache;
begin
Result:=false;
if Caches.fItems.Count<>fItems.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.