1{***************************************************************************
2 *                                                                         *
3 *   This source is free software; you can redistribute it and/or modify   *
4 *   it under the terms of the GNU General Public License as published by  *
5 *   the Free Software Foundation; either version 2 of the License, or     *
6 *   (at your option) any later version.                                   *
7 *                                                                         *
8 *   This code is distributed in the hope that it will be useful, but      *
9 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
10 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
11 *   General Public License for more details.                              *
12 *                                                                         *
13 *   A copy of the GNU General Public License is available on the World    *
14 *   Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also      *
15 *   obtain it by writing to the Free Software Foundation,                 *
16 *   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.        *
17 *                                                                         *
18 ***************************************************************************
19
20  Command line utility to compile lazarus projects and packages.
21}
22program lazbuild;
23
24
25{$mode objfpc}{$H+}
26
27uses
28  {$IFDEF unix}
29  cthreads,
30  {$ENDIF}
31  Classes, SysUtils, math, CustApp,
32  Interfaces, // this includes the NoGUI widgetset
33  // LazUtils
34  Masks, LConvEncoding, FileUtil, LazFileUtils, LazLoggerBase, LazUtilities,
35  LazUTF8, Laz2_XMLCfg, UITypes, LazStringUtils,
36  // LCL
37  LCLPlatformDef, Forms,
38  // Codetools
39  CodeCache, CodeToolManager, DefineTemplates, FileProcs,
40  // BuildIntf
41  BaseIDEIntf, MacroIntf, PackageIntf, LazMsgWorker, ProjectIntf, IDEExternToolIntf,
42  CompOptsIntf, IDEOptionsIntf, PackageDependencyIntf,
43  // IDE
44  InitialSetupProc, ExtToolsConsole, CompilerOptions,
45  ApplicationBundle, TransferMacros, EnvironmentOpts, IDETranslations,
46  LazarusIDEStrConsts, IDECmdLine, MiscOptions, Project, LazConf, PackageDefs,
47  PackageLinks, PackageSystem, InterPkgConflictFiles, BuildLazDialog,
48  BuildProfileManager, BuildManager, BaseBuildManager, ModeMatrixOpts;
49
50type
51  TPkgAction = (
52    lpaBuild, // build package, default
53    lpaInstall, // install package
54    lpaAddPkgLinks // register, no build
55    );
56
57  { TLazBuildApplication }
58
59  TLazBuildApplication = class(TCustomApplication)
60  private
61    FBuildAll: boolean;
62    FBuildIDE: boolean;
63    FBuildIDEOptions: string;
64    FBuildModeOverride: String;
65    FBuildRecursive: boolean;
66    fCompilerInCfg: string;
67    fCompilerOverride: String;
68    fCPUOverride: String;
69    FCreateMakefile: boolean;
70    fInitialized: boolean;
71    fInitResult: boolean;
72    fLazarusDirInCfg: string;
73    fLazarusDirOverride : String;
74    FMaxProcessCount: integer;
75    FNoWriteProject: Boolean;
76    fOSOverride: String;
77    FPackageAction: TPkgAction;
78    FPkgGraphVerbosity: TPkgVerbosityFlags;
79    FSkipDependencies: boolean;
80    fWidgetsetOverride: String;
81
82    // codetools
83    procedure OnCodeBufferDecodeLoaded({%H-}Code: TCodeBuffer;
84         const {%H-}Filename: string; var Source, DiskEncoding, MemEncoding: string);
85    procedure OnCodeBufferEncodeSaving(Code: TCodeBuffer;
86                                    const {%H-}Filename: string; var Source: string);
87
88    // global package functions
89    procedure GetDependencyOwnerDescription(Dependency: TPkgDependency;
90                                            out Description: string);
91    procedure GetDependencyOwnerDirectory(Dependency: TPkgDependency;
92                                          out Directory: string);
93    // Event procedure that adds every package added to the package graph to the (user) package links
94    procedure PackageGraphAddPackage(Pkg: TLazPackage);
95    function PackageGraphCheckInterPkgFiles(IDEObject: TObject;
96                          PkgList: TFPList; out FilesChanged: boolean): boolean;
97
98    // project
99    procedure OnProjectChangeInfoFile(TheProject: TProject);
100
101    // dialogs
102    function OnIDEMessageDialog(const aCaption, aMsg: string;
103                                {%H-}DlgType: TMsgDlgType; {%H-}Buttons: TMsgDlgButtons;
104                                const {%H-}HelpKeyword: string): Integer;
105    function OnIDEQuestionDialog(const aCaption, aMsg: string;
106                                 {%H-}DlgType: TMsgDlgType; {%H-}Buttons: array of const;
107                                 const {%H-}HelpKeyword: string): Integer;
108  protected
109    function GetParams(Index: Integer): String; override;
110    function GetParamCount: Integer; override;
111
112    // Builds project or package, depending on extension.
113    // Packages can also be specified by package name if they are known to the IDE.
114    function BuildFile(Filename: string): boolean;
115
116    // packages
117    // Build a package identified by filename and return build result
118    function BuildPackage(const AFilename: string): boolean;
119    // Load package file into loaded packages (package graph), overwriting any package with the same name
120    function LoadPackage(const AFilename: string): TLazPackage;
121    procedure CompilePackage(APackage: TLazPackage; Flags: TPkgCompileFlags);
122    procedure DoCreateMakefile(APackage: TLazPackage);
123    procedure CheckPackageGraphForCompilation(APackage: TLazPackage;
124                                 FirstDependency: TPkgDependency);
125
126    // projects
127    function BuildProject(const AFilename: string): boolean;
128    function LoadProject(const AFilename: string): TProject;
129    procedure CloseProject(var AProject: TProject);
130
131    // Adding packages to list of to-be-installed packages in the IDE.
132    // The packages can then be installed by recompiling the IDE (because we're using static packages)
133    function AddPackagesToInstallList(const PackageNamesOrFiles: TStringList): boolean;
134    function AddCmdLinePackageLinks(const PackageNamesOrFiles: TStringList): boolean;
135
136    // IDE
137    function BuildLazarusIDE: boolean;
138    function CompileAutoInstallPackages(Clean: boolean): boolean;
139
140    function Init: boolean;
141    procedure LoadEnvironmentOptions;
142    procedure LoadMiscellaneousOptions;
143    procedure SetupMacros;
144    procedure SetupCodetools;
145    procedure SetupPackageSystem;
146    procedure SetupDialogs;
147    procedure StoreBaseSettings;
148    function RepairedCheckOptions(Const ShortOptions : String;
149                   Const Longopts : TStrings; Opts,NonOpts : TStrings) : String;
150  public
151    // Files (or package names) passed by the user to Lazbuild:
152    Files: TStringList;
153    constructor Create(TheOwner: TComponent); override;
154    destructor Destroy; override;
155
156    procedure Run;
157    function ParseParameters: boolean;
158    procedure WriteUsage;
159    procedure Error(ErrorCode: Byte; const ErrorMsg: string);
160
161    property PackageAction: TPkgAction read FPackageAction write FPackageAction;
162    property BuildAll: boolean read FBuildAll write FBuildAll;// build all files of project/package
163    property BuildRecursive: boolean read FBuildRecursive // apply BuildAll flag to dependencies
164                                     write FBuildRecursive;
165    property SkipDependencies: boolean read FSkipDependencies
166                                            write FSkipDependencies;
167    property BuildIDE: boolean read FBuildIDE write FBuildIDE; // build IDE (as opposed to a project/package etc)
168    property BuildIDEOptions: string read FBuildIDEOptions write FBuildIDEOptions;
169    property CreateMakefile: boolean read FCreateMakefile write FCreateMakefile;
170    property WidgetSetOverride: String read fWidgetsetOverride
171                                            write fWidgetsetOverride;
172    property OSOverride: String read fOSOverride write fOSOverride;
173    property CPUOverride: String read fCPUOverride write fCPUOverride;
174    property CompilerOverride: String read fCompilerOverride write fCompilerOverride;
175    property LazarusDirOverride: String read fLazarusDirOverride write fLazarusDirOverride;
176    property BuildModeOverride: String read FBuildModeOverride write FBuildModeOverride;
177    property MaxProcessCount: integer read FMaxProcessCount write FMaxProcessCount;
178    property NoWriteProject: boolean read FNoWriteProject write FNoWriteProject;
179    property PkgGraphVerbosity: TPkgVerbosityFlags read FPkgGraphVerbosity write FPkgGraphVerbosity;
180  end;
181
182var
183  LazBuildApp: TLazBuildApplication = nil;
184
185const
186  ErrorFileNotFound = 1;
187  ErrorBuildFailed = 2;
188  ErrorLoadPackageFailed = 3;
189  ErrorPackageNameInvalid = 4;
190  ErrorLoadProjectFailed = 5;
191  VersionStr = {$I version.inc};
192
193procedure FilterConfigFileContent;
194var
195  l: TStrings;
196  i: Integer;
197begin
198  ResetParamsAndCfg;
199  l := GetCfgFileContent;
200  if l = nil then exit;
201  i := l.Count - 1;
202  while i >= 0 do begin
203    if not(
204        (copy(l[i], 1, 22) = '--primary-config-path=') or
205        (copy(l[i], 1, 24) = '--secondary-config-path=') or
206        (copy(l[i], 1,  6) = '--pcp=') or
207        (copy(l[i], 1,  6) = '--scp=')
208       )
209    then
210      l.Delete(i);
211    dec(i);
212  end;
213end;
214
215Function ToolParamCount: Integer;
216begin
217  Result := GetParamsAndCfgFile.Count - 1;
218end;
219
220Function ToolParamStr(Param : Integer) : Ansistring;
221begin
222  if Param >= GetParamsAndCfgFile.Count then
223    Result := ''
224  else
225    Result := GetParamsAndCfgFile[Param];
226end;
227
228procedure GetDescriptionOfDependencyOwner(Dependency: TPkgDependency;
229  out Description: string);
230var
231  DepOwner: TObject;
232begin
233  DepOwner:=Dependency.Owner;
234  if (DepOwner<>nil) then begin
235    if DepOwner is TLazPackage then begin
236      Description:=Format(lisPkgMangPackage, [TLazPackage(DepOwner).IDAsString]);
237    end else if DepOwner is TProject then begin
238      Description:=Format(lisPkgMangProject,
239                          [ExtractFileNameOnly(TProject(DepOwner).ProjectInfoFile)]);
240    end else begin
241      Description:=dbgsName(DepOwner)
242    end;
243  end else begin
244    Description:=Format(lisPkgMangDependencyWithoutOwner, [Dependency.AsString]);
245  end;
246end;
247
248procedure GetDirectoryOfDependencyOwner(Dependency: TPkgDependency;
249  out Directory: string);
250var
251  DepOwner: TObject;
252begin
253  DepOwner:=Dependency.Owner;
254  if (DepOwner<>nil) then begin
255    if DepOwner is TLazPackage then begin
256      Directory:=TLazPackage(DepOwner).Directory;
257    end else if DepOwner is TProject then begin
258      Directory:=TProject(DepOwner).Directory;
259    end else begin
260      Directory:=''
261    end;
262  end else begin
263    Directory:=''
264  end;
265end;
266
267{ TLazBuildApplication }
268
269procedure TLazBuildApplication.OnCodeBufferEncodeSaving(Code: TCodeBuffer;
270  const Filename: string; var Source: string);
271begin
272  if (Code.DiskEncoding<>'') and (Code.MemEncoding<>'')
273  and (Code.DiskEncoding<>Code.MemEncoding) then begin
274    {$IFDEF VerboseIDEEncoding}
275    DebugLn(['TLazBuildApplication.OnCodeBufferEncodeSaving Filename=',Code.Filename,' Mem=',Code.MemEncoding,' to Disk=',Code.DiskEncoding]);
276    {$ENDIF}
277    Source:=ConvertEncoding(Source,Code.MemEncoding,Code.DiskEncoding);
278    {$IF FPC_FULLVERSION >= 20701}
279    //SetCodePage(Source,CP_ACP);
280    {$ENDIF}
281  end;
282end;
283
284procedure TLazBuildApplication.OnCodeBufferDecodeLoaded(Code: TCodeBuffer;
285  const Filename: string; var Source, DiskEncoding, MemEncoding: string);
286begin
287  //DebugLn(['TLazBuildApplication.OnCodeBufferDecodeLoaded Filename=',Filename,' Encoding=',GuessEncoding(Source)]);
288  DiskEncoding:='';
289  if DiskEncoding='' then
290    DiskEncoding:=GuessEncoding(Source);
291  MemEncoding:=EncodingUTF8;
292  if (DiskEncoding<>MemEncoding) then begin
293    {$IFDEF VerboseIDEEncoding}
294    DebugLn(['TLazBuildApplication.OnCodeBufferDecodeLoaded Filename=',Filename,' Disk=',DiskEncoding,' to Mem=',MemEncoding]);
295    {$ENDIF}
296    Source:=ConvertEncoding(Source,DiskEncoding,MemEncoding);
297    //DebugLn(['TLazBuildApplication.OnCodeBufferDecodeLoaded ',Source]);
298  end;
299end;
300
301procedure TLazBuildApplication.GetDependencyOwnerDescription(
302  Dependency: TPkgDependency; out Description: string);
303begin
304  GetDescriptionOfDependencyOwner(Dependency,Description);
305end;
306
307procedure TLazBuildApplication.GetDependencyOwnerDirectory(
308  Dependency: TPkgDependency; out Directory: string);
309begin
310  GetDirectoryOfDependencyOwner(Dependency,Directory);
311end;
312
313procedure TLazBuildApplication.PackageGraphAddPackage(Pkg: TLazPackage);
314begin
315  if FileExistsUTF8(Pkg.FileName) then LazPackageLinks.AddUserLink(Pkg);
316end;
317
318function TLazBuildApplication.PackageGraphCheckInterPkgFiles(
319  IDEObject: TObject; PkgList: TFPList; out FilesChanged: boolean): boolean;
320begin
321  Result:=CheckInterPkgFiles(IDEObject,PkgList,FilesChanged);
322end;
323
324procedure TLazBuildApplication.OnProjectChangeInfoFile(TheProject: TProject);
325begin
326  if TheProject<>Project1 then exit;
327  if TheProject.IsVirtual then
328    CodeToolBoss.SetGlobalValue(ExternalMacroStart+'ProjPath',VirtualDirectory)
329  else
330    CodeToolBoss.SetGlobalValue(ExternalMacroStart+'ProjPath',Project1.Directory)
331end;
332
333function TLazBuildApplication.OnIDEMessageDialog(const aCaption, aMsg: string;
334  DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; const HelpKeyword: string
335  ): Integer;
336begin
337  DumpStack;
338  Error(ErrorBuildFailed, Format(lisLazbuildIsNonInteractiveAbortingNow, [
339    aCaption, LineEnding, aMsg, LineEnding]));
340  Result:=mrCancel;
341end;
342
343function TLazBuildApplication.OnIDEQuestionDialog(const aCaption, aMsg: string;
344  DlgType: TMsgDlgType; Buttons: array of const; const HelpKeyword: string
345  ): Integer;
346begin
347  DumpStack;
348  Error(ErrorBuildFailed, Format(lisLazbuildIsNonInteractiveAbortingNow, [
349    aCaption, LineEnding, aMsg, LineEnding]));
350  Result:=mrCancel;
351end;
352
353function TLazBuildApplication.GetParams(Index: Integer): String;
354begin
355  Result := ToolParamStr(Index);
356end;
357
358function TLazBuildApplication.GetParamCount: Integer;
359begin
360  Result := ToolParamCount;
361end;
362
363function TLazBuildApplication.BuildFile(Filename: string): boolean;
364var
365  OriginalFilename: string;
366  Package: TLazPackageLink;
367begin
368  Result:=false;
369  OriginalFilename:=FileName;
370
371  Filename:=CleanAndExpandFilename(Filename);
372  if not FileExistsUTF8(Filename) then
373  begin
374    // File doesn't exist.
375
376    // Check for packages if the specified name is a valid identifier
377    //debugln(['TLazBuildApplication.BuildFile ',OriginalFilename]);
378    if IsValidPkgName(OriginalFileName) then begin
379      if PackageAction=lpaAddPkgLinks then begin
380        Error(ErrorFileNotFound,'lpk file expected, but '+OriginalFilename+' found');
381        Exit;
382      end;
383      // Initialize package graph with base packages etc:
384      if not Init then exit;
385      // Could be a known but not installed package
386      // so try and get package filename from all other known packages
387      Package:=TLazPackageLink(LazPackageLinks.FindLinkWithPkgName(OriginalFileName));
388      if Package=nil then begin
389        // Not found after everything we tried
390        if FilenameExtIs(Filename,'lpi', true) then
391          Error(ErrorFileNotFound,'file not found: '+OriginalFilename)
392        else
393          Error(ErrorFileNotFound,'package not found: '+OriginalFilename);
394      end
395      else begin
396        // We found a package link
397        case PackageAction of
398        lpaBuild:
399          begin
400            Result:=BuildPackage(Package.LPKFilename);
401            exit;
402          end;
403        lpaInstall:
404          exit(true); // this is handled in AddPackagesToInstallList
405        end;
406      end;
407    end;
408
409    Error(ErrorFileNotFound, 'file not found: '+OriginalFilename);
410    Exit;
411  end
412  else if DirPathExists(Filename) then
413    begin
414    Error(ErrorFileNotFound,'file "'+Filename+'" is a directory');
415    Exit;
416    end
417  else begin
418    // File exists:
419    if FilenameExtIs(Filename,'lpk',true) then begin
420      case PackageAction of
421      lpaBuild: Result:=BuildPackage(Filename);
422      lpaInstall: Result:=true; // this is handled in AddPackagesToInstallList
423      lpaAddPkgLinks: Result:=true;
424      end;
425    end else if FilenameExtIs(Filename,'lpi',true) then
426      Result:=BuildProject(Filename)
427    else if FilenameExtIs(Filename,'lpr',true) then begin
428      Filename:=ChangeFileExt(Filename,'.lpi');
429      if FileExists(Filename) then
430        Result:=BuildProject(Filename)
431      else
432        Error(ErrorFileNotFound,'file not found: '+Filename);
433    end else
434      Error(ErrorBuildFailed,'don''t know how to build: '+Filename);
435  end;
436end;
437
438function TLazBuildApplication.BuildPackage(const AFilename: string): boolean;
439var
440  APackage: TLazPackage;
441  Flags: TPkgCompileFlags;
442begin
443  Result:=false;
444
445  if not Init then exit;
446
447  if ConsoleVerbosity>=0 then
448    debugln(['Hint: (lazarus) compile package "',AFilename,'"']);
449
450  APackage:=LoadPackage(AFilename);
451  if APackage=nil then
452    Error(ErrorLoadPackageFailed, 'unable to load package "'+AFilename+'"');
453
454  Flags:=[];
455  if BuildAll then
456    Include(Flags,pcfCleanCompile)
457  else
458    Include(Flags,pcfOnlyIfNeeded);
459  if BuildRecursive and BuildAll then
460    Include(Flags,pcfCompileDependenciesClean);
461  if SkipDependencies then
462    Include(Flags,pcfDoNotCompileDependencies);
463
464  if (Length(OSOverride) <> 0) then
465    APackage.CompilerOptions.TargetOS:=OSOverride;
466  if (Length(CPUOverride) <> 0) then
467    APackage.CompilerOptions.TargetCPU:=CPUOverride;
468
469  if CreateMakefile then
470    DoCreateMakefile(APackage)
471  else
472    CompilePackage(APackage,Flags);
473
474  LazPackageLinks.SaveUserLinks(true);
475
476  Result:=true;
477end;
478
479function TLazBuildApplication.LoadPackage(const AFilename: string): TLazPackage;
480var
481  XMLConfig: TXMLConfig;
482  ConflictPkg: TLazPackage;
483begin
484  // check if package is already loaded
485  Result:=PackageGraph.FindPackageWithFilename(AFilename);
486  if (Result<>nil) then exit;
487  if not FileExistsUTF8(AFilename) then
488    Error(ErrorLoadPackageFailed,'Package file not found "'+AFilename+'"');
489
490  Result:=TLazPackage.Create;
491  // load the package file
492  XMLConfig:=TXMLConfig.Create(AFilename);
493  try
494    Result.Filename:=AFilename;
495    Result.LoadFromXMLConfig(XMLConfig,'Package/');
496  finally
497    XMLConfig.Free;
498  end;
499  // check Package Name
500  if not IsValidPkgName(Result.Name) then
501    Error(ErrorPackageNameInvalid,
502          Format(lisPkgMangThePackageNameOfTheFileIsInvalid,
503                 [Result.Name, LineEnding, Result.Filename]));
504  // check if Package with same name is already loaded
505  ConflictPkg:=PackageGraph.FindPackageWithName(Result.Name,nil);
506  if ConflictPkg<>nil then begin
507    // replace package
508    PackageGraph.ReplacePackage(ConflictPkg,Result);
509  end else begin
510    // add to graph
511    PackageGraph.AddPackage(Result);
512  end;
513  // save package file links
514  LazPackageLinks.SaveUserLinks;
515end;
516
517function TLazBuildApplication.BuildLazarusIDE: boolean;
518var
519  Flags: TBuildLazarusFlags;
520  CurResult: TModalResult;
521  BuildLazProfiles: TBuildLazarusProfiles;
522  CurProf: TBuildLazarusProfile;
523  InheritedOptionStrings: TInheritedCompOptsStrings;
524  TargetDir: String;
525  i: Integer;
526  s: String;
527  Builder: TLazarusBuilder;
528begin
529  Result:=false;
530  if not Init then exit;
531
532  LoadMiscellaneousOptions;
533  BuildLazProfiles:=MiscellaneousOptions.BuildLazProfiles;
534  CurProf:=BuildLazProfiles.Current;
535  if BuildModeOverride<>'' then
536  begin
537    i:=BuildLazProfiles.IndexByName(BuildModeOverride);
538    if i<0 then
539    begin
540      debugln(['Error: (lazarus) IDE build mode "'+BuildModeOverride+'" not found']);
541      if ConsoleVerbosity>=-2 then begin
542        debugln;
543        debugln('Available IDE build modes:');
544        for i:=0 to BuildLazProfiles.Count-1 do
545        begin
546          if BuildLazProfiles[i]=CurProf then
547            dbgout('* ')
548          else
549            dbgout('  ');
550          debugln(BuildLazProfiles[i].Name);
551        end;
552        debugln;
553      end;
554      Halt(ErrorBuildFailed);
555    end;
556    CurProf:=BuildLazProfiles[i];
557    BuildLazProfiles.CurrentIndex:=i;
558  end;
559  if ConsoleVerbosity>=0 then
560    debugln(['Hint: (lazarus) Building Lazarus IDE with profile "',CurProf.Name,'"']);
561
562  if (Length(OSOverride) <> 0) then
563    CurProf.TargetOS:=OSOverride;
564  if (Length(CPUOverride) <> 0) then
565    CurProf.TargetCPU:=CPUOverride;
566
567  if WidgetSetOverride<>'' then
568    CurProf.TargetPlatform:=DirNameToLCLPlatform(WidgetSetOverride)
569  else
570    CurProf.TargetPlatform:=GetBuildLCLWidgetType;
571  if BuildIDEOptions<>'' then
572  begin
573    s:=CurProf.ExtraOptions;
574    if s<>'' then
575      s+=' ';
576    s+=BuildIDEOptions;
577    CurProf.ExtraOptions:=s;
578  end;
579  if BuildAll then
580    CurProf.IdeBuildMode:=bmCleanAllBuild;
581  MainBuildBoss.SetBuildTargetIDE;
582  Flags:=[];
583
584  // try loading install packages
585  PackageGraph.LoadAutoInstallPackages(BuildLazProfiles.StaticAutoInstallPackages);
586
587  // create target directory
588  TargetDir:=CurProf.TargetDirectory;
589  IDEMacros.SubstituteMacros(TargetDir);
590  if not ForceDirectory(TargetDir) then begin
591    if ConsoleVerbosity>=-1 then
592      DebugLn('Warning: (lazarus) failed creating IDE target directory "',TargetDir,'" (TLazBuildApplication.BuildLazarusIDE)');
593    exit;
594  end;
595
596  // clean
597  Builder:=TLazarusBuilder.Create;
598  try
599    Builder.ProfileChanged:=false;
600
601    if BuildLazProfiles.Current.IdeBuildMode=bmCleanAllBuild then begin
602      Builder.PackageOptions:='';
603      CurResult:=Builder.MakeLazarus(BuildLazProfiles.Current,
604                  Flags+[blfDontBuild]);
605      if CurResult<>mrOk then begin
606        if ConsoleVerbosity>=-1 then
607          DebugLn('Error: (lazarus) Building IDE: Clean all failed.');
608        exit;
609      end;
610    end;
611
612    // save list of install packages
613    CurResult:=PackageGraph.SaveAutoInstallConfig;
614    if CurResult<>mrOk then begin
615      if ConsoleVerbosity>=-1 then
616        DebugLn('Error: (lazarus) Building IDE: failed saving IDE make config files.');
617      exit;
618    end;
619
620    // compile auto install static packages
621    if not CompileAutoInstallPackages(BuildLazProfiles.Current.IdeBuildMode<>bmBuild)
622    then begin
623      if ConsoleVerbosity>=-1 then
624        DebugLn('Error: (lazarus) Building IDE: Compile AutoInstall Packages failed.');
625      exit;
626    end;
627
628    // create inherited compiler options
629    Builder.PackageOptions:=PackageGraph.GetIDEInstallPackageOptions(InheritedOptionStrings{%H-});
630
631    // save idemake.cfg
632    CurResult:=Builder.SaveIDEMakeOptions(BuildLazProfiles.Current,Flags+[blfBackupOldExe]);
633    if CurResult<>mrOk then begin
634      if ConsoleVerbosity>=-1 then
635        DebugLn('Error: (lazarus) Building IDE: failed saving idemake.cfg');
636      exit;
637    end;
638
639    // compile IDE
640    CurResult:=Builder.MakeLazarus(BuildLazProfiles.Current,
641                           Flags+[blfUseMakeIDECfg,blfOnlyIDE]);
642    if CurResult<>mrOk then begin
643      if ConsoleVerbosity>=-1 then
644        DebugLn('Error: (lazarus) Building IDE: Building IDE failed.');
645      exit;
646    end;
647
648    Result:=true;
649  finally
650    Builder.Free;
651  end;
652end;
653
654function TLazBuildApplication.CompileAutoInstallPackages(Clean: boolean): boolean;
655var
656  Dependency: TPkgDependency;
657  OldDependency: TPkgDependency;
658  CurResult: TModalResult;
659  CompilePolicy: TPackageUpdatePolicy;
660begin
661  Result:=false;
662  PackageGraph.BeginUpdate(false);
663  try
664    Dependency:=PackageGraph.FirstAutoInstallDependency;
665    while Dependency<>nil do begin
666      OldDependency:=Dependency;
667      Dependency:=Dependency.NextRequiresDependency;
668      if OldDependency.LoadPackageResult<>lprSuccess then begin
669        raise Exception.Create(Format(
670            lisPkgMangThePackageIsMarkedForInstallationButCanNotBeFound, [
671            OldDependency.AsString, LineEnding]));
672      end;
673    end;
674
675    // check consistency
676    CheckPackageGraphForCompilation(nil,
677                      PackageGraph.FirstAutoInstallDependency);
678
679    // compile all auto install dependencies
680    CompilePolicy:=pupAsNeeded;
681    if (BuildRecursive and BuildAll) or Clean then
682      CompilePolicy:=pupOnRebuildingAll;
683    CurResult:=PackageGraph.CompileRequiredPackages(nil,
684                   PackageGraph.FirstAutoInstallDependency,false,CompilePolicy);
685    if CurResult<>mrOk then exit;
686
687  finally
688    PackageGraph.EndUpdate;
689  end;
690  Result:=true;
691end;
692
693procedure TLazBuildApplication.CompilePackage(APackage: TLazPackage;
694  Flags: TPkgCompileFlags);
695begin
696  if APackage.Missing then
697    Error(ErrorBuildFailed,APackage.IDAsString+' lpk file missing');
698
699  // check graph for circles and broken dependencies
700  if not (pcfDoNotCompileDependencies in Flags) then begin
701    CheckPackageGraphForCompilation(APackage,nil);
702  end;
703
704  if PackageGraph.CompilePackage(APackage,Flags,false)<>mrOk then
705    Error(ErrorBuildFailed,APackage.IDAsString+' compilation failed');
706end;
707
708procedure TLazBuildApplication.DoCreateMakefile(APackage: TLazPackage);
709begin
710  if ConsoleVerbosity>0 then
711    debugln(['Hint: (lazarus) [TLazBuildApplication.DoCreateMakefile] ',APackage.Filename]);
712  PackageGraph.WriteMakeFile(APackage);
713end;
714
715procedure TLazBuildApplication.CheckPackageGraphForCompilation(
716  APackage: TLazPackage; FirstDependency: TPkgDependency);
717
718  function PathListToString(PathList: TFPList): string;
719  var
720    i: Integer;
721    Item: TObject;
722  begin
723    Result:='';
724    for i:=0 to PathList.Count-1 do begin
725      Item:=TObject(PathList[i]);
726      if Result<>'' then
727        Result:=Result+'->';
728      if Item is TPkgDependency then begin
729        Result:=Result+TPkgDependency(Item).AsString;
730      end else if Item is TProject then begin
731        Result:=Result
732                +'Project:'+ExtractFileNameOnly(TProject(Item).ProjectInfoFile);
733      end else if Item is TLazPackage then begin
734        Result:=Result+TLazPackage(Item).IDAsString;
735      end else begin
736        Result:=Result+'Unknown:'+dbgsName(Item);
737      end;
738    end;
739  end;
740
741var
742  PathList: TFPList;
743begin
744  PathList:=nil;
745  try
746    // check for broken dependencies
747    PathList:=PackageGraph.FindBrokenDependencyPath(APackage,FirstDependency);
748    if PathList<>nil then
749      Error(ErrorLoadPackageFailed,'Broken dependency: '+PathListToString(PathList));
750
751    // check for circle dependencies
752    PathList:=PackageGraph.FindCycleDependencyPath(APackage,FirstDependency);
753    if PathList<>nil then
754      Error(ErrorLoadPackageFailed,'Circle dependency: '+PathListToString(PathList));
755  finally
756    PathList.Free;
757  end;
758end;
759
760function TLazBuildApplication.BuildProject(const AFilename: string): boolean;
761var
762  CompilerFilename: String;
763  WorkingDir: String;
764  SrcFilename: String;
765  CompilerParams: String;
766  ToolBefore: TProjectCompilationToolOptions;
767  ToolAfter: TProjectCompilationToolOptions;
768  UnitOutputDirectory: String;
769  TargetExeName: String;
770  TargetExeDir: String;
771  CompilePolicy: TPackageUpdatePolicy;
772  i,MatchCount: Integer;
773  CompileHint: String;
774  CompReason: TCompileReason;
775  NeedBuildAllFlag: Boolean;
776  MatrixOption: TBuildMatrixOption;
777  ModeMask: TMask;
778  CurResult: Boolean;
779
780  function StartBuilding : boolean;
781  begin
782    Result := false;
783
784    // then override specific options
785    if (OSOverride<>'') then
786      Project1.CompilerOptions.TargetOS:=OSOverride;
787    if (CPUOverride<>'') then
788      Project1.CompilerOptions.TargetCPU:=CPUOverride;
789    if (WidgetSetOverride<>'') then begin
790      MatrixOption:=Project1.BuildModes.SessionMatrixOptions.Add(bmotIDEMacro);
791      MatrixOption.Modes:=Project1.ActiveBuildMode.Identifier;
792      MatrixOption.MacroName:='LCLWidgetType';
793      MatrixOption.Value:=WidgetSetOverride;
794    end;
795    // apply options
796    MainBuildBoss.SetBuildTargetProject1(true,smsfsSkip);
797
798    try
799      if not SkipDependencies then
800      begin
801        // compile required packages
802        CheckPackageGraphForCompilation(nil,Project1.FirstRequiredDependency);
803        PackageGraph.BeginUpdate(false);
804        // automatically compile required packages
805        CompilePolicy:=pupAsNeeded;
806        if BuildRecursive and BuildAll then
807          CompilePolicy:=pupOnRebuildingAll;
808        if PackageGraph.CompileRequiredPackages(nil,Project1.FirstRequiredDependency,
809                                  not (pfUseDesignTimePackages in Project1.Flags),
810                                  CompilePolicy)<>mrOk
811        then
812          Error(ErrorBuildFailed,'Project dependencies of '+AFilename);
813      end;
814
815      WorkingDir:=Project1.Directory;
816      SrcFilename:=CreateRelativePath(Project1.MainUnitInfo.Filename,WorkingDir);
817
818      NeedBuildAllFlag:=false;
819      CompileHint:='';
820      if (CompReason in Project1.CompilerOptions.CompileReasons) then begin
821        // only check if NeedBuildAllFlag will be set
822        MainBuildBoss.DoCheckIfProjectNeedsCompilation(Project1, NeedBuildAllFlag,CompileHint);
823      end;
824
825      // execute compilation tool 'Before'
826      ToolBefore:=TProjectCompilationToolOptions(Project1.CompilerOptions.ExecuteBefore);
827      if (CompReason in ToolBefore.CompileReasons) then begin
828        if ToolBefore.Execute(Project1.Directory,
829          lisProject2+lisExecutingCommandBefore, CompileHint)<>mrOk
830        then
831          Error(ErrorBuildFailed,'failed "tool before" of project '+AFilename);
832      end;
833
834      // create unit output directory
835      UnitOutputDirectory:=Project1.CompilerOptions.GetUnitOutPath(false);
836      if not ForceDirectory(UnitOutputDirectory) then
837        Error(ErrorBuildFailed,'Unable to create project unit output directory '+UnitOutputDirectory);
838
839      // create target output directory
840      TargetExeName := Project1.CompilerOptions.CreateTargetFilename;
841      TargetExeDir := ExtractFilePath(TargetExeName);
842      if not ForceDirectory(TargetExeDir) then
843        Error(ErrorBuildFailed,'Unable to create project target directory '+TargetExeDir);
844
845      // create LazBuildApp bundle
846      if Project1.UseAppBundle and (Project1.MainUnitID>=0)
847      and ((MainBuildBoss.GetLCLWidgetType=LCLPlatformDirNames[lpCarbon])
848        or (MainBuildBoss.GetLCLWidgetType=LCLPlatformDirNames[lpCocoa]))
849      then begin
850        if not (CreateApplicationBundle(TargetExeName, Project1.Title) in [mrOk,mrIgnore]) then
851          Error(ErrorBuildFailed,'Unable to create application bundle for '+TargetExeName);
852        if not (CreateAppBundleSymbolicLink(TargetExeName) in [mrOk,mrIgnore]) then
853          Error(ErrorBuildFailed,'Unable to create application bundle symbolic link for '+TargetExeName);
854      end;
855
856      // update all lrs files
857      MainBuildBoss.UpdateProjectAutomaticFiles('');
858
859      // regenerate resources
860      if not Project1.ProjResources.Regenerate(SrcFileName, False, True, '') then
861      begin
862        if ConsoleVerbosity>=-1 then
863          DebugLn('Error: (lazarus) Project1.Resources.Regenerate failed of ',SrcFilename);
864      end;
865
866      // get compiler parameters
867      if CompilerOverride <> '' then
868        CompilerFilename := CompilerOverride
869      else
870        CompilerFilename:=Project1.GetCompilerFilename;
871      //DebugLn(['TLazBuildApplication.BuildProject CompilerFilename="',CompilerFilename,'" CompilerPath="',Project1.CompilerOptions.CompilerPath,'"']);
872      // CompileHint: use absolute paths, same as TBuildManager.DoCheckIfProjectNeedsCompilation
873      CompilerParams:=Project1.CompilerOptions.MakeOptionsString([ccloAbsolutePaths])
874                                             +' '+PrepareCmdLineOption(SrcFilename);
875
876      if (CompReason in Project1.CompilerOptions.CompileReasons) then begin
877        // compile
878
879        // write state file to avoid building clean every time
880        if Project1.SaveStateFile(CompilerFilename,CompilerParams,false)<>mrOk then
881          Error(ErrorBuildFailed,'failed saving statefile of project '+AFilename);
882        if TheCompiler.Compile(Project1,WorkingDir,CompilerFilename,CompilerParams,
883                               BuildAll or NeedBuildAllFlag,false,false,false,
884                               CompileHint)<>mrOk
885        then
886          Error(ErrorBuildFailed,'failed compiling of project '+AFilename);
887        // compilation succeded -> write state file
888        if Project1.SaveStateFile(CompilerFilename,CompilerParams,true)<>mrOk then
889          Error(ErrorBuildFailed,'failed saving statefile of project '+AFilename);
890      end;
891
892      // execute compilation tool 'After'
893      ToolAfter:=TProjectCompilationToolOptions(Project1.CompilerOptions.ExecuteAfter);
894      if (CompReason in ToolAfter.CompileReasons) then begin
895        if ToolAfter.Execute(Project1.Directory,
896          lisProject2+lisExecutingCommandAfter,CompileHint)<>mrOk
897        then
898          Error(ErrorBuildFailed,'failed "tool after" of project '+AFilename);
899      end;
900
901      // no need to check for mrOk, we are exit if it wasn't
902      Result:=true;
903    finally
904      if not SkipDependencies then
905        PackageGraph.EndUpdate;
906    end;
907  end;
908
909begin
910  Result:=false;
911  CloseProject(Project1);
912
913  if not Init then exit;
914
915  Project1:=LoadProject(AFilename);
916
917  if Project1.MainUnitInfo=nil then
918    Error(ErrorBuildFailed,'project has no main unit');
919
920  if BuildAll then
921    CompReason:= crBuild
922  else
923    CompReason:= crCompile;
924
925  // first override build mode
926  if (BuildModeOverride<>'') then
927  begin
928    CurResult := true;
929
930    MatchCount := 0;
931    ModeMask := TMask.Create(BuildModeOverride,[]);
932    for i := 0 to Project1.BuildModes.Count-1 do
933    begin
934      if ModeMask.Matches(Project1.BuildModes[i].Identifier) then
935      begin
936        inc(MatchCount);
937        Project1.ActiveBuildMode := Project1.BuildModes[i];
938        CurResult := CurResult and StartBuilding;
939      end;
940    end;
941    ModeMask.Free;
942
943    if MatchCount=0 then // No matches
944    begin
945      debugln([Format(lisERRORInvalidBuildMode, [BuildModeOverride])]);
946      if ConsoleVerbosity>=0 then
947      begin
948        debugln;
949        if Project1.BuildModes.Count>1 then
950        begin
951          debugln(lisAvailableProjectBuildModes);
952          for i:=0 to Project1.BuildModes.Count-1 do
953          begin
954            if Project1.BuildModes[i]=Project1.ActiveBuildMode then
955              dbgout('* ')
956            else
957              dbgout('  ');
958            debugln(Project1.BuildModes[i].Identifier);
959          end;
960        end else begin
961          debugln(lisThisProjectHasOnlyTheDefaultBuildMode);
962        end;
963        debugln;
964      end;
965      Halt(ErrorBuildFailed);
966    end;
967
968    Result := CurResult;
969  end
970  else
971    Result := StartBuilding;
972
973  // Auto increment build number
974  if Result and not NoWriteProject
975  and Project1.ProjResources.VersionInfo.UseVersionInfo
976  and Project1.ProjResources.VersionInfo.AutoIncrementBuild
977  then begin
978    if FileIsWritable(AFilename) then
979    begin
980      Project1.ProjResources.DoAfterBuild(CompReason, Project1.IsVirtual);
981      Project1.WriteProject(Project1.PublishOptions.WriteFlags,AFileName,EnvironmentOptions.BuildMatrixOptions)
982    end
983    else
984    begin
985      if ConsoleVerbosity>=-1 then
986        DebugLn('Error: (lazarus) Project1.WriteProject skipped for read-only ',SrcFilename);
987    end;
988  end;
989end;
990
991function TLazBuildApplication.LoadProject(const AFilename: string): TProject;
992var
993  ProjectDesc: TProjectDescriptor;
994begin
995  ProjectDesc:=TProjectDescriptor.Create;
996  try
997    Result:=TProject.Create(ProjectDesc);
998    // custom initialization
999    Result.BeginUpdate(true);
1000    if ProjectDesc.InitProject(Result)<>mrOk then begin
1001      Result.EndUpdate;
1002      Result.Free;
1003      Result:=nil;
1004    end;
1005    Result.EndUpdate;
1006
1007    Result.MainProject:=true;
1008    Result.OnFileBackup:=@BuildBoss.BackupFileForWrite;
1009    Result.OnChangeProjectInfoFile:=@OnProjectChangeInfoFile;
1010
1011  finally
1012    ProjectDesc.Free;
1013  end;
1014
1015  Result.BeginUpdate(true);
1016  try
1017    // read project info file
1018    if Result.ReadProject(AFilename,EnvironmentOptions.BuildMatrixOptions)<>mrOk then
1019      Error(ErrorLoadProjectFailed,'Project '+AFilename);
1020    //BuildBoss.RescanCompilerDefines(true);
1021
1022    // load required packages
1023    PackageGraph.OpenRequiredDependencyList(Result.FirstRequiredDependency);
1024  finally
1025    Result.EndUpdate;
1026  end;
1027  IncreaseCompilerParseStamp;
1028end;
1029
1030procedure TLazBuildApplication.CloseProject(var AProject: TProject);
1031begin
1032  // free project, if it is still there
1033  FreeThenNil(AProject);
1034end;
1035
1036function TLazBuildApplication.AddPackagesToInstallList(
1037  const PackageNamesOrFiles: TStringList): boolean;
1038var
1039  i: integer;
1040  Package: TLazPackage;
1041  PackageLink: TLazPackageLink;
1042  PackageName: String;
1043  PkgFilename: String;
1044  ErrorMsg: String;
1045  ErrCode: Byte;
1046begin
1047  Result:=false;
1048  if not Init then exit;
1049
1050  LoadMiscellaneousOptions;
1051
1052  ErrorMsg:='';
1053  ErrCode:=ErrorPackageNameInvalid;
1054  for i:=0 to PackageNamesOrFiles.Count -1 do
1055  begin
1056    // Look for package name in all known packages
1057    PackageName:='';
1058    PkgFilename:='';
1059    if pvPkgSearch in fPkgGraphVerbosity then
1060      debugln(['Info: (lazarus) [TLazBuildApplication.AddPackagesToInstallList] "',PackageNamesOrFiles[i],'"']);
1061    if FilenameExtIs(PackageNamesOrFiles[i],'lpk',true) then
1062      PkgFilename:=ExpandFileNameUTF8(PackageNamesOrFiles[i])
1063    else if IsValidPkgName(PackageNamesOrFiles[i]) then begin
1064      PackageLink:=TLazPackageLink(LazPackageLinks.FindLinkWithPkgName(PackageNamesOrFiles[i]));
1065      if PackageLink=nil then
1066      begin
1067        ErrorMsg+='Can not find package '+PackageNamesOrFiles[i]+', so it is not marked for installation.'+LineEnding;
1068        continue;
1069      end;
1070      PkgFilename:=PackageLink.LPKFilename;
1071    end else begin
1072      ErrorMsg+=PackageNamesOrFiles[i]+' is not a package, so it is not marked for installation.'+LineEnding;
1073      continue;
1074    end;
1075    Package:=LoadPackage(PkgFilename);
1076    if Package=nil then
1077    begin
1078      ErrorMsg+='Could not load '+PackageNamesOrFiles[i]+', so it is not marked for installation.'+LineEnding;
1079      ErrCode:=ErrorLoadPackageFailed;
1080      continue;
1081    end;
1082    if Package.PackageType in [lptRunTime,lptRunTimeOnly] then
1083    begin
1084      ErrorMsg+='Package '+PackageNamesOrFiles[i]+' is only for runtime.'+LineEnding;
1085      continue;
1086    end;
1087    PackageName:=Package.Name;
1088    // set it as (static) autoinstall: select for installation
1089    if ConsoleVerbosity>=0 then
1090      debugln(['Hint: (lazarus) adding package "'+PkgFilename+'" to install list of IDE']);
1091    if MiscellaneousOptions.BuildLazProfiles.StaticAutoInstallPackages.IndexOf(PackageName)<0 then
1092      MiscellaneousOptions.BuildLazProfiles.StaticAutoInstallPackages.Add(PackageName);
1093  end;
1094  if ErrorMsg<>'' then begin
1095    ErrorMsg:=UTF8Trim(ErrorMsg);
1096    Error(ErrCode,ErrorMsg);
1097    exit;
1098  end;
1099  // save list
1100  MiscellaneousOptions.Save;
1101  LazPackageLinks.SaveUserLinks(true);
1102
1103  Result:=true;
1104end;
1105
1106function TLazBuildApplication.AddCmdLinePackageLinks(
1107  const PackageNamesOrFiles: TStringList): boolean;
1108var
1109  ErrorMsg, PkgFilename: String;
1110  i, ErrCode: Integer;
1111  Package: TLazPackage;
1112begin
1113  Result:=false;
1114  if not Init then exit;
1115
1116  ErrorMsg:='';
1117  ErrCode:=ErrorLoadPackageFailed;
1118  for i:=0 to PackageNamesOrFiles.Count -1 do
1119  begin
1120    // Look for package name in all known packages
1121    PkgFilename:=PackageNamesOrFiles[i];
1122    if not FilenameExtIs(PkgFilename,'lpk',true) then begin
1123      ErrorMsg+=PkgFilename+' is not a package (.lpk), so it is not registered.'+LineEnding;
1124      continue;
1125    end;
1126    PkgFilename:=ExpandFileNameUTF8(PkgFilename);
1127
1128    Package:=LoadPackage(PkgFilename);
1129    if Package=nil then
1130    begin
1131      ErrorMsg+='Could not load '+PkgFilename+', so it is not registered.'+LineEnding;
1132      continue;
1133    end;
1134    if ConsoleVerbosity>=0 then
1135      debugln(['Hint: (lazarus) registering package link "'+PkgFilename+'".']);
1136    LazPackageLinks.AddUserLink(Package);
1137  end;
1138  if ErrorMsg<>'' then begin
1139    ErrorMsg:=UTF8Trim(ErrorMsg);
1140    Error(ErrCode,ErrorMsg);
1141    exit;
1142  end;
1143
1144  LazPackageLinks.SaveUserLinks(true);
1145  Result:=true;
1146end;
1147
1148function TLazBuildApplication.Init: boolean;
1149begin
1150  if fInitialized then exit(fInitResult);
1151  fInitResult:=false;
1152  fInitialized:=true;
1153
1154  if ConsoleVerbosity>=0 then
1155    debugln(['Hint: (lazarus) primary config path: ',GetPrimaryConfigPath]);
1156  CreatePrimaryConfigPath;
1157
1158  MainBuildBoss:=TBuildManager.Create(nil);
1159  SetupMacros;
1160  LoadEnvironmentOptions;
1161  if Terminated then exit(false);
1162  LoadMiscellaneousOptions;
1163  SetupLazarusDirectory;
1164  SetupCodetools;
1165  SetupFPCExeFilename;
1166  SetupPackageSystem;
1167  MainBuildBoss.SetupExternalTools(TExternalToolsConsole);
1168  ExtToolConsole:=TLazExtToolConsole.Create(nil);
1169  MainBuildBoss.SetupCompilerInterface;
1170
1171  StoreBaseSettings;
1172
1173  // load static base packages
1174  PackageGraph.LoadStaticBasePackages;
1175
1176  MainBuildBoss.SetBuildTarget(OSOverride,CPUOverride,WidgetSetOverride,smsfsSkip,true);
1177
1178  fInitResult:=true;
1179  Result:=fInitResult;
1180end;
1181
1182procedure TLazBuildApplication.LoadEnvironmentOptions;
1183var
1184  Note: string;
1185begin
1186  with EnvironmentOptions do begin
1187    CreateConfig;
1188    Load(false);
1189    fCompilerInCfg:=CompilerFilename;
1190    fLazarusDirInCfg:=LazarusDirectory;
1191
1192    if LazBuildApp.HasOption('language') then begin
1193      if ConsoleVerbosity>=0 then
1194        debugln('Note: (lazarus) overriding language with command line: ',
1195          LazBuildApp.GetOptionValue('language'));
1196      EnvironmentOptions.LanguageID:=LazBuildApp.GetOptionValue('language');
1197    end;
1198    TranslateResourceStrings(EnvironmentOptions.GetParsedLazarusDirectory,
1199                             EnvironmentOptions.LanguageID);
1200    if CompilerOverride<>'' then
1201      CompilerFilename:=CompilerOverride;
1202    //debugln(['TLazBuildApplication.LoadEnvironmentOptions LazarusDirectory="',LazarusDirectory,'"']);
1203    if LazarusDirOverride<>'' then
1204      LazarusDirectory:=CleanAndExpandDirectory(LazarusDirOverride);
1205    if MaxProcessCount>=0 then
1206      // set command line override
1207      MaxExtToolsInParallel:=MaxProcessCount;
1208  end;
1209  if not FileExistsUTF8(EnvironmentOptions.GetParsedLazarusDirectory
1210    +GetForcedPathDelims('packager/registration/fcl.lpk'))
1211  then begin
1212    CheckLazarusDirectoryQuality(EnvironmentOptions.GetParsedLazarusDirectory,Note);
1213    if ConsoleVerbosity>=-1 then
1214      debugln(['Error: (lazarus) invalid Lazarus directory "'+EnvironmentOptions.LazarusDirectory+'": '+Note]);
1215    Terminate;
1216  end;
1217end;
1218
1219procedure TLazBuildApplication.LoadMiscellaneousOptions;
1220begin
1221  if MiscellaneousOptions<>nil then exit;
1222  MiscellaneousOptions:=TMiscellaneousOptions.Create;
1223  MiscellaneousOptions.Load;
1224end;
1225
1226procedure TLazBuildApplication.SetupMacros;
1227begin
1228  MainBuildBoss.SetupTransferMacros;
1229end;
1230
1231procedure TLazBuildApplication.SetupCodetools;
1232begin
1233  // create a test unit needed to get from the compiler all macros and search paths
1234  CodeToolBoss.CompilerDefinesCache.TestFilename:=CreateCompilerTestPascalFilename;
1235  CodeToolBoss.SourceCache.OnEncodeSaving:=@OnCodeBufferEncodeSaving;
1236  CodeToolBoss.SourceCache.OnDecodeLoaded:=@OnCodeBufferDecodeLoaded;
1237  CodeToolBoss.SourceCache.DefaultEncoding:=EncodingUTF8;
1238
1239  MainBuildBoss.LoadCompilerDefinesCaches;
1240  // create a test unit needed to get from the compiler all macros and search paths
1241  CodeToolBoss.CompilerDefinesCache.TestFilename:=CreateCompilerTestPascalFilename;
1242end;
1243
1244procedure TLazBuildApplication.SetupPackageSystem;
1245begin
1246  OnGetDependencyOwnerDescription:=@GetDependencyOwnerDescription;
1247  OnGetDependencyOwnerDirectory:=@GetDependencyOwnerDirectory;
1248
1249  // package links
1250  LazPackageLinks:=TLazPackageLinks.Create;
1251  LazPackageLinks.UpdateAll;
1252
1253  // package graph
1254  PackageGraph:=TLazPackageGraph.Create;
1255  PackageGraphInterface:=PackageGraph;
1256  PackageGraph.OnAddPackage:=@PackageGraphAddPackage;
1257  PackageGraph.OnCheckInterPkgFiles:=@PackageGraphCheckInterPkgFiles;
1258  PackageGraph.Verbosity:=PkgGraphVerbosity;
1259end;
1260
1261procedure TLazBuildApplication.SetupDialogs;
1262begin
1263  LazMessageWorker:=@OnIDEMessageDialog;
1264  LazQuestionWorker:=@OnIDEQuestionDialog;
1265end;
1266
1267procedure TLazBuildApplication.StoreBaseSettings;
1268var
1269  StoreLazDir: Boolean;
1270  StoreCompPath: Boolean;
1271  Cfg: TXMLConfig;
1272begin
1273  StoreLazDir:=(fLazarusDirInCfg='') and (EnvironmentOptions.LazarusDirectory<>'');
1274  StoreCompPath:=(fCompilerInCfg='') and (EnvironmentOptions.CompilerFilename<>'');
1275  if (not StoreLazDir) and (not StoreCompPath) then exit;
1276
1277  try
1278    if ConsoleVerbosity>=-1 then
1279    begin
1280      dbgout('Hint: (lazarus) storing');
1281      if StoreLazDir then
1282        dbgout(' Lazarus directory "',EnvironmentOptions.LazarusDirectory,'"');
1283      if StoreCompPath then
1284        dbgout(' Compiler path "',EnvironmentOptions.CompilerFilename,'"');
1285      debugln(' in "',EnvironmentOptions.Filename,'"');
1286    end;
1287    Cfg:=TXMLConfig.Create(EnvironmentOptions.Filename);
1288    try
1289      if StoreLazDir then
1290        Cfg.SetValue('EnvironmentOptions/LazarusDirectory/Value',
1291                     EnvironmentOptions.LazarusDirectory);
1292      if StoreCompPath then
1293        Cfg.SetValue('EnvironmentOptions/CompilerFilename/Value',
1294                     EnvironmentOptions.CompilerFilename);
1295      Cfg.Flush;
1296    finally
1297      Cfg.Free;
1298    end;
1299  except
1300    on E: Exception do
1301      debugln(['Error: (lazarus) unable to edit file ',EnvironmentOptions.Filename]);
1302  end;
1303end;
1304
1305function TLazBuildApplication.RepairedCheckOptions(const ShortOptions: String;
1306  const Longopts: TStrings; Opts, NonOpts: TStrings): String;
1307
1308Var
1309  I,J,L,P : Integer;
1310  O,OV : String;
1311  HaveArg : Boolean;
1312  NeedArg: Boolean;
1313
1314  Function FindLongOpt(S : String) : boolean;
1315  Var
1316    I : integer;
1317  begin
1318    If CaseSensitiveOptions then
1319      begin
1320      I:=LongOpts.Count-1;
1321      While (I>=0) and (LongOpts[i]<>S) do
1322        Dec(i);
1323      end
1324    else
1325      begin
1326      S:=UpperCase(S);
1327      I:=LongOpts.Count-1;
1328      While (I>=0) and (UpperCase(LongOpts[i])<>S) do
1329        Dec(i);
1330      end;
1331    Result:=(I<>-1);
1332  end;
1333
1334begin
1335  Result:='';
1336  I:=1;
1337  While (I<=ToolParamCount) and (Result='') do
1338    begin
1339    O:=ToolParamStr(I);
1340    If (Length(O)=0) or (O[1]<>OptionChar) then
1341      begin
1342      If Assigned(NonOpts) then
1343        NonOpts.Add(O)
1344      end
1345    else
1346      begin
1347      If (Length(O)<2) then
1348        Result:=Format(lisErrInvalidOption,[i,O])
1349      else
1350        begin
1351        HaveArg:=False;
1352        OV:='';
1353        // Long option ?
1354        If (O[2]=OptionChar) then
1355          begin
1356          Delete(O,1,2);
1357          J:=Pos('=',O);
1358          If J<>0 then
1359            begin
1360            HaveArg:=true;
1361            OV:=O;
1362            Delete(OV,1,J);
1363            O:=Copy(O,1,J-1);
1364            end;
1365          // Switch Option
1366          If FindLongopt(O) then
1367            begin
1368            If HaveArg then
1369              Result:=Format(lisErrNoOptionAllowed,[I,O]);
1370            end
1371          else
1372            begin // Required argument
1373            If FindLongOpt(O+':') then
1374              begin
1375              If Not HaveArg then
1376                Result:=Format(lisErrOptionNeeded,[I,O]);
1377              end
1378            else
1379              begin // Optional Argument.
1380              If not FindLongOpt(O+'::') then
1381                Result:=Format(lisErrInvalidOption,[I,O]);
1382              end;
1383            end;
1384          end
1385        else // Short Option.
1386          begin
1387          HaveArg:=(I<ToolParamCount) and (Length(ToolParamStr(I+1))>0)
1388                   and (ToolParamStr(I+1)[i]<>OptionChar);
1389          If HaveArg then
1390            OV:=ToolParamStr(I+1);
1391          If Not CaseSensitiveOptions then
1392            O:=LowerCase(O);
1393          L:=Length(O);
1394          J:=2;
1395          NeedArg:=false;
1396          While (result='') and (J<=L) do
1397            begin
1398            P:=Pos(O[J],ShortOptions);
1399            If (P=0) or (O[j]=':') then
1400              Result:=Format(lisErrInvalidOption,[I,O[J]])
1401            else
1402              begin
1403              If (P<Length(ShortOptions)) and (Shortoptions[P+1]=':') then
1404                begin
1405                // Required argument
1406                NeedArg:=true;
1407                if ConsoleVerbosity>0 then
1408                  debugln(['P ',P,' J ',J,' ',O[J],' ',l,' Havearg ',HaveArg]);
1409                If ((P+1)=Length(ShortOptions)) or (Shortoptions[P+2]<>':') Then
1410                  If (J<L) or not haveArg then // Must be last in multi-opt !!
1411                    Result:=Format(lisErrOptionNeeded,[I,O[J]]);
1412                O:=O[j]; // O is added to arguments.
1413                end;
1414              end;
1415            Inc(J);
1416            end;
1417          if not NeedArg then HaveArg:=false;
1418          If HaveArg then
1419            begin
1420            Inc(I); // Skip argument.
1421            O:=O[Length(O)]; // O is added to arguments !
1422            end;
1423          end;
1424        If HaveArg and (Result='') then
1425          If Assigned(Opts) then
1426            Opts.Add(O+'='+OV);
1427        end;
1428      end;
1429    Inc(I);
1430    end;
1431end;
1432
1433constructor TLazBuildApplication.Create(TheOwner: TComponent);
1434begin
1435  inherited Create(TheOwner);
1436  SetupDialogs;
1437  Files:=TStringList.Create;
1438  fMaxProcessCount:=-1;
1439end;
1440
1441destructor TLazBuildApplication.Destroy;
1442begin
1443  CloseProject(Project1);
1444
1445  if Assigned(PackageGraph) then
1446  begin
1447    PackageGraph.FreeAutoInstallDependencies;
1448    FreeThenNil(PackageGraph);
1449  end;
1450
1451  FreeThenNil(LazPackageLinks);
1452  FreeThenNil(TheCompiler);
1453  FreeAndNil(ExtToolConsole);
1454  FreeThenNil(GlobalMacroList);
1455  FreeThenNil(IDEMacros);
1456  FreeThenNil(MiscellaneousOptions);
1457  FreeThenNil(EnvironmentOptions);
1458  FreeThenNil(MainBuildBoss);
1459
1460  FreeAndNil(Files);
1461  inherited Destroy;
1462end;
1463
1464procedure TLazBuildApplication.Run;
1465var
1466  i: Integer;
1467begin
1468  if not ParseParameters then exit;
1469
1470  // Build all projects/packages specified by the user...
1471  // except packages to be added the IDE install list.
1472  for i:=0 to Files.Count-1 do begin
1473    if not BuildFile(Files[i]) then begin
1474      if ConsoleVerbosity>=-1 then
1475        debugln('Error: (lazarus) Building failed: ',Files[i]);
1476      ExitCode := ErrorBuildFailed;
1477      exit;
1478    end;
1479  end;
1480
1481  // Add user-requested packages to IDE install list:
1482  case PackageAction of
1483  lpaInstall:
1484    if not AddPackagesToInstallList(Files) then begin
1485      if ConsoleVerbosity>=-1 then
1486        debugln('Error: (lazarus) Installing package(s) failed: ',Files.Text);
1487      ExitCode := ErrorBuildFailed;
1488      exit;
1489    end;
1490  lpaAddPkgLinks:
1491    if not AddCmdLinePackageLinks(Files) then begin
1492      if ConsoleVerbosity>=-1 then
1493        debugln('Error: (lazarus) Adding package(s) links failed: ',Files.Text);
1494      ExitCode := ErrorBuildFailed;
1495      exit;
1496    end;
1497  end;
1498
1499  if BuildIDE then begin
1500    if not BuildLazarusIDE then begin
1501      ExitCode := ErrorBuildFailed;
1502      exit;
1503    end;
1504  end;
1505end;
1506
1507function TLazBuildApplication.ParseParameters: boolean;
1508var
1509  Options: TStringList;
1510  NonOptions: TStringList;
1511  ErrorMsg: String;
1512  LongOptions: TStringList;
1513  i: Integer;
1514  p: String;
1515  FilesNeeded: Boolean;
1516begin
1517  Result:=false;
1518  if (ToolParamCount<=0)
1519   or (CompareText(ToolParamStr(1),'--help')=0)
1520   or (CompareText(ToolParamStr(1),'-help')=0)
1521   or (CompareText(ToolParamStr(1),'-?')=0)
1522   or (CompareText(ToolParamStr(1),'-h')=0)
1523  then begin
1524    WriteUsage;
1525    exit;
1526  end;
1527  if HasOption('h','help') or HasOption('?') then begin
1528    WriteUsage;
1529    exit;
1530  end;
1531  if HasOption('v','version') then begin
1532    writeln(VersionStr);
1533    exit;
1534  end;
1535
1536  // ConsoleVerbosity
1537  for i:=1 to ToolParamCount do begin
1538    p:=ToolParamStr(i);
1539    if p='--verbose' then
1540      ConsoleVerbosity:=Max(1,ConsoleVerbosity+1)
1541    else if (p='-q') or (p='--quiet') then
1542      ConsoleVerbosity:=Min(0,ConsoleVerbosity-1);
1543  end;
1544  CTConsoleVerbosity:=ConsoleVerbosity;
1545
1546  Options:=TStringList.Create;
1547  NonOptions:=TStringList.Create;
1548  LongOptions:=TStringList.Create;
1549  try
1550    LongOptions.Add('quiet');
1551    LongOptions.Add('verbose');
1552    LongOptions.Add('verbose-pkgsearch');
1553    LongOptions.Add('primary-config-path:');
1554    LongOptions.Add('pcp:');
1555    LongOptions.Add('secondary-config-path:');
1556    LongOptions.Add('scp:');
1557    LongOptions.Add('language:');
1558    LongOptions.Add('add-package');
1559    LongOptions.Add('add-package-link');
1560    LongOptions.Add('build-all');
1561    LongOptions.Add('build-ide:');
1562    LongOptions.Add('recursive');
1563    LongOptions.Add('skip-dependencies');
1564    LongOptions.Add('widgetset:');
1565    LongOptions.Add('ws:');
1566    LongOptions.Add('operating-system:');
1567    LongOptions.Add('os:');
1568    LongOptions.Add('cpu:');
1569    LongOptions.Add('bm:');
1570    LongOptions.Add('build-mode:');
1571    LongOptions.Add('compiler:');
1572    LongOptions.Add('lazarusdir:');
1573    LongOptions.Add('create-makefile');
1574    LongOptions.Add('max-process-count:');
1575    LongOptions.Add('no-write-project');
1576    ErrorMsg:=RepairedCheckOptions('lBrdq',LongOptions,Options,NonOptions);
1577    if ErrorMsg<>'' then begin
1578      writeln(ErrorMsg);
1579      writeln('');
1580      exit;
1581    end;
1582
1583    FilesNeeded:=true;
1584
1585    if HasOption('verbose-pkgsearch') then
1586      Include(fPkgGraphVerbosity,pvPkgSearch);
1587
1588    // PackageAction: register lpk files
1589    if HasOption('add-package-link') then begin
1590      if ConsoleVerbosity>=0 then
1591        writeln('Parameter: add-package-link');
1592      if PackageAction<>lpaBuild then begin
1593        writeln('Error: invalid combination of package actions');
1594        WriteUsage;
1595        exit;
1596      end;
1597      FilesNeeded:=false;
1598      PackageAction:=lpaAddPkgLinks;
1599    end;
1600
1601    // PackageAction: install lpk files
1602    if HasOption('add-package') then begin
1603      if ConsoleVerbosity>=0 then
1604        writeln('Parameter: add-package');
1605      if PackageAction<>lpaBuild then begin
1606        writeln('Error: invalid combination of package actions');
1607        WriteUsage;
1608        exit;
1609      end;
1610      PackageAction:=lpaInstall;
1611      FilesNeeded:=false;
1612    end;
1613
1614    // building IDE
1615    if HasOption('build-ide') then begin
1616      BuildIDE:=true;
1617      BuildIDEOptions:=GetOptionValue('build-ide');
1618      FilesNeeded:=false;
1619      if ConsoleVerbosity>=0 then
1620        writeln('Parameter: build-ide=',BuildIDEOptions);
1621    end;
1622
1623    // files
1624    Files.Assign(NonOptions);
1625    if FilesNeeded and (Files.Count=0) then begin
1626      writeln('Error: missing file');
1627      WriteUsage;
1628      exit;
1629    end;
1630
1631    // primary config path
1632    if HasOption('primary-config-path') then begin
1633      SetPrimaryConfigPath(GetOptionValue('primary-config-path'));
1634      if ConsoleVerbosity>=0 then
1635        writeln('Parameter: primary-config-path=',GetPrimaryConfigPath);
1636    end else if HasOption('pcp') then begin
1637      SetPrimaryConfigPath(GetOptionValue('pcp'));
1638      if ConsoleVerbosity>=0 then
1639        writeln('Parameter: pcp=',GetPrimaryConfigPath);
1640    end;
1641
1642    // secondary config path
1643    if HasOption('secondary-config-path') then begin
1644      SetPrimaryConfigPath(GetOptionValue('secondary-config-path'));
1645      if ConsoleVerbosity>=0 then
1646        writeln('Parameter: secondary-config-path=',GetSecondaryConfigPath);
1647    end else if HasOption('scp') then begin
1648      SetSecondaryConfigPath(GetOptionValue('scp'));
1649      if ConsoleVerbosity>=0 then
1650        writeln('Parameter: scp=',GetSecondaryConfigPath);
1651    end;
1652
1653    // build all
1654    if HasOption('B','build-all') then begin
1655      BuildAll:=true;
1656      if ConsoleVerbosity>=0 then
1657        writeln('Parameter: build-all');
1658    end;
1659    if HasOption('r','recursive') then begin
1660      BuildAll:=true;
1661      BuildRecursive:=true;
1662      if ConsoleVerbosity>=0 then
1663        writeln('Parameter: recursive');
1664    end;
1665    if HasOption('d','skip-dependencies') then begin
1666      SkipDependencies:=true;
1667      if ConsoleVerbosity>=0 then
1668        writeln('Parameter: skip-dependencies');
1669    end;
1670    if BuildRecursive and SkipDependencies then begin
1671      writeln('Error: --recursive and --skip-dependencies. You have to make up your mind.');
1672      WriteUsage;
1673      exit;
1674    end;
1675
1676    // overides
1677    // widgetset
1678    if HasOption('ws') then begin
1679      WidgetSetOverride := GetOptionValue('ws');
1680      if ConsoleVerbosity>=0 then
1681        writeln('Parameter: ws=',WidgetSetOverride);
1682    end else if HasOption('widgetset') then begin
1683      WidgetSetOverride := GetOptionValue('widgetset');
1684      if ConsoleVerbosity>=0 then
1685        writeln('Parameter: widgetset=',WidgetSetOverride);
1686    end;
1687
1688    // operating system
1689    if HasOption('os') then begin
1690      OSOverride := GetOptionValue('os');
1691      if ConsoleVerbosity>=0 then
1692        writeln('Parameter: os=',OSOverride);
1693    end else if HasOption('operating-system') then begin
1694      OSOverride := GetOptionValue('operating-system');
1695      if ConsoleVerbosity>=0 then
1696        writeln('Parameter: operating-system=',OSOverride);
1697    end;
1698
1699    // cpu
1700    if HasOption('cpu') then begin
1701      CPUOverride := GetOptionValue('cpu');
1702      if ConsoleVerbosity>=0 then
1703        writeln('Parameter: cpu=',CPUOverride);
1704    end;
1705
1706    // build mode
1707    if HasOption('bm') then begin
1708      BuildModeOverride := GetOptionValue('bm');
1709      if ConsoleVerbosity>=0 then
1710        writeln('Parameter: bm=',BuildModeOverride);
1711    end else if HasOption('build-mode') then begin
1712      BuildModeOverride := GetOptionValue('build-mode');
1713      if ConsoleVerbosity>=0 then
1714        writeln('Parameter: build-mode=',BuildModeOverride);
1715    end;
1716
1717    // compiler
1718    if HasOption('compiler') then begin
1719      CompilerOverride := GetOptionValue('compiler');
1720      if ConsoleVerbosity>=0 then
1721        writeln('Parameter: compiler=',CompilerOverride);
1722    end;
1723
1724    // lazarusdir
1725    if HasOption('lazarusdir') then begin
1726      LazarusDirOverride := GetOptionValue('lazarusdir');
1727      if ConsoleVerbosity>=0 then
1728        writeln('Parameter: lazarusdir=',LazarusDirOverride);
1729    end;
1730
1731    // max-process-count
1732    if HasOption('max-process-count') then begin
1733      MaxProcessCount:=StrToInt(GetOptionValue('max-process-count'));
1734      if ConsoleVerbosity>=0 then
1735        writeln('Parameter: max-process-count=',MaxProcessCount);
1736    end;
1737
1738    if HasOption('no-write-project') then
1739    begin
1740      NoWriteProject := true;
1741      if ConsoleVerbosity>=0 then
1742        writeln('Parameter: no-write-project');
1743    end;
1744
1745    if HasOption('create-makefile') then
1746    begin
1747      CreateMakefile := true;
1748      if ConsoleVerbosity>=0 then
1749        writeln('Parameter: create-makefile');
1750      if PackageAction<>lpaBuild then
1751        Error(ErrorPackageNameInvalid,'You can not combine --create-makefile and --add-package');
1752    end;
1753  finally
1754    Options.Free;
1755    NonOptions.Free;
1756    LongOptions.Free;
1757  end;
1758  Result:=true;
1759end;
1760
1761procedure TLazBuildApplication.WriteUsage;
1762const
1763  space = '                      ';
1764
1765  function LongToConsole(s: string): string;
1766  begin
1767    Result:=UTF8ToConsole(BreakString(s,75, length(space)))
1768  end;
1769
1770  procedure w(Msg: string);
1771  begin
1772    writeln(LongToConsole(Msg));
1773  end;
1774
1775begin
1776  TranslateResourceStrings(ProgramDirectoryWithBundle,'');
1777  writeln('');
1778  writeln('lazbuild [options] <project/package filename or package name>');
1779  writeln('');
1780  w(lisEdtExtToolParameters);
1781  writeln('');
1782  writeln('--help or -?');
1783  w(space+listhisHelpMessage);
1784  writeln('-B or --build-all');
1785  w(space+lisBuildAllFilesOfProjectPackageIDE);
1786  writeln('-r or --recursive');
1787  w(space+lisApplyBuildFlagsBToDependenciesToo);
1788  writeln('-d or --skip-dependencies');
1789  w(space+lisDoNotCompileDependencies);
1790  writeln('--build-ide=<options>');
1791  w(space+lisBuildIDEWithPackages);
1792  writeln('-v or --version');
1793  w(space+lisShowVersionAndExit);
1794  writeln('-q or --quiet');
1795  w(space+lisBeLessVerboseCanBeGivenMultipleTimes);
1796  w(space+'Passing quiet two times, will pass -vw-n-h-i-l-d-u-t-p-c-x- to the compiler');
1797  writeln('--verbose');
1798  w(space+lisBeMoreVerboseCanBeGivenMultipleTimes);
1799  writeln('--verbose-pkgsearch');
1800  w(space+'Write what package files are searched and found');
1801  writeln('');
1802
1803  writeln('--add-package');
1804  w(space+lisAddPackageSToListOfInstalledPackagesCombineWithBui);
1805  writeln('--add-package-link=<.lpk file>');
1806  w(space+lisOnlyRegisterTheLazarusPackageFilesLpkDoNotBuild);
1807  writeln('--create-makefile');
1808  w(space+lisInsteadOfCompilePackageCreateASimpleMakefile);
1809  writeln('');
1810
1811  writeln(PrimaryConfPathOptLong,'<path>');
1812  writeln('or ',PrimaryConfPathOptShort,'<path>');
1813  w(space+lisprimaryConfigDirectoryWhereLazarusStoresItsConfig+LazConf.GetPrimaryConfigPath);
1814  writeln('');
1815  writeln(SecondaryConfPathOptLong,'<path>');
1816  writeln('or ',SecondaryConfPathOptShort,'<path>');
1817  w(space+lissecondaryConfigDirectoryWhereLazarusSearchesFor+LazConf.GetSecondaryConfigPath);
1818  writeln('');
1819  writeln('--operating-system=<operating-system>');
1820  writeln('or --os=<operating-system>');
1821  writeln(LongToConsole(Format(
1822    lisOverrideTheProjectOperatingSystemEGWin32LinuxDefau, [space,
1823    GetCompiledTargetOS])));
1824  writeln('');
1825  writeln('--widgetset=<widgetset>');
1826  writeln('or --ws=<widgetset>');
1827  writeln(LongToConsole(Format(
1828    lisOverrideTheProjectWidgetsetEGGtkGtk2QtWin32CarbonD, [space,
1829    LCLPlatformDirNames[GetBuildLCLWidgetType]])));
1830  writeln('');
1831  writeln('--cpu=<cpu>');
1832  writeln(LongToConsole(Format(
1833    lisOverrideTheProjectCpuEGI386X86_64PowerpcPowerpc_64, [space,
1834    GetCompiledTargetCPU])));
1835  writeln('');
1836  writeln('--build-mode=<project/ide build mode>');
1837  writeln('or --bm=<project/ide build mode>');
1838  writeln(LongToConsole(Format(lisOverrideTheProjectBuildMode,[space])));
1839  writeln('');
1840  writeln('--compiler=<ppcXXX>');
1841  writeln(LongToConsole(Format(
1842    lisOverrideTheDefaultCompilerEGPpc386Ppcx64PpcppcEtcD, [space])));
1843  writeln('');
1844  writeln(LanguageOpt);
1845  w(space+lisOverrideLanguage);
1846  writeln('');
1847  writeln('--lazarusdir=<Lazarus directory>');
1848  w(space+lisLazarusDirOverride);
1849  writeln('');
1850  writeln('--max-process-count=<count>');
1851  w(space+lisMaximumNumberOfThreadsForCompilingInParallelDefaul);
1852  writeln('');
1853  writeln('--no-write-project');
1854  w(space+lisDoNotWriteUpdatedProjectInfoAfterBuild);
1855  writeln('');
1856end;
1857
1858procedure TLazBuildApplication.Error(ErrorCode: Byte; const ErrorMsg: string);
1859begin
1860  writeln('Error: (lazbuild) ',LineBreaksToSystemLineBreaks(ErrorMsg));
1861  Halt(ErrorCode);
1862end;
1863
1864begin
1865  // When quick rebuilding lazbuild, FPC rebuilds only the lazbuild.lpr, so any
1866  // flag that should work with quick build must be set here.
1867  // At the moment there is no flag
1868
1869  HasGUI:=false;
1870  ConsoleVerbosity:=-1;
1871  FilterConfigFileContent;
1872  // free LCL Application to help debugging nogui issues
1873  Application.Free;
1874  // start our own LazBuildApp
1875  LazBuildApp:=TLazBuildApplication.Create(nil);
1876  LazBuildApp.Run;
1877  LazBuildApp.Free;
1878end.
1879
1880