IDE: moved package compile code to packagesystem, IDEIntf: removed IsPartOfProject flag of Backup functions, lazbuidl: package compiling

git-svn-id: trunk@9821 -
This commit is contained in:
mattias 2006-09-06 22:40:37 +00:00
parent cbbc16493d
commit f7855da268
34 changed files with 1813 additions and 1525 deletions

View File

@ -102,7 +102,7 @@ const
'i386', 'powerpc', 'm68k', 'x86_64', 'sparc', 'arm'
);
Lazarus_CPU_OS_Widget_Combinations: array[1..31] of string = (
Lazarus_CPU_OS_Widget_Combinations: array[1..31] of shortstring = (
'i386-linux-gtk',
'i386-linux-gnome',
'i386-linux-gtk2',

View File

@ -1823,11 +1823,11 @@ begin
for i:=Low(Args) to High(Args) do begin
case Args[i].VType of
vtInteger: DbgOut(dbgs(Args[i].vinteger));
vtInt64: DbgOut(dbgs(Args[i].VInt64));
vtQWord: DbgOut(dbgs(Args[i].VQWord));
vtInt64: DbgOut(dbgs(Args[i].VInt64^));
vtQWord: DbgOut(dbgs(Args[i].VQWord^));
vtBoolean: DbgOut(dbgs(Args[i].vboolean));
vtExtended: DbgOut(dbgs(Args[i].VExtended^));
vtCurrency: DbgOut(dbgs(Args[i].vCurrency));
vtCurrency: DbgOut(dbgs(Args[i].vCurrency^));
vtString: DbgOut(Args[i].VString^);
vtAnsiString: DbgOut(AnsiString(Args[i].VAnsiString));
vtChar: DbgOut(Args[i].VChar);

View File

@ -1188,13 +1188,13 @@ begin
mtError,[mbCancel,mbAbort],'');
exit;
end;
TextConverter:=TIDETextConverter.Create(nil);
try
TextConverter.Filename:=TempCHeaderFilename;
FLastUsedFilename:=TextConverter.Filename;
TextConverter.LoadFromFile(InputFilename);
DebugLn(['TH2PasConverter.ConvertFile TempCHeaderFilename="',TempCHeaderFilename,'" CurrentType=',ord(TextConverter.CurrentType),' ',FileSize(TempCHeaderFilename)]);
DebugLn(['TH2PasConverter.ConvertFile TempCHeaderFilename="',TempCHeaderFilename,'" CurrentType=',ord(TextConverter.CurrentType),' FileSize=',FileSize(TempCHeaderFilename)]);
// run converters for .h file to make it compatible for h2pas
Result:=TextConverter.Execute(Project.PreH2PasTools);
@ -1208,9 +1208,9 @@ begin
try
Tool.Title:='h2pas';
Tool.H2PasFile:=AFile;
DebugLn(['TH2PasConverter.ConvertFile AAA TempCHeaderFilename="',TempCHeaderFilename,'" CurrentType=',ord(TextConverter.CurrentType),' ',FileSize(TempCHeaderFilename)]);
DebugLn(['TH2PasConverter.ConvertFile AAA TempCHeaderFilename="',TempCHeaderFilename,'" CurrentType=',ord(TextConverter.CurrentType),' FileSize=',FileSize(TempCHeaderFilename)]);
Tool.TargetFilename:=TextConverter.Filename;
DebugLn(['TH2PasConverter.ConvertFile BBB TempCHeaderFilename="',TempCHeaderFilename,'" CurrentType=',ord(TextConverter.CurrentType),' ',FileSize(TempCHeaderFilename)]);
DebugLn(['TH2PasConverter.ConvertFile BBB TempCHeaderFilename="',TempCHeaderFilename,'" CurrentType=',ord(TextConverter.CurrentType),' FileSize=',FileSize(TempCHeaderFilename)]);
Tool.Filename:=GetH2PasFilename;
Tool.CmdLineParams:=AFile.GetH2PasParameters(Tool.TargetFilename);
Tool.ScanOutput:=true;
@ -1218,7 +1218,7 @@ begin
Tool.WorkingDirectory:=Project.BaseDir;
Tool.OnParseLine:=@OnParseH2PasLine;
DebugLn(['TH2PasConverter.ConvertFile Tool.Filename="',Tool.Filename,'" Tool.CmdLineParams="',Tool.CmdLineParams,'"']);
Result:=LazarusIDE.RunExternalTool(Tool);
Result:=RunExternalTool(Tool);
if Result<>mrOk then exit(mrAbort);
if FindH2PasErrorMessage>=0 then exit(mrAbort);
finally

View File

@ -153,6 +153,7 @@ var
Tool: TCustomTextConverterTool;
begin
Tool:=GetCurrentTool;
//DebugLn(['TTextConvListEditor.PropertyGridModified ',dbgsName(Tool)]);
if Tool=nil then exit;
MakeToolCaptionAndNameUnique(Tool);
Modified:=true;
@ -265,6 +266,7 @@ begin
for i:=0 to FListOfTools.ComponentCount-1 do begin
Tool:=FListOfTools.Components[i] as TCustomTextConverterTool;
sl.Add(Tool.Caption);
//DebugLn(['TTextConvListEditor.UpdateToolsListBox Caption=',Tool.Caption,' ',dbgsName(Tool)]);
end;
end;
// save selection
@ -320,7 +322,8 @@ begin
Result:=TCustomTextConverterTool(FListOfTools.Components[i]);
end;
procedure TTextConvListEditor.MakeToolCaptionUnique(NewTool: TCustomTextConverterTool);
procedure TTextConvListEditor.MakeToolCaptionUnique(
NewTool: TCustomTextConverterTool);
var
NewCaption: String;
@ -337,6 +340,15 @@ var
end;
Result:=true;
NewTool.Caption:=NewCaption;
if (FListOfTools<>nil) then begin
for i:=0 to FListOfTools.ComponentCount-1 do begin
if FListOfTools.Components[i]=NewTool then begin
if (i<ToolsListBox.Items.Count) then begin
ToolsListBox.Items[i]:=NewTool.Caption;
end;
end;
end;
end;
end;
begin

View File

@ -734,7 +734,7 @@ begin
if LFMCode<>nil then begin
// save LFM file
DebugLn('ConvertDelphiToLazarusUnit Save LFM');
Result:=MainIDEInterface.DoSaveCodeBufferToFile(LFMCode,LFMCode.Filename,false);
Result:=SaveCodeBufferToFile(LFMCode,LFMCode.Filename);
if Result<>mrOk then exit;
// convert lfm to lrs

View File

@ -33,7 +33,8 @@ unit BaseBuildManager;
interface
uses
Classes, SysUtils, Project;
Classes, SysUtils, Forms,
Project;
type
@ -56,6 +57,16 @@ type
function GetTestBuildDirectory: string; virtual; abstract;
function IsTestUnitFilename(const AFilename: string): boolean; virtual; abstract;
function GetTargetUnitFilename(AnUnitInfo: TUnitInfo): string; virtual; abstract;
function CheckAmbiguousSources(const AFilename: string;
Compiling: boolean): TModalResult; virtual; abstract;
function DeleteAmbiguousFiles(const Filename:string
): TModalResult; virtual; abstract;
function CheckUnitPathForAmbiguousPascalFiles(const BaseDir, TheUnitPath,
CompiledExt, ContextDescription: string
): TModalResult; virtual; abstract;
function BackupFile(const Filename: string): TModalResult; virtual; abstract;
end;
var

View File

@ -33,13 +33,13 @@ unit BuildManager;
interface
uses
Classes, SysUtils,
Classes, SysUtils, AVL_Tree,
// LCL
LCLProc, Dialogs, FileUtil,
LCLProc, Dialogs, FileUtil, Forms, Controls,
// codetools
CodeToolManager, DefineTemplates,
// IDEIntf
MacroIntf, IDEDialogs,
SrcEditorIntf, ProjectIntf, MacroIntf, IDEDialogs, IDEExternToolIntf,
// IDE
LazarusIDEStrConsts, DialogProcs, IDEProcs, CodeToolsOptions, InputHistory,
MiscOptions, LazConf, EnvironmentOpts, TransferMacros, CompilerOptions,
@ -89,6 +89,8 @@ type
function CTMacroFuncProjectIncPath(Data: Pointer): boolean;
function CTMacroFuncProjectSrcPath(Data: Pointer): boolean;
procedure OnCmdLineCreate(var CmdLine: string; var Abort: boolean);
function OnRunCompilerWithOptions(ExtTool: TIDEExternalToolOptions;
CompOptions: TBaseCompilerOptions): TModalResult;
protected
OverrideTargetOS: string;
OverrideTargetCPU: string;
@ -118,6 +120,15 @@ type
procedure GetFPCCompilerParamsForEnvironmentTest(out Params: string);
procedure RescanCompilerDefines(OnlyIfCompilerChanged: boolean);
function CheckAmbiguousSources(const AFilename: string;
Compiling: boolean): TModalResult; override;
function DeleteAmbiguousFiles(const Filename:string
): TModalResult; override;
function CheckUnitPathForAmbiguousPascalFiles(const BaseDir, TheUnitPath,
CompiledExt, ContextDescription: string
): TModalResult; override;
function BackupFile(const Filename: string): TModalResult; override;
// methods for building
procedure SetBuildTarget(const TargetOS, TargetCPU, LCLWidgetType: string);
procedure SetBuildTargetIDE;
@ -130,6 +141,24 @@ var
implementation
type
TUnitFile = record
UnitName: string;
Filename: string;
end;
PUnitFile = ^TUnitFile;
function CompareUnitFiles(UnitFile1, UnitFile2: PUnitFile): integer;
begin
Result:=CompareText(UnitFile1^.UnitName,UnitFile2^.UnitName);
end;
function CompareUnitNameAndUnitFile(UnitName: PChar;
UnitFile: PUnitFile): integer;
begin
Result:=CompareStringPointerI(UnitName,PChar(UnitFile^.UnitName));
end;
{ TBuildManager }
function TBuildManager.OnSubstituteCompilerOption(
@ -142,18 +171,21 @@ begin
GlobalMacroList.SubstituteStr(Result,CompilerOptionMacroPlatformIndependent)
else
GlobalMacroList.SubstituteStr(Result,CompilerOptionMacroNormal);
if System.Pos('CompPath',UnparsedValue)>0 then
DebugLn(['TBuildManager.OnSubstituteCompilerOption UnparsedValue="',UnparsedValue,'" Result="',Result,'" ',GlobalMacroList.FindByName('CompPath')<>nil]);
end;
constructor TBuildManager.Create;
begin
MainBuildBoss:=Self;
inherited Create;
OnBackupFileInteractive:=@BackupFile;
RunCompilerWithOptions:=@OnRunCompilerWithOptions;
end;
destructor TBuildManager.Destroy;
begin
OnBackupFileInteractive:=nil;
inherited Destroy;
MainBuildBoss:=nil;
end;
@ -488,6 +520,404 @@ begin
end;
end;
function TBuildManager.CheckAmbiguousSources(const AFilename: string;
Compiling: boolean): TModalResult;
function DeleteAmbiguousFile(const AmbiguousFilename: string): TModalResult;
begin
if not DeleteFile(AmbiguousFilename) then begin
Result:=IDEMessageDialog(lisErrorDeletingFile,
Format(lisUnableToDeleteAmbiguousFile, ['"', AmbiguousFilename, '"']),
mtError,[mbOk,mbAbort]);
end else
Result:=mrOk;
end;
function RenameAmbiguousFile(const AmbiguousFilename: string): TModalResult;
var
NewFilename: string;
begin
NewFilename:=AmbiguousFilename+'.ambiguous';
if not RenameFile(AmbiguousFilename,NewFilename) then
begin
Result:=IDEMessageDialog(lisErrorRenamingFile,
Format(lisUnableToRenameAmbiguousFileTo, ['"', AmbiguousFilename, '"',
#13, '"', NewFilename, '"']),
mtError,[mbOk,mbAbort]);
end else
Result:=mrOk;
end;
function AddCompileWarning(const AmbiguousFilename: string): TModalResult;
begin
Result:=mrOk;
if Compiling then begin
TheOutputFilter.ReadConstLine(
Format(lisWarningAmbiguousFileFoundSourceFileIs,
['"', AmbiguousFilename, '"', '"', AFilename, '"']), true);
end;
end;
function CheckFile(const AmbiguousFilename: string): TModalResult;
begin
Result:=mrOk;
if not FileExists(AmbiguousFilename) then exit;
if Compiling then begin
Result:=AddCompileWarning(AmbiguousFilename);
exit;
end;
case EnvironmentOptions.AmbiguousFileAction of
afaAsk:
begin
Result:=IDEMessageDialog(lisAmbiguousFileFound,
Format(lisThereIsAFileWithTheSameNameAndASimilarExtension, [#13,
AFilename, #13, AmbiguousFilename, #13, #13]),
mtWarning,[mbYes,mbIgnore,mbAbort]);
case Result of
mrYes: Result:=DeleteAmbiguousFile(AmbiguousFilename);
mrIgnore: Result:=mrOk;
end;
end;
afaAutoDelete:
Result:=DeleteAmbiguousFile(AmbiguousFilename);
afaAutoRename:
Result:=RenameAmbiguousFile(AmbiguousFilename);
afaWarnOnCompile:
Result:=AddCompileWarning(AmbiguousFilename);
else
Result:=mrOk;
end;
end;
var
Ext, LowExt: string;
i: integer;
begin
Result:=mrOk;
if EnvironmentOptions.AmbiguousFileAction=afaIgnore then exit;
if (EnvironmentOptions.AmbiguousFileAction=afaWarnOnCompile)
and not Compiling then exit;
if FilenameIsPascalUnit(AFilename) then begin
Ext:=ExtractFileExt(AFilename);
LowExt:=lowercase(Ext);
for i:=Low(PascalFileExt) to High(PascalFileExt) do begin
if LowExt<>PascalFileExt[i] then begin
Result:=CheckFile(ChangeFileExt(AFilename,PascalFileExt[i]));
if Result<>mrOk then exit;
end;
end;
end;
end;
function TBuildManager.DeleteAmbiguousFiles(const Filename: string
): TModalResult;
var
ADirectory: String;
FileInfo: TSearchRec;
ShortFilename: String;
CurFilename: String;
IsPascalUnit: Boolean;
UnitName: String;
begin
Result:=mrOk;
if EnvironmentOptions.AmbiguousFileAction=afaIgnore then exit;
if EnvironmentOptions.AmbiguousFileAction
in [afaAsk,afaAutoDelete,afaAutoRename]
then begin
ADirectory:=AppendPathDelim(ExtractFilePath(Filename));
if SysUtils.FindFirst(ADirectory+GetAllFilesMask,faAnyFile,FileInfo)=0 then
begin
ShortFilename:=ExtractFileName(Filename);
IsPascalUnit:=FilenameIsPascalUnit(ShortFilename);
UnitName:=ExtractFilenameOnly(ShortFilename);
repeat
if (FileInfo.Name='.') or (FileInfo.Name='..')
or (FileInfo.Name='')
or ((FileInfo.Attr and faDirectory)<>0) then continue;
if (ShortFilename=FileInfo.Name) then continue;
if (AnsiCompareText(ShortFilename,FileInfo.Name)<>0)
and ((not IsPascalUnit) or (not FilenameIsPascalUnit(FileInfo.Name))
or (AnsiCompareText(UnitName,ExtractFilenameOnly(FileInfo.Name))<>0))
then
continue;
CurFilename:=ADirectory+FileInfo.Name;
if EnvironmentOptions.AmbiguousFileAction=afaAsk then begin
if IDEMessageDialog(lisDeleteAmbiguousFile,
Format(lisAmbiguousFileFoundThisFileCanBeMistakenWithDelete, ['"',
CurFilename, '"', #13, '"', ShortFilename, '"', #13, #13]),
mtConfirmation,[mbYes,mbNo])=mrNo
then continue;
end;
if EnvironmentOptions.AmbiguousFileAction in [afaAutoDelete,afaAsk]
then begin
if not DeleteFile(CurFilename) then begin
IDEMessageDialog(lisDeleteFileFailed,
Format(lisPkgMangUnableToDeleteFile, ['"', CurFilename, '"']),
mtError,[mbOk]);
end;
end else if EnvironmentOptions.AmbiguousFileAction=afaAutoRename then
begin
Result:=BackupFile(CurFilename);
if Result=mrABort then exit;
Result:=mrOk;
end;
until SysUtils.FindNext(FileInfo)<>0;
end;
FindClose(FileInfo);
end;
end;
{-------------------------------------------------------------------------------
function TBuildManager.CheckUnitPathForAmbiguousPascalFiles(
const BaseDir, TheUnitPath, CompiledExt, ContextDescription: string
): TModalResult;
Collect all pascal files and all compiled units in the unit path and check
for ambiguous files. For example: doubles.
-------------------------------------------------------------------------------}
function TBuildManager.CheckUnitPathForAmbiguousPascalFiles(const BaseDir,
TheUnitPath, CompiledExt, ContextDescription: string): TModalResult;
procedure FreeUnitTree(var Tree: TAVLTree);
var
ANode: TAVLTreeNode;
AnUnitFile: PUnitFile;
begin
if Tree<>nil then begin
ANode:=Tree.FindLowest;
while ANode<>nil do begin
AnUnitFile:=PUnitFile(ANode.Data);
Dispose(AnUnitFile);
ANode:=Tree.FindSuccessor(ANode);
end;
Tree.Free;
Tree:=nil;
end;
end;
var
EndPos: Integer;
StartPos: Integer;
CurDir: String;
FileInfo: TSearchRec;
SourceUnitTree, CompiledUnitTree: TAVLTree;
ANode: TAVLTreeNode;
CurUnitName: String;
CurFilename: String;
AnUnitFile: PUnitFile;
CurUnitTree: TAVLTree;
FileInfoNeedClose: Boolean;
UnitPath: String;
begin
Result:=mrOk;
UnitPath:=TrimSearchPath(TheUnitPath,BaseDir);
SourceUnitTree:=TAVLTree.Create(TListSortCompare(@CompareUnitFiles));
CompiledUnitTree:=TAVLTree.Create(TListSortCompare(@CompareUnitFiles));
FileInfoNeedClose:=false;
try
// collect all units (.pas, .pp, compiled units)
EndPos:=1;
while EndPos<=length(UnitPath) do begin
StartPos:=EndPos;
while (StartPos<=length(UnitPath)) and (UnitPath[StartPos]=';') do
inc(StartPos);
EndPos:=StartPos;
while (EndPos<=length(UnitPath)) and (UnitPath[EndPos]<>';') do
inc(EndPos);
if EndPos>StartPos then begin
CurDir:=AppendPathDelim(TrimFilename(copy(
UnitPath,StartPos,EndPos-StartPos)));
FileInfoNeedClose:=true;
if SysUtils.FindFirst(CurDir+GetAllFilesMask,faAnyFile,FileInfo)=0 then begin
repeat
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
or ((FileInfo.Attr and faDirectory)<>0) then continue;
if FilenameIsPascalUnit(FileInfo.Name) then
CurUnitTree:=SourceUnitTree
else if (CompareFileExt(FileInfo.Name,CompiledExt,false)=0) then
CurUnitTree:=CompiledUnitTree
else
continue;
CurUnitName:=ExtractFilenameOnly(FileInfo.Name);
CurFilename:=CurDir+FileInfo.Name;
// check if unit already found
ANode:=CurUnitTree.FindKey(PChar(CurUnitName),
TListSortCompare(@CompareUnitNameAndUnitFile));
if ANode<>nil then begin
// pascal unit exists twice
Result:=MessageDlg('Ambiguous unit found',
'The unit '+CurUnitName+' exists twice in the unit path of the '
+ContextDescription+':'#13
+#13
+'1. "'+PUnitFile(ANode.Data)^.Filename+'"'#13
+'2. "'+CurFilename+'"'#13
+#13
+'Hint: Check if two packages contain a unit with the same name.',
mtWarning,[mbAbort,mbIgnore],0);
if Result<>mrIgnore then exit;
end;
// add unit to tree
New(AnUnitFile);
AnUnitFile^.UnitName:=CurUnitName;
AnUnitFile^.Filename:=CurFilename;
CurUnitTree.Add(AnUnitFile);
until SysUtils.FindNext(FileInfo)<>0;
end;
FindClose(FileInfo);
FileInfoNeedClose:=false;
end;
end;
finally
// clean up
if FileInfoNeedClose then FindClose(FileInfo);
FreeUnitTree(SourceUnitTree);
FreeUnitTree(CompiledUnitTree);
end;
Result:=mrOk;
end;
function TBuildManager.BackupFile(const Filename: string): TModalResult;
var BackupFilename, CounterFilename: string;
AText,ACaption:string;
BackupInfo: TBackupInfo;
FilePath, FileNameOnly, FileExt, SubDir: string;
i: integer;
IsPartOfProject: boolean;
begin
Result:=mrOk;
if not (FileExists(Filename)) then exit;
IsPartOfProject:=(Project1<>nil)
and (Project1.FindFile(Filename,[pfsfOnlyProjectFiles])<>nil);
if IsPartOfProject then
BackupInfo:=EnvironmentOptions.BackupInfoProjectFiles
else
BackupInfo:=EnvironmentOptions.BackupInfoOtherFiles;
if (BackupInfo.BackupType=bakNone)
or ((BackupInfo.BackupType=bakSameName) and (BackupInfo.SubDirectory='')) then
exit;
FilePath:=ExtractFilePath(Filename);
FileExt:=ExtractFileExt(Filename);
FileNameOnly:=ExtractFilenameOnly(Filename);
if BackupInfo.SubDirectory<>'' then begin
SubDir:=FilePath+BackupInfo.SubDirectory;
repeat
if not DirPathExists(SubDir) then begin
if not CreateDir(SubDir) then begin
Result:=IDEMessageDialog('Warning',
Format(lisUnableToCreateBackupDirectory, ['"',SubDir, '"'])
,mtWarning,[mbAbort,mbRetry,mbIgnore]);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
end;
until Result<>mrRetry;
end;
if BackupInfo.BackupType in
[bakSymbolInFront,bakSymbolBehind,bakUserDefinedAddExt,bakSameName] then
begin
case BackupInfo.BackupType of
bakSymbolInFront:
BackupFilename:=FileNameOnly+'.~'+copy(FileExt,2,length(FileExt)-1);
bakSymbolBehind:
BackupFilename:=FileNameOnly+FileExt+'~';
bakUserDefinedAddExt:
BackupFilename:=FileNameOnly+FileExt+'.'+BackupInfo.AdditionalExtension;
bakSameName:
BackupFilename:=FileNameOnly+FileExt;
end;
if BackupInfo.SubDirectory<>'' then
BackupFilename:=SubDir+PathDelim+BackupFilename
else
BackupFilename:=FilePath+BackupFilename;
// remove old backup file
repeat
if FileExists(BackupFilename) then begin
if not DeleteFile(BackupFilename) then begin
ACaption:=lisDeleteFileFailed;
AText:=Format(lisUnableToRemoveOldBackupFile, ['"', BackupFilename,
'"']);
Result:=IDEMessageDialog(ACaption,AText,mtError,
[mbAbort,mbRetry,mbIgnore]);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
end;
until Result<>mrRetry;
end else begin
// backup with counter
if BackupInfo.SubDirectory<>'' then
BackupFilename:=SubDir+PathDelim+FileNameOnly+FileExt+';'
else
BackupFilename:=Filename+';';
if BackupInfo.MaxCounter<=0 then begin
// search first non existing backup filename
i:=1;
while FileExists(BackupFilename+IntToStr(i)) do inc(i);
BackupFilename:=BackupFilename+IntToStr(i);
end else begin
// rename all backup files (increase number)
i:=1;
while FileExists(BackupFilename+IntToStr(i))
and (i<=BackupInfo.MaxCounter) do inc(i);
if i>BackupInfo.MaxCounter then begin
dec(i);
CounterFilename:=BackupFilename+IntToStr(BackupInfo.MaxCounter);
// remove old backup file
repeat
if FileExists(CounterFilename) then begin
if not DeleteFile(CounterFilename) then begin
ACaption:=lisDeleteFileFailed;
AText:=Format(lisUnableToRemoveOldBackupFile, ['"',
CounterFilename, '"']);
Result:=MessageDlg(ACaption,AText,mtError,
[mbAbort,mbRetry,mbIgnore],0);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
end;
until Result<>mrRetry;
end;
// rename all old backup files
dec(i);
while i>=1 do begin
repeat
if not RenameFile(BackupFilename+IntToStr(i),
BackupFilename+IntToStr(i+1)) then
begin
ACaption:=lisRenameFileFailed;
AText:=Format(lisUnableToRenameFileTo, ['"', BackupFilename+IntToStr
(i), '"', '"', BackupFilename+IntToStr(i+1), '"']);
Result:=MessageDlg(ACaption,AText,mtError,
[mbAbort,mbRetry,mbIgnore],0);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
until Result<>mrRetry;
dec(i);
end;
BackupFilename:=BackupFilename+'1';
end;
end;
// backup file
repeat
if not IDEProcs.BackupFile(Filename,BackupFilename) then begin
ACaption:=lisBackupFileFailed;
AText:=Format(lisUnableToBackupFileTo, ['"', Filename, '"', '"',
BackupFilename, '"']);
Result:=IDEMessageDialog(ACaption,AText,mterror,[mbabort,mbretry,mbignore]);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
until Result<>mrRetry;
end;
function TBuildManager.MacroFuncMakeExe(const Filename: string;
const Data: PtrInt; var Abort: boolean): string;
var
@ -685,6 +1115,16 @@ begin
Abort:=not GlobalMacroList.SubstituteStr(CmdLine);
end;
function TBuildManager.OnRunCompilerWithOptions(
ExtTool: TIDEExternalToolOptions; CompOptions: TBaseCompilerOptions
): TModalResult;
begin
if SourceEditorWindow<>nil then
SourceEditorWindow.ClearErrorLines;
Result:=EnvironmentOptions.ExternalTools.Run(ExtTool,GlobalMacroList,
TheOutputFilter,CompOptions);
end;
procedure TBuildManager.SetBuildTarget(const TargetOS, TargetCPU,
LCLWidgetType: string);
var

View File

@ -41,8 +41,8 @@ unit CompilerOptions;
interface
uses
Classes, SysUtils, FileProcs, FileUtil, LCLProc,
Laz_XMLCfg, ProjectIntf, MacroIntf,
Classes, SysUtils, FileProcs, FileUtil, LCLProc, Forms, Controls,
Laz_XMLCfg, ProjectIntf, MacroIntf, IDEExternToolIntf, SrcEditorIntf,
IDEProcs, LazConf, TransferMacros;
type
@ -256,6 +256,7 @@ type
procedure SaveToXMLConfig(XMLConfig: TXMLConfig; const Path: string); virtual;
procedure CreateDiff(CompOpts: TCompilationToolOptions;
Tool: TCompilerDiffTool); virtual;
function Execute(const WorkingDir, ToolTitle: string): TModalResult;
end;
TCompilationToolClass = class of TCompilationToolOptions;
@ -453,12 +454,16 @@ const
type
TCompilerGraphStampIncreasedEvent = procedure of object;
TRunCompilerWithOptions = function(ExtTool: TIDEExternalToolOptions;
ACompilerOptions: TBaseCompilerOptions): TModalResult of object;
var
CompilerParseStamp: integer; // TimeStamp of base value for macros
CompilerGraphStamp: integer; // TimeStamp of IDE graph (e.g. packages)
OnParseString: TParseStringEvent;
CompilerGraphStampIncreased: TCompilerGraphStampIncreasedEvent;
OnParseString: TParseStringEvent = nil;
CompilerGraphStampIncreased: TCompilerGraphStampIncreasedEvent = nil;
RunCompilerWithOptions: TRunCompilerWithOptions = nil;
procedure IncreaseCompilerParseStamp;
procedure IncreaseCompilerGraphStamp;
@ -2953,6 +2958,46 @@ begin
Tool.AddDiff('ShowAllMessages',ShowAllMessages,CompOpts.ShowAllMessages);
end;
function TCompilationToolOptions.Execute(const WorkingDir, ToolTitle: string
): TModalResult;
var
ProgramFilename, Params: string;
ExtTool: TIDEExternalToolOptions;
Filename: String;
begin
if Command='' then begin
Result:=mrOk;
exit;
end;
if SourceEditorWindow<>nil then
SourceEditorWindow.ClearErrorLines;
SplitCmdLine(Command,ProgramFilename,Params);
if not FilenameIsAbsolute(ProgramFilename) then begin
Filename:=FindProgram(ProgramFilename,WorkingDir,true);
if Filename<>'' then ProgramFilename:=Filename;
end;
ExtTool:=TIDEExternalToolOptions.Create;
try
ExtTool.Filename:=ProgramFilename;
ExtTool.ScanOutputForFPCMessages:=ScanForFPCMessages;
ExtTool.ScanOutputForMakeMessages:=ScanForMakeMessages;
ExtTool.ScanOutput:=true;
ExtTool.ShowAllOutput:=ShowAllMessages;
ExtTool.Title:=ToolTitle;
ExtTool.WorkingDirectory:=WorkingDir;
ExtTool.CmdLineParams:=Params;
// run
Result:=RunExternalTool(ExtTool);
finally
// clean up
ExtTool.Free;
end;
end;
{ TGlobalCompilerOptions }
procedure TGlobalCompilerOptions.SetTargetCPU(const AValue: string);

View File

@ -51,14 +51,23 @@ type
lbfCreateClearOnError
);
TLoadBufferFlags = set of TLoadBufferFlag;
TOnBackupFileInteractive =
function(const Filename: string): TModalResult of object;
var
OnBackupFileInteractive: TOnBackupFileInteractive = nil;
function BackupFileInteractive(const Filename: string): TModalResult;
function RenameFileWithErrorDialogs(const SrcFilename, DestFilename: string;
ExtraButtons: TMsgDlgButtons): TModalResult;
function CopyFileWithErrorDialogs(const SrcFilename, DestFilename: string;
ExtraButtons: TMsgDlgButtons): TModalResult;
function LoadCodeBuffer(var ACodeBuffer: TCodeBuffer; const AFilename: string;
Flags: TLoadBufferFlags): TModalResult;
function SaveCodeBuffer(var ACodeBuffer: TCodeBuffer): TModalResult;
function SaveCodeBuffer(ACodeBuffer: TCodeBuffer): TModalResult;
function SaveCodeBufferToFile(ACodeBuffer: TCodeBuffer;
const Filename: string; Backup: boolean = false): TModalResult;
function LoadStringListFromFile(const Filename, ListTitle: string;
var sl: TStrings): TModalResult;
function CreateEmptyFile(const Filename: string;
@ -72,7 +81,8 @@ function ForceDirectoryInteractive(Directory: string;
function DeleteFileInteractive(const Filename: string;
ErrorButtons: TMsgDlgButtons): TModalResult;
function SaveStringToFile(const Filename, Content: string;
ErrorButtons: TMsgDlgButtons): TModalResult;
ErrorButtons: TMsgDlgButtons; const Context: string = ''
): TModalResult;
function ConvertLFMToLRSFileInteractive(const LFMFilename,
LRSFilename: string): TModalResult;
function IfNotOkJumpToCodetoolErrorAndAskToAbort(Ok: boolean;
@ -82,6 +92,14 @@ procedure NotImplementedDialog(const Feature: string);
implementation
function BackupFileInteractive(const Filename: string): TModalResult;
begin
if Assigned(OnBackupFileInteractive) then
Result:=OnBackupFileInteractive(Filename)
else
Result:=mrOk;
end;
function RenameFileWithErrorDialogs(const SrcFilename, DestFilename: string;
ExtraButtons: TMsgDlgButtons): TModalResult;
var
@ -192,7 +210,7 @@ begin
end;
end;
function SaveCodeBuffer(var ACodeBuffer: TCodeBuffer): TModalResult;
function SaveCodeBuffer(ACodeBuffer: TCodeBuffer): TModalResult;
begin
repeat
if ACodeBuffer.Save then begin
@ -205,6 +223,30 @@ begin
until Result<>mrRetry;
end;
function SaveCodeBufferToFile(ACodeBuffer: TCodeBuffer; const Filename: string;
Backup: boolean): TModalResult;
var
ACaption,AText:string;
begin
if Backup then begin
Result:=BackupFileInteractive(Filename);
if Result<>mrOk then exit;
end else
Result:=mrOk;
repeat
if ACodeBuffer.SaveToFile(Filename) then begin
Result:=mrOk;
end else begin
ACaption:=lisWriteError;
AText:=Format(lisUnableToWriteToFile, ['"', Filename, '"']);
Result:=IDEMessageDialog(ACaption,AText,mtError,
[mbAbort, mbRetry, mbIgnore]);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
until Result<>mrRetry;
end;
function LoadStringListFromFile(const Filename, ListTitle: string;
var sl: TStrings): TModalResult;
begin
@ -362,7 +404,7 @@ begin
end;
function SaveStringToFile(const Filename, Content: string;
ErrorButtons: TMsgDlgButtons): TModalResult;
ErrorButtons: TMsgDlgButtons; const Context: string): TModalResult;
var
fs: TFileStream;
begin
@ -380,7 +422,9 @@ begin
on E: Exception do begin
Result:=IDEMessageDialog('Write error',
'Write error: '+E.Message+#13
+'File: '+Filename,mtError,[mbAbort]+ErrorButtons);
+'File: '+Filename+#13
+Context,
mtError,[mbAbort]+ErrorButtons);
end;
end;
end;

View File

@ -24,6 +24,7 @@
This unit defines a dialog for the lazarus environment options and a class to
store the options in a xml file.
ToDo: split this into two units - the dialog and the options.
}
unit EnvironmentOpts;
@ -37,7 +38,8 @@ uses
{$ENDIF}
Classes, SysUtils, FPCAdds, LCLProc, Forms, Controls, Buttons, GraphType,
Graphics, ExtCtrls, StdCtrls, Spin, FileUtil, LResources, Dialogs,
Laz_XMLCfg, ObjectInspector, IDEWindowIntf,
Laz_XMLCfg,
ObjectInspector, IDEWindowIntf,
LazarusIDEStrConsts, TransferMacros, LazConf, ExtToolDialog, IDEProcs,
IDEOptionDefs, InputHistory, EditorOptions, IDETranslations;

View File

@ -247,7 +247,7 @@ var
procedure ProcessMessages;
begin
Application.ProcessMessages;
if Application<>nil then Application.ProcessMessages;
if (Progress<>nil) and Progress.Abort then
Result:=mrAbort;
end;
@ -342,6 +342,7 @@ var
AReplace:=ReplaceText;
if sesoRegExpr in Flags then
AReplace:=RE.Substitute(AReplace);
DebugLn(['DoReplaceLine Replace with "',AReplace,'"']);
SrcEditPosValid:=false;
@ -572,7 +573,7 @@ begin
FoundStartPos.Y,FoundStartPos.X);
OriginalFile.AbsoluteToLineCol(NewMatchEndPos,
FoundEndPos.Y,FoundEndPos.X);
//DebugLn(['SearchInText NewMatchStartPos=',NewMatchStartPos,' NewMatchEndPos=',NewMatchEndPos,' FoundStartPos=',dbgs(FoundStartPos),' FoundEndPos=',dbgs(FoundEndPos),' Found="',dbgstr(copy(Src,NewMatchStartPos,NewMatchEndPos-NewMatchStartPos)),'"']);
DebugLn(['SearchInText NewMatchStartPos=',NewMatchStartPos,' NewMatchEndPos=',NewMatchEndPos,' FoundStartPos=',dbgs(FoundStartPos),' FoundEndPos=',dbgs(FoundEndPos),' Found="',dbgstr(copy(Src,NewMatchStartPos,NewMatchEndPos-NewMatchStartPos)),'" Replace=',sesoReplace in Flags]);
if sesoReplace in Flags then begin
DoReplaceLine
end else begin

View File

@ -53,6 +53,10 @@ const
LanguageOpt='--language=';
resourcestring
lisErrInvalidOption = 'Invalid option at position %d: "%s"';
lisErrNoOptionAllowed = 'Option at position %d does not allow an argument: %s';
lisErrOptionNeeded = 'Option at position %d needs an argument : %s';
lisEnterTransla = 'Enter translation language';
// version
lisLazarusVersionString = '%s beta'; // %s is the versionstring (eg. 0.9.10)

View File

@ -22,22 +22,23 @@
!!! Under construction. !!!
ToDo:
Separate the visual parts in the IDE from the package and build system.
Separate the visual parts in the IDE from the project and build system.
}
program lazbuild;
{$mode objfpc}{$H+}
uses
Classes, SysUtils, CustApp, LCLProc, Forms, Controls, FileUtil,
Classes, SysUtils, CustApp, LCLProc, Dialogs, Forms, Controls, FileUtil,
Process,
// codetools
CodeToolManager, Laz_XMLCfg,
// IDEIntf
MacroIntf, PackageIntf,
MacroIntf, PackageIntf, IDEDialogs,
// IDE
IDEProcs, InitialSetupDlgs, OutputFilter, Compiler, CompilerOptions,
TransferMacros, EnvironmentOpts, IDETranslations, LazarusIDEStrConsts,
LazConf, BasePkgManager, PackageDefs, PackageLinks, PackageSystem,
Project, LazConf, PackageDefs, PackageLinks, PackageSystem,
BuildManager, BaseBuildManager;
type
@ -60,13 +61,21 @@ type
// global package functions
procedure GetDependencyOwnerDescription(Dependency: TPkgDependency;
var Description: string);
out Description: string);
procedure GetDependencyOwnerDirectory(Dependency: TPkgDependency;
var Directory: string);
out Directory: string);
procedure GetWritablePkgOutputDirectory(APackage: TLazPackage;
var AnOutDirectory: string);
// package graph
procedure PackageGraphAddPackage(Pkg: TLazPackage);
// dialogs
function OnIDEMessageDialog(const aCaption, aMsg: string;
DlgType: TMsgDlgType; Buttons: TMsgDlgButtons;
const HelpKeyword: string): Integer;
function OnIDEQuestionDialog(const aCaption, aMsg: string;
DlgType: TMsgDlgType; Buttons: array of const;
const HelpKeyword: string): Integer;
protected
function BuildFile(Filename: string): boolean;
function BuildPackage(const AFilename: string): boolean;
@ -79,6 +88,9 @@ type
procedure SetupOutputFilter;
procedure SetupMacros;
procedure SetupPackageSystem;
procedure SetupDialogs;
Function RepairedCheckOptions(Const ShortOptions : String;
Const Longopts : TStrings; Opts,NonOpts : TStrings) : String;
public
Files: TStringList;
constructor Create(TheOwner: TComponent); override;
@ -92,12 +104,56 @@ type
write FBuildRecursive;
end;
var
Application: TLazBuildApplication = nil;
const
ErrorFileNotFound = 1;
ErrorBuildFailed = 2;
ErrorLoadPackageFailed = 3;
ErrorPackageNameInvalid = 4;
procedure GetDescriptionOfDependencyOwner(Dependency: TPkgDependency;
out Description: string);
var
DepOwner: TObject;
begin
DepOwner:=Dependency.Owner;
if (DepOwner<>nil) then begin
if DepOwner is TLazPackage then begin
Description:=Format(lisPkgMangPackage, [TLazPackage(DepOwner).IDAsString]
);
end else if DepOwner is TProject then begin
Description:=Format(lisPkgMangProject, [ExtractFileNameOnly(TProject(
DepOwner).ProjectInfoFile)]);
end else begin
Description:=dbgsName(DepOwner)
end;
end else begin
Description:=Format(lisPkgMangDependencyWithoutOwner, [Dependency.AsString]
);
end;
end;
procedure GetDirectoryOfDependencyOwner(Dependency: TPkgDependency;
out Directory: string);
var
DepOwner: TObject;
begin
DepOwner:=Dependency.Owner;
if (DepOwner<>nil) then begin
if DepOwner is TLazPackage then begin
Directory:=TLazPackage(DepOwner).Directory;
end else if DepOwner is TProject then begin
Directory:=TProject(DepOwner).ProjectDirectory;
end else begin
Directory:=''
end;
end else begin
Directory:=''
end;
end;
{ TLazBuildApplication }
procedure TLazBuildApplication.OnExtToolFreeOutputFilter(
@ -113,13 +169,13 @@ begin
end;
procedure TLazBuildApplication.GetDependencyOwnerDescription(
Dependency: TPkgDependency; var Description: string);
Dependency: TPkgDependency; out Description: string);
begin
GetDescriptionOfDependencyOwner(Dependency,Description);
end;
procedure TLazBuildApplication.GetDependencyOwnerDirectory(
Dependency: TPkgDependency; var Directory: string);
Dependency: TPkgDependency; out Directory: string);
begin
GetDirectoryOfDependencyOwner(Dependency,Directory);
end;
@ -151,6 +207,24 @@ begin
if FileExists(Pkg.FileName) then PkgLinks.AddUserLink(Pkg);
end;
function TLazBuildApplication.OnIDEMessageDialog(const aCaption, aMsg: string;
DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; const HelpKeyword: string
): Integer;
begin
DumpStack;
Error(ErrorBuildFailed,aMsg);
Result:=mrCancel;
end;
function TLazBuildApplication.OnIDEQuestionDialog(const aCaption, aMsg: string;
DlgType: TMsgDlgType; Buttons: array of const; const HelpKeyword: string
): Integer;
begin
DumpStack;
Error(ErrorBuildFailed,aMsg);
Result:=mrCancel;
end;
function TLazBuildApplication.BuildFile(Filename: string): boolean;
begin
Result:=false;
@ -170,16 +244,23 @@ var
Flags: TPkgCompileFlags;
begin
Result:=false;
Init;
APackage:=LoadPackage(AFilename);
if APackage=nil then
Error(ErrorLoadPackageFailed, 'unable to load package "'+AFilename+'"');
Flags:=[];
if BuildAll then
Include(Flags,pcfCleanCompile);
Include(Flags,pcfCleanCompile)
else
Include(Flags,pcfOnlyIfNeeded);
if BuildRecursive and BuildAll then
Include(Flags,pcfCompileDependenciesClean);
CompilePackage(APackage,Flags);
Result:=true;
end;
function TLazBuildApplication.LoadPackage(const AFilename: string): TLazPackage;
@ -229,7 +310,8 @@ begin
CheckPackageGraphForCompilation(APackage,nil);
end;
{$NOTE TODO: move code from package manager to packagegraph and use it here}
if PackageGraph.CompilePackage(APackage,Flags)<>mrOk then
Error(ErrorBuildFailed,APackage.IDAsString+' compilation failed');
end;
procedure TLazBuildApplication.CheckPackageGraphForCompilation(
@ -237,16 +319,29 @@ procedure TLazBuildApplication.CheckPackageGraphForCompilation(
function PathListToString(PathList: TFPList): string;
var
Dependency: TPkgDependency;
i: Integer;
Item: TObject;
begin
Result:='';
for i:=0 to PathList.Count-1 do begin
Dependency:=TPkgDependency(PathList[0]);
if Dependency is TPkgDependency then begin
Item:=TObject(PathList[0]);
if Item is TPkgDependency then begin
if Result<>'' then
Result:=Result+'>';
Result:=Result+Dependency.AsString;
Result:=Result+TPkgDependency(Item).AsString;
end else if Item is TProject then begin
if Result<>'' then
Result:=Result+'>';
Result:=Result
+'Project:'+ExtractFileNameOnly(TProject(Item).ProjectInfoFile);
end else if Item is TLazPackage then begin
if Result<>'' then
Result:=Result+'>';
Result:=Result+TLazPackage(Item).IDAsString;
end else begin
if Result<>'' then
Result:=Result+'>';
Result:=Result+'Unknown:'+dbgsName(Item);
end;
end;
end;
@ -290,6 +385,9 @@ begin
SetupOutputFilter;
MainBuildBoss.SetupCompilerInterface;
// create static base packages
PackageGraph.AddStaticBasePackages;
fInitResult:=true;
end;
@ -337,9 +435,149 @@ begin
PackageGraph.OnAddPackage:=@PackageGraphAddPackage;
end;
procedure TLazBuildApplication.SetupDialogs;
begin
IDEMessageDialog:=@OnIDEMessageDialog;
IDEQuestionDialog:=@OnIDEQuestionDialog;
end;
function TLazBuildApplication.RepairedCheckOptions(const ShortOptions: String;
const Longopts: TStrings; Opts, NonOpts: TStrings): String;
Var
I,J,L,P : Integer;
O,OV,SO : String;
HaveArg : Boolean;
NeedArg: Boolean;
Function FindLongOpt(S : String) : boolean;
Var
I : integer;
begin
If CaseSensitiveOptions then
begin
I:=LongOpts.Count-1;
While (I>=0) and (LongOpts[i]<>S) do
Dec(i);
end
else
begin
S:=UpperCase(S);
I:=LongOpts.Count-1;
While (I>=0) and (UpperCase(LongOpts[i])<>S) do
Dec(i);
end;
Result:=(I<>-1);
end;
begin
If CaseSensitiveOptions then
SO:=Shortoptions
else
SO:=LowerCase(Shortoptions);
Result:='';
I:=1;
While (I<=ParamCount) and (Result='') do
begin
O:=Paramstr(I);
If (Length(O)=0) or (O[1]<>OptionChar) then
begin
If Assigned(NonOpts) then
NonOpts.Add(O)
end
else
begin
If (Length(O)<2) then
Result:=Format(lisErrInvalidOption,[i,O])
else
begin
HaveArg:=False;
OV:='';
// Long option ?
If (O[2]=OptionChar) then
begin
Delete(O,1,2);
J:=Pos('=',O);
If J<>0 then
begin
HaveArg:=true;
OV:=O;
Delete(OV,1,J);
O:=Copy(O,1,J-1);
end;
// Switch Option
If FindLongopt(O) then
begin
If HaveArg then
Result:=Format(lisErrNoOptionAllowed,[I,O])
end
else
begin // Required argument
If FindLongOpt(O+':') then
begin
If Not HaveArg then
Result:=Format(lisErrOptionNeeded,[I,O]);
end
else
begin // Optional Argument.
If not FindLongOpt(O+'::') then
Result:=Format(lisErrInvalidOption,[I,O]);
end;
end;
end
else // Short Option.
begin
HaveArg:=(I<ParamCount) and (Length(ParamStr(I+1))>0)
and (ParamStr(I+1)[i]<>OptionChar);
If HaveArg then
OV:=Paramstr(I+1);
If Not CaseSensitiveOptions then
O:=LowerCase(O);
L:=Length(O);
J:=2;
NeedArg:=false;
While (result='') and (J<=L) do
begin
P:=Pos(O[J],ShortOptions);
If (P=0) or (O[j]=':') then
Result:=Format(lisErrInvalidOption,[I,O[J]])
else
begin
If (P<Length(ShortOptions)) and (Shortoptions[P+1]=':') then
begin
// Required argument
NeedArg:=true;
Writeln('P ',P,' J ',J,' ',O[J],' ',l,' Havearg ',HaveArg);
If ((P+1)=Length(ShortOptions)) or (Shortoptions[P+2]<>':') Then
If (J<L) or not haveArg then // Must be last in multi-opt !!
Result:=Format(lisErrOptionNeeded,[I,O[J]]);
O:=O[j]; // O is added to arguments.
end;
end;
Inc(J);
end;
if not NeedArg then HaveArg:=false;
If HaveArg then
begin
Inc(I); // Skip argument.
O:=O[Length(O)]; // O is added to arguments !
end;
end;
If HaveArg and (Result='') then
If Assigned(Opts) then
Opts.Add(O+'='+OV);
end;
end;
Inc(I);
end;
end;
constructor TLazBuildApplication.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
TOutputFilterProcess:=TProcess;
Files:=TStringList.Create;
end;
@ -408,7 +646,7 @@ begin
LongOptions.Add('language');
LongOptions.Add('build-all');
LongOptions.Add('recursive');
ErrorMsg:=CheckOptions('lBR',LongOptions,Options,NonOptions);
ErrorMsg:=RepairedCheckOptions('lBR',LongOptions,Options,NonOptions);
if ErrorMsg<>'' then begin
writeln(ErrorMsg);
writeln('');
@ -418,6 +656,7 @@ begin
// files
Files.Assign(NonOptions);
if Files.Count=0 then begin
writeln('Error: missing file');
WriteUsage;
exit;
end;
@ -482,9 +721,10 @@ begin
Halt(ErrorCode);
end;
var
Application: TLazBuildApplication;
begin
// free LCL application
FreeAndNil(Forms.Application);
// start our own application
Application:=TLazBuildApplication.Create(nil);
Application.Run;
Application.Free;

View File

@ -53,6 +53,15 @@ unit Main;
interface
// TODO: Test on all platforms
{$IFNDEF DisableAsyncProcess}
{$IFDEF Linux}
{$IFDEF CPUI386}
{off $DEFINE UseAsyncProcess}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$I ide.inc}
uses
@ -60,7 +69,7 @@ uses
MemCheck,
{$ENDIF}
// fpc packages
Classes, SysUtils, Process, TypInfo,
Classes, SysUtils, Process, AsyncProcess, TypInfo,
// lcl
LCLProc, LCLMemManager, LCLType, LCLIntf, LMessages, LResources, StdCtrls,
Forms, Buttons, Menus, FileUtil, Controls, GraphType, Graphics, ExtCtrls,
@ -101,7 +110,7 @@ uses
// debugger
RunParamsOpts, BaseDebugManager, DebugManager,
// packager
PkgManager, BasePkgManager,
PackageSystem, PkgManager, BasePkgManager,
// source editing
UnitEditor, CodeToolsOptions, IDEOptionDefs, CheckLFMDlg,
CodeToolsDefines, DiffDialog, DiskDiffsDialog, UnitInfoDlg, EditorOptions,
@ -691,13 +700,10 @@ type
// external tools
function PrepareForCompile: TModalResult; override;
function RunExternalTool(Tool: TIDEExternalToolOptions): TModalResult; override;
function OnRunExternalTool(Tool: TIDEExternalToolOptions): TModalResult;
function DoRunExternalTool(Index: integer): TModalResult;
function DoSaveBuildIDEConfigs(Flags: TBuildLazarusFlags): TModalResult; override;
function DoBuildLazarus(Flags: TBuildLazarusFlags): TModalResult; override;
function DoExecuteCompilationTool(Tool: TCompilationToolOptions;
const WorkingDir, ToolTitle: string
): TModalResult; override;
function DoBuildFile: TModalResult;
function DoRunFile: TModalResult;
function DoConfigBuildFile: TModalResult;
@ -733,20 +739,11 @@ type
Flags: TFindSourceFlags): string; override;
function FileExistsInIDE(const Filename: string;
SearchFlags: TProjectFileSearchFlags): boolean;
function DoSaveStreamToFile(AStream:TStream; const Filename:string;
IsPartOfProject:boolean): TModalResult;
function DoSaveStringToFile(const Filename, Src,
FileDescription: string): TModalResult; override;
function LoadIDECodeBuffer(var ACodeBuffer: TCodeBuffer;
const AFilename: string;
Flags: TLoadBufferFlags): TModalResult;
function DoLoadMemoryStreamFromFile(MemStream: TMemoryStream;
const AFilename:string): TModalResult;
function DoSaveCodeBufferToFile(ABuffer: TCodeBuffer;
const AFilename: string;
IsPartOfProject:boolean): TModalResult; override;
function DoBackupFile(const Filename:string;
IsPartOfProject:boolean): TModalResult; override;
function DoRenameUnitLowerCase(AnUnitInfo: TUnitInfo;
AskUser: boolean): TModalresult;
function DoCheckFilesOnDisk(Instantaneous: boolean = false): TModalResult; override;
@ -1031,6 +1028,12 @@ begin
inherited Create(TheOwner);
SetupDialogs;
RunExternalTool:=@OnRunExternalTool;
{$IFDEF UseAsyncProcess}
TOutputFilterProcess:=TAsyncProcess;
{$ELSE}
TOutputFilterProcess:=TProcess;
{$ENDIF}
MainBuildBoss:=TBuildManager.Create;
@ -4203,8 +4206,7 @@ begin
// stream text to file
TxtCompStream.Position:=0;
LFMCode.LoadFromStream(TxtCompStream);
Result:=DoSaveCodeBufferToFile(LFMCode,LFMCode.Filename,
AnUnitInfo.IsPartOfProject);
Result:=SaveCodeBufferToFile(LFMCode,LFMCode.Filename);
if not Result=mrOk then exit;
Result:=mrCancel;
finally
@ -4266,16 +4268,14 @@ begin
if ResourceCode<>nil then begin
if not (sfSaveToTestDir in Flags) then begin
if (ResourceCode.Modified) then begin
Result:=DoSaveCodeBufferToFile(ResourceCode,ResourceCode.Filename,
AnUnitInfo.IsPartOfProject);
Result:=SaveCodeBufferToFile(ResourceCode,ResourceCode.Filename);
if not Result=mrOk then exit;
end;
end else begin
TestFilename:=MainBuildBoss.GetTestUnitFilename(AnUnitInfo);
Result:=DoSaveCodeBufferToFile(ResourceCode,
Result:=SaveCodeBufferToFile(ResourceCode,
ChangeFileExt(TestFilename,
ExtractFileExt(ResourceCode.Filename)),
false);
ExtractFileExt(ResourceCode.Filename)));
if not Result=mrOk then exit;
end;
end;
@ -4483,8 +4483,7 @@ begin
end;
// save file
Result:=DoSaveCodeBufferToFile(NewSource,NewSource.Filename,
AnUnitInfo.IsPartOfProject);
Result:=SaveCodeBufferToFile(NewSource,NewSource.Filename);
if Result<>mrOk then exit;
// change packages containing the file
@ -5023,7 +5022,7 @@ begin
Result.EndUpdate;
Result.MainProject:=true;
Result.OnFileBackup:=@DoBackupFile;
Result.OnFileBackup:=@MainBuildBoss.BackupFile;
Result.OnLoadProjectInfo:=@OnLoadProjectInfoFromXMLConfig;
Result.OnSaveProjectInfo:=@OnSaveProjectInfoToXMLConfig;
Result.OnGetTestDirectory:=@OnProjectGetTestDirectory;
@ -5730,7 +5729,7 @@ begin
end;
if sfCheckAmbiguousFiles in Flags then
DoCheckAmbiguousSources(DestFilename,false);
MainBuildBoss.CheckAmbiguousSources(DestFilename,false);
{$IFDEF IDE_DEBUG}
writeln('*** HasResources=',ActiveUnitInfo.HasResources);
@ -6324,32 +6323,6 @@ begin
until FileIsUnique(Result);
end;
function TMainIDE.DoSaveStringToFile(const Filename, Src,
FileDescription: string): TModalResult;
var
fs: TFileStream;
begin
try
ClearFile(Filename,true);
InvalidateFileStateCache;
fs:=TFileStream.Create(Filename,fmCreate);
try
if Src<>'' then
fs.Write(Src[1],length(Src));
finally
fs.Free;
end;
except
on E: Exception do begin
Result:=MessageDlg(lisPkgMangErrorWritingFile,
Format(lisUnableToWrite, [FileDescription, #13, '"', Filename, '"']),
mtError,[mbCancel,mbAbort],0);
exit;
end;
end;
Result:=mrOk;
end;
function TMainIDE.LoadIDECodeBuffer(var ACodeBuffer: TCodeBuffer;
const AFilename: string; Flags: TLoadBufferFlags): TModalResult;
begin
@ -6711,8 +6684,7 @@ begin
end else
DestFilename:=MainBuildBoss.GetTestUnitFilename(MainUnitInfo);
if not SkipSavingMainSource then begin
Result:=DoSaveCodeBufferToFile(MainUnitInfo.Source, DestFilename,
not (sfSaveToTestDir in Flags));
Result:=SaveCodeBufferToFile(MainUnitInfo.Source, DestFilename);
if Result=mrAbort then exit;
end;
end;
@ -7237,7 +7209,7 @@ begin
AnUnitInfo:=Project1.Units[i];
if (AnUnitInfo.IsPartOfProject) and (not AnUnitInfo.IsVirtual) then begin
DestFilename:=MainBuildBoss.GetTargetUnitFilename(AnUnitInfo);
Result:=DoCheckAmbiguousSources(DestFilename,true);
Result:=MainBuildBoss.CheckAmbiguousSources(DestFilename,true);
if Result<>mrOk then exit;
end;
end;
@ -7348,7 +7320,8 @@ begin
end;
// check all required packages
Result:=PkgBoss.DoCheckIfDependenciesNeedCompilation(AProject,StateFileAge);
Result:=PackageGraph.CheckIfDependenciesNeedCompilation(
AProject.FirstRequiredDependency,StateFileAge);
if Result<>mrNo then exit;
Result:=mrYes;
@ -7506,9 +7479,9 @@ begin
end;
CompilerFilename:=Project1.CompilerOptions.CompilerPath;
GlobalMacroList.SubstituteStr(CompilerFilename);
DebugLn(['TMainIDE.DoBuildProject A Project1.GetCompilerFilename="',Project1.GetCompilerFilename,'" CompilerFilename="',CompilerFilename,'" CompilerPath="',Project1.CompilerOptions.CompilerPath,'"']);
//DebugLn(['TMainIDE.DoBuildProject A Project1.GetCompilerFilename="',Project1.GetCompilerFilename,'" CompilerFilename="',CompilerFilename,'" CompilerPath="',Project1.CompilerOptions.CompilerPath,'"']);
CompilerFilename:=Project1.GetCompilerFilename;
DebugLn(['TMainIDE.DoBuildProject CompilerFilename="',CompilerFilename,'" CompilerPath="',Project1.CompilerOptions.CompilerPath,'"']);
//DebugLn(['TMainIDE.DoBuildProject CompilerFilename="',CompilerFilename,'" CompilerPath="',Project1.CompilerOptions.CompilerPath,'"']);
CompilerParams:=Project1.CompilerOptions.MakeOptionsString(SrcFilename,nil,[])
+' '+PrepareCmdLineOption(SrcFilename);
@ -7538,9 +7511,8 @@ begin
ToolBefore:=TProjectCompilationToolOptions(
Project1.CompilerOptions.ExecuteBefore);
if (AReason in ToolBefore.CompileReasons) then begin
Result:=DoExecuteCompilationTool(Project1.CompilerOptions.ExecuteBefore,
Project1.ProjectDirectory,
lisExecutingCommandBefore);
Result:=Project1.CompilerOptions.ExecuteBefore.Execute(
Project1.ProjectDirectory,lisExecutingCommandBefore);
if Result<>mrOk then exit;
end;
end;
@ -7576,9 +7548,8 @@ begin
Project1.CompilerOptions.ExecuteAfter);
// no need to check for mrOk, we are exit if it wasn't
if (AReason in ToolAfter.CompileReasons) then begin
Result:=DoExecuteCompilationTool(Project1.CompilerOptions.ExecuteAfter,
Project1.ProjectDirectory,
lisExecutingCommandAfter);
Result:=Project1.CompilerOptions.ExecuteAfter.Execute(
Project1.ProjectDirectory,lisExecutingCommandAfter);
if Result<>mrOk then exit;
end;
end;
@ -7911,7 +7882,7 @@ begin
if FPCPatch=0 then ;
CompiledUnitExt:=MiscellaneousOptions.BuildLazOpts.CompiledUnitExt(
FPCVersion,FPCRelease);
Result:=DoCheckUnitPathForAmbiguousPascalFiles(
Result:=MainBuildBoss.CheckUnitPathForAmbiguousPascalFiles(
EnvironmentOptions.LazarusDirectory,
InheritedOptionStrings[icoUnitPath],
CompiledUnitExt,'IDE');
@ -7949,45 +7920,6 @@ begin
mnuRestartClicked(nil);
end;
function TMainIDE.DoExecuteCompilationTool(Tool: TCompilationToolOptions;
const WorkingDir, ToolTitle: string): TModalResult;
var
ProgramFilename, Params: string;
ExtTool: TExternalToolOptions;
Filename: String;
begin
if Tool.Command='' then begin
Result:=mrOk;
exit;
end;
SourceNotebook.ClearErrorLines;
SplitCmdLine(Tool.Command,ProgramFilename,Params);
if not FilenameIsAbsolute(ProgramFilename) then begin
Filename:=FindProgram(ProgramFilename,WorkingDir,true);
if Filename<>'' then ProgramFilename:=Filename;
end;
ExtTool:=TExternalToolOptions.Create;
try
ExtTool.Filename:=ProgramFilename;
ExtTool.ScanOutputForFPCMessages:=Tool.ScanForFPCMessages;
ExtTool.ScanOutputForMakeMessages:=Tool.ScanForMakeMessages;
ExtTool.ScanOutput:=true;
ExtTool.ShowAllOutput:=Tool.ShowAllMessages;
ExtTool.Title:=ToolTitle;
ExtTool.WorkingDirectory:=WorkingDir;
ExtTool.CmdLineParams:=Params;
// run
Result:=EnvironmentOptions.ExternalTools.Run(ExtTool,GlobalMacroList);
finally
// clean up
ExtTool.Free;
end;
end;
function TMainIDE.DoBuildFile: TModalResult;
var
ActiveSrcEdit: TSourceEditor;
@ -8435,7 +8367,7 @@ begin
end;
end;
function TMainIDE.RunExternalTool(Tool: TIDEExternalToolOptions): TModalResult;
function TMainIDE.OnRunExternalTool(Tool: TIDEExternalToolOptions): TModalResult;
begin
SourceNotebook.ClearErrorLines;
Result:=EnvironmentOptions.ExternalTools.Run(Tool,GlobalMacroList);
@ -8570,26 +8502,6 @@ begin
Result:=SourceNoteBook.FindSourceEditorWithPageIndex(AnUnitInfo.EditorIndex);
end;
function TMainIDE.DoSaveStreamToFile(AStream:TStream;
const Filename:string; IsPartOfProject:boolean):TModalResult;
// save to file with backup and user interaction
var AText,ACaption:string;
NewBuf: TCodeBuffer;
begin
Result:=DoBackupFile(Filename,IsPartOfProject);
if Result<>mrOk then exit;
repeat
NewBuf:=CodeToolBoss.CreateFile(FileName);
if (NewBuf<>nil) or (not NewBuf.SaveToFile(Filename)) then begin
ACaption:=lisCodeToolsDefsWriteError;
AText:=Format(lisUnableToSaveFile, ['"', Filename, '"']);
Result:=MessageDlg(ACaption,AText,mterror, [mbabort, mbretry, mbignore],0);
if Result=mrIgnore then Result:=mrOk;
if Result=mrAbort then exit;
end;
until Result<>mrRetry;
end;
function TMainIDE.DoLoadMemoryStreamFromFile(MemStream: TMemoryStream;
const AFilename:string): TModalResult;
var FileStream: TFileStream;
@ -8615,168 +8527,6 @@ begin
until Result<>mrRetry;
end;
function TMainIDE.DoSaveCodeBufferToFile(ABuffer: TCodeBuffer;
const AFilename: string; IsPartOfProject:boolean): TModalResult;
var
ACaption,AText:string;
begin
Result:=DoBackupFile(AFilename,IsPartOfProject);
if Result<>mrOk then exit;
repeat
if ABuffer.SaveToFile(AFilename) then begin
Result:=mrOk;
end else begin
ACaption:=lisWriteError;
AText:=Format(lisUnableToWriteToFile, ['"', AFilename, '"']);
Result:=MessageDlg(ACaption,AText,mtError,[mbAbort, mbRetry, mbIgnore],0);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
until Result<>mrRetry;
end;
{-------------------------------------------------------------------------------
TMainIDE DoBackupFile
Params: const Filename:string;
IsPartOfProject:boolean
Returns: TModalResult
Rename existing file to backup file.
-------------------------------------------------------------------------------}
function TMainIDE.DoBackupFile(const Filename:string;
IsPartOfProject:boolean): TModalResult;
var BackupFilename, CounterFilename: string;
AText,ACaption:string;
BackupInfo: TBackupInfo;
FilePath, FileNameOnly, FileExt, SubDir: string;
i: integer;
begin
Result:=mrOk;
if not (FileExists(Filename)) then exit;
if IsPartOfProject then
BackupInfo:=EnvironmentOptions.BackupInfoProjectFiles
else
BackupInfo:=EnvironmentOptions.BackupInfoOtherFiles;
if (BackupInfo.BackupType=bakNone)
or ((BackupInfo.BackupType=bakSameName) and (BackupInfo.SubDirectory='')) then
exit;
FilePath:=ExtractFilePath(Filename);
FileExt:=ExtractFileExt(Filename);
FileNameOnly:=ExtractFilenameOnly(Filename);
if BackupInfo.SubDirectory<>'' then begin
SubDir:=FilePath+BackupInfo.SubDirectory;
repeat
if not DirPathExists(SubDir) then begin
if not CreateDir(SubDir) then begin
Result:=MessageDlg(Format(lisUnableToCreateBackupDirectory, ['"',
SubDir, '"'])
,mtWarning,[mbAbort,mbRetry,mbIgnore],0);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
end;
until Result<>mrRetry;
end;
if BackupInfo.BackupType in
[bakSymbolInFront,bakSymbolBehind,bakUserDefinedAddExt,bakSameName] then
begin
case BackupInfo.BackupType of
bakSymbolInFront:
BackupFilename:=FileNameOnly+'.~'+copy(FileExt,2,length(FileExt)-1);
bakSymbolBehind:
BackupFilename:=FileNameOnly+FileExt+'~';
bakUserDefinedAddExt:
BackupFilename:=FileNameOnly+FileExt+'.'+BackupInfo.AdditionalExtension;
bakSameName:
BackupFilename:=FileNameOnly+FileExt;
end;
if BackupInfo.SubDirectory<>'' then
BackupFilename:=SubDir+PathDelim+BackupFilename
else
BackupFilename:=FilePath+BackupFilename;
// remove old backup file
repeat
if FileExists(BackupFilename) then begin
if not DeleteFile(BackupFilename) then begin
ACaption:=lisDeleteFileFailed;
AText:=Format(lisUnableToRemoveOldBackupFile, ['"', BackupFilename,
'"']);
Result:=MessageDlg(ACaption,AText,mtError,[mbAbort,mbRetry,mbIgnore],
0);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
end;
until Result<>mrRetry;
end else begin
// backup with counter
if BackupInfo.SubDirectory<>'' then
BackupFilename:=SubDir+PathDelim+FileNameOnly+FileExt+';'
else
BackupFilename:=Filename+';';
if BackupInfo.MaxCounter<=0 then begin
// search first non existing backup filename
i:=1;
while FileExists(BackupFilename+IntToStr(i)) do inc(i);
BackupFilename:=BackupFilename+IntToStr(i);
end else begin
// rename all backup files (increase number)
i:=1;
while FileExists(BackupFilename+IntToStr(i))
and (i<=BackupInfo.MaxCounter) do inc(i);
if i>BackupInfo.MaxCounter then begin
dec(i);
CounterFilename:=BackupFilename+IntToStr(BackupInfo.MaxCounter);
// remove old backup file
repeat
if FileExists(CounterFilename) then begin
if not DeleteFile(CounterFilename) then begin
ACaption:=lisDeleteFileFailed;
AText:=Format(lisUnableToRemoveOldBackupFile, ['"',
CounterFilename, '"']);
Result:=MessageDlg(ACaption,AText,mtError,
[mbAbort,mbRetry,mbIgnore],0);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
end;
until Result<>mrRetry;
end;
// rename all old backup files
dec(i);
while i>=1 do begin
repeat
if not RenameFile(BackupFilename+IntToStr(i),
BackupFilename+IntToStr(i+1)) then
begin
ACaption:=lisRenameFileFailed;
AText:=Format(lisUnableToRenameFileTo, ['"', BackupFilename+IntToStr
(i), '"', '"', BackupFilename+IntToStr(i+1), '"']);
Result:=MessageDlg(ACaption,AText,mtError,
[mbAbort,mbRetry,mbIgnore],0);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
until Result<>mrRetry;
dec(i);
end;
BackupFilename:=BackupFilename+'1';
end;
end;
// backup file
repeat
if not BackupFile(Filename,BackupFilename) then begin
ACaption:=lisBackupFileFailed;
AText:=Format(lisUnableToBackupFileTo, ['"', Filename, '"', '"',
BackupFilename, '"']);
Result:=MessageDlg(ACaption,AText,mterror,[mbabort,mbretry,mbignore],0);
if Result=mrAbort then exit;
if Result=mrIgnore then Result:=mrOk;
end;
until Result<>mrRetry;
end;
function TMainIDE.DoRenameUnitLowerCase(AnUnitInfo: TUnitInfo;
AskUser: boolean): TModalresult;
var

View File

@ -143,13 +143,6 @@ type
var ActiveSourceEditor: TSourceEditor; var ActiveUnitInfo: TUnitInfo); virtual; abstract;
function GetSourceEditorForUnitInfo(AnUnitInfo: TUnitInfo): TSourceEditor; virtual; abstract;
function DoCheckAmbiguousSources(const AFilename: string;
Compiling: boolean): TModalResult; override;
function DoDeleteAmbiguousFiles(const Filename:string
): TModalResult; override;
function DoCheckUnitPathForAmbiguousPascalFiles(const BaseDir, TheUnitPath,
CompiledExt, ContextDescription: string
): TModalResult; override;
function DoOpenMacroFile(Sender: TObject; const AFilename: string
): TModalResult; override;
@ -178,24 +171,6 @@ var
implementation
type
TUnitFile = record
UnitName: string;
Filename: string;
end;
PUnitFile = ^TUnitFile;
function CompareUnitFiles(UnitFile1, UnitFile2: PUnitFile): integer;
begin
Result:=AnsiCompareText(UnitFile1^.UnitName,UnitFile2^.UnitName);
end;
function CompareUnitNameAndUnitFile(UnitName: PChar;
UnitFile: PUnitFile): integer;
begin
Result:=CompareStringPointerI(UnitName,PChar(UnitFile^.UnitName));
end;
{ TMainIDEBase }
procedure TMainIDEBase.mnuWindowsItemClick(Sender: TObject);
@ -957,286 +932,14 @@ begin
[ofOnlyIfExists,ofAddToRecent,ofRegularFile,ofConvertMacros]);
end;
function TMainIDEBase.DoDeleteAmbiguousFiles(const Filename: string
): TModalResult;
var
ADirectory: String;
FileInfo: TSearchRec;
ShortFilename: String;
CurFilename: String;
IsPascalUnit: Boolean;
UnitName: String;
begin
Result:=mrOk;
if EnvironmentOptions.AmbiguousFileAction=afaIgnore then exit;
if EnvironmentOptions.AmbiguousFileAction
in [afaAsk,afaAutoDelete,afaAutoRename]
then begin
ADirectory:=AppendPathDelim(ExtractFilePath(Filename));
if SysUtils.FindFirst(ADirectory+GetAllFilesMask,faAnyFile,FileInfo)=0 then
begin
ShortFilename:=ExtractFileName(Filename);
IsPascalUnit:=FilenameIsPascalUnit(ShortFilename);
UnitName:=ExtractFilenameOnly(ShortFilename);
repeat
if (FileInfo.Name='.') or (FileInfo.Name='..')
or (FileInfo.Name='')
or ((FileInfo.Attr and faDirectory)<>0) then continue;
if (ShortFilename=FileInfo.Name) then continue;
if (AnsiCompareText(ShortFilename,FileInfo.Name)<>0)
and ((not IsPascalUnit) or (not FilenameIsPascalUnit(FileInfo.Name))
or (AnsiCompareText(UnitName,ExtractFilenameOnly(FileInfo.Name))<>0))
then
continue;
CurFilename:=ADirectory+FileInfo.Name;
if EnvironmentOptions.AmbiguousFileAction=afaAsk then begin
if MessageDlg(lisDeleteAmbiguousFile,
Format(lisAmbiguousFileFoundThisFileCanBeMistakenWithDelete, ['"',
CurFilename, '"', #13, '"', ShortFilename, '"', #13, #13]),
mtConfirmation,[mbYes,mbNo],0)=mrNo
then continue;
end;
if EnvironmentOptions.AmbiguousFileAction in [afaAutoDelete,afaAsk]
then begin
if not DeleteFile(CurFilename) then begin
MessageDlg(lisDeleteFileFailed,
Format(lisPkgMangUnableToDeleteFile, ['"', CurFilename, '"']),
mtError,[mbOk],0);
end;
end else if EnvironmentOptions.AmbiguousFileAction=afaAutoRename then
begin
Result:=DoBackupFile(CurFilename,false);
if Result=mrABort then exit;
Result:=mrOk;
end;
until SysUtils.FindNext(FileInfo)<>0;
end;
FindClose(FileInfo);
end;
end;
{-------------------------------------------------------------------------------
function TMainIDEBase.DoCheckUnitPathForAmbiguousPascalFiles(
const BaseDir, TheUnitPath, CompiledExt, ContextDescription: string
): TModalResult;
Collect all pascal files and all compiled units in the unit path and check
for ambiguous files. For example: doubles.
-------------------------------------------------------------------------------}
function TMainIDEBase.DoCheckUnitPathForAmbiguousPascalFiles(
const BaseDir, TheUnitPath, CompiledExt, ContextDescription: string): TModalResult;
procedure FreeUnitTree(var Tree: TAVLTree);
var
ANode: TAVLTreeNode;
AnUnitFile: PUnitFile;
begin
if Tree<>nil then begin
ANode:=Tree.FindLowest;
while ANode<>nil do begin
AnUnitFile:=PUnitFile(ANode.Data);
Dispose(AnUnitFile);
ANode:=Tree.FindSuccessor(ANode);
end;
Tree.Free;
Tree:=nil;
end;
end;
var
EndPos: Integer;
StartPos: Integer;
CurDir: String;
FileInfo: TSearchRec;
SourceUnitTree, CompiledUnitTree: TAVLTree;
ANode: TAVLTreeNode;
CurUnitName: String;
CurFilename: String;
AnUnitFile: PUnitFile;
CurUnitTree: TAVLTree;
FileInfoNeedClose: Boolean;
UnitPath: String;
begin
Result:=mrOk;
UnitPath:=TrimSearchPath(TheUnitPath,BaseDir);
//writeln('TMainIDEBase.DoCheckUnitPathForAmbiguousPascalFiles A UnitPath="',UnitPath,'" Ext=',CompiledExt,' Context=',ContextDescription);
SourceUnitTree:=TAVLTree.Create(TListSortCompare(@CompareUnitFiles));
CompiledUnitTree:=TAVLTree.Create(TListSortCompare(@CompareUnitFiles));
FileInfoNeedClose:=false;
try
// collect all units (.pas, .pp, compiled units)
EndPos:=1;
while EndPos<=length(UnitPath) do begin
StartPos:=EndPos;
while (StartPos<=length(UnitPath)) and (UnitPath[StartPos]=';') do
inc(StartPos);
EndPos:=StartPos;
while (EndPos<=length(UnitPath)) and (UnitPath[EndPos]<>';') do
inc(EndPos);
if EndPos>StartPos then begin
CurDir:=AppendPathDelim(TrimFilename(copy(
UnitPath,StartPos,EndPos-StartPos)));
FileInfoNeedClose:=true;
if SysUtils.FindFirst(CurDir+GetAllFilesMask,faAnyFile,FileInfo)=0 then begin
repeat
if (FileInfo.Name='.') or (FileInfo.Name='..') or (FileInfo.Name='')
or ((FileInfo.Attr and faDirectory)<>0) then continue;
if FilenameIsPascalUnit(FileInfo.Name) then
CurUnitTree:=SourceUnitTree
else if (CompareFileExt(FileInfo.Name,CompiledExt,false)=0) then
CurUnitTree:=CompiledUnitTree
else
continue;
CurUnitName:=ExtractFilenameOnly(FileInfo.Name);
CurFilename:=CurDir+FileInfo.Name;
// check if unit already found
ANode:=CurUnitTree.FindKey(PChar(CurUnitName),
TListSortCompare(@CompareUnitNameAndUnitFile));
if ANode<>nil then begin
// pascal unit exists twice
Result:=MessageDlg('Ambiguous unit found',
'The unit '+CurUnitName+' exists twice in the unit path of the '
+ContextDescription+':'#13
+#13
+'1. "'+PUnitFile(ANode.Data)^.Filename+'"'#13
+'2. "'+CurFilename+'"'#13
+#13
+'Hint: Check if two packages contain a unit with the same name.',
mtWarning,[mbAbort,mbIgnore],0);
if Result<>mrIgnore then exit;
end;
// add unit to tree
New(AnUnitFile);
AnUnitFile^.UnitName:=CurUnitName;
AnUnitFile^.Filename:=CurFilename;
CurUnitTree.Add(AnUnitFile);
until SysUtils.FindNext(FileInfo)<>0;
end;
FindClose(FileInfo);
FileInfoNeedClose:=false;
end;
end;
finally
// clean up
if FileInfoNeedClose then FindClose(FileInfo);
FreeUnitTree(SourceUnitTree);
FreeUnitTree(CompiledUnitTree);
end;
Result:=mrOk;
end;
{-------------------------------------------------------------------------------
function TMainIDEBase.DoCheckAmbiguousSources(const AFilename: string
): TModalResult;
Checks if file exists with same name and similar extension. The compiler
prefers for example .pp to .pas files. So, if we save a .pas file delete .pp
file, so that compiling does what is expected.
-------------------------------------------------------------------------------}
function TMainIDEBase.DoCheckAmbiguousSources(const AFilename: string;
Compiling: boolean): TModalResult;
function DeleteAmbiguousFile(const AmbiguousFilename: string): TModalResult;
begin
if not DeleteFile(AmbiguousFilename) then begin
Result:=MessageDlg(lisErrorDeletingFile,
Format(lisUnableToDeleteAmbiguousFile, ['"', AmbiguousFilename, '"']),
mtError,[mbOk,mbAbort],0);
end else
Result:=mrOk;
end;
function RenameAmbiguousFile(const AmbiguousFilename: string): TModalResult;
var
NewFilename: string;
begin
NewFilename:=AmbiguousFilename+'.ambiguous';
if not RenameFile(AmbiguousFilename,NewFilename) then
begin
Result:=MessageDlg(lisErrorRenamingFile,
Format(lisUnableToRenameAmbiguousFileTo, ['"', AmbiguousFilename, '"',
#13, '"', NewFilename, '"']),
mtError,[mbOk,mbAbort],0);
end else
Result:=mrOk;
end;
function AddCompileWarning(const AmbiguousFilename: string): TModalResult;
begin
Result:=mrOk;
if Compiling then begin
TheOutputFilter.ReadConstLine(Format(lisWarningAmbiguousFileFoundSourceFileIs,
['"', AmbiguousFilename, '"', '"', AFilename, '"']), true);
end;
end;
function CheckFile(const AmbiguousFilename: string): TModalResult;
begin
Result:=mrOk;
if not FileExists(AmbiguousFilename) then exit;
if Compiling then begin
Result:=AddCompileWarning(AmbiguousFilename);
exit;
end;
case EnvironmentOptions.AmbiguousFileAction of
afaAsk:
begin
Result:=MessageDlg(lisAmbiguousFileFound,
Format(lisThereIsAFileWithTheSameNameAndASimilarExtension, [#13,
AFilename, #13, AmbiguousFilename, #13, #13]),
mtWarning,[mbYes,mbIgnore,mbAbort],0);
case Result of
mrYes: Result:=DeleteAmbiguousFile(AmbiguousFilename);
mrIgnore: Result:=mrOk;
end;
end;
afaAutoDelete:
Result:=DeleteAmbiguousFile(AmbiguousFilename);
afaAutoRename:
Result:=RenameAmbiguousFile(AmbiguousFilename);
afaWarnOnCompile:
Result:=AddCompileWarning(AmbiguousFilename);
else
Result:=mrOk;
end;
end;
var
Ext, LowExt: string;
i: integer;
begin
Result:=mrOk;
if EnvironmentOptions.AmbiguousFileAction=afaIgnore then exit;
if (EnvironmentOptions.AmbiguousFileAction=afaWarnOnCompile)
and not Compiling then exit;
if FilenameIsPascalUnit(AFilename) then begin
Ext:=ExtractFileExt(AFilename);
LowExt:=lowercase(Ext);
for i:=Low(PascalFileExt) to High(PascalFileExt) do begin
if LowExt<>PascalFileExt[i] then begin
Result:=CheckFile(ChangeFileExt(AFilename,PascalFileExt[i]));
if Result<>mrOk then exit;
end;
end;
end;
end;
procedure TMainIDEBase.UpdateWindowsMenu;
var
WindowsList: TList;
WindowsList: TFPList;
i: Integer;
CurMenuItem: TIDEMenuItem;
AForm: TForm;
begin
WindowsList:=TList.Create;
WindowsList:=TFPList.Create;
// add typical IDE windows at the start of the list
if (SourceNotebook<>nil) and (SourceNotebook.Visible) then
WindowsList.Add(SourceNotebook);
@ -1245,7 +948,7 @@ begin
// add special IDE windows
for i:=0 to Screen.FormCount-1 do begin
AForm:=Screen.Forms[i];
if (AForm<>MainIDEBar) and (AForm<>SplashForm)
if (AForm.Parent=nil) and (AForm<>MainIDEBar) and (AForm<>SplashForm)
and (AForm.Designer=nil) and (AForm.Visible)
and (WindowsList.IndexOf(AForm)<0) then
WindowsList.Add(AForm);

View File

@ -154,28 +154,11 @@ type
function PrepareForCompile: TModalResult; virtual; abstract;
function DoSaveBuildIDEConfigs(Flags: TBuildLazarusFlags): TModalResult; virtual; abstract;
function DoBuildLazarus(Flags: TBuildLazarusFlags): TModalResult; virtual; abstract;
function DoExecuteCompilationTool(Tool: TCompilationToolOptions;
const WorkingDir, ToolTitle: string
): TModalResult; virtual; abstract;
function DoSaveForBuild: TModalResult; virtual; abstract;
function DoCheckFilesOnDisk(Instantaneous: boolean = false): TModalResult; virtual; abstract;
function DoPublishModule(Options: TPublishModuleOptions;
const SrcDirectory, DestDirectory: string
): TModalResult; virtual; abstract;
function DoCheckAmbiguousSources(const AFilename: string;
Compiling: boolean): TModalResult; virtual; abstract;
function DoSaveStringToFile(const Filename, Src,
FileDescription: string): TModalResult; virtual; abstract;
function DoSaveCodeBufferToFile(ABuffer: TCodeBuffer;
const AFilename: string;
IsPartOfProject:boolean): TModalResult; virtual; abstract;
function DoBackupFile(const Filename:string;
IsPartOfProject:boolean): TModalResult; virtual; abstract;
function DoDeleteAmbiguousFiles(const Filename:string
): TModalResult; virtual; abstract;
function DoCheckUnitPathForAmbiguousPascalFiles(const BaseDir, TheUnitPath,
CompiledExt, ContextDescription: string
): TModalResult; virtual; abstract;
procedure UpdateWindowsMenu; virtual; abstract;
procedure SaveEnvironment; virtual; abstract;

View File

@ -119,8 +119,8 @@ type
procedure ShowTopMessage;
procedure Clear; override;
procedure GetVisibleMessageAt(Index: integer; var Msg, MsgDirectory: string);
procedure BeginBlock;
procedure EndBlock;
procedure BeginBlock; override;
procedure EndBlock; override;
procedure ClearItems;
function LinesCount: integer; override;
function VisibleItemCount: integer;

View File

@ -26,15 +26,6 @@ unit OutputFilter;
interface
// TODO: Test on all platforms
{$IFNDEF DisableAsyncProcess}
{$IFDEF Linux}
{$IFDEF CPUI386}
{off $DEFINE UseAsyncProcess}
{$ENDIF}
{$ENDIF}
{$ENDIF}
uses
Classes, Math, SysUtils, Forms, Controls, CompilerOptions, Project, Process,
AsyncProcess, LCLProc, DynQueue, FileUtil,
@ -48,12 +39,6 @@ type
TOnGetIncludePath = function(const Directory: string;
UseCache: boolean): string of object;
{$IFDEF UseAsyncProcess}
TOutputFilterProcess = TAsyncProcess;
{$ELSE}
TOutputFilterProcess = TProcess;
{$ENDIF}
TOuputFilterOption = (
ofoShowAll, // don't filter
ofoSearchForFPCMessages, // scan for freepascal compiler messages
@ -192,6 +177,12 @@ type
EOutputFilterError = class(Exception)
end;
type
TProcessClass = class of TProcess;
var
TOutputFilterProcess: TProcessClass = nil;
const
ErrorTypeNames : array[TErrorType] of string = (
'None','Hint','Note','Warning','Error','Fatal','Panic'
@ -274,7 +265,7 @@ begin
fProcess.Execute;
repeat
Application.ProcessMessages;
if Application<>nil then Application.ProcessMessages;
if StopExecute then begin
fProcess.Terminate(0);
Aborted:=true;
@ -1285,4 +1276,3 @@ end;
end.

View File

@ -57,8 +57,7 @@ type
TUnitInfo = class;
TProject = class;
TOnFileBackup = function(const FileToBackup:string;
IsPartOfProject:boolean):TModalResult of object;
TOnFileBackup = function(const FileToBackup: string):TModalResult of object;
TOnUnitNameChange = procedure(AnUnitInfo: TUnitInfo;
const OldUnitName, NewUnitName: string;
CheckIfAllowed: boolean;
@ -484,8 +483,7 @@ type
function GetUnits(Index: integer): TUnitInfo;
function JumpHistoryCheckPosition(
APosition:TProjectJumpHistoryPosition): boolean;
function OnUnitFileBackup(const Filename: string;
IsPartOfProject:boolean): TModalResult;
function OnUnitFileBackup(const Filename: string): TModalResult;
procedure OnLoadSaveFilename(var AFilename: string; Load: boolean);
procedure OnUnitNameChange(AnUnitInfo: TUnitInfo;
const OldUnitName, NewUnitName: string;
@ -766,7 +764,7 @@ begin
exit;
end;
if Assigned(fOnFileBackup) then begin
Result:=fOnFileBackup(Filename,IsPartOfProject);
Result:=fOnFileBackup(Filename);
if Result=mrAbort then exit;
end;
repeat
@ -795,7 +793,7 @@ begin
exit;
end;
if Assigned(fOnFileBackup) then begin
Result:=fOnFileBackup(Filename,false);
Result:=fOnFileBackup(Filename);
if Result=mrAbort then exit;
end;
repeat
@ -1579,7 +1577,7 @@ begin
else
CfgFilename := ProjectInfoFile;
if Assigned(fOnFileBackup) then begin
Result:=fOnFileBackup(CfgFilename,true);
Result:=fOnFileBackup(CfgFilename);
if Result=mrAbort then exit;
end;
CfgFilename:=SetDirSeparators(CfgFilename);
@ -1695,7 +1693,7 @@ begin
//DebugLn('TProject.WriteProject Write Session File="',CurSessionFilename,'"');
if Assigned(fOnFileBackup) then begin
Result:=fOnFileBackup(CurSessionFilename,true);
Result:=fOnFileBackup(CurSessionFilename);
if Result=mrAbort then exit;
end;
CurSessionFilename:=SetDirSeparators(CurSessionFilename);
@ -2806,11 +2804,10 @@ begin
UpdateSessionFilename;
end;
function TProject.OnUnitFileBackup(const Filename:string;
IsPartOfProject: boolean):TModalResult;
function TProject.OnUnitFileBackup(const Filename: string): TModalResult;
begin
if Assigned(fOnFileBackup) then
Result:=fOnFileBackup(Filename,IsPartOfProject)
Result:=fOnFileBackup(Filename)
else
Result:=mrOk;
end;

View File

@ -621,7 +621,7 @@ type
function SomethingModified: boolean;
procedure UpdateStatusBar;
Procedure ClearUnusedEditorComponents(Force: boolean);
procedure ClearErrorLines;
procedure ClearErrorLines; override;
procedure ClearExecutionLines;
procedure CloseTabClicked(Sender: TObject);

View File

@ -104,6 +104,12 @@ type
property ShowAllOutput: boolean read FShowAllOutput write SetShowAllOutput;
property OnParseLine: TOnIDEExtToolParseLine read FOnParseLine write FOnParseLine;
end;
type
TRunExternalTool = function (Tool: TIDEExternalToolOptions): TModalResult of object;
var
RunExternalTool: TRunExternalTool = nil;// set by the IDE
implementation

View File

@ -183,11 +183,13 @@ type
procedure AddMsg(const Msg, CurDir: string; OriginalIndex: integer); virtual; abstract;
property Lines[Index: integer]: TIDEMessageLine read GetLines; default;
function LinesCount: integer; virtual; abstract;
procedure BeginBlock; virtual; abstract;
procedure EndBlock; virtual; abstract;
end;
var
IDEMsgQuickFixes: TIDEMsgQuickFixItems; // initialized by the IDE
IDEMessagesWindow: TIDEMessagesWindowInterface;// initialized by the IDE
IDEMsgQuickFixes: TIDEMsgQuickFixItems = nil; // initialized by the IDE
IDEMessagesWindow: TIDEMessagesWindowInterface = nil;// initialized by the IDE
procedure RegisterIDEMsgQuickFix(Item: TIDEMsgQuickFixItem);
function RegisterIDEMsgQuickFix(const Name, Caption, RegExpr: string;

View File

@ -120,7 +120,7 @@ type
trtMatchCase, // search case sensitive
trtWholeWord, // search at word boundaries
trtRegExpr, // use regular expressions for find and replace
trtMultiLine // ignore line boundaries. The expression can span multiple lines.
trtMultiLine // ignore type of line endings in pattern (e.g. #10 = #13#10)
//TODO trtSearchInReplacement,// when replaced, continue search at start of replacement, instead of end of replacement
//TODO trtReplaceUntilNotFound// restart replace until pattern not found
);
@ -578,7 +578,7 @@ begin
if aText=nil then exit;
if SearchFor='' then exit(mrOk);
Source:=aText.Source;
Flags:=[];
Flags:=[sesoReplace,sesoReplaceAll];
if trtMatchCase in Options then Include(Flags,sesoMatchCase);
if trtWholeWord in Options then Include(Flags,sesoWholeWord);
if trtRegExpr in Options then Include(Flags,sesoRegExpr);

View File

@ -199,9 +199,6 @@ type
function GetProjectFileWithRootComponent(AComponent: TComponent): TLazProjectFile; virtual; abstract;
function GetProjectFileWithDesigner(ADesigner: TIDesigner): TLazProjectFile; virtual; abstract;
// external tools
function RunExternalTool(Tool: TIDEExternalToolOptions): TModalResult; virtual; abstract;
// events
procedure RemoveAllHandlersOfObject(AnObject: TObject);
procedure AddHandlerOnSavingAll(const OnSaveAllEvent: TModalResultFunction;
@ -213,7 +210,7 @@ type
end;
var
LazarusIDE: TLazIDEInterface; // will be set by the IDE
LazarusIDE: TLazIDEInterface = nil; // will be set by the IDE
implementation

View File

@ -524,7 +524,7 @@ type
{ TObjectInspector }
TObjectInspector = class (TForm)
TObjectInspector = class(TForm)
AvailPersistentComboBox: TComboBox;
Splitter1: TSplitter;
ComponentTree: TComponentTreeView;
@ -1106,6 +1106,7 @@ begin
DoPaint(true)
else
FPropertyEditorHook.RefreshPropertyValues;
//DebugLn(['TOICustomPropertyGrid.SetRowValue ',CurRow.Name,' ',CurRow.Editor.GetVisualValue,' ',Assigned(FOnModified)]);
if Assigned(FOnModified) then FOnModified(Self);
end;

View File

@ -53,6 +53,18 @@ type
);
TPkgCompileFlags = set of TPkgCompileFlag;
const
PkgCompileFlagNames: array[TPkgCompileFlag] of string = (
'pcfCleanCompile',
'pcfDoNotCompileDependencies',
'pcfDoNotCompilePackage',
'pcfCompileDependenciesClean',
'pcfOnlyIfNeeded',
'pcfDoNotSaveEditorFiles',
'pcfCreateMakefile'
);
type
{ TPackageEditingInterface }
TPackageEditingInterface = class(TComponent)
@ -134,10 +146,25 @@ var
procedure RegisterPackageDescriptor(PkgDesc: TPackageDescriptor);
function PackageDescriptorStd: TPackageDescriptor;
function PkgCompileFlagsToString(Flags: TPkgCompileFlags): string;
implementation
function PkgCompileFlagsToString(Flags: TPkgCompileFlags): string;
var
f: TPkgCompileFlag;
begin
Result:='';
for f:=Low(TPkgCompileFlag) to High(TPkgCompileFlag) do begin
if not (f in Flags) then continue;
if Result<>'' then Result:=Result+',';
Result:=Result+PkgCompileFlagNames[f];
end;
Result:='['+Result+']';
end;
procedure RegisterPackageDescriptor(PkgDesc: TPackageDescriptor);
var
NewItemPkg: TNewItemPackage;

View File

@ -148,6 +148,7 @@ type
function GetEditorControlSettings(EditControl: TControl): boolean; virtual; abstract;
function GetHighlighterSettings(Highlighter: TObject): boolean; virtual; abstract;
procedure ClearErrorLines; virtual; abstract;
end;

View File

@ -1244,7 +1244,7 @@ type
function(AComponent: TComponent): TCustomForm of object;
var
OnGetDesignerForm: TGetDesignerFormEvent;
OnGetDesignerForm: TGetDesignerFormEvent = nil;
function GetParentForm(Control:TControl): TCustomForm;
function GetFirstParentForm(Control:TControl): TCustomForm;
@ -1263,16 +1263,16 @@ function GetLongHint(const Hint: string): string;
var
Application: TApplication;
Screen: TScreen;
Application: TApplication = nil;
Screen: TScreen = nil;
ExceptionObject: TExceptObject;
HintWindowClass: THintWindowClass=THintWindow;
HintWindowClass: THintWindowClass = THintWindow;
type
TMessageBoxFunction =
function(Text, Caption : PChar; Flags : Longint) : Integer;
var
MessageBoxFunction: TMessageBoxFunction;
MessageBoxFunction: TMessageBoxFunction = nil;
const
DefaultBorderIcons : array[TFormBorderStyle] of TBorderIcons =
@ -1747,8 +1747,8 @@ end;
initialization
LCLProc.OwnerFormDesignerModifiedProc:=@IfOwnerIsFormThenDesignerModified;
Screen:= TScreen.Create(nil);
Application:= TApplication.Create(nil);
Screen:=TScreen.Create(nil);
Application:=TApplication.Create(nil);
{$IFDEF UseFCLDataModule}
RegisterInitComponentHandler(TComponent,@InitResourceComponent);

View File

@ -642,7 +642,6 @@ end;
------------------------------------------------------------------------------}
procedure TCustomForm.DoDestroy;
begin
DebugLn(['TCustomForm.DoDestroy ',dbgsName(Self)]);
if Assigned(FOnDestroy) then FOnDestroy(Self);
end;

View File

@ -102,14 +102,18 @@ begin
FFormList.Insert(0, ACustomForm);
end;
end;
MoveFormToZFront(ACustomForm);
end;
procedure TScreen.MoveFormToZFront(ACustomForm: TCustomForm);
//var i: Integer;
begin
if (FCustomFormsZOrdered.Count=0)
or (TObject(FCustomFormsZOrdered[0])<>ACustomForm) then begin
FCustomFormsZOrdered.Remove(ACustomForm);
FCustomFormsZOrdered.Insert(0, ACustomForm);
//for i:=0 to FCustomFormsZOrdered.Count-1 do
// DebugLn(['TScreen.MoveFormToZFront ',i,'/',FCustomFormsZOrdered.Count,' ',dbgsName(CustomFormsZOrdered[i])]);
end;
end;

View File

@ -44,7 +44,7 @@ uses
{$IFDEF IDE_MEM_CHECK}
MemCheck,
{$ENDIF}
Classes, SysUtils, Forms, FileUtil,
Classes, SysUtils, Forms, FileUtil, LCLProc,
LazIDEIntf, PackageIntf, MenuIntf,
LazarusIDEStrConsts, EnvironmentOpts,
PackageDefs, ComponentReg, CompilerOptions, Project;
@ -114,10 +114,6 @@ type
Flags: TPkgCompileFlags): TModalResult; virtual; abstract;
function DoCompilePackage(APackage: TLazPackage; Flags: TPkgCompileFlags;
Globals: TGlobalCompilerOptions = nil): TModalResult; virtual; abstract;
function DoSavePackageMainSource(APackage: TLazPackage;
Flags: TPkgCompileFlags): TModalResult; virtual; abstract;
function DoCheckIfDependenciesNeedCompilation(DependencyOwner: TObject;
StateFileAge: longint): TModalResult; virtual; abstract;
// package installation
procedure LoadInstalledPackages; virtual; abstract;
@ -145,24 +141,13 @@ const
'pofRevert'
);
PkgCompileFlagNames: array[TPkgCompileFlag] of string = (
'pcfCleanCompile',
'pcfDoNotCompileDependencies',
'pcfDoNotCompilePackage',
'pcfCompileDependenciesClean',
'pcfOnlyIfNeeded',
'pcfDoNotSaveEditorFiles',
'pcfCreateMakefile'
);
function PkgSaveFlagsToString(Flags: TPkgSaveFlags): string;
function PkgOpenFlagsToString(Flags: TPkgOpenFlags): string;
function PkgCompileFlagsToString(Flags: TPkgCompileFlags): string;
procedure GetDescriptionOfDependencyOwner(Dependency: TPkgDependency;
var Description: string);
out Description: string);
procedure GetDirectoryOfDependencyOwner(Dependency: TPkgDependency;
var Directory: string);
out Directory: string);
implementation
@ -193,21 +178,8 @@ begin
Result:='['+Result+']';
end;
function PkgCompileFlagsToString(Flags: TPkgCompileFlags): string;
var
f: TPkgCompileFlag;
begin
Result:='';
for f:=Low(TPkgCompileFlag) to High(TPkgCompileFlag) do begin
if not (f in Flags) then continue;
if Result<>'' then Result:=Result+',';
Result:=Result+PkgCompileFlagNames[f];
end;
Result:='['+Result+']';
end;
procedure GetDescriptionOfDependencyOwner(Dependency: TPkgDependency;
var Description: string);
out Description: string);
var
DepOwner: TObject;
begin
@ -222,7 +194,7 @@ begin
end else if DepOwner=PkgBoss then begin
Description:=lisPkgMangLazarus;
end else begin
Description:=DepOwner.ClassName
Description:=dbgsName(DepOwner)
end;
end else begin
Description:=Format(lisPkgMangDependencyWithoutOwner, [Dependency.AsString]
@ -231,7 +203,7 @@ begin
end;
procedure GetDirectoryOfDependencyOwner(Dependency: TPkgDependency;
var Directory: string);
out Directory: string);
var
DepOwner: TObject;
begin

View File

@ -64,9 +64,9 @@ type
TGetAllRequiredPackagesEvent =
procedure(FirstDependency: TPkgDependency; var List: TFPList) of object;
TGetDependencyOwnerDescription =
procedure(Dependency: TPkgDependency; var Description: string) of object;
procedure(Dependency: TPkgDependency; out Description: string) of object;
TGetDependencyOwnerDirectory =
procedure(Dependency: TPkgDependency; var Directory: string) of object;
procedure(Dependency: TPkgDependency; out Directory: string) of object;
TGetWritablePkgOutputDirectory =
procedure(APackage: TLazPackage; var AnOutDirectory: string) of object;
@ -814,12 +814,12 @@ const
var
// All TPkgDependency are added to this AVL tree (sorted for names, not version!)
PackageDependencies: TAVLTree; // tree of TPkgDependency
PackageDependencies: TAVLTree = nil; // tree of TPkgDependency
OnGetAllRequiredPackages: TGetAllRequiredPackagesEvent;
OnGetDependencyOwnerDescription: TGetDependencyOwnerDescription;
OnGetDependencyOwnerDirectory: TGetDependencyOwnerDirectory;
OnGetWritablePkgOutputDirectory: TGetWritablePkgOutputDirectory;
OnGetAllRequiredPackages: TGetAllRequiredPackagesEvent = nil;
OnGetDependencyOwnerDescription: TGetDependencyOwnerDescription = nil;
OnGetDependencyOwnerDirectory: TGetDependencyOwnerDirectory = nil;
OnGetWritablePkgOutputDirectory: TGetWritablePkgOutputDirectory = nil;
function CompareLazPackageID(Data1, Data2: Pointer): integer;
function CompareNameWithPackageID(Key, Data: Pointer): integer;

View File

@ -45,9 +45,14 @@ uses
{$IFDEF IDE_MEM_CHECK}
MemCheck,
{$ENDIF}
Classes, SysUtils, FileUtil,
AVL_Tree, Laz_XMLCfg,
LCLProc, Forms, Controls, Dialogs, LazarusIDEStrConsts, IDEProcs, LazConf,
// FPC + LCL
Classes, SysUtils, FileUtil, LCLProc, Forms, Controls, Dialogs,
// codetools
AVL_Tree, Laz_XMLCfg, CodeCache, BasicCodeTools, CodeToolManager,
// IDEIntf,
SrcEditorIntf, IDEExternToolIntf, IDEDialogs, IDEMsgIntf, PackageIntf,
// IDE
LazarusIDEStrConsts, IDEProcs, LazConf, TransferMacros, DialogProcs,
CompilerOptions, PackageLinks, PackageDefs, LazarusPackageIntf, ComponentReg,
RegisterFCL, RegisterLCL, RegisterSynEdit, RegisterIDEIntf;
@ -70,12 +75,23 @@ const
fpfSearchAllExisting = fpfSearchEverywhere+[fpfPkgLinkMustExist];
type
TPkgUninstallFlag = (
puifDoNotConfirm,
puifDoNotBuildIDE
);
TPkgUninstallFlags = set of TPkgUninstallFlag;
TPkgAddedEvent = procedure(APackage: TLazPackage) of object;
TPkgDeleteEvent = procedure(APackage: TLazPackage) of object;
TPkgWriteMakeFile = function(APackage: TLazPackage): TModalResult of object;
TPkgUninstall = function(APackage: TLazPackage;
Flags: TPkgUninstallFlags): TModalResult of object;
TDependencyModifiedEvent = procedure(ADependency: TPkgDependency) of object;
TEndUpdateEvent = procedure(Sender: TObject; GraphChanged: boolean) of object;
TFindFPCUnitEvent = procedure(const UnitName, Directory: string;
var Filename: string) of object;
TPkgDeleteAmbiguousFiles = function(const Filename: string): TModalResult of object;
{ TLazPackageGraph }
@ -93,9 +109,12 @@ type
FOnAddPackage: TPkgAddedEvent;
FOnBeginUpdate: TNotifyEvent;
FOnChangePackageName: TPkgChangeNameEvent;
FOnDeleteAmbiguousFiles: TPkgDeleteAmbiguousFiles;
FOnDeletePackage: TPkgDeleteEvent;
FOnDependencyModified: TDependencyModifiedEvent;
FOnEndUpdate: TEndUpdateEvent;
FOnUninstallPackage: TPkgUninstall;
FOnWriteMakeFile: TPkgWriteMakeFile;
FRegistrationFile: TPkgFile;
FRegistrationPackage: TLazPackage;
FRegistrationUnitName: string;
@ -115,6 +134,8 @@ type
procedure UpdateBrokenDependenciesToPackage(APackage: TLazPackage);
function OpenDependencyWithPackageLink(Dependency: TPkgDependency;
PkgLink: TPackageLink): boolean;
function DeleteAmbiguousFiles(const Filename: string): TModalResult;
procedure AddMessage(const Msg, Directory: string);
public
constructor Create;
destructor Destroy; override;
@ -213,6 +234,26 @@ type
procedure ChangePackageID(APackage: TLazPackage;
const NewName: string; NewVersion: TPkgVersion;
RenameDependencies: boolean);
function SavePackageCompiledState(APackage: TLazPackage;
const CompilerFilename, CompilerParams: string): TModalResult;
function LoadPackageCompiledState(APackage: TLazPackage;
IgnoreErrors: boolean): TModalResult;
function CheckIfDependenciesNeedCompilation(FirstDependency: TPkgDependency;
StateFileAge: longint): TModalResult;
function CheckIfPackageNeedsCompilation(APackage: TLazPackage;
const CompilerFilename, CompilerParams, SrcFilename: string
): TModalResult;
function PreparePackageOutputDirectory(APackage: TLazPackage;
CleanUp: boolean): TModalResult;
function CheckAmbiguousPackageUnits(APackage: TLazPackage): TModalResult;
function SavePackageMainSource(APackage: TLazPackage;
Flags: TPkgCompileFlags): TModalResult;
function CompileRequiredPackages(APackage: TLazPackage;
FirstDependency: TPkgDependency;
Globals: TGlobalCompilerOptions;
Policies: TPackageUpdatePolicies): TModalResult;
function CompilePackage(APackage: TLazPackage; Flags: TPkgCompileFlags;
Globals: TGlobalCompilerOptions = nil): TModalResult;
public
// registration
procedure RegisterUnitHandler(const TheUnitName: string;
@ -260,6 +301,12 @@ type
property OnDeletePackage: TPkgDeleteEvent read FOnDeletePackage
write FOnDeletePackage;
property OnEndUpdate: TEndUpdateEvent read FOnEndUpdate write FOnEndUpdate;
property OnDeleteAmbiguousFiles: TPkgDeleteAmbiguousFiles
read FOnDeleteAmbiguousFiles write FOnDeleteAmbiguousFiles;
property OnWriteMakeFile: TPkgWriteMakeFile read FOnWriteMakeFile
write FOnWriteMakeFile;
property OnUninstallPackage: TPkgUninstall read FOnUninstallPackage
write FOnUninstallPackage;
property Packages[Index: integer]: TLazPackage read GetPackages; default; // see Count for the number
property RegistrationFile: TPkgFile read FRegistrationFile;
property RegistrationPackage: TLazPackage read FRegistrationPackage
@ -269,7 +316,7 @@ type
end;
var
PackageGraph: TLazPackageGraph;
PackageGraph: TLazPackageGraph = nil;
implementation
@ -375,7 +422,7 @@ begin
DebugLn('invalid Package file "'+AFilename+'".');
exit;
end;
if CompareText(PkgLink.Name,NewPackage.Name)<>0 then exit;
if SysUtils.CompareText(PkgLink.Name,NewPackage.Name)<>0 then exit;
// ok
Result:=true;
AddPackage(NewPackage);
@ -386,6 +433,23 @@ begin
end;
end;
function TLazPackageGraph.DeleteAmbiguousFiles(const Filename: string
): TModalResult;
begin
if Assigned(OnDeleteAmbiguousFiles) then
Result:=OnDeleteAmbiguousFiles(Filename)
else
Result:=mrOk;
end;
procedure TLazPackageGraph.AddMessage(const Msg, Directory: string);
begin
if Assigned(IDEMessagesWindow) then
IDEMessagesWindow.AddMsg(Msg, Directory,-1)
else
DebugLn(['TLazPackageGraph.AddMessage Msg="',Msg,'" Directory="',Directory,'"']);
end;
constructor TLazPackageGraph.Create;
begin
OnGetAllRequiredPackages:=@GetAllRequiredPackages;
@ -1909,6 +1973,756 @@ begin
EndUpdate;
end;
function TLazPackageGraph.SavePackageCompiledState(APackage: TLazPackage;
const CompilerFilename, CompilerParams: string): TModalResult;
var
XMLConfig: TXMLConfig;
StateFile: String;
CompilerFileDate: Integer;
begin
Result:=mrCancel;
StateFile:=APackage.GetStateFilename;
try
CompilerFileDate:=FileAge(CompilerFilename);
XMLConfig:=TXMLConfig.CreateClean(StateFile);
try
XMLConfig.SetValue('Compiler/Value',CompilerFilename);
XMLConfig.SetValue('Compiler/Date',CompilerFileDate);
XMLConfig.SetValue('Params/Value',CompilerParams);
InvalidateFileStateCache;
XMLConfig.Flush;
finally
XMLConfig.Free;
end;
APackage.LastCompilerFilename:=CompilerFilename;
APackage.LastCompilerFileDate:=CompilerFileDate;
APackage.LastCompilerParams:=CompilerParams;
APackage.StateFileDate:=FileAge(StateFile);
APackage.Flags:=APackage.Flags+[lpfStateFileLoaded];
except
on E: Exception do begin
Result:=IDEMessageDialog(lisPkgMangErrorWritingFile,
Format(lisPkgMangUnableToWriteStateFileOfPackageError, ['"', StateFile,
'"', #13, APackage.IDAsString, #13, E.Message]),
mtError,[mbAbort,mbCancel]);
exit;
end;
end;
Result:=mrOk;
end;
function TLazPackageGraph.LoadPackageCompiledState(APackage: TLazPackage;
IgnoreErrors: boolean): TModalResult;
var
XMLConfig: TXMLConfig;
StateFile: String;
StateFileAge: Integer;
begin
StateFile:=APackage.GetStateFilename;
if not FileExists(StateFile) then begin
DebugLn('TLazPackageGraph.LoadPackageCompiledState Statefile not found: ',StateFile);
APackage.Flags:=APackage.Flags-[lpfStateFileLoaded];
Result:=mrOk;
exit;
end;
// read the state file
StateFileAge:=FileAge(StateFile);
if (not (lpfStateFileLoaded in APackage.Flags))
or (APackage.StateFileDate<>StateFileAge) then begin
APackage.Flags:=APackage.Flags-[lpfStateFileLoaded];
try
XMLConfig:=TXMLConfig.Create(StateFile);
try
APackage.LastCompilerFilename:=XMLConfig.GetValue('Compiler/Value','');
APackage.LastCompilerFileDate:=XMLConfig.GetValue('Compiler/Date',0);
APackage.LastCompilerParams:=XMLConfig.GetValue('Params/Value','');
finally
XMLConfig.Free;
end;
APackage.StateFileDate:=StateFileAge;
except
on E: Exception do begin
if IgnoreErrors then begin
Result:=mrOk;
end else begin
Result:=IDEMessageDialog(lisPkgMangErrorReadingFile,
Format(lisPkgMangUnableToReadStateFileOfPackageError, ['"',
StateFile, '"', #13, APackage.IDAsString, #13, E.Message]),
mtError,[mbCancel,mbAbort]);
end;
exit;
end;
end;
APackage.Flags:=APackage.Flags+[lpfStateFileLoaded];
end;
Result:=mrOk;
end;
function TLazPackageGraph.CheckIfDependenciesNeedCompilation(
FirstDependency: TPkgDependency; StateFileAge: longint): TModalResult;
function GetOwnerID: string;
begin
OnGetDependencyOwnerDescription(FirstDependency,Result);
end;
var
Dependency: TPkgDependency;
RequiredPackage: TLazPackage;
OtherStateFile: String;
begin
Dependency:=FirstDependency;
if Dependency=nil then begin
Result:=mrNo;
exit;
end;
while Dependency<>nil do begin
if (Dependency.LoadPackageResult=lprSuccess) then begin
RequiredPackage:=Dependency.RequiredPackage;
// check compile state file of required package
if not RequiredPackage.AutoCreated then begin
Result:=LoadPackageCompiledState(RequiredPackage,false);
if Result<>mrOk then exit;
Result:=mrYes;
if not (lpfStateFileLoaded in RequiredPackage.Flags) then begin
DebugLn('TPkgManager.CheckIfDependenciesNeedCompilation No state file for ',RequiredPackage.IDAsString);
exit;
end;
if StateFileAge<RequiredPackage.StateFileDate then begin
DebugLn('TPkgManager.CheckIfDependenciesNeedCompilation Required ',
RequiredPackage.IDAsString,' State file is newer than ',
'State file ',GetOwnerID);
exit;
end;
end;
// check output state file of required package
if RequiredPackage.OutputStateFile<>'' then begin
OtherStateFile:=RequiredPackage.OutputStateFile;
GlobalMacroList.SubstituteStr(OtherStateFile);
if FileExists(OtherStateFile)
and (FileAge(OtherStateFile)>StateFileAge) then begin
DebugLn('TPkgManager.CheckIfDependenciesNeedCompilation Required ',
RequiredPackage.IDAsString,' OtherState file "',OtherStateFile,'"'
,' is newer than State file ',GetOwnerID);
Result:=mrYes;
exit;
end;
end;
end;
Dependency:=Dependency.NextRequiresDependency;
end;
Result:=mrNo;
end;
function TLazPackageGraph.CheckIfPackageNeedsCompilation(APackage: TLazPackage;
const CompilerFilename, CompilerParams, SrcFilename: string): TModalResult;
var
StateFilename: String;
StateFileAge: Integer;
i: Integer;
CurFile: TPkgFile;
begin
Result:=mrYes;
{$IFDEF VerbosePkgCompile}
writeln('TLazPackageGraph.CheckIfPackageNeedsCompilation A ',APackage.IDAsString);
{$ENDIF}
// check state file
StateFilename:=APackage.GetStateFilename;
Result:=LoadPackageCompiledState(APackage,false);
if Result<>mrOk then exit;
if not (lpfStateFileLoaded in APackage.Flags) then begin
DebugLn('TLazPackageGraph.CheckIfPackageNeedsCompilation No state file for ',APackage.IDAsString);
Result:=mrYes;
exit;
end;
StateFileAge:=FileAge(StateFilename);
// check main source file
if FileExists(SrcFilename) and (StateFileAge<FileAge(SrcFilename)) then
begin
DebugLn('TLazPackageGraph.CheckIfPackageNeedsCompilation SrcFile outdated ',APackage.IDAsString);
Result:=mrYes;
exit;
end;
// check all required packages
Result:=CheckIfDependenciesNeedCompilation(APackage.FirstRequiredDependency,
StateFileAge);
if Result<>mrNo then exit;
Result:=mrYes;
// check compiler and params
if CompilerFilename<>APackage.LastCompilerFilename then begin
DebugLn('TLazPackageGraph.CheckIfPackageNeedsCompilation Compiler filename changed for ',APackage.IDAsString);
DebugLn(' Old="',APackage.LastCompilerFilename,'"');
DebugLn(' Now="',CompilerFilename,'"');
exit;
end;
if not FileExists(CompilerFilename) then begin
DebugLn('TLazPackageGraph.CheckIfPackageNeedsCompilation Compiler filename not found for ',APackage.IDAsString);
DebugLn(' File="',CompilerFilename,'"');
exit;
end;
if FileAge(CompilerFilename)<>APackage.LastCompilerFileDate then begin
DebugLn('TLazPackageGraph.CheckIfPackageNeedsCompilation Compiler file changed for ',APackage.IDAsString);
DebugLn(' File="',CompilerFilename,'"');
exit;
end;
if CompilerParams<>APackage.LastCompilerParams then begin
DebugLn('TLazPackageGraph.CheckIfPackageNeedsCompilation Compiler params changed for ',APackage.IDAsString);
DebugLn(' Old="',APackage.LastCompilerParams,'"');
DebugLn(' Now="',CompilerParams,'"');
exit;
end;
// check package files
if StateFileAge<FileAge(APackage.Filename) then begin
DebugLn('TLazPackageGraph.CheckIfPackageNeedsCompilation StateFile older than lpk ',APackage.IDAsString);
exit;
end;
for i:=0 to APackage.FileCount-1 do begin
CurFile:=APackage.Files[i];
//debugln('TLazPackageGraph.CheckIfPackageNeedsCompilation CurFile.Filename="',CurFile.Filename,'" ',FileExists(CurFile.Filename),' ',StateFileAge<FileAge(CurFile.Filename));
if FileExists(CurFile.Filename)
and (StateFileAge<FileAge(CurFile.Filename)) then begin
DebugLn('TLazPackageGraph.CheckIfPackageNeedsCompilation Src has changed ',APackage.IDAsString,' ',CurFile.Filename);
exit;
end;
end;
{$IFDEF VerbosePkgCompile}
writeln('TLazPackageGraph.CheckIfPackageNeedsCompilation END ',APackage.IDAsString);
{$ENDIF}
Result:=mrNo;
end;
function TLazPackageGraph.CompileRequiredPackages(APackage: TLazPackage;
FirstDependency: TPkgDependency; Globals: TGlobalCompilerOptions;
Policies: TPackageUpdatePolicies): TModalResult;
var
AutoPackages: TFPList;
i: Integer;
begin
{$IFDEF VerbosePkgCompile}
writeln('TLazPackageGraph.CompileRequiredPackages A ');
{$ENDIF}
AutoPackages:=PackageGraph.GetAutoCompilationOrder(APackage,FirstDependency,
Policies);
if AutoPackages<>nil then begin
//DebugLn('TLazPackageGraph.CompileRequiredPackages B Count=',IntToStr(AutoPackages.Count));
try
i:=0;
while i<AutoPackages.Count do begin
Result:=CompilePackage(TLazPackage(AutoPackages[i]),
[pcfDoNotCompileDependencies,pcfOnlyIfNeeded,
pcfDoNotSaveEditorFiles],Globals);
if Result<>mrOk then exit;
inc(i);
end;
finally
AutoPackages.Free;
end;
end;
{$IFDEF VerbosePkgCompile}
writeln('TLazPackageGraph.CompileRequiredPackages END ');
{$ENDIF}
Result:=mrOk;
end;
function TLazPackageGraph.CompilePackage(APackage: TLazPackage;
Flags: TPkgCompileFlags; Globals: TGlobalCompilerOptions): TModalResult;
var
PkgCompileTool: TIDEExternalToolOptions;
CompilerFilename: String;
CompilerParams: String;
EffektiveCompilerParams: String;
SrcFilename: String;
CompilePolicies: TPackageUpdatePolicies;
begin
Result:=mrCancel;
DebugLn('TLazPackageGraph.CompilePackage A ',APackage.IDAsString,' Flags=',PkgCompileFlagsToString(Flags));
if APackage.AutoCreated then begin
DebugLn(['TLazPackageGraph.CompilePackage failed because autocreated: ',APackage.IDAsString]);
exit;
end;
BeginUpdate(false);
try
// automatically compile required packages
if not (pcfDoNotCompileDependencies in Flags) then begin
CompilePolicies:=[pupAsNeeded];
if pcfCompileDependenciesClean in Flags then
Include(CompilePolicies,pupOnRebuildingAll);
Result:=CompileRequiredPackages(APackage,nil,Globals,
CompilePolicies);
if Result<>mrOk then begin
DebugLn(['TLazPackageGraph.CompilePackage CompileRequiredPackages failed: ',APackage.IDAsString]);
exit;
end;
end;
SrcFilename:=APackage.GetSrcFilename;
CompilerFilename:=APackage.GetCompilerFilename;
CompilerParams:=APackage.CompilerOptions.MakeOptionsString(Globals,
APackage.CompilerOptions.DefaultMakeOptionsFlags)
+' '+CreateRelativePath(SrcFilename,APackage.Directory);
//DebugLn(['TLazPackageGraph.CompilePackage SrcFilename="',SrcFilename,'" CompilerFilename="',CompilerFilename,'" CompilerParams="',CompilerParams,'"']);
// check if compilation is neccessary
if (pcfOnlyIfNeeded in Flags) then begin
Result:=CheckIfPackageNeedsCompilation(APackage,
CompilerFilename,CompilerParams,
SrcFilename);
if Result=mrNo then begin
DebugLn(['TLazPackageGraph.CompilePackage ',APackage.IDAsString,' does not need compilation.']);
Result:=mrOk;
exit;
end;
if Result<>mrYes then begin
DebugLn(['TLazPackageGraph.CompilePackage CheckIfPackageNeedsCompilation failed: ',APackage.IDAsString]);
exit;
end;
end;
// auto increase version
// ToDo
if IDEMessagesWindow<>nil then
IDEMessagesWindow.BeginBlock;
try
Result:=PreparePackageOutputDirectory(APackage,pcfCleanCompile in Flags);
if Result<>mrOk then begin
DebugLn('TLazPackageGraph.CompilePackage PreparePackageOutputDirectory failed: ',APackage.IDAsString);
exit;
end;
// create package main source file
Result:=SavePackageMainSource(APackage,Flags);
if Result<>mrOk then begin
DebugLn('TLazPackageGraph.CompilePackage SavePackageMainSource failed: ',APackage.IDAsString);
exit;
end;
// check ambiguous units
Result:=CheckAmbiguousPackageUnits(APackage);
if Result<>mrOk then begin
DebugLn('TLazPackageGraph.CompilePackage CheckAmbiguousPackageUnits failed: ',APackage.IDAsString);
exit;
end;
// create Makefile
if ((pcfCreateMakefile in Flags)
or (APackage.CompilerOptions.CreateMakefileOnBuild))
and Assigned(OnWriteMakeFile) then begin
Result:=OnWriteMakeFile(APackage);
if Result<>mrOk then begin
DebugLn('TLazPackageGraph.CompilePackage DoWriteMakefile failed: ',APackage.IDAsString);
exit;
end;
end;
// run compilation tool 'Before'
if not (pcfDoNotCompilePackage in Flags) then begin
Result:=APackage.CompilerOptions.ExecuteBefore.Execute(
APackage.Directory,'Executing command before');
if Result<>mrOk then begin
DebugLn(['TLazPackageGraph.CompilePackage ExecuteBefore failed: ',APackage.IDAsString]);
exit;
end;
end;
// create external tool to run the compiler
DebugLn('TPkgManager.DoCompilePackage Compiler="',CompilerFilename,'"');
DebugLn('TPkgManager.DoCompilePackage Params="',CompilerParams,'"');
DebugLn('TPkgManager.DoCompilePackage WorkingDir="',APackage.Directory,'"');
if (not APackage.CompilerOptions.SkipCompiler)
and (not (pcfDoNotCompilePackage in Flags)) then begin
// check compiler filename
try
CheckIfFileIsExecutable(CompilerFilename);
except
on e: Exception do begin
DebugLn(['TLazPackageGraph.CompilePackage ',APackage.IDAsString,' ',e.Message]);
Result:=IDEMessageDialog(lisPkgManginvalidCompilerFilename,
Format(lisPkgMangTheCompilerFileForPackageIsNotAValidExecutable, [
APackage.IDAsString, #13, E.Message]),
mtError,[mbCancel,mbAbort]);
exit;
end;
end;
// change compiler parameters for compiling clean
EffektiveCompilerParams:=CompilerParams;
if pcfCleanCompile in Flags then begin
if EffektiveCompilerParams<>'' then
EffektiveCompilerParams:='-B '+EffektiveCompilerParams
else
EffektiveCompilerParams:='-B';
end;
PkgCompileTool:=TIDEExternalToolOptions.Create;
try
PkgCompileTool.Title:='Compiling package '+APackage.IDAsString;
PkgCompileTool.ScanOutputForFPCMessages:=true;
PkgCompileTool.ScanOutputForMakeMessages:=true;
PkgCompileTool.WorkingDirectory:=APackage.Directory;
PkgCompileTool.Filename:=CompilerFilename;
PkgCompileTool.CmdLineParams:=EffektiveCompilerParams;
// clear old errors
if SourceEditorWindow<>nil then
SourceEditorWindow.ClearErrorLines;
// compile package
Result:=RunCompilerWithOptions(PkgCompileTool,APackage.CompilerOptions);
if Result<>mrOk then exit;
// compilation succeded -> write state file
Result:=SavePackageCompiledState(APackage,
CompilerFilename,CompilerParams);
if Result<>mrOk then begin
DebugLn(['TLazPackageGraph.CompilePackage SavePackageCompiledState failed: ',APackage.IDAsString]);
exit;
end;
finally
// clean up
PkgCompileTool.Free;
end;
end;
// run compilation tool 'After'
if not (pcfDoNotCompilePackage in Flags) then begin
Result:=APackage.CompilerOptions.ExecuteAfter.Execute(
APackage.Directory,'Executing command after');
if Result<>mrOk then begin
DebugLn(['TLazPackageGraph.CompilePackage ExecuteAfter failed: ',APackage.IDAsString]);
exit;
end;
end;
finally
if IDEMessagesWindow<>nil then
IDEMessagesWindow.BeginBlock;
if Result<>mrOk then begin
if (APackage.AutoInstall<>pitNope) and (APackage.Installed=pitNope)
and (OnUninstallPackage<>nil) then begin
// package was tried to install, but failed
// -> ask user if the package should be removed from the installation
// list
if IDEMessageDialog(lisInstallationFailed,
Format(lisPkgMangThePackageFailedToCompileRemoveItFromTheInstallati,
['"', APackage.IDAsString, '"', #13]), mtConfirmation,
[mbYes,mbIgnore])=mrYes then
begin
OnUninstallPackage(APackage,[puifDoNotConfirm,puifDoNotBuildIDE]);
end;
end;
end;
end;
finally
PackageGraph.EndUpdate;
end;
Result:=mrOk;
end;
function TLazPackageGraph.PreparePackageOutputDirectory(APackage: TLazPackage;
CleanUp: boolean): TModalResult;
var
OutputDir: String;
StateFile: String;
PkgSrcDir: String;
i: Integer;
CurFile: TPkgFile;
OutputFileName: String;
begin
OutputDir:=APackage.GetOutputDirectory;
StateFile:=APackage.GetStateFilename;
PkgSrcDir:=ExtractFilePath(APackage.GetSrcFilename);
// create the output directory
if not ForceDirectory(OutputDir) then begin
Result:=IDEMessageDialog(lisPkgMangUnableToCreateDirectory,
Format(lisPkgMangUnableToCreateOutputDirectoryForPackage, ['"',
OutputDir, '"', #13, APackage.IDAsString]),
mtError,[mbCancel,mbAbort]);
exit;
end;
// delete old Compile State file
if FileExists(StateFile) and not DeleteFile(StateFile) then begin
Result:=IDEMessageDialog(lisPkgMangUnableToDeleteFilename,
Format(lisPkgMangUnableToDeleteOldStateFileForPackage, ['"', StateFile,
'"', #13, APackage.IDAsString]),
mtError,[mbCancel,mbAbort]);
exit;
end;
APackage.Flags:=APackage.Flags-[lpfStateFileLoaded];
// create the package src directory
if not ForceDirectory(PkgSrcDir) then begin
Result:=IDEMessageDialog(lisPkgMangUnableToCreateDirectory,
Format(lisPkgMangUnableToCreatePackageSourceDirectoryForPackage, ['"',
PkgSrcDir, '"', #13, APackage.IDAsString]),
mtError,[mbCancel,mbAbort]);
exit;
end;
// clean up if wanted
if CleanUp then begin
for i:=0 to APackage.FileCount-1 do begin
CurFile:=APackage.Files[i];
if not (CurFile.FileType in PkgFileUnitTypes) then continue;
OutputFileName:=AppendPathDelim(OutputDir)+CurFile.UnitName+'.ppu';
Result:=DeleteFileInteractive(OutputFileName,[mbIgnore,mbAbort]);
if Result in [mrCancel,mrAbort] then exit;
end;
end;
Result:=mrOk;
end;
function TLazPackageGraph.CheckAmbiguousPackageUnits(APackage: TLazPackage
): TModalResult;
var
i: Integer;
CurFile: TPkgFile;
CurUnitName: String;
SrcDirs: String;
PkgDir: String;
PkgOutputDir: String;
YesToAll: Boolean;
function CheckFile(const ShortFilename: string): TModalResult;
var
AmbiguousFilename: String;
SearchFlags: TSearchFileInPathFlags;
begin
Result:=mrOk;
SearchFlags:=[];
if CompareFilenames(PkgDir,PkgOutputDir)=0 then
Include(SearchFlags,sffDontSearchInBasePath);
repeat
AmbiguousFilename:=SearchFileInPath(ShortFilename,PkgDir,SrcDirs,';',
SearchFlags);
if (AmbiguousFilename='') then exit;
if not YesToAll then
Result:=IDEMessageDialog(lisAmbiguousUnitFound,
Format(lisTheFileWasFoundInOneOfTheSourceDirectoriesOfThePac, ['"',
AmbiguousFilename, '"', #13, APackage.IDAsString, #13, #13]),
mtWarning,[mbYes,mbYesToAll,mbNo,mbAbort])
else
Result:=mrYesToAll;
if Result=mrNo then
Result:=mrOk;
if Result in [mrYes,mrYesToAll] then begin
YesToAll:=Result=mrYesToAll;
if (not DeleteFile(AmbiguousFilename))
and (IDEMessageDialog(lisPkgMangDeleteFailed, Format(lisDeletingOfFileFailed,
['"', AmbiguousFilename, '"']), mtError, [mbIgnore, mbCancel])
<>mrIgnore) then
begin
Result:=mrCancel;
exit;
end;
Result:=mrOk;
end else
break;
until false;
end;
begin
Result:=mrOk;
YesToAll:=False;
// search in every source directory for compiled versions of the units
// A source directory is a directory with a used unit and it is not the output
// directory
SrcDirs:=APackage.GetSourceDirs(true,true);
PkgOutputDir:=AppendPathDelim(APackage.GetOutputDirectory);
SrcDirs:=RemoveSearchPaths(SrcDirs,PkgOutputDir);
if SrcDirs='' then exit;
PkgDir:=AppendPathDelim(APackage.Directory);
for i:=0 to APackage.FileCount-1 do begin
CurFile:=APackage.Files[i];
if CurFile.FileType<>pftUnit then continue;
CurUnitName:=lowercase(CurFile.UnitName);
if CurUnitName='' then continue;
Result:=CheckFile(CurUnitName+'.ppu');
if Result<>mrOk then exit;
Result:=CheckFile(CurUnitName+'.ppw');
if Result<>mrOk then exit;
Result:=CheckFile(CurUnitName+'.ppl');
if Result<>mrOk then exit;
end;
Result:=mrOk;
end;
function TLazPackageGraph.SavePackageMainSource(APackage: TLazPackage;
Flags: TPkgCompileFlags): TModalResult;
var
SrcFilename: String;
UsedUnits: String;
Src: String;
i: Integer;
e: String;
CurFile: TPkgFile;
CodeBuffer: TCodeBuffer;
CurUnitName: String;
RegistrationCode: String;
HeaderSrc: String;
OutputDir: String;
OldShortenSrc: String;
NeedsRegisterProcCall: boolean;
CurSrcUnitName: String;
NewShortenSrc: String;
begin
{$IFDEF VerbosePkgCompile}
writeln('TLazPackageGraph.SavePackageMainSource A');
{$ENDIF}
// check if package is ready for saving
OutputDir:=APackage.GetOutputDirectory;
if not DirPathExists(OutputDir) then begin
Result:=IDEMessageDialog(lisEnvOptDlgDirectoryNotFound,
Format(lisPkgMangPackageHasNoValidOutputDirectory, ['"',
APackage.IDAsString, '"', #13, '"', OutputDir, '"']),
mtError,[mbCancel,mbAbort]);
exit;
end;
SrcFilename:=APackage.GetSrcFilename;
// delete ambiguous files
Result:=DeleteAmbiguousFiles(SrcFilename);
if Result=mrAbort then begin
DebugLn('TLazPackageGraph.SavePackageMainSource DoDeleteAmbiguousFiles failed');
exit;
end;
// collect unitnames
e:=LineEnding;
UsedUnits:='';
RegistrationCode:='';
for i:=0 to APackage.FileCount-1 do begin
CurFile:=APackage.Files[i];
// update unitname
if FilenameIsPascalUnit(CurFile.Filename)
and (CurFile.FileType in PkgFileUnitTypes) then begin
CurUnitName:=ExtractFileNameOnly(CurFile.Filename);
if CurUnitName=lowercase(CurUnitName) then begin
// the filename is all lowercase, so we can use the nicer unitname from
// the source.
CodeBuffer:=CodeToolBoss.LoadFile(CurFile.Filename,false,false);
if CodeBuffer<>nil then begin
// if the unit is edited, the unitname is probably already cached
CurSrcUnitName:=CodeToolBoss.GetCachedSourceName(CodeBuffer);
// if not then parse it
if SysUtils.CompareText(CurSrcUnitName,CurUnitName)<>0 then
CurSrcUnitName:=CodeToolBoss.GetSourceName(CodeBuffer,false);
// if it makes sense, update unitname
if SysUtils.CompareText(CurSrcUnitName,CurFile.UnitName)=0 then
CurFile.UnitName:=CurSrcUnitName;
end;
if SysUtils.CompareText(CurUnitName,CurFile.UnitName)=0 then
CurUnitName:=CurFile.UnitName
else
CurFile.UnitName:=CurUnitName;
end;
if (CurUnitName<>'') and IsValidIdent(CurUnitName) then begin
NeedsRegisterProcCall:=CurFile.HasRegisterProc
and (APackage.PackageType in [lptDesignTime,lptRunAndDesignTime]);
if NeedsRegisterProcCall or CurFile.AddToUsesPkgSection then begin
if UsedUnits<>'' then
UsedUnits:=UsedUnits+', ';
UsedUnits:=UsedUnits+CurUnitName;
end;
if NeedsRegisterProcCall then begin
RegistrationCode:=RegistrationCode+
' RegisterUnit('''+CurUnitName+''',@'+CurUnitName+'.Register);'+e;
end;
end else begin
AddMessage('WARNING: unit name invalid '+CurFile.Filename
+', package='+APackage.IDAsString,
APackage.Directory);
end;
end;
end;
// append registration code only for design time packages
if (APackage.PackageType in [lptDesignTime,lptRunAndDesignTime]) then begin
RegistrationCode:=
'procedure Register;'+e
+'begin'+e
+RegistrationCode
+'end;'+e
+e
+'initialization'+e
+' RegisterPackage('''+APackage.Name+''',@Register);'
+e;
if UsedUnits<>'' then UsedUnits:=UsedUnits+', ';
UsedUnits:=UsedUnits+'LazarusPackageIntf';
end;
// create source
HeaderSrc:=lisPkgMangThisSourceIsOnlyUsedToCompileAndInstallThePackage;
HeaderSrc:= '{ '
+lisPkgMangThisFileWasAutomaticallyCreatedByLazarusDoNotEdit+e
+lisPkgMangThisSourceIsOnlyUsedToCompileAndInstallThePackage+e
+' }'+e+e;
Src:='unit '+APackage.Name+';'+e
+e
+'interface'+e
+e;
if UsedUnits<>'' then
Src:=Src
+'uses'+e
+' '+UsedUnits+';'+e
+e;
Src:=Src
+'implementation'+e
+e
+RegistrationCode
+'end.'+e;
Src:=CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.
BeautifyStatement(Src,0);
Src:=HeaderSrc+Src;
// check if old code is already uptodate
Result:=LoadCodeBuffer(CodeBuffer,SrcFilename,[lbfQuiet,lbfCheckIfText,
lbfUpdateFromDisk,lbfCreateClearOnError]);
if Result<>mrOk then begin
DebugLn('TLazPackageGraph.SavePackageMainSource LoadCodeBuffer ',SrcFilename,' failed');
exit;
end;
OldShortenSrc:=CodeToolBoss.ExtractCodeWithoutComments(CodeBuffer);
NewShortenSrc:=CleanCodeFromComments(Src,
CodeToolBoss.GetNestedCommentsFlagForFile(CodeBuffer.Filename));
if CompareTextIgnoringSpace(OldShortenSrc,NewShortenSrc,true)=0 then begin
Result:=mrOk;
exit;
end;
if OldShortenSrc<>NewShortenSrc then begin
DebugLn('TLazPackageGraph.SavePackageMainSource Src changed ',dbgs(length(OldShortenSrc)),' ',dbgs(length(NewShortenSrc)));
end;
// save source
Result:=SaveStringToFile(SrcFilename,Src,[],lisPkgMangpackageMainSourceFile);
if Result<>mrOk then begin
DebugLn('TLazPackageGraph.SavePackageMainSource SaveStringToFile ',SrcFilename,' failed');
exit;
end;
Result:=mrOk;
end;
function TLazPackageGraph.GetBrokenDependenciesWhenChangingPkgID(
APackage: TLazPackage; const NewName: string; NewVersion: TPkgVersion
): TFPList;
@ -2250,7 +3064,8 @@ begin
// try defaultfilename
AFilename:=Dependency.DefaultFilename;
if (CompareFileExt(AFilename,'lpk')=0)
and (CompareText(ExtractFileNameOnly(AFilename),Dependency.PackageName)=0)
and (SysUtils.CompareText(
ExtractFileNameOnly(AFilename),Dependency.PackageName)=0)
then begin
if not FilenameIsAbsolute(AFilename) then begin
CurDir:=GetDependencyOwnerDirectory(Dependency);

View File

@ -51,7 +51,7 @@ uses
AVL_Tree, Laz_XMLCfg,
// IDE Interface
IDEExternToolIntf, NewItemIntf, ProjectIntf, PackageIntf, MenuIntf,
MacroIntf, LazIDEIntf,
IDEMsgIntf, MacroIntf, LazIDEIntf,
// IDE
LazConf, LazarusIDEStrConsts, IDEProcs, ObjectLists, DialogProcs, IDECommands,
EnvironmentOpts, MiscOptions, InputHistory, ProjectDefs, Project,
@ -62,17 +62,10 @@ uses
ProjectInspector, ComponentPalette, UnitEditor, AddFileToAPackageDlg,
LazarusPackageIntf, PublishProjectDlg, InstallPkgSetDlg,
// bosses
BasePkgManager,
BaseBuildManager, BasePkgManager,
MainBar, MainIntf, MainBase;
type
TPkgUninstallFlag = (
puifDoNotConfirm,
puifDoNotBuildIDE
);
TPkgUninstallFlags = set of TPkgUninstallFlag;
{ TPkgManager }
TPkgManager = class(TBasePkgManager)
@ -152,9 +145,9 @@ type
// misc
procedure GetDependencyOwnerDescription(Dependency: TPkgDependency;
var Description: string);
out Description: string);
procedure GetDependencyOwnerDirectory(Dependency: TPkgDependency;
var Directory: string);
out Directory: string);
procedure GetWritablePkgOutputDirectory(APackage: TLazPackage;
var AnOutDirectory: string);
procedure OnCheckInstallPackageList(PkgIDList: TFPList; var Ok: boolean);
@ -165,23 +158,9 @@ type
// helper functions
function DoShowSavePackageAsDialog(APackage: TLazPackage): TModalResult;
function DoWriteMakefile(APackage: TLazPackage): TModalResult;
function CompileRequiredPackages(APackage: TLazPackage;
FirstDependency: TPkgDependency;
Globals: TGlobalCompilerOptions;
Policies: TPackageUpdatePolicies): TModalResult;
function CheckPackageGraphForCompilation(APackage: TLazPackage;
FirstDependency: TPkgDependency;
const Directory: string): TModalResult;
function DoPreparePackageOutputDirectory(APackage: TLazPackage;
CleanUp: boolean): TModalResult;
function DoSavePackageCompiledState(APackage: TLazPackage;
const CompilerFilename, CompilerParams: string): TModalResult;
function DoLoadPackageCompiledState(APackage: TLazPackage;
IgnoreErrors: boolean): TModalResult;
function CheckIfPackageNeedsCompilation(APackage: TLazPackage;
const CompilerFilename, CompilerParams,
SrcFilename: string): TModalResult;
function CheckAmbiguousPackageUnits(APackage: TLazPackage): TModalResult;
function MacroFunctionPkgSrcPath(Data: Pointer): boolean;
function MacroFunctionPkgUnitPath(Data: Pointer): boolean;
function MacroFunctionPkgIncPath(Data: Pointer): boolean;
@ -282,11 +261,7 @@ type
Flags: TPkgCompileFlags): TModalResult; override;
function DoCompilePackage(APackage: TLazPackage; Flags: TPkgCompileFlags;
Globals: TGlobalCompilerOptions = nil): TModalResult; override;
function DoSavePackageMainSource(APackage: TLazPackage;
Flags: TPkgCompileFlags): TModalResult; override;
function DoCreatePackageMakefile(APackage: TLazPackage): TModalResult;
function DoCheckIfDependenciesNeedCompilation(DependencyOwner: TObject;
StateFileAge: longint): TModalResult; override;
// package installation
procedure LoadInstalledPackages; override;
@ -556,13 +531,13 @@ begin
end;
procedure TPkgManager.GetDependencyOwnerDescription(
Dependency: TPkgDependency; var Description: string);
Dependency: TPkgDependency; out Description: string);
begin
GetDescriptionOfDependencyOwner(Dependency,Description);
end;
procedure TPkgManager.GetDependencyOwnerDirectory(Dependency: TPkgDependency;
var Directory: string);
out Directory: string);
begin
GetDirectoryOfDependencyOwner(Dependency,Directory);
end;
@ -775,7 +750,7 @@ end;
function TPkgManager.OnPackageEditorDeleteAmbiguousFiles(Sender: TObject;
APackage: TLazPackage; const Filename: string): TModalResult;
begin
Result:=MainIDE.DoDeleteAmbiguousFiles(Filename);
Result:=BuildBoss.DeleteAmbiguousFiles(Filename);
end;
function TPkgManager.OnPackageEditorAddToProject(Sender: TObject;
@ -1248,7 +1223,7 @@ var
MakefileFPCFilename: String;
UnitOutputPath: String;
UnitPath: String;
FPCMakeTool: TExternalToolOptions;
FPCMakeTool: TIDEExternalToolOptions;
CodeBuffer: TCodeBuffer;
MainSrcFile: String;
CustomOptions: String;
@ -1339,11 +1314,11 @@ begin
CodeBuffer.Source:=s;
//debugln('TPkgManager.DoWriteMakefile MakefileFPCFilename="',MakefileFPCFilename,'"');
Result:=MainIDE.DoSaveCodeBufferToFile(CodeBuffer,MakefileFPCFilename,false);
Result:=SaveCodeBufferToFile(CodeBuffer,MakefileFPCFilename);
if Result<>mrOk then exit;
// call fpcmake to create the Makefile
FPCMakeTool:=TExternalToolOptions.Create;
FPCMakeTool:=TIDEExternalToolOptions.Create;
try
FPCMakeTool.Title:='Creating Makefile for package '+APackage.IDAsString;
FPCMakeTool.WorkingDirectory:=APackage.Directory;
@ -1357,7 +1332,7 @@ begin
SourceNotebook.ClearErrorLines;
// compile package
Result:=LazarusIDE.RunExternalTool(FPCMakeTool);
Result:=RunExternalTool(FPCMakeTool);
if Result<>mrOk then begin
Result:=IDEMessageDialog('fpcmake failed',
'Calling '+FPCMakeTool.Filename+' to create Makefile from '
@ -1373,39 +1348,6 @@ begin
Result:=mrOk;
end;
function TPkgManager.CompileRequiredPackages(APackage: TLazPackage;
FirstDependency: TPkgDependency; Globals: TGlobalCompilerOptions;
Policies: TPackageUpdatePolicies): TModalResult;
var
AutoPackages: TFPList;
i: Integer;
begin
{$IFDEF VerbosePkgCompile}
writeln('TPkgManager.CompileRequiredPackages A ');
{$ENDIF}
AutoPackages:=PackageGraph.GetAutoCompilationOrder(APackage,FirstDependency,
Policies);
if AutoPackages<>nil then begin
//DebugLn('TPkgManager.CompileRequiredPackages B Count=',IntToStr(AutoPackages.Count));
try
i:=0;
while i<AutoPackages.Count do begin
Result:=DoCompilePackage(TLazPackage(AutoPackages[i]),
[pcfDoNotCompileDependencies,pcfOnlyIfNeeded,
pcfDoNotSaveEditorFiles],Globals);
if Result<>mrOk then exit;
inc(i);
end;
finally
AutoPackages.Free;
end;
end;
{$IFDEF VerbosePkgCompile}
writeln('TPkgManager.CompileRequiredPackages END ');
{$ENDIF}
Result:=mrOk;
end;
function TPkgManager.CheckPackageGraphForCompilation(APackage: TLazPackage;
FirstDependency: TPkgDependency; const Directory: string): TModalResult;
var
@ -1514,380 +1456,6 @@ begin
Result:=mrOk;
end;
function TPkgManager.DoSavePackageCompiledState(APackage: TLazPackage;
const CompilerFilename, CompilerParams: string): TModalResult;
var
XMLConfig: TXMLConfig;
StateFile: String;
CompilerFileDate: Integer;
begin
StateFile:=APackage.GetStateFilename;
try
CompilerFileDate:=FileAge(CompilerFilename);
XMLConfig:=TXMLConfig.CreateClean(StateFile);
try
XMLConfig.SetValue('Compiler/Value',CompilerFilename);
XMLConfig.SetValue('Compiler/Date',CompilerFileDate);
XMLConfig.SetValue('Params/Value',CompilerParams);
InvalidateFileStateCache;
XMLConfig.Flush;
finally
XMLConfig.Free;
end;
APackage.LastCompilerFilename:=CompilerFilename;
APackage.LastCompilerFileDate:=CompilerFileDate;
APackage.LastCompilerParams:=CompilerParams;
APackage.StateFileDate:=FileAge(StateFile);
APackage.Flags:=APackage.Flags+[lpfStateFileLoaded];
except
on E: Exception do begin
Result:=IDEMessageDialog(lisPkgMangErrorWritingFile,
Format(lisPkgMangUnableToWriteStateFileOfPackageError, ['"', StateFile,
'"', #13, APackage.IDAsString, #13, E.Message]),
mtError,[mbAbort,mbCancel]);
exit;
end;
end;
Result:=MainIDE.DoDeleteAmbiguousFiles(StateFile);
if Result<>mrOk then exit;
end;
function TPkgManager.DoLoadPackageCompiledState(APackage: TLazPackage;
IgnoreErrors: boolean): TModalResult;
var
XMLConfig: TXMLConfig;
StateFile: String;
StateFileAge: Integer;
begin
StateFile:=APackage.GetStateFilename;
if not FileExists(StateFile) then begin
DebugLn('TPkgManager.DoLoadPackageCompiledState Statefile not found: ',StateFile);
APackage.Flags:=APackage.Flags-[lpfStateFileLoaded];
Result:=mrOk;
exit;
end;
// read the state file
StateFileAge:=FileAge(StateFile);
if (not (lpfStateFileLoaded in APackage.Flags))
or (APackage.StateFileDate<>StateFileAge) then begin
APackage.Flags:=APackage.Flags-[lpfStateFileLoaded];
try
XMLConfig:=TXMLConfig.Create(StateFile);
try
APackage.LastCompilerFilename:=XMLConfig.GetValue('Compiler/Value','');
APackage.LastCompilerFileDate:=XMLConfig.GetValue('Compiler/Date',0);
APackage.LastCompilerParams:=XMLConfig.GetValue('Params/Value','');
finally
XMLConfig.Free;
end;
APackage.StateFileDate:=StateFileAge;
except
on E: Exception do begin
if IgnoreErrors then begin
Result:=mrOk;
end else begin
Result:=IDEMessageDialog(lisPkgMangErrorReadingFile,
Format(lisPkgMangUnableToReadStateFileOfPackageError, ['"',
StateFile, '"', #13, APackage.IDAsString, #13, E.Message]),
mtError,[mbCancel,mbAbort]);
end;
exit;
end;
end;
APackage.Flags:=APackage.Flags+[lpfStateFileLoaded];
end;
Result:=mrOk;
end;
function TPkgManager.DoPreparePackageOutputDirectory(APackage: TLazPackage;
CleanUp: boolean): TModalResult;
var
OutputDir: String;
StateFile: String;
PkgSrcDir: String;
i: Integer;
CurFile: TPkgFile;
CompiledUnitExt: String;
FPCVersion, FPCRelease, FPCPatch: integer;
OutputFileName: String;
begin
OutputDir:=APackage.GetOutputDirectory;
StateFile:=APackage.GetStateFilename;
PkgSrcDir:=ExtractFilePath(APackage.GetSrcFilename);
// create the output directory
if not ForceDirectory(OutputDir) then begin
Result:=IDEMessageDialog(lisPkgMangUnableToCreateDirectory,
Format(lisPkgMangUnableToCreateOutputDirectoryForPackage, ['"',
OutputDir, '"', #13, APackage.IDAsString]),
mtError,[mbCancel,mbAbort]);
exit;
end;
// delete old Compile State file
if FileExists(StateFile) and not DeleteFile(StateFile) then begin
Result:=IDEMessageDialog(lisPkgMangUnableToDeleteFilename,
Format(lisPkgMangUnableToDeleteOldStateFileForPackage, ['"', StateFile,
'"', #13, APackage.IDAsString]),
mtError,[mbCancel,mbAbort]);
exit;
end;
APackage.Flags:=APackage.Flags-[lpfStateFileLoaded];
// create the package src directory
if not ForceDirectory(PkgSrcDir) then begin
Result:=IDEMessageDialog(lisPkgMangUnableToCreateDirectory,
Format(lisPkgMangUnableToCreatePackageSourceDirectoryForPackage, ['"',
PkgSrcDir, '"', #13, APackage.IDAsString]),
mtError,[mbCancel,mbAbort]);
exit;
end;
// clean up if wanted
if CleanUp then begin
CodeToolBoss.GetFPCVersionForDirectory(PkgSrcDir,
FPCVersion,FPCRelease,FPCPatch);
if FPCPatch=0 then ;
CompiledUnitExt:=GetDefaultCompiledUnitExt(FPCVersion,FPCRelease);
for i:=0 to APackage.FileCount-1 do begin
CurFile:=APackage.Files[i];
if not (CurFile.FileType in PkgFileUnitTypes) then continue;
OutputFileName:=AppendPathDelim(OutputDir)+CurFile.UnitName+CompiledUnitExt;
Result:=DeleteFileInteractive(OutputFileName,[mbIgnore,mbAbort]);
if Result in [mrCancel,mrAbort] then exit;
end;
end;
Result:=mrOk;
end;
function TPkgManager.CheckIfPackageNeedsCompilation(APackage: TLazPackage;
const CompilerFilename, CompilerParams, SrcFilename: string): TModalResult;
var
StateFilename: String;
StateFileAge: Integer;
i: Integer;
CurFile: TPkgFile;
begin
Result:=mrYes;
{$IFDEF VerbosePkgCompile}
writeln('TPkgManager.CheckIfPackageNeedsCompilation A ',APackage.IDAsString);
{$ENDIF}
// check state file
StateFilename:=APackage.GetStateFilename;
Result:=DoLoadPackageCompiledState(APackage,false);
if Result<>mrOk then exit;
if not (lpfStateFileLoaded in APackage.Flags) then begin
DebugLn('TPkgManager.CheckIfPackageNeedsCompilation No state file for ',APackage.IDAsString);
Result:=mrYes;
exit;
end;
StateFileAge:=FileAge(StateFilename);
// check main source file
if FileExists(SrcFilename) and (StateFileAge<FileAge(SrcFilename)) then
begin
DebugLn('TPkgManager.CheckIfPackageNeedsCompilation SrcFile outdated ',APackage.IDAsString);
Result:=mrYes;
exit;
end;
// check all required packages
Result:=DoCheckIfDependenciesNeedCompilation(APackage,StateFileAge);
if Result<>mrNo then exit;
Result:=mrYes;
// check compiler and params
if CompilerFilename<>APackage.LastCompilerFilename then begin
DebugLn('TPkgManager.CheckIfPackageNeedsCompilation Compiler filename changed for ',APackage.IDAsString);
DebugLn(' Old="',APackage.LastCompilerFilename,'"');
DebugLn(' Now="',CompilerFilename,'"');
exit;
end;
if not FileExists(CompilerFilename) then begin
DebugLn('TPkgManager.CheckIfPackageNeedsCompilation Compiler filename not found for ',APackage.IDAsString);
DebugLn(' File="',CompilerFilename,'"');
exit;
end;
if FileAge(CompilerFilename)<>APackage.LastCompilerFileDate then begin
DebugLn('TPkgManager.CheckIfPackageNeedsCompilation Compiler file changed for ',APackage.IDAsString);
DebugLn(' File="',CompilerFilename,'"');
exit;
end;
if CompilerParams<>APackage.LastCompilerParams then begin
DebugLn('TPkgManager.CheckIfPackageNeedsCompilation Compiler params changed for ',APackage.IDAsString);
DebugLn(' Old="',APackage.LastCompilerParams,'"');
DebugLn(' Now="',CompilerParams,'"');
exit;
end;
// check package files
if StateFileAge<FileAge(APackage.Filename) then begin
DebugLn('TPkgManager.CheckIfPackageNeedsCompilation StateFile older than lpk ',APackage.IDAsString);
exit;
end;
for i:=0 to APackage.FileCount-1 do begin
CurFile:=APackage.Files[i];
//writeln('TPkgManager.CheckIfPackageNeedsCompilation CurFile.Filename="',CurFile.Filename,'" ',FileExists(CurFile.Filename),' ',StateFileAge<FileAge(CurFile.Filename));
if FileExists(CurFile.Filename)
and (StateFileAge<FileAge(CurFile.Filename)) then begin
DebugLn('TPkgManager.CheckIfPackageNeedsCompilation Src has changed ',APackage.IDAsString,' ',CurFile.Filename);
exit;
end;
end;
{$IFDEF VerbosePkgCompile}
writeln('TPkgManager.CheckIfPackageNeedsCompilation END ',APackage.IDAsString);
{$ENDIF}
Result:=mrNo;
end;
function TPkgManager.DoCheckIfDependenciesNeedCompilation(
DependencyOwner: TObject; StateFileAge: longint): TModalResult;
function GetOwnerID: string;
begin
if DependencyOwner is TLazPackageID then
Result:=TLazPackageID(DependencyOwner).IDAsString
else if DependencyOwner is TProject then
Result:=TProject(DependencyOwner).IDAsString
else
Result:=dbgsName(DependencyOwner);
end;
var
Dependency: TPkgDependency;
RequiredPackage: TLazPackage;
OtherStateFile: String;
begin
if DependencyOwner is TLazPackage then
Dependency:=TLazPackage(DependencyOwner).FirstRequiredDependency
else if DependencyOwner is TProject then
Dependency:=TProject(DependencyOwner).FirstRequiredDependency
else begin
Result:=mrNo;
exit;
end;
while Dependency<>nil do begin
if (Dependency.LoadPackageResult=lprSuccess) then begin
RequiredPackage:=Dependency.RequiredPackage;
// check compile state file of required package
if not RequiredPackage.AutoCreated then begin
Result:=DoLoadPackageCompiledState(RequiredPackage,false);
if Result<>mrOk then exit;
Result:=mrYes;
if not (lpfStateFileLoaded in RequiredPackage.Flags) then begin
DebugLn('TPkgManager.CheckIfDependenciesNeedCompilation No state file for ',RequiredPackage.IDAsString);
exit;
end;
if StateFileAge<RequiredPackage.StateFileDate then begin
DebugLn('TPkgManager.CheckIfDependenciesNeedCompilation Required ',
RequiredPackage.IDAsString,' State file is newer than ',
'State file ',GetOwnerID);
exit;
end;
end;
// check output state file of required package
if RequiredPackage.OutputStateFile<>'' then begin
OtherStateFile:=RequiredPackage.OutputStateFile;
IDEMacros.SubstituteMacros(OtherStateFile);
if FileExists(OtherStateFile)
and (FileAge(OtherStateFile)>StateFileAge) then begin
DebugLn('TPkgManager.CheckIfDependenciesNeedCompilation Required ',
RequiredPackage.IDAsString,' OtherState file "',OtherStateFile,'"'
,' is newer than State file ',GetOwnerID);
Result:=mrYes;
exit;
end;
end;
end;
Dependency:=Dependency.NextRequiresDependency;
end;
Result:=mrNo;
end;
function TPkgManager.CheckAmbiguousPackageUnits(APackage: TLazPackage
): TModalResult;
var
i: Integer;
CurFile: TPkgFile;
CurUnitName: String;
SrcDirs: String;
PkgDir: String;
PkgOutputDir: String;
YesToAll: Boolean;
function CheckFile(const ShortFilename: string): TModalResult;
var
AmbiguousFilename: String;
SearchFlags: TSearchFileInPathFlags;
begin
Result:=mrOk;
SearchFlags:=[];
if CompareFilenames(PkgDir,PkgOutputDir)=0 then
Include(SearchFlags,sffDontSearchInBasePath);
repeat
AmbiguousFilename:=SearchFileInPath(ShortFilename,PkgDir,SrcDirs,';',
SearchFlags);
if (AmbiguousFilename='') then exit;
if not YesToAll then
Result:=IDEMessageDialog(lisAmbiguousUnitFound,
Format(lisTheFileWasFoundInOneOfTheSourceDirectoriesOfThePac, ['"',
AmbiguousFilename, '"', #13, APackage.IDAsString, #13, #13]),
mtWarning,[mbYes,mbYesToAll,mbNo,mbAbort])
else
Result:=mrYesToAll;
if Result=mrNo then
Result:=mrOk;
if Result in [mrYes,mrYesToAll] then begin
YesToAll:=Result=mrYesToAll;
if (not DeleteFile(AmbiguousFilename))
and (IDEMessageDialog(lisPkgMangDeleteFailed, Format(lisDeletingOfFileFailed,
['"', AmbiguousFilename, '"']), mtError, [mbIgnore, mbCancel])
<>mrIgnore) then
begin
Result:=mrCancel;
exit;
end;
Result:=mrOk;
end else
break;
until false;
end;
begin
Result:=mrOk;
YesToAll:=False;
// search in every source directory for compiled versions of the units
// A source directory is a directory with a used unit and it is not the output
// directory
SrcDirs:=APackage.GetSourceDirs(true,true);
PkgOutputDir:=AppendPathDelim(APackage.GetOutputDirectory);
SrcDirs:=RemoveSearchPaths(SrcDirs,PkgOutputDir);
if SrcDirs='' then exit;
PkgDir:=AppendPathDelim(APackage.Directory);
for i:=0 to APackage.FileCount-1 do begin
CurFile:=APackage.Files[i];
if CurFile.FileType<>pftUnit then continue;
CurUnitName:=lowercase(CurFile.UnitName);
if CurUnitName='' then continue;
Result:=CheckFile(CurUnitName+'.ppu');
if Result<>mrOk then exit;
Result:=CheckFile(CurUnitName+'.ppw');
if Result<>mrOk then exit;
Result:=CheckFile(CurUnitName+'.ppl');
if Result<>mrOk then exit;
end;
Result:=mrOk;
end;
function TPkgManager.MacroFunctionPkgSrcPath(Data: Pointer): boolean;
var
FuncData: PReadFunctionData;
@ -2192,6 +1760,9 @@ begin
PackageGraph.OnDependencyModified:=@PackageGraphDependencyModified;
PackageGraph.OnBeginUpdate:=@PackageGraphBeginUpdate;
PackageGraph.OnEndUpdate:=@PackageGraphEndUpdate;
PackageGraph.OnDeleteAmbiguousFiles:=@BuildBoss.DeleteAmbiguousFiles;
PackageGraph.OnWriteMakeFile:=@DoWriteMakefile;
PackageGraph.OnUninstallPackage:=@DoUninstallPackage;
// package editors
PackageEditors:=TPackageEditors.Create;
@ -2721,11 +2292,11 @@ begin
end;
// backup old file
Result:=MainIDE.DoBackupFile(APackage.Filename,true);
Result:=BuildBoss.BackupFile(APackage.Filename);
if Result=mrAbort then exit;
// delete ambiguous files
Result:=MainIDE.DoDeleteAmbiguousFiles(APackage.Filename);
Result:=BuildBoss.DeleteAmbiguousFiles(APackage.Filename);
if Result=mrAbort then exit;
// save
@ -2855,7 +2426,8 @@ begin
try
// automatically compile required packages
if not (pcfDoNotCompileDependencies in Flags) then begin
Result:=CompileRequiredPackages(nil,AProject.FirstRequiredDependency,
Result:=PackageGraph.CompileRequiredPackages(nil,
AProject.FirstRequiredDependency,
AProject.CompilerOptions.Globals,
[pupAsNeeded]);
if Result<>mrOk then exit;
@ -2869,13 +2441,6 @@ end;
function TPkgManager.DoCompilePackage(APackage: TLazPackage;
Flags: TPkgCompileFlags; Globals: TGlobalCompilerOptions): TModalResult;
var
PkgCompileTool: TExternalToolOptions;
CompilerFilename: String;
CompilerParams: String;
EffektiveCompilerParams: String;
SrcFilename: String;
CompilePolicies: TPackageUpdatePolicies;
begin
Result:=mrCancel;
@ -2904,330 +2469,7 @@ begin
Result:=WarnAboutMissingPackageFiles(APackage);
if Result<>mrOk then exit;
PackageGraph.BeginUpdate(false);
try
// automatically compile required packages
if not (pcfDoNotCompileDependencies in Flags) then begin
CompilePolicies:=[pupAsNeeded];
if pcfCompileDependenciesClean in Flags then
Include(CompilePolicies,pupOnRebuildingAll);
Result:=CompileRequiredPackages(APackage,nil,Globals,CompilePolicies);
if Result<>mrOk then exit;
end;
SrcFilename:=APackage.GetSrcFilename;
CompilerFilename:=APackage.GetCompilerFilename;
CompilerParams:=APackage.CompilerOptions.MakeOptionsString(Globals,
APackage.CompilerOptions.DefaultMakeOptionsFlags)
+' '+CreateRelativePath(SrcFilename,APackage.Directory);
// check if compilation is neccessary
if (pcfOnlyIfNeeded in Flags) then begin
Result:=CheckIfPackageNeedsCompilation(APackage,
CompilerFilename,CompilerParams,
SrcFilename);
if Result=mrNo then begin
Result:=mrOk;
exit;
end;
if Result<>mrYes then exit;
end;
// auto increase version
// ToDo
MessagesView.BeginBlock;
try
Result:=DoPreparePackageOutputDirectory(APackage,pcfCleanCompile in Flags);
if Result<>mrOk then begin
DebugLn('TPkgManager.DoCompilePackage DoPreparePackageOutputDirectory failed');
exit;
end;
// create package main source file
Result:=DoSavePackageMainSource(APackage,Flags);
if Result<>mrOk then begin
DebugLn('TPkgManager.DoCompilePackage DoSavePackageMainSource failed');
exit;
end;
// check ambiguous units
Result:=CheckAmbiguousPackageUnits(APackage);
if Result<>mrOk then begin
DebugLn('TPkgManager.DoCompilePackage CheckAmbiguousPackageUnits failed');
exit;
end;
// create Makefile
if (pcfCreateMakefile in Flags)
or (APackage.CompilerOptions.CreateMakefileOnBuild) then begin
Result:=DoWriteMakefile(APackage);
if Result<>mrOk then begin
DebugLn('TPkgManager.DoCompilePackage DoWriteMakefile failed');
exit;
end;
end;
// run compilation tool 'Before'
if not (pcfDoNotCompilePackage in Flags) then begin
Result:=MainIDE.DoExecuteCompilationTool(
APackage.CompilerOptions.ExecuteBefore,
APackage.Directory,'Executing command before');
if Result<>mrOk then exit;
end;
// create external tool to run the compiler
DebugLn('TPkgManager.DoCompilePackage Compiler="',CompilerFilename,'"');
DebugLn('TPkgManager.DoCompilePackage Params="',CompilerParams,'"');
DebugLn('TPkgManager.DoCompilePackage WorkingDir="',APackage.Directory,'"');
if (not APackage.CompilerOptions.SkipCompiler)
and (not (pcfDoNotCompilePackage in Flags)) then begin
// check compiler filename
try
CheckIfFileIsExecutable(CompilerFilename);
except
on e: Exception do begin
Result:=IDEMessageDialog(lisPkgManginvalidCompilerFilename,
Format(lisPkgMangTheCompilerFileForPackageIsNotAValidExecutable, [
APackage.IDAsString, #13, E.Message]),
mtError,[mbCancel,mbAbort]);
exit;
end;
end;
// change compiler parameters for compiling clean
EffektiveCompilerParams:=CompilerParams;
if pcfCleanCompile in Flags then begin
if EffektiveCompilerParams<>'' then
EffektiveCompilerParams:='-B '+EffektiveCompilerParams
else
EffektiveCompilerParams:='-B';
end;
PkgCompileTool:=TExternalToolOptions.Create;
try
PkgCompileTool.Title:='Compiling package '+APackage.IDAsString;
PkgCompileTool.ScanOutputForFPCMessages:=true;
PkgCompileTool.ScanOutputForMakeMessages:=true;
PkgCompileTool.WorkingDirectory:=APackage.Directory;
PkgCompileTool.Filename:=CompilerFilename;
PkgCompileTool.CmdLineParams:=EffektiveCompilerParams;
// clear old errors
SourceNotebook.ClearErrorLines;
// compile package
Result:=EnvironmentOptions.ExternalTools.Run(PkgCompileTool,
GlobalMacroList,nil,APackage.CompilerOptions);
if Result<>mrOk then exit;
// compilation succeded -> write state file
Result:=DoSavePackageCompiledState(APackage,
CompilerFilename,CompilerParams);
if Result<>mrOk then exit;
finally
// clean up
PkgCompileTool.Free;
end;
end;
// run compilation tool 'After'
if not (pcfDoNotCompilePackage in Flags) then begin
Result:=MainIDE.DoExecuteCompilationTool(
APackage.CompilerOptions.ExecuteAfter,
APackage.Directory,'Executing command after');
if Result<>mrOk then exit;
end;
finally
MessagesView.EndBlock;
if Result<>mrOk then begin
if (APackage.AutoInstall<>pitNope) and (APackage.Installed=pitNope) then
begin
// package was tried to install, but failed
// -> ask user if the package should be removed from the installation
// list
if IDEMessageDialog(lisInstallationFailed,
Format(
lisPkgMangThePackageFailedToCompileRemoveItFromTheInstallati, [
'"', APackage.IDAsString, '"', #13]), mtConfirmation,
[mbYes,mbIgnore])=mrYes then
begin
DoUninstallPackage(APackage,[puifDoNotConfirm,puifDoNotBuildIDE]);
end;
end;
end;
end;
finally
if not (pcfDoNotSaveEditorFiles in Flags) then begin
// check for changed files on disk
MainIDE.DoCheckFilesOnDisk;
end;
PackageGraph.EndUpdate;
end;
Result:=mrOk;
end;
function TPkgManager.DoSavePackageMainSource(APackage: TLazPackage;
Flags: TPkgCompileFlags): TModalResult;
var
SrcFilename: String;
UsedUnits: String;
Src: String;
i: Integer;
e: String;
CurFile: TPkgFile;
CodeBuffer: TCodeBuffer;
CurUnitName: String;
RegistrationCode: String;
HeaderSrc: String;
OutputDir: String;
OldShortenSrc: String;
NeedsRegisterProcCall: boolean;
CurSrcUnitName: String;
NewShortenSrc: String;
begin
{$IFDEF VerbosePkgCompile}
writeln('TPkgManager.DoSavePackageMainSource A');
{$ENDIF}
// check if package is ready for saving
OutputDir:=APackage.GetOutputDirectory;
if not DirPathExists(OutputDir) then begin
Result:=IDEMessageDialog(lisEnvOptDlgDirectoryNotFound,
Format(lisPkgMangPackageHasNoValidOutputDirectory, ['"',
APackage.IDAsString, '"', #13, '"', OutputDir, '"']),
mtError,[mbCancel,mbAbort]);
exit;
end;
SrcFilename:=APackage.GetSrcFilename;
// delete ambiguous files
Result:=MainIDE.DoDeleteAmbiguousFiles(SrcFilename);
if Result=mrAbort then begin
DebugLn('TPkgManager.DoSavePackageMainSource DoDeleteAmbiguousFiles failed');
exit;
end;
// collect unitnames
e:=LineEnding;
UsedUnits:='';
RegistrationCode:='';
for i:=0 to APackage.FileCount-1 do begin
CurFile:=APackage.Files[i];
// update unitname
if FilenameIsPascalUnit(CurFile.Filename)
and (CurFile.FileType in PkgFileUnitTypes) then begin
CurUnitName:=ExtractFileNameOnly(CurFile.Filename);
if CurUnitName=lowercase(CurUnitName) then begin
// the filename is all lowercase, so we can use the nicer unitname from
// the source.
CodeBuffer:=CodeToolBoss.LoadFile(CurFile.Filename,false,false);
if CodeBuffer<>nil then begin
// if the unit is edited, the unitname is probably already cached
CurSrcUnitName:=CodeToolBoss.GetCachedSourceName(CodeBuffer);
// if not then parse it
if SysUtils.CompareText(CurSrcUnitName,CurUnitName)<>0 then
CurSrcUnitName:=CodeToolBoss.GetSourceName(CodeBuffer,false);
// if it makes sense, update unitname
if SysUtils.CompareText(CurSrcUnitName,CurFile.UnitName)=0 then
CurFile.UnitName:=CurSrcUnitName;
end;
if SysUtils.CompareText(CurUnitName,CurFile.UnitName)=0 then
CurUnitName:=CurFile.UnitName
else
CurFile.UnitName:=CurUnitName;
end;
if (CurUnitName<>'') and IsValidIdent(CurUnitName) then begin
NeedsRegisterProcCall:=CurFile.HasRegisterProc
and (APackage.PackageType in [lptDesignTime,lptRunAndDesignTime]);
if NeedsRegisterProcCall or CurFile.AddToUsesPkgSection then begin
if UsedUnits<>'' then
UsedUnits:=UsedUnits+', ';
UsedUnits:=UsedUnits+CurUnitName;
end;
if NeedsRegisterProcCall then begin
RegistrationCode:=RegistrationCode+
' RegisterUnit('''+CurUnitName+''',@'+CurUnitName+'.Register);'+e;
end;
end else begin
MessagesView.AddMsg('WARNING: unit name invalid '+CurFile.Filename
+', package='+APackage.IDAsString,
APackage.Directory,-1);
end;
end;
end;
// append registration code only for design time packages
if (APackage.PackageType in [lptDesignTime,lptRunAndDesignTime]) then begin
RegistrationCode:=
'procedure Register;'+e
+'begin'+e
+RegistrationCode
+'end;'+e
+e
+'initialization'+e
+' RegisterPackage('''+APackage.Name+''',@Register);'
+e;
if UsedUnits<>'' then UsedUnits:=UsedUnits+', ';
UsedUnits:=UsedUnits+'LazarusPackageIntf';
end;
// create source
HeaderSrc:=lisPkgMangThisSourceIsOnlyUsedToCompileAndInstallThePackage;
HeaderSrc:= '{ '
+lisPkgMangThisFileWasAutomaticallyCreatedByLazarusDoNotEdit+e
+lisPkgMangThisSourceIsOnlyUsedToCompileAndInstallThePackage+e
+' }'+e+e;
Src:='unit '+APackage.Name+';'+e
+e
+'interface'+e
+e;
if UsedUnits<>'' then
Src:=Src
+'uses'+e
+' '+UsedUnits+';'+e
+e;
Src:=Src
+'implementation'+e
+e
+RegistrationCode
+'end.'+e;
Src:=CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.
BeautifyStatement(Src,0);
Src:=HeaderSrc+Src;
// check if old code is already uptodate
Result:=LoadCodeBuffer(CodeBuffer,SrcFilename,[lbfQuiet,lbfCheckIfText,
lbfUpdateFromDisk,lbfCreateClearOnError]);
if Result<>mrOk then begin
DebugLn('TPkgManager.DoSavePackageMainSource LoadCodeBuffer ',SrcFilename,' failed');
exit;
end;
OldShortenSrc:=CodeToolBoss.ExtractCodeWithoutComments(CodeBuffer);
NewShortenSrc:=CleanCodeFromComments(Src,
CodeToolBoss.GetNestedCommentsFlagForFile(CodeBuffer.Filename));
if CompareTextIgnoringSpace(OldShortenSrc,NewShortenSrc,true)=0 then begin
Result:=mrOk;
exit;
end;
if OldShortenSrc<>NewShortenSrc then begin
DebugLn('TPkgManager.DoSavePackageMainSource Src changed ',dbgs(length(OldShortenSrc)),' ',dbgs(length(NewShortenSrc)));
end;
// save source
Result:=MainIDE.DoSaveStringToFile(SrcFilename, Src,
lisPkgMangpackageMainSourceFile);
if Result<>mrOk then begin
DebugLn('TPkgManager.DoSavePackageMainSource DoSaveStringToFile ',SrcFilename,' failed');
exit;
end;
Result:=mrOk;
Result:=PackageGraph.CompilePackage(APackage,Flags,Globals);
end;
function TPkgManager.DoCreatePackageMakefile(APackage: TLazPackage
@ -4081,7 +3323,7 @@ begin
end;
// compile all auto install dependencies
Result:=CompileRequiredPackages(nil,FirstAutoInstallDependency,
Result:=PackageGraph.CompileRequiredPackages(nil,FirstAutoInstallDependency,
MiscellaneousOptions.BuildLazOpts.Globals,[pupAsNeeded]);
if Result<>mrOk then exit;
@ -4110,8 +3352,8 @@ begin
Dependency:=Dependency.NextRequiresDependency;
end;
StaticPckIncludeFile:=ConfigDir+'staticpackages.inc';
Result:=MainIDE.DoSaveStringToFile(StaticPckIncludeFile,StaticPackagesInc,
lisPkgMangstaticPackagesConfigFile);
Result:=SaveStringToFile(StaticPckIncludeFile,StaticPackagesInc,[],
lisPkgMangstaticPackagesConfigFile);
if Result<>mrOk then exit;
TargetDir:=MiscellaneousOptions.BuildLazOpts.TargetDirectory;