diff --git a/ide/buildlazdialog.pas b/ide/buildlazdialog.pas
index 017063dc21..f0a4c130f9 100644
--- a/ide/buildlazdialog.pas
+++ b/ide/buildlazdialog.pas
@@ -200,8 +200,10 @@ type
function ShowConfigBuildLazDlg(AProfiles: TBuildLazarusProfiles;
ADisableCompilation: Boolean): TModalResult;
function MakeLazarus(Profile: TBuildLazarusProfile; Flags: TBuildLazarusFlags): TModalResult;
+ function MakeIDEUsingLazbuild(Clean: boolean): TModalResult;
function IsWriteProtected(Profile: TBuildLazarusProfile): Boolean;
function SaveIDEMakeOptions(Profile: TBuildLazarusProfile; Flags: TBuildLazarusFlags): TModalResult;
+ function SearchMakeExe(Interactive: boolean): string;
public
property PackageOptions: string read fPackageOptions write fPackageOptions;
property ProfileChanged: boolean read fProfileChanged write fProfileChanged;
@@ -455,18 +457,7 @@ begin
if s<>'' then
EnvironmentOverrides.Values['PP']:=s;
- Executable:=EnvironmentOptions.GetParsedMakeFilename;
- if (Executable<>'') and (not FileExistsUTF8(Executable)) then
- Executable:=FindDefaultExecutablePath(Executable);
- if (Executable='') or (not FileExistsUTF8(Executable)) then begin
- Executable:=FindDefaultMakePath;
- if (Executable='') or (not FileExistsUTF8(Executable)) then begin
- IDEMessageDialog(lisMakeNotFound,
- Format(lisTheProgramMakeWasNotFoundThisToolIsNeededToBuildLa, [LineEnding]),
- mtError, [mbCancel]);
- exit;
- end;
- end;
+ Executable:=SearchMakeExe(true);
// add -w option to print leaving/entering messages of "make"
AddCmdLineParam('-w',false);
@@ -564,6 +555,99 @@ begin
end;
end;
+function TLazarusBuilder.MakeIDEUsingLazbuild(Clean: boolean): TModalResult;
+var
+ s, MakeExe, LazbuildExe: String;
+ Tool: TAbstractExternalTool;
+ EnvironmentOverrides: TStringList;
+begin
+ Result:=mrCancel;
+
+ EnvironmentOverrides:=TStringList.Create;
+ try
+ EnvironmentOverrides.Values['LANG']:= 'en_US';
+ s:=EnvironmentOptions.GetParsedCompilerFilename;
+ if s<>'' then
+ EnvironmentOverrides.Values['PP']:=s;
+
+ MakeExe:=SearchMakeExe(true);
+ fWorkingDir:=EnvironmentOptions.GetParsedLazarusDirectory;
+ if not CheckDirectoryWritable(fWorkingDir) then
+ exit;
+
+ // clean up
+ if Clean then
+ begin
+ Tool:=ExternalToolList.Add('make distclean');
+ Tool.Reference(Self,ClassName);
+ try
+ Tool.Data:=TIDEExternalToolData.Create(IDEToolCompileIDE,'make distclean',
+ MakeExe);
+ Tool.FreeData:=true;
+ Tool.Process.Executable:=MakeExe;
+ Tool.Process.Parameters.Add('distclean');
+ Tool.Process.CurrentDirectory:=fWorkingDir;
+ Tool.AddParsers(SubToolMake);
+ Tool.EnvironmentOverrides:=EnvironmentOverrides;
+ Tool.Execute;
+ Tool.WaitForExit;
+ if Tool.ErrorMessage<>'' then
+ exit(mrCancel);
+ finally
+ Tool.Release(Self);
+ end;
+ end;
+
+ // build lazbuild
+ Tool:=ExternalToolList.Add('make lazbuild');
+ Tool.Reference(Self,ClassName);
+ try
+ Tool.Data:=TIDEExternalToolData.Create(IDEToolCompileIDE,'make lazbuild',
+ MakeExe);
+ Tool.FreeData:=true;
+ Tool.Process.Executable:=MakeExe;
+ Tool.Process.Parameters.Add('lazbuild');
+ Tool.AddParsers(SubToolFPC);
+ Tool.AddParsers(SubToolMake);
+ Tool.Process.CurrentDirectory:=fWorkingDir;
+ Tool.EnvironmentOverrides:=EnvironmentOverrides;
+ Tool.Execute;
+ Tool.WaitForExit;
+ if Tool.ErrorMessage<>'' then
+ exit(mrCancel);
+ finally
+ Tool.Release(Self);
+ end;
+
+ // build the IDE using lazbuild
+ LazbuildExe:=AppendPathDelim(fWorkingDir)+'lazbuild'+GetExeExt;
+ Tool:=ExternalToolList.Add('lazbuild --useride=');
+ Tool.Reference(Self,ClassName);
+ try
+ Tool.Data:=TIDEExternalToolData.Create(IDEToolCompileIDE,'lazbuild --user-ide=',
+ MakeExe);
+ Tool.FreeData:=true;
+ Tool.Process.Executable:=LazbuildExe;
+ Tool.Process.Parameters.Add('--user-ide=');
+ Tool.Process.Parameters.Add('--lazarusdir=.');
+ Tool.Process.Parameters.Add('--pcp='+GetPrimaryConfigPath);
+ Tool.AddParsers(SubToolFPC);
+ Tool.AddParsers(SubToolMake);
+ Tool.Process.CurrentDirectory:=fWorkingDir;
+ Tool.EnvironmentOverrides:=EnvironmentOverrides;
+ Tool.Execute;
+ Tool.WaitForExit;
+ if Tool.ErrorMessage<>'' then
+ exit(mrCancel);
+ finally
+ Tool.Release(Self);
+ end;
+
+ finally
+ EnvironmentOverrides.Free;
+ end;
+end;
+
procedure TLazarusBuilder.SpecialIdeConfig;
var
MakeIDECfgFilename: string;
@@ -998,6 +1082,25 @@ begin
Result:=mrOk;
end;
+function TLazarusBuilder.SearchMakeExe(Interactive: boolean): string;
+begin
+ Result:=EnvironmentOptions.GetParsedMakeFilename;
+ if (Result<>'') and (not FileExistsUTF8(Result)) then
+ Result:=FindDefaultExecutablePath(Result);
+ if (Result='') or (not FileExistsUTF8(Result)) then begin
+ Result:=FindDefaultMakePath;
+ if (Result='') or (not FileExistsUTF8(Result)) then begin
+ Result:='';
+ if not Interactive then
+ exit;
+ IDEMessageDialog(lisMakeNotFound,
+ Format(lisTheProgramMakeWasNotFoundThisToolIsNeededToBuildLa, [LineEnding]),
+ mtError, [mbCancel]);
+ exit;
+ end;
+ end;
+end;
+
{ TConfigureBuildLazarusDlg }
constructor TConfigureBuildLazarusDlg.Create(TheOwner: TComponent);
diff --git a/ide/lazarus.lpi b/ide/lazarus.lpi
index 6dffcbf4b9..ed80aff64d 100644
--- a/ide/lazarus.lpi
+++ b/ide/lazarus.lpi
@@ -609,6 +609,7 @@
+
diff --git a/ide/main.pp b/ide/main.pp
index 0d4b5d3efb..b176f4cea9 100644
--- a/ide/main.pp
+++ b/ide/main.pp
@@ -7837,6 +7837,10 @@ var
PkgCompileFlags: TPkgCompileFlags;
OldToolStatus: TIDEToolStatus;
CompilerKind: TPascalCompiler;
+ {$IFDEF EnableBuildIDEUsingLazbuild}
+ ErrMsg: String;
+ r: integer;
+ {$ENDIF}
begin
if ToolStatus<>itNone then begin
IDEMessageDialog(lisNotNow,lisYouCanNotBuildLazarusWhileDebuggingOrCompiling,
@@ -7883,7 +7887,27 @@ begin
end;
MainBuildBoss.SetBuildTargetIDE;
- PackageGraph.ParseBasePackages;
+ {$IFDEF EnableBuildIDEUsingLazbuild}
+ ErrMsg:=PackageGraph.SrcBasePackagesNeedLazbuild;
+ if ErrMsg<>'' then
+ begin
+ r:=IDEQuestionDialog('Major changes detected',
+ 'The Lazarus sources use a different list of base packages.'+LineEnding
+ +'It is recommended to compile the IDE clean using lazbuild.',
+ mtConfirmation,[mrYes,'Clean up + lazbuild',21,'No clean up + lazbuild',mrIgnore,'Compile normally',mrCancel]);
+ case r of
+ mrYes:
+ exit(fBuilder.MakeIDEUsingLazbuild(true));
+ 21:
+ exit(fBuilder.MakeIDEUsingLazbuild(false));
+ mrIgnore: ;
+ else
+ exit;
+ end;
+ end;
+ {$ELSE}
+ PackageGraph.ParseBasePackages(false);
+ {$ENDIF}
// clean up
PkgCompileFlags:=[];
diff --git a/packager/installpkgsetdlg.pas b/packager/installpkgsetdlg.pas
index e43437de59..ca010b65db 100644
--- a/packager/installpkgsetdlg.pas
+++ b/packager/installpkgsetdlg.pas
@@ -1155,7 +1155,7 @@ procedure TInstallPkgSetDialog.AddToUninstall;
APackage:=PackageGraph.FindPackageWithID(aPackageID);
if APackage<>nil then begin
// check if package is a base package
- if PackageGraph.IsStaticBasePackage(APackage.Name) then begin
+ if PackageGraph.IsCompiledInBasePackage(APackage.Name) then begin
MessageDlg(lisUninstallImpossible,
Format(lisThePackageCanNotBeUninstalledBecauseItIsNeededByTh, [
APackage.Name]), mtError, [mbCancel], 0);
diff --git a/packager/lpkcache.pas b/packager/lpkcache.pas
index f9d12bf616..bd7120a93b 100644
--- a/packager/lpkcache.pas
+++ b/packager/lpkcache.pas
@@ -242,7 +242,7 @@ begin
Info.LPKFilename:=CurFilename;
Info.InLazSrc:=FileIsInPath(Info.LPKFilename,
EnvironmentOptions.GetParsedLazarusDirectory);
- Info.Base:=Info.InLazSrc and PackageGraph.IsStaticBasePackage(Info.ID.Name);
+ Info.Base:=Info.InLazSrc and PackageGraph.IsCompiledInBasePackage(Info.ID.Name);
Pkg:=PackageGraph.FindPackageWithFilename(Info.LPKFilename);
if Pkg<>nil then
Info.Installed:=Pkg.Installed;
diff --git a/packager/packagesystem.pas b/packager/packagesystem.pas
index fd11377332..26431f4ff7 100644
--- a/packager/packagesystem.pas
+++ b/packager/packagesystem.pas
@@ -430,14 +430,15 @@ type
public
// installed packages
FirstAutoInstallDependency: TPkgDependency;
- function ParseBasePackages: boolean; // read list from current sources
+ function ParseBasePackages(Verbose: boolean): boolean; // read list from current sources
+ function SrcBasePackagesNeedLazbuild: string; // check if compiled-in and source base pkg list differ that a built using make is needed
procedure LoadStaticBasePackages;
procedure LoadAutoInstallPackages(PkgList: TStringList);
procedure SortAutoInstallDependencies;
function GetIDEInstallPackageOptions(
var InheritedOptionStrings: TInheritedCompOptsStrings): string;
function SaveAutoInstallConfig: TModalResult;// for the uses section
- function IsStaticBasePackage(PackageName: string): boolean;
+ function IsCompiledInBasePackage(PackageName: string): boolean;
procedure FreeAutoInstallDependencies;
public
// registration
@@ -476,6 +477,7 @@ type
property Verbosity: TPkgVerbosityFlags read FVerbosity write FVerbosity;
// base packages
+ property SrcBasePackages: TStringListUTF8Fast read FSrcBasePackages;
property FCLPackage: TLazPackage read FFCLPackage;
property LCLBasePackage: TLazPackage read FLCLBasePackage;
property LCLPackage: TLazPackage read FLCLPackage;
@@ -2123,7 +2125,7 @@ begin
FTree.Add(APackage);
FItems.Add(APackage);
- if IsStaticBasePackage(APackage.Name) then begin
+ if IsCompiledInBasePackage(APackage.Name) then begin
APackage.Installed:=pitStatic;
APackage.AutoInstall:=pitStatic;
if SysUtils.CompareText(APackage.Name,'FCL')=0 then begin
@@ -2375,7 +2377,7 @@ begin
APackage:=TLazPackage(PkgList[i]);
if (APackage=nil)
or APackage.Missing
- or IsStaticBasePackage(APackage.Name)
+ or IsCompiledInBasePackage(APackage.Name)
or (APackage.PackageType in [lptRunTime,lptRunTimeOnly])
then continue;
@@ -2398,7 +2400,7 @@ begin
lisPkgMangstaticPackagesConfigFile);
end;
-function TLazPackageGraph.IsStaticBasePackage(PackageName: string): boolean;
+function TLazPackageGraph.IsCompiledInBasePackage(PackageName: string): boolean;
var
bp: TLazarusIDEBasePkg;
begin
@@ -5119,18 +5121,34 @@ begin
Result:=mrOk;
end;
-function TLazPackageGraph.ParseBasePackages: boolean;
+function TLazPackageGraph.ParseBasePackages(Verbose: boolean): boolean;
var
LazDir, SrcFilename, Atom, PkgName: String;
Code: TCodeBuffer;
p, AtomStart: integer;
begin
+ Result:=false;
LazDir:=EnvironmentOptions.GetParsedLazarusDirectory;
- if LazDir='' then exit;
+ if (LazDir='') or not FilenameIsPascalSource(LazDir) then
+ begin
+ if Verbose then
+ debugln(['Error: (lazarus) TLazPackageGraph.ParseBasePackages missing LazarusDir "',LazDir,'"']);
+ exit;
+ end;
SrcFilename:=AppendPathDelim(LazDir)+'packager'+PathDelim+'pkgsysbasepkgs.pas';
- if not FileExistsCached(SrcFilename) then exit;
+ if not FileExistsCached(SrcFilename) then
+ begin
+ if Verbose then
+ debugln(['Error: (lazarus) TLazPackageGraph.ParseBasePackages file not found: "',SrcFilename,'"']);
+ exit;
+ end;
Code:=CodeToolBoss.LoadFile(SrcFilename,true,false);
- if Code=nil then exit;
+ if Code=nil then
+ begin
+ if Verbose then
+ debugln(['Error: (lazarus) TLazPackageGraph.ParseBasePackages failed to load "',SrcFilename,'"']);
+ exit;
+ end;
if (FSrcBasePackagesFilename=SrcFilename)
and (FSrcBasePackagesFileChangeStep=Code.FileChangeStep) then
exit(true); // cache valid
@@ -5140,7 +5158,11 @@ begin
FSrcBasePackages.Clear;
if SearchCodeInSource(Code.Source,'LazarusIDEBasePkgNames:',1,p,false)<1 then
+ begin
+ if Verbose then
+ debugln(['Error: (lazarus) TLazPackageGraph.ParseBasePackages failed to find LazarusIDEBasePkgNames in "',SrcFilename,'"']);
exit;
+ end;
AtomStart:=p;
repeat
Atom:=ReadNextPascalAtom(Code.Source,p,AtomStart);
@@ -5152,6 +5174,51 @@ begin
FSrcBasePackages.Add(PkgName);
end;
until false;
+ Result:=true;
+end;
+
+function TLazPackageGraph.SrcBasePackagesNeedLazbuild: string;
+var
+ i: Integer;
+ PkgName, aFilename: String;
+ bp: TLazarusIDEBasePkg;
+ Pkg: TLazPackage;
+begin
+ Result:='';
+ if not ParseBasePackages(true) then
+ exit('Unable to parse base package list.');
+
+ // check if all source base packages will be installed
+ for i:=0 to FSrcBasePackages.Count-1 do
+ begin
+ PkgName:=FSrcBasePackages[i];
+ if IsCompiledInBasePackage(PkgName) then
+ continue;
+ // new base package
+ if FindDependencyByNameInList(FirstAutoInstallDependency,pddRequires,PkgName)<>nil
+ then
+ exit; // it will be installed anyway -> ok
+ // the sources need a base package, that this IDE will not install
+ // -> better use lazbuild for building
+ exit('Sources need a new base package "'+PkgName+'"');
+ end;
+
+ // check if all compiled-in base packages are also source base packages
+ for bp in TLazarusIDEBasePkg do
+ begin
+ PkgName:=LazarusIDEBasePkgNames[bp];
+ if FSrcBasePackages.IndexOf(PkgName)>=0 then continue;
+ // sources do not listen this as base package
+ Pkg:=FindPackageWithName(PkgName,nil);
+ if Pkg=nil then continue;
+ if Pkg.IsVirtual then
+ exit('Sources do not use "'+PkgName+'" as base package.'); // avoid IDE package check errors and use lazbuild
+ aFilename:=Pkg.GetResolvedFilename(true);
+ if aFilename='' then
+ exit('Sources do not use "'+PkgName+'" as base package.'); // avoid IDE package check errors and use lazbuild
+ if not FileExistsCached(aFilename) then
+ exit('Sources do not use "'+PkgName+'" as base package.'); // avoid IDE package check errors and use lazbuild
+ end;
end;
function TLazPackageGraph.PreparePackageOutputDirectory(APackage: TLazPackage;
@@ -5992,7 +6059,7 @@ begin
// -> unable to load this dependency due to conflict
debugln('Error: (lazarus) Open dependency found incompatible package: searched for '
+Dependency.AsString(true,false)+', but found '+APackage.IDAsString);
- if IsStaticBasePackage(APackage.Name) then
+ if IsCompiledInBasePackage(APackage.Name) then
begin
//debugln(['Note: (lazarus) LazarusDir="',EnvironmentOptions.GetParsedLazarusDirectory,'"']);
// wrong base package
@@ -6144,7 +6211,7 @@ begin
OpenDependency(Dependency,false);
if Dependency.LoadPackageResult<>lprSuccess then begin
// a valid lpk file of the installed package can not be found
- IsBasePkg:=IsStaticBasePackage(Dependency.PackageName);
+ IsBasePkg:=IsCompiledInBasePackage(Dependency.PackageName);
// -> create a broken package
BrokenPackage:=TLazPackage.CreateAndClear;
with BrokenPackage do begin
diff --git a/packager/pkgmanager.pas b/packager/pkgmanager.pas
index 9ad5901fe0..1c5b586d15 100644
--- a/packager/pkgmanager.pas
+++ b/packager/pkgmanager.pas
@@ -1522,7 +1522,7 @@ begin
while Dependency<>nil do begin
if (Dependency.LoadPackageResult=lprSuccess)
and (not Dependency.RequiredPackage.Missing)
- and (not PackageGraph.IsStaticBasePackage(Dependency.PackageName))
+ and (not PackageGraph.IsCompiledInBasePackage(Dependency.PackageName))
and (not (Dependency.RequiredPackage.PackageType in [lptRunTime,lptRunTimeOnly]))
then begin
if sl.IndexOf(Dependency.PackageName)<0 then begin
@@ -4004,7 +4004,7 @@ var
function PkgInOldLazarusDir(APackage: TLazPackage): boolean;
begin
Result:=FileIsInPath(APackage.Filename,OldLazarusSrcDir)
- or PackageGraph.IsStaticBasePackage(APackage.Name)
+ or PackageGraph.IsCompiledInBasePackage(APackage.Name)
or (SysUtils.CompareText(copy(APackage.Filename,1,length(LazDirMacro)),LazDirMacro)=0)
end;
@@ -5531,7 +5531,7 @@ begin
PkgList:=nil;
FPMakeList:=nil;
try
- PackageGraph.ParseBasePackages;
+ PackageGraph.ParseBasePackages(false);
// check if package is designtime package
if APackage.PackageType in [lptRunTime,lptRunTimeOnly] then begin
@@ -5681,7 +5681,7 @@ begin
end;
// check if package is a lazarus base package
- if PackageGraph.IsStaticBasePackage(APackage.Name) then begin
+ if PackageGraph.IsCompiledInBasePackage(APackage.Name) then begin
Result:=IDEMessageDialogAb(lisUninstallImpossible,
Format(lisThePackageCanNotBeUninstalledBecauseItIsNeededByTh,[APackage.Name]),
mtError,[mbCancel],ShowAbort);
@@ -5704,7 +5704,7 @@ begin
if Result<>mrOk then exit;
end;
- PackageGraph.ParseBasePackages;
+ PackageGraph.ParseBasePackages(false);
// remove package from auto installed packages
if APackage.AutoInstall<>pitNope then begin
@@ -5919,7 +5919,7 @@ begin
NewFirstAutoInstallDependency:=nil;
PkgList:=nil;
try
- PackageGraph.ParseBasePackages;
+ PackageGraph.ParseBasePackages(false);
if not (piiifClear in Flags) then
begin
@@ -5991,7 +5991,7 @@ begin
CurDependency:=PackageGraph.FirstAutoInstallDependency;
while CurDependency<>nil do begin
if (CurDependency.RequiredPackage<>nil)
- and (not PackageGraph.IsStaticBasePackage(CurDependency.PackageName)) then
+ and (not PackageGraph.IsCompiledInBasePackage(CurDependency.PackageName)) then
CurDependency.RequiredPackage.AutoInstall:=pitNope;
CurDependency:=CurDependency.NextRequiresDependency;
end;
@@ -6066,7 +6066,7 @@ begin
Dependencies:=nil;
while OldDependency<>nil do begin
if (OldDependency.RequiredPackage<>nil)
- and PackageGraph.IsStaticBasePackage(OldDependency.RequiredPackage.Name) then
+ and PackageGraph.IsCompiledInBasePackage(OldDependency.RequiredPackage.Name) then
begin
Dependency:=TPkgDependency.Create;
Dependency.Assign(OldDependency);