lazarus/components/codetools/codetoolsconfig.pas
2023-07-26 13:36:16 +01:00

451 lines
14 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 helps to setup and configure the codetools.
Example:
Create an empty unit empty.pas and do
Options:=TCodeToolsOptions.Create;
Options.LoadFromFile('config.xml');
Options.FPCPath:='/usr/bin/ppc386';
Options.FPCSrcDir:='/home/username/freepascal/fpc';
Options.LazarusSrcDir:='/home/username/pascal/lazarus';
Options.ProjectDir:='/home/username/pascal/project1/';
Options.TestPascalFile:=Options.ProjectDir+'empty.pas';
CodeToolBoss.Init(Options);
Options.SaveToFile('config.xml');
Options.Free;
.. use CodeToolBoss ..
}
unit CodeToolsConfig;
{$mode objfpc}{$H+}
{$I codetools.inc}
interface
uses
Classes, SysUtils, Laz2_XMLCfg, Laz2_XMLRead, Laz2_XMLWrite, Laz2_DOM,
FileProcs, LazFileUtils, LazFileCache, LazUTF8, CodeCache, DefineTemplates;
type
{ TCodeBufXMLConfig }
TCodeBufXMLConfig = class(TRttiXMLConfig)
private
FCodeCache: TCodeCache;
protected
fKeepFileAttributes: boolean;
procedure ReadXMLFile(out ADoc: TXMLDocument; const AFilename: String); override;
procedure WriteXMLFile(ADoc: TXMLDocument; const AFileName: String); override;
function GetCache: TCodeCache;
public
constructor CreateWithCache(AFilename: string;
LoadContent: boolean = true; // init/load from disk
LoadFileAttributes: boolean = true; // load lineending and encoding
ASource: string = ''; // init with this source
ACache: TCodeCache = nil);
property CodeCache: TCodeCache read FCodeCache write FCodeCache;
property KeepFileAttributes: boolean read fKeepFileAttributes write fKeepFileAttributes;
end;
var
DefaultConfigCodeCache: TCodeCache = nil; // set by CodeToolBoss
type
{ TCodeToolsOptions }
TCodeToolsOptions = class
private
FConfigCaches: TPCTargetConfigCaches;
FFPCOptions: string;
FFPCPath: string;
FFPCSrcDir: string;
FLazarusSrcDir: string;
FLazarusSrcOptions: string;
FLCLWidgetType: string;
FModified: boolean;
FPPUExt: string;
FProjectDir: string;
FSourceCaches: TFPCSourceCaches;
FSubtarget: string;
FTargetOS: string;
FTargetProcessor: string;
FTestPascalFile: string;
procedure SetFPCOptions(const AValue: string);
procedure SetFPCPath(const AValue: string);
procedure SetFPCSrcDir(const AValue: string);
procedure SetLazarusSrcDir(const AValue: string);
procedure SetLCLWidgetType(const AValue: string);
procedure SetLazarusSrcOptions(const AValue: string);
procedure SetModified(const AValue: boolean);
procedure SetPPUExt(const AValue: string);
procedure SetProjectDir(const AValue: string);
procedure SetSubtarget(AValue: string);
procedure SetTargetOS(const AValue: string);
procedure SetTargetProcessor(const AValue: string);
procedure SetTestPascalFile(const AValue: string);
public
constructor Create;
destructor Destroy; override;
procedure InitWithEnvironmentVariables;
function FindDefaultCompilerFilename: string;
procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string);
procedure LoadFromXMLConfig(XMLConfig: TXMLConfig; const Path: string);
procedure SaveToFile(const Filename: string);
procedure LoadFromFile(const Filename: string);
property Modified: boolean read FModified write SetModified;
// FPC
property FPCSrcDir: string read FFPCSrcDir write SetFPCSrcDir; // e.g. /usr/share/fpcsrc
property FPCPath: string read FFPCPath write SetFPCPath; // e.g. /usr/bin/fpc or /usr/bin/ppc386
property FPCOptions: string read FFPCOptions write SetFPCOptions; // extra options for fpc
property TargetOS: string read FTargetOS write SetTargetOS;
property TargetProcessor: string read FTargetProcessor write SetTargetProcessor;
property Subtarget: string read FSubtarget write SetSubtarget;
property TestPascalFile: string read FTestPascalFile write SetTestPascalFile; // points to an empty unit
property PPUExt: string read FPPUExt write SetPPUExt;
property SourceCaches: TFPCSourceCaches read FSourceCaches;
property ConfigCaches: TPCTargetConfigCaches read FConfigCaches;
// Project
property ProjectDir: string read FProjectDir write SetProjectDir;
// Lazarus
property LazarusSrcDir: string read FLazarusSrcDir write SetLazarusSrcDir;
property LCLWidgetType: string read FLCLWidgetType write SetLCLWidgetType;
property LazarusSrcOptions: string read FLazarusSrcOptions write SetLazarusSrcOptions;
end;
implementation
{ TCodeToolsOptions }
procedure TCodeToolsOptions.SetFPCOptions(const AValue: string);
begin
if FFPCOptions=AValue then exit;
FFPCOptions:=AValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetFPCPath(const AValue: string);
var
NewValue: String;
begin
NewValue:=TrimAndExpandFilename(AValue);
if FFPCPath=NewValue then exit;
FFPCPath:=NewValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetFPCSrcDir(const AValue: string);
var
NewValue: String;
begin
NewValue:=TrimAndExpandFilename(AValue);
if FFPCSrcDir=NewValue then exit;
FFPCSrcDir:=NewValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetLazarusSrcDir(const AValue: string);
var
NewValue: String;
begin
NewValue:=TrimAndExpandFilename(AValue);
if FLazarusSrcDir=NewValue then exit;
FLazarusSrcDir:=NewValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetLCLWidgetType(const AValue: string);
begin
if FLCLWidgetType=AValue then exit;
FLCLWidgetType:=AValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetLazarusSrcOptions(const AValue: string);
begin
if FLazarusSrcOptions=AValue then exit;
FLazarusSrcOptions:=AValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetModified(const AValue: boolean);
begin
if FModified=AValue then exit;
FModified:=AValue;
end;
procedure TCodeToolsOptions.SetPPUExt(const AValue: string);
begin
if FPPUExt=AValue then exit;
FPPUExt:=AValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetProjectDir(const AValue: string);
begin
if FProjectDir=AValue then exit;
FProjectDir:=AppendPathDelim(AValue);
Modified:=true;
end;
procedure TCodeToolsOptions.SetSubtarget(AValue: string);
begin
if FSubtarget=AValue then Exit;
FSubtarget:=AValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetTargetOS(const AValue: string);
begin
if FTargetOS=AValue then exit;
FTargetOS:=AValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetTargetProcessor(const AValue: string);
begin
if FTargetProcessor=AValue then exit;
FTargetProcessor:=AValue;
Modified:=true;
end;
procedure TCodeToolsOptions.SetTestPascalFile(const AValue: string);
begin
if FTestPascalFile=AValue then exit;
FTestPascalFile:=AValue;
Modified:=true;
end;
constructor TCodeToolsOptions.Create;
begin
FPPUExt:='.ppu';
FLCLWidgetType:='gtk2';
FConfigCaches:=TPCTargetConfigCaches.Create(nil);
FSourceCaches:=TFPCSourceCaches.Create(nil);
end;
destructor TCodeToolsOptions.Destroy;
begin
FreeAndNil(FConfigCaches);
FreeAndNil(FSourceCaches);
inherited Destroy;
end;
procedure TCodeToolsOptions.InitWithEnvironmentVariables;
{ procedure WriteEnv;
var
i: Integer;
begin
for i:=0 to GetEnvironmentVariableCount-1 do
debugln(['TCodeToolsOptions.InitWithEnvironmentVariables ',i,' ',GetEnvironmentStringUTF8(i)]);
end;
}
begin
if GetEnvironmentVariableUTF8('PP')<>'' then
FPCPath:=GetEnvironmentVariableUTF8('PP')
else if (FPCPath='') or not FileExistsCached(FPCPath) then
FPCPath:=FindDefaultCompilerFilename;
if GetEnvironmentVariableUTF8('FPCDIR')<>'' then
FPCSrcDir:=GetEnvironmentVariableUTF8('FPCDIR');
if GetEnvironmentVariableUTF8('LAZARUSDIR')<>'' then
LazarusSrcDir:=GetEnvironmentVariableUTF8('LAZARUSDIR');
if GetEnvironmentVariableUTF8('FPCTARGET')<>'' then
TargetOS:=GetEnvironmentVariableUTF8('FPCTARGET');
if GetEnvironmentVariableUTF8('FPCTARGETCPU')<>'' then
TargetProcessor:=GetEnvironmentVariableUTF8('FPCTARGETCPU');
if GetEnvironmentVariableUTF8('FPCSUBTARGET')<>'' then
Subtarget:=GetEnvironmentVariableUTF8('FPCSUBTARGET');
end;
function TCodeToolsOptions.FindDefaultCompilerFilename: string;
begin
Result:=SearchFileInPath(GetDefaultCompilerFilename,'',
GetEnvironmentVariableUTF8('PATH'),PathSeparator,ctsfcDefault);
end;
procedure TCodeToolsOptions.SaveToXMLConfig(XMLConfig: TXMLConfig;
const Path: string);
begin
XMLConfig.SetDeleteValue(Path+'FPC/Options/Value',FPCOptions,'');
XMLConfig.SetDeleteValue(Path+'FPC/CompilerPath/Value',FPCPath,'');
XMLConfig.SetDeleteValue(Path+'FPC/SrcDir/Value',FPCSrcDir,'');
XMLConfig.SetDeleteValue(Path+'FPC/TargetOS/Value',TargetOS,'');
XMLConfig.SetDeleteValue(Path+'FPC/TargetProcessor/Value',TargetProcessor,'');
XMLConfig.SetDeleteValue(Path+'FPC/Subtarget/Value',Subtarget,'');
XMLConfig.SetDeleteValue(Path+'FPC/PPUExt/Value',PPUExt,'.ppu');
XMLConfig.SetDeleteValue(Path+'FPC/TestPascalFile/Value',TestPascalFile,'');
XMLConfig.SetDeleteValue(Path+'Lazarus/SrcDir/Value',LazarusSrcDir,'');
XMLConfig.SetDeleteValue(Path+'Lazarus/SrcDirOptions/Value',LazarusSrcOptions,'');
XMLConfig.SetDeleteValue(Path+'Lazarus/LCLWidgetType/Value',LCLWidgetType,'');
XMLConfig.SetDeleteValue(Path+'Project/Dir/Value',ProjectDir,'');
FConfigCaches.SaveToXMLConfig(XMLConfig,Path+'FPCConfigCaches/');
FSourceCaches.SaveToXMLConfig(XMLConfig,Path+'FPCSrcDirCaches/');
Modified:=false;
end;
procedure TCodeToolsOptions.LoadFromXMLConfig(XMLConfig: TXMLConfig;
const Path: string);
begin
FPCOptions:=XMLConfig.GetValue(Path+'FPC/Options/Value','');
FPCPath:=XMLConfig.GetValue(Path+'FPC/CompilerPath/Value','');
FPCSrcDir:=XMLConfig.GetValue(Path+'FPC/SrcDir/Value','');
TargetOS:=XMLConfig.GetValue(Path+'FPC/TargetOS/Value','');
TargetProcessor:=XMLConfig.GetValue(Path+'FPC/TargetProcessor/Value','');
Subtarget:=XMLConfig.GetValue(Path+'FPC/Subtarget/Value','');
PPUExt:=XMLConfig.GetValue(Path+'FPC/PPUExt/Value','.ppu');
TestPascalFile:=XMLConfig.GetValue(Path+'FPC/TestPascalFile/Value','');
FConfigCaches.LoadFromXMLConfig(XMLConfig,Path+'FPCConfigCaches/');
FSourceCaches.LoadFromXMLConfig(XMLConfig,Path+'FPCSrcDirCaches/');
LazarusSrcDir:=XMLConfig.GetValue(Path+'Lazarus/SrcDir/Value','');
LazarusSrcOptions:=XMLConfig.GetValue(Path+'Lazarus/SrcDirOptions/Value','');
LCLWidgetType:=XMLConfig.GetValue(Path+'Lazarus/LCLWidgetType/Value','');
ProjectDir:=XMLConfig.GetValue(Path+'Project/Dir/Value','');
Modified:=false;
end;
procedure TCodeToolsOptions.SaveToFile(const Filename: string);
var
XMLConfig: TXMLConfig;
begin
XMLConfig:=TXMLConfig.CreateClean(Filename);
try
SaveToXMLConfig(XMLConfig,'CodeToolsOptions/');
XMLConfig.Flush;
finally
XMLConfig.Free;
end;
end;
procedure TCodeToolsOptions.LoadFromFile(const Filename: string);
var
XMLConfig: TXMLConfig;
begin
XMLConfig:=TXMLConfig.Create(Filename);
try
LoadFromXMLConfig(XMLConfig,'CodeToolsOptions/');
XMLConfig.Flush;
finally
XMLConfig.Free;
end;
end;
{ TCodeBufXMLConfig }
procedure TCodeBufXMLConfig.ReadXMLFile(out ADoc: TXMLDocument;
const AFilename: String);
var
Buf: TCodeBuffer;
ms: TMemoryStream;
Cache: TCodeCache;
begin
Cache:=GetCache;
if Cache<>nil then begin
Buf:=Cache.LoadFile(AFilename);
if Buf<>nil then begin
fKeepFileAttributes:=true;
ms:=TMemoryStream.Create;
try
Buf.SaveToStream(ms);
ms.Position:=0;
Laz2_XMLRead.ReadXMLFile(ADoc, ms, ReadFlags);
exit; // success
finally
ms.Free;
end;
end;
end;
// try default (this will create the normal exceptions)
inherited ReadXMLFile(ADoc, AFilename);
end;
procedure TCodeBufXMLConfig.WriteXMLFile(ADoc: TXMLDocument;
const AFileName: String);
var
Buf: TCodeBuffer;
ms: TMemoryStream;
Cache: TCodeCache;
begin
Cache:=GetCache;
if Cache<>nil then begin
Buf:=nil;
if (not fKeepFileAttributes) or (not FileExistsCached(AFileName)) then
Buf:=Cache.CreateFile(AFilename)
else
Buf:=Cache.LoadFile(AFilename);
if Buf<>nil then begin
fKeepFileAttributes:=true;
ms:=TMemoryStream.Create;
try
Laz2_XMLWrite.WriteXMLFile(ADoc, ms, WriteFlags);
ms.Position:=0;
Buf.LoadFromStream(ms);
if Buf.FileOnDiskIsEqual then exit;
//debugln(['TCodeBufXMLConfig.WriteXMLFile writing ',AFileName,' ...']);
if Buf.Save then exit; // success
finally
ms.Free;
end;
end;
end;
// try default (this will create the normal exceptions)
inherited WriteXMLFile(ADoc, AFileName);
end;
function TCodeBufXMLConfig.GetCache: TCodeCache;
begin
Result:=CodeCache;
if Result=nil then
Result:=DefaultConfigCodeCache;
end;
constructor TCodeBufXMLConfig.CreateWithCache(AFilename: string;
LoadContent: boolean; LoadFileAttributes: boolean; ASource: string;
ACache: TCodeCache);
begin
CodeCache:=ACache;
fKeepFileAttributes:=LoadFileAttributes;
if (ASource<>'') then
inherited CreateWithSource(AFilename,ASource)
else if LoadContent then
inherited Create(AFilename)
else
inherited CreateClean(AFilename);
end;
end.