unit compiler_compilation_options; {$mode objfpc}{$H+} interface uses // RTL + FCL + LCL Classes, sysutils, Controls, StdCtrls, Dialogs, ComboEx, // CodeTools FileProcs, DefineTemplates, CodeToolManager, LinkScanner, // LazUtils FileUtil, LazFileUtils, // IDEIntf IDEOptionsIntf, CompOptsIntf, IDEDialogs, IDEUtils, IDEExternToolIntf, // IDE Project, CompilerOptions, PackageDefs, LazarusIDEStrConsts, EnvironmentOpts, LazConf, IDEProcs, DialogProcs, InputHistory, InitialSetupProc; type { TCompilerCompilationOptionsFrame } TCompilerCompilationOptionsFrame = class(TAbstractIDEOptionsEditor) BrowseCompilerButton: TButton; ExecAfterParsersCheckComboBox: TCheckComboBox; ExecAfterParsersLabel: TLabel; ExecAfterParsersSumLabel: TLabel; ExecBeforeBrowseButton: TButton; chkCompilerBuild: TCheckBox; chkCompilerCompile: TCheckBox; chkCompilerRun: TCheckBox; chkCreateMakefile: TCheckBox; chkExecAfterBuild: TCheckBox; chkExecAfterCompile: TCheckBox; chkExecAfterRun: TCheckBox; chkExecBeforeBuild: TCheckBox; chkExecBeforeCompile: TCheckBox; chkExecBeforeRun: TCheckBox; cobCompiler: TComboBox; ExecAfterBrowseButton: TButton; ExecBeforeParsersSumLabel: TLabel; ExecuteAfterCommandComboBox: TComboBox; ExecuteAfterCommandLabel: TLabel; ExecuteAfterGroupBox: TGroupBox; ExecuteBeforeCommandComboBox: TComboBox; ExecuteBeforeCommandLabel: TLabel; ExecuteBeforeGroupBox: TGroupBox; ExecBeforeParsersCheckComboBox: TCheckComboBox; ExecBeforeParsersLabel: TLabel; grpCompiler: TGroupBox; lblCompiler: TLabel; lblRunIfCompiler: TLabel; lblRunIfExecAfter: TLabel; lblRunIfExecBefore: TLabel; procedure CompCmdBrowseButtonClick(Sender: TObject); procedure ExecAfterParsersCheckComboBoxItemChange(Sender: TObject; {%H-}AIndex: Integer); procedure ExecBeforeParsersCheckComboBoxItemChange(Sender: TObject; {%H-}AIndex: Integer); private procedure ReadSettingsParsers(ToolOpts: TCompilationToolOptions; Cmb: TCheckComboBox; Lbl: TLabel); procedure WriteSettingsParsers(ToolOpts: TCompilationToolOptions; Cmb: TCheckComboBox); procedure UpdateParsersLabel(Lbl: TLabel; Cmb: TCheckComboBox); public function GetTitle: string; override; procedure Setup({%H-}ADialog: TAbstractOptionsEditorDialog); override; procedure ReadSettings(AOptions: TAbstractIDEOptions); override; procedure WriteSettings(AOptions: TAbstractIDEOptions); override; class function SupportedOptionsClass: TAbstractIDEOptionsClass; override; end; implementation {$R *.lfm} { TCompilerCompilationOptionsFrame } procedure TCompilerCompilationOptionsFrame.CompCmdBrowseButtonClick( Sender: TObject); function ShowQuality(Quality: TSDFilenameQuality; const Filename, Note: string): boolean; begin if Quality<>sddqCompatible then begin if IDEMessageDialog(lisCCOWarningCaption, Format( lisTheCompilerFileDoesNotLookCorrect, [Filename, #13, Note]), mtWarning,[mbIgnore,mbCancel])<>mrIgnore then exit(false); end; Result:=true; end; var OpenDialog: TOpenDialog; NewFilename: string; Quality: TSDFilenameQuality; Note: string; s: string; OldFilename: string; OldParams: string; Combo: TComboBox; ok: Boolean; begin OpenDialog:=TOpenDialog.Create(nil); try InputHistories.ApplyFileDialogSettings(OpenDialog); OpenDialog.Options:=OpenDialog.Options+[ofFileMustExist]; OpenDialog.Filter:=dlgFilterAll+'|'+GetAllFilesMask; OldFilename:=''; OldParams:=''; // set title if Sender=BrowseCompilerButton then begin Combo:=cobCompiler; OpenDialog.Title:=Format(lisChooseCompilerExecutable,[GetDefaultCompilerFilename]) end else if (Sender=ExecAfterBrowseButton) then begin Combo:=ExecuteAfterCommandComboBox; OpenDialog.Title:=lisChooseExecutable; SplitCmdLine(Combo.Text,OldFilename,OldParams); end else if (Sender=ExecBeforeBrowseButton) then begin Combo:=ExecuteBeforeCommandComboBox; OpenDialog.Title:=lisChooseExecutable; SplitCmdLine(Combo.Text,OldFilename,OldParams); end else exit; if not OpenDialog.Execute then exit; NewFilename:=TrimAndExpandFilename(OpenDialog.Filename); // check, even if new file is old filename, so the user see the warnings again ok:=false; if Sender=BrowseCompilerButton then begin // check compiler filename case GetPascalCompilerFromExeName(NewFilename) of pcPas2js: if IsPas2JSExecutable(NewFilename,s) then begin // check pas2js Quality:=CheckPas2jsQuality(NewFilename,Note, CodeToolBoss.CompilerDefinesCache.TestFilename); if not ShowQuality(Quality,NewFilename,Note) then exit; ok:=true; end; else if IsFPCExecutable(NewFilename,s) then begin // check fpc Quality:=CheckCompilerQuality(NewFilename,Note, CodeToolBoss.CompilerDefinesCache.TestFilename); if not ShowQuality(Quality,NewFilename,Note) then exit; ok:=true; end; end; // maybe a script if (not ok) and not CheckExecutable(OldFilename,NewFilename,lisInvalidExecutable,lisInvalidExecutableMessageText) then exit; ok:=true; end else if (Sender=ExecBeforeBrowseButton) or (Sender=ExecAfterBrowseButton) then begin // check executable if not CheckExecutable(OldFilename,NewFilename,lisInvalidExecutable,lisInvalidExecutableMessageText) then exit; ok:=true; end; SetComboBoxText(Combo,NewFilename,cstFilename); finally InputHistories.StoreFileDialogSettings(OpenDialog); OpenDialog.Free; end; end; procedure TCompilerCompilationOptionsFrame. ExecAfterParsersCheckComboBoxItemChange(Sender: TObject; AIndex: Integer); begin UpdateParsersLabel(ExecAfterParsersSumLabel,ExecAfterParsersCheckComboBox); end; procedure TCompilerCompilationOptionsFrame. ExecBeforeParsersCheckComboBoxItemChange(Sender: TObject; AIndex: Integer); begin UpdateParsersLabel(ExecBeforeParsersSumLabel,ExecBeforeParsersCheckComboBox); end; procedure TCompilerCompilationOptionsFrame.ReadSettingsParsers( ToolOpts: TCompilationToolOptions; Cmb: TCheckComboBox; Lbl: TLabel); const BoolToChecked: array[boolean] of TCheckBoxState = (cbUnchecked,cbChecked); var l: TFPList; i, j: Integer; ParserClass: TExtToolParserClass; s: String; begin l:=TFPList.Create; try // add registered parsers for i:=0 to ExternalToolList.ParserCount-1 do begin ParserClass:=ExternalToolList.Parsers[i]; j:=0; while (j=ParserClass.Priority) do inc(j); l.Insert(j,ParserClass); end; Cmb.Clear; for i:=0 to l.Count-1 do begin ParserClass:=TExtToolParserClass(l[i]); s:=ParserClass.GetLocalizedParserName; Cmb.AddItem(s,BoolToChecked[ToolOpts.HasParser[ParserClass.GetParserName]]); end; // add not registered parsers // Note: this happens when opening a project, which needs a designtime-package for i:=0 to ToolOpts.Parsers.Count-1 do begin s:=ToolOpts.Parsers[i]; if ExternalToolList.FindParserWithName(s)=nil then Cmb.AddItem(s,cbChecked); end; UpdateParsersLabel(Lbl,Cmb); finally l.Free; end; end; procedure TCompilerCompilationOptionsFrame.WriteSettingsParsers( ToolOpts: TCompilationToolOptions; Cmb: TCheckComboBox); var sl: TStringList; i, j: Integer; begin sl:=TStringList.Create; try for i:=0 to Cmb.Items.Count-1 do if Cmb.Checked[i] then begin j:=ExternalToolList.ParserCount-1; while (j>=0) and (Cmb.Items[i]<>ExternalToolList.Parsers[i].GetLocalizedParserName) do dec(j); if j>=0 then sl.Add(ExternalToolList.Parsers[i].GetParserName) else sl.Add(Cmb.Items[i]); // not registered parser end; ToolOpts.Parsers:=sl; finally sl.Free; end; end; procedure TCompilerCompilationOptionsFrame.UpdateParsersLabel(Lbl: TLabel; Cmb: TCheckComboBox); var s: String; i: Integer; begin s:=''; for i:=0 to Cmb.Items.Count-1 do begin if Cmb.Checked[i] then begin if s<>'' then s:=s+', '; s:=s+Cmb.Items[i]; end; end; Lbl.Caption:=s; end; function TCompilerCompilationOptionsFrame.GetTitle: string; begin Result := dlgCOCompilerCommands; end; procedure TCompilerCompilationOptionsFrame.Setup(ADialog: TAbstractOptionsEditorDialog); begin chkCreateMakefile.Caption := dlgCOCreateMakefile; chkCreateMakefile.Hint := lisEnabledOnlyForPackages; ExecuteBeforeGroupBox.Caption := lisCOExecuteBefore; lblRunIfExecBefore.Caption := lisCOCallOn; chkExecBeforeBuild.Caption := lisBuildStage; chkExecBeforeCompile.Caption := lisCompileStage; chkExecBeforeRun.Caption := lisRunStage; ExecuteBeforeCommandComboBox.Text := ''; ExecuteBeforeCommandLabel.Caption := lisCOCommand; ExecBeforeParsersLabel.Caption:=lisParsers; grpCompiler.Caption := lisCompiler; lblRunIfCompiler.Caption := lisCOCallOn; chkCompilerBuild.Caption := lisBuildStage; chkCompilerBuild.Checked := True; chkCompilerCompile.Caption := lisCompileStage; chkCompilerCompile.Checked := True; chkCompilerRun.Caption := lisRunStage; chkCompilerRun.Checked := True; lblCompiler.Caption := lisCOCommand; cobCompiler.Text := ''; BrowseCompilerButton.Hint:=lisBrowseAndSelectACompiler+ExeExt+')'; ExecuteAfterGroupBox.Caption := lisCOExecuteAfter; chkExecAfterBuild.Caption := lisBuildStage; chkExecAfterCompile.Caption := lisCompileStage; chkExecAfterRun.Caption := lisRunStage; ExecuteAfterCommandComboBox.Text := ''; ExecuteAfterCommandLabel.Caption := lisCOCommand; ExecAfterParsersLabel.Caption:=lisParsers; lblRunIfExecAfter.Caption := lisCOCallOn; end; procedure TCompilerCompilationOptionsFrame.ReadSettings(AOptions: TAbstractIDEOptions); var Options: TBaseCompilerOptions absolute AOptions; begin chkCreateMakefile.Checked := Options.CreateMakefileOnBuild; // execute before with ExecuteBeforeCommandComboBox do begin Items.BeginUpdate; Items.Assign(InputHistories.HistoryLists.GetList('BuildExecBefore',true,rltFile)); SetComboBoxText(ExecuteBeforeCommandComboBox,Options.ExecuteBefore.Command,cstCaseSensitive); Items.EndUpdate; end; if Options.ExecuteBefore is TProjectCompilationToolOptions then with TProjectCompilationToolOptions(Options.ExecuteBefore) do begin chkExecBeforeCompile.Checked := crCompile in CompileReasons; chkExecBeforeBuild.Checked := crBuild in CompileReasons; chkExecBeforeRun.Checked := crRun in CompileReasons; lblRunIfExecBefore.Visible := True; chkExecBeforeCompile.Visible := True; chkExecBeforeBuild.Visible := True; chkExecBeforeRun.Visible := True; end else begin lblRunIfExecBefore.Visible := False; chkExecBeforeCompile.Visible := False; chkExecBeforeBuild.Visible := False; chkExecBeforeRun.Visible := False; end; ReadSettingsParsers(Options.ExecuteBefore,ExecBeforeParsersCheckComboBox, ExecBeforeParsersSumLabel); // compiler path with cobCompiler do begin Items.BeginUpdate; Items.Assign(EnvironmentOptions.CompilerFileHistory); AddFilenameToList(Items,DefaultCompilerPath); SetComboBoxText(cobCompiler,Options.CompilerPath,cstFilename); Items.EndUpdate; end; if Options is TProjectCompilerOptions then with TProjectCompilerOptions(Options) do begin chkCreateMakefile.Enabled:=false; lblRunIfCompiler.Visible := True; chkCompilerCompile.AnchorToNeighbour(akLeft, 30, lblRunIfCompiler); chkCompilerCompile.Checked := crCompile in CompileReasons; chkCompilerBuild.Checked := crBuild in CompileReasons; chkCompilerRun.Checked := crRun in CompileReasons; chkCompilerCompile.Caption := lisCompileStage; chkCompilerCompile.Visible := True; chkCompilerBuild.Visible := True; chkCompilerRun.Visible := True; cobCompiler.AnchorToNeighbour(akTop, 0, chkCompilerCompile); end else if Options is TPkgCompilerOptions then begin chkCreateMakefile.Enabled:=true; lblRunIfCompiler.Visible := False; chkCompilerCompile.AnchorParallel(akTop, 6, chkCompilerCompile.Parent); chkCompilerCompile.AnchorParallel(akLeft, 6, chkCompilerCompile.Parent); chkCompilerCompile.Visible := True; chkCompilerCompile.Caption := lisCOSkipCallingCompiler; chkCompilerCompile.Checked := TPkgCompilerOptions(Options).SkipCompiler; chkCompilerBuild.Visible := False; chkCompilerRun.Visible := False; cobCompiler.AnchorToNeighbour(akTop, 0, chkCompilerCompile); end else begin lblRunIfCompiler.Visible := False; chkCompilerCompile.Visible := False; chkCompilerBuild.Visible := False; chkCompilerRun.Visible := False; cobCompiler.AnchorParallel(akTop, 0, lblCompiler.Parent); end; // execute after with ExecuteAfterCommandComboBox do begin Items.BeginUpdate; Items.Assign(InputHistories.HistoryLists.GetList('BuildExecAfter',true,rltFile)); SetComboBoxText(ExecuteAfterCommandComboBox,Options.ExecuteAfter.Command,cstCaseSensitive); Items.EndUpdate; end; if Options.ExecuteAfter is TProjectCompilationToolOptions then with TProjectCompilationToolOptions(Options.ExecuteAfter) do begin chkExecAfterCompile.Checked := crCompile in CompileReasons; chkExecAfterBuild.Checked := crBuild in CompileReasons; chkExecAfterRun.Checked := crRun in CompileReasons; lblRunIfExecAfter.Visible := True; chkExecAfterCompile.Visible := True; chkExecAfterBuild.Visible := True; chkExecAfterRun.Visible := True; end else begin lblRunIfExecAfter.Visible := False; chkExecAfterCompile.Visible := False; chkExecAfterBuild.Visible := False; chkExecAfterRun.Visible := False; end; ReadSettingsParsers(Options.ExecuteAfter,ExecAfterParsersCheckComboBox, ExecAfterParsersSumLabel); end; procedure TCompilerCompilationOptionsFrame.WriteSettings(AOptions: TAbstractIDEOptions); function MakeCompileReasons(const ACompile, ABuild, ARun: TCheckBox): TCompileReasons; begin Result := []; if ACompile.Checked then Include(Result, crCompile); if ABuild.Checked then Include(Result, crBuild); if ARun.Checked then Include(Result, crRun); end; var Options: TBaseCompilerOptions absolute AOptions; begin Options.CreateMakefileOnBuild := chkCreateMakefile.Checked; // execute before Options.ExecuteBefore.Command := ExecuteBeforeCommandComboBox.Text; with InputHistories.HistoryLists.GetList('BuildExecBefore',true,rltCaseSensitive) do begin Assign(ExecuteBeforeCommandComboBox.Items); Push(Options.ExecuteBefore.Command); end; WriteSettingsParsers(Options.ExecuteBefore,ExecBeforeParsersCheckComboBox); if Options.ExecuteBefore is TProjectCompilationToolOptions then begin TProjectCompilationToolOptions(Options.ExecuteBefore).CompileReasons := MakeCompileReasons(chkExecBeforeCompile, chkExecBeforeBuild, chkExecBeforeRun); end; // compiler path Options.CompilerPath := cobCompiler.Text; EnvironmentOptions.CompilerFileHistory.Assign(cobCompiler.Items); AddToRecentList(Options.CompilerPath,EnvironmentOptions.CompilerFileHistory,30,rltFile); if Options is TProjectCompilerOptions then begin TProjectCompilerOptions(Options).CompileReasons := MakeCompileReasons(chkCompilerCompile, chkCompilerBuild, chkCompilerRun); end else if Options is TPkgCompilerOptions then TPkgCompilerOptions(Options).SkipCompiler := chkCompilerCompile.Checked; // execute after Options.ExecuteAfter.Command := ExecuteAfterCommandComboBox.Text; with InputHistories.HistoryLists.GetList('BuildExecAfter',true,rltCaseSensitive) do begin Assign(ExecuteAfterCommandComboBox.Items); Push(Options.ExecuteAfter.Command); end; WriteSettingsParsers(Options.ExecuteAfter,ExecAfterParsersCheckComboBox); if Options.ExecuteAfter is TProjectCompilationToolOptions then begin TProjectCompilationToolOptions(Options.ExecuteAfter).CompileReasons := MakeCompileReasons(chkExecAfterCompile, chkExecAfterBuild, chkExecAfterRun); end; end; class function TCompilerCompilationOptionsFrame.SupportedOptionsClass: TAbstractIDEOptionsClass; begin Result := TBaseCompilerOptions; end; initialization RegisterIDEOptionsEditor(GroupCompiler, TCompilerCompilationOptionsFrame, CompilerOptionsCompilation); RegisterIDEOptionsEditor(GroupPkgCompiler, TCompilerCompilationOptionsFrame, CompilerOptionsCompilation); end.