Jump to content
CoMPi74

Build / Output messages filtering plugin

Recommended Posts

Hi there,

 

I am looking for some kind of plugin which allows to catch and filter out build / output messages for selected group of files (let say, I have a project with hundreds of units but I just want to see messages for a few units I am assigned to). Is there such a tool? Or any suggestion how to develop such a tool?

 

Thanks in advance

 

Piotr 

Share this post


Link to post

When you say messages - do you mean hints and warnings?


(IMO, Hints and warnings are bugs waiting to happen and needs to be fixed on sight)

  • Like 2

Share this post


Link to post
9 minutes ago, Lars Fosdal said:

When you say messages - do you mean hints and warnings?


(IMO, Hints and warnings are bugs waiting to happen and needs to be fixed on sight)

Yes, exactly. And I have to say, I fully agree with above claim :) That is my main reason I am looking for such a tool. Any suggestions?

Share this post


Link to post

Not that I know of.

I am on my team like a hawk to have them clean up code that generates hints and warnings before they commit, so usually what I see is mine. :classic_ninja:

 

But - it could be useful.  Perhaps @dummzeuch has something up his sleeve?

Share this post


Link to post

@Kas Ob. I did not realize there is such a great web page :) I will definitely read it. Thank you.

Share this post


Link to post
37 minutes ago, Lars Fosdal said:

Perhaps @dummzeuch has something up his sleeve?

I've got something called msbuildfilter as part of my buildtools, But

  1. It solves a different problem even though it does parse the msbuild output.
  2. It's not open source and I can't easily make it. So it's not possible to simply adapt it to this purpose

So, no, nothing readily available up my sleeve. 😉

Share this post


Link to post

Just jotting down what my brain generates - what if...

- Each hint warning could display the last git username that touched the file

- If the file is changed but not committed, it would be your name

- A filter could be added to highlight messages for specific username(s) and/or unit names - or hide messages not matching the filter

 

Share this post


Link to post

AFAIK, there is currently no mechanism to intercept the message display via OTAPI.

Share this post


Link to post

It's all a song of the future :) I was thinking about a much simpler tool. Because I know best what files interest me, at least initially, I assume that the filtering will be based on a selected list of files (e.g. read from a text file).

Share this post


Link to post

Years ago I wrote the "JEDI Uses Wizard" which scanned compiler messages to "catch" unresolved symbol errors and offer adding appropriate units to the uses clause. With no official OpenTools API available, it had to use a hack to retrieve the compiler output from the message window's treeview.
The code is very old and perhaps a bit dangerous (although back then it seemed stable) and I have no idea if it still works today (the IDE internals might have changed). See if it helps you:
https://github.com/project-jedi/jcl/blob/master/jcl/experts/useswizard/JCLUsesWizard.pas

  • Like 1

Share this post


Link to post
Guest
30 minutes ago, CoMPi74 said:

That's not very good news 😕 

Uwe is right there is no direct way to receive these messages.

 

But if you up to do it yourself and learn huge deal of valuable experience, then there is a way, to do that you need to hook one these if not all

IOTAMessageServices70.AddCompilerMessage

IOTAMessageServices80.AddCompilerMessage and its overloaded version

 

In theory one of these should be your target if not then you want to go after the custom messages, but begin with the AddCompilerMessage, and use https://github.com/MahdiSafsafi/DDetours

Share this post


Link to post
Guest

@CoMPi74 Sorry, but i think DDetours will not help you there !

So before wasting your time, you should know that i don't think you will get the result, the problem is more complicated and direct hook will not be possible here, still though knowing how to use hooking and reading Dave blog are very valuable knowledge.

Share this post


Link to post

I had the same use case a few months ago, and I was glad to find out that you can at least easily select, copy & paste the compiler output as text lines. Writing yourself a tool that filters the output (for example, by unit or severity) should be trivial. The extra step to select, copy & paste might be annoying, but better than nothing.

Share this post


Link to post
8 hours ago, Ondrej Kelle said:

Years ago I wrote the "JEDI Uses Wizard" which scanned compiler messages to "catch" unresolved symbol errors and offer adding appropriate units to the uses clause. With no official OpenTools API available, it had to use a hack to retrieve the compiler output from the message window's treeview.

Which Delphi version was that for? My guess would be Delphi 7 or earlier, because later versions use a VirtualTreeview and I found no way to get at its contents.

Share this post


Link to post
Guest

I believe that there is few points to attack here, for now i found one (ugly one) that exists on compiler message chain.

 

Will try to hook it after checking it existence in multiple IDE's, but can't go further than Seattle, will try this evening, hoping to not lose the interest due to boredom.

Share this post


Link to post
Guest

Here working code, at least for few IDE's i tested with.

 

unit CaptureCompilerOutput;

interface

uses
  SysUtils, Windows, ToolsAPI, DDetours, VCL.Dialogs;

implementation

const
{$IFDEF VER210} // Delphi 2010
  CoreIDEPackage = 'CoreIde140.bpl';
  HProcName =
    '@Msglines@TCompilerMsgLine@$bctr$qqr17Compintf@TMsgKindix20System@UnicodeStringiit3t3ox54System@%DelphiInterface$t26Msglinesintf@IMessageGroup%';
{$ENDIF}

{$IFDEF VER260} // Delphi XE5
  CoreIDEPackage = 'CoreIde190.bpl';
  HProcName =
    '@Msglines@TCompilerMsgLine@$bctr$qqr17Compintf@TMsgKindix20System@UnicodeStringiit3t3ox54System@%DelphiInterface$t26Msglinesintf@IMessageGroup%';
{$ENDIF}

{$IFDEF VER290} // Delphi XE8
  CoreIDEPackage = 'CoreIde220.bpl';
  HProcName =
    '@Msglines@TCompilerMsgLine@$bctr$qqr17Compintf@TMsgKindix20System@UnicodeStringiit3t3ox53System@%DelphiInterface$26Msglinesintf@IMessageGroup%';
{$ENDIF}

{$IFDEF VER300} // Delphi 10 (Seattle)
  CoreIDEPackage = 'CoreIde230.bpl';
  HProcName =
    '@Msglines@TCompilerMsgLine@$bctr$qqr17Compintf@TMsgKindix20System@UnicodeStringiit3t3ox53System@%DelphiInterface$26Msglinesintf@IMessageGroup%';
{$ENDIF}

type
  THookedCM = function(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11: Pointer): Pointer;
  TCompilerMsgType = (cmkHint, cmkWarn, cmkError, cmkFatal, cmkInfo);

var
  HandleCoreIDEBpl: THandle;
  FCompilerMsgLineProc: Pointer;
  TrampolineProc: THookedCM;

procedure CompilerMessage(const Source, Msg, FileName: string; MsgKind: TCompilerMsgType);
begin
  //   put your code here 
  if MsgKind <> cmkInfo then
  begin
    ShowMessage('1 -> ' + Source + #13#10 + '2 -> ' + Msg + #13#10 + '3 -> ' + FileName +
      #13#10 + '4 -> ' + IntToStr(Ord(MsgKind)));
  end;
end;

function HookedProc(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11: Pointer): Pointer;
begin
  CompilerMessage(PChar(P9), PChar(P8), PChar(P5), TCompilerMsgType(P3));
  Result := TrampolineProc(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11);
end;

procedure HookCompilerMessages;
begin
  HandleCoreIDEBpl := GetModuleHandle(CoreIDEPackage);
  FCompilerMsgLineProc := GetProcAddress(HandleCoreIDEBpl, HProcName);
  if FCompilerMsgLineProc = nil then
    ShowMessage('The function address couldn''t be found, Check package and function name.')
  else
    TrampolineProc := InterceptCreate(FCompilerMsgLineProc, @HookedProc);
end;

procedure UnHookCompilerMessages;
begin
  InterceptRemove(@TrampolineProc);
end;

initialization
  HookCompilerMessages;

finalization
  UnHookCompilerMessages;

end.

The two consts belongs to the running IDE, Delphi 2010 and XE5 did has different declaration for that function, XE8 and 10 did has the same export name for that function, so there is a chance later versions did not change it,

As how to obtain it?

It is declared in the CoreIdeXX.bpl as export, so easy to find and add. 

Also the TCompilerMsgType is same as TOTAMessageKind in ToolsAPI.pas, but i can be 100% sure so i declared it, for me it looks accurate.

 

The three text strings from the compiler will be isolated along with the kind in CompilerMessage.

Share this post


Link to post
17 hours ago, dummzeuch said:

Which Delphi version was that for? My guess would be Delphi 7 or earlier, because later versions use a VirtualTreeview and I found no way to get at its contents.

From the comment about TLine from coreide60.bpl, it might have been Delphi 6.

Sorry if it's no longer applicable.

Share this post


Link to post
Guest

Refined version with source line number.

 

unit CaptureCompilerOutput;

interface

uses
  SysUtils, Windows, ToolsAPI, DDetours{, VCL.Dialogs};

implementation

const
  HPROC_NAME_OLD =
    '@Msglines@TCompilerMsgLine@$bctr$qqr17Compintf@TMsgKindix20System@UnicodeStringiit3t3ox54System@%DelphiInterface$t26Msglinesintf@IMessageGroup%';
  HPROC_NAME_NEWER =
    '@Msglines@TCompilerMsgLine@$bctr$qqr17Compintf@TMsgKindix20System@UnicodeStringiit3t3ox53System@%DelphiInterface$26Msglinesintf@IMessageGroup%';

{$IFDEF VER200} // Delphi 2009
  COREIDEPACKAGE = 'CoreIde120.bpl';
  HPROCNAME = HPROC_NAME_OLD;
{$ENDIF}
{$IFDEF VER210} // Delphi 2010
  COREIDEPACKAGE = 'CoreIde140.bpl';
  HPROCNAME = HPROC_NAME_OLD;
{$ENDIF}
{$IFDEF VER260} // Delphi Xe5
  COREIDEPACKAGE = 'CoreIde190.bpl';
  HPROCNAME = HPROC_NAME_OLD;
{$ENDIF}
{$IFDEF VER290} // Delphi Xe8
  COREIDEPACKAGE = 'CoreIde220.bpl';
  HPROCNAME = HPROC_NAME_NEWER;
{$ENDIF}
{$IFDEF VER300} // Delphi 10 (Seattle)
  COREIDEPACKAGE = 'CoreIde230.bpl';
  HPROCNAME = HPROC_NAME_NEWER;
{$ENDIF}

type
  THookedCM = function(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11: Pointer): Pointer;
  TCompilerMsgType = (cmkHint, cmkWarn, cmkError, cmkFatal, cmkInfo);

var
  HandleCoreIDEBpl: THandle;
  FCompilerMsgLineProc: Pointer;
  TrampolineProc: THookedCM;

function CompilerMTypeToStr(Cmt: TCompilerMsgType): string;
begin
  case Cmt of
    cmkHint:  Result := 'Hint';
    cmkWarn:  Result := 'Warning';
    cmkError: Result := 'Error';
    cmkFatal: Result := 'Fatal';
    cmkInfo:  Result := 'Info';
  else
    Result := 'Uknown';
  end;
end;

// Returning false will prevent this message form being added to IDE's Message Window
function CompilerMessage(const From, Msg, SourceFile: string; SourceLine: Integer; MsgKind:
  TCompilerMsgType): Boolean;
begin
  {if MsgKind <> cmkInfo then
  begin
    ShowMessage('From -> ' + From + #13#10 + 'Message -> ' + Msg + #13#10 +
      'SourceFile -> ' + SourceFile + #13#10 + 'SourceLine -> ' + IntToStr(SourceLine) +
      #13#10 + 'MessageKind -> ' + CompilerMTypeToStr(MsgKind));
  end; }
  // Returning false will prevent this message form being added to IDE's Message Window
  Result := True;
end;

function HookedProc(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11: Pointer): Pointer;
begin
  if CompilerMessage(PChar(P9), PChar(P8), PChar(P5), integer(P6), TCompilerMsgType(P3)) then
    Result := TrampolineProc(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11)
  else
    Result := nil;
end;

procedure HookCompilerMessages;
begin
  HandleCoreIDEBpl := GetModuleHandle(COREIDEPACKAGE);
  if HandleCoreIDEBpl = 0 then
    raise Exception.Create('CompilerMessagesHook : Package ' + COREIDEPACKAGE + ' not found.');
  FCompilerMsgLineProc := GetProcAddress(HandleCoreIDEBpl, HPROCNAME);
  if FCompilerMsgLineProc = nil then
    raise Exception.Create('CompilerMessagesHook : The following function can''t be located in '
      + COREIDEPACKAGE + #13#10 + HPROCNAME);
  TrampolineProc := InterceptCreate(FCompilerMsgLineProc, @HookedProc);
end;

procedure UnHookCompilerMessages;
begin
  InterceptRemove(@TrampolineProc);
end;

initialization
  HookCompilerMessages;

finalization
  UnHookCompilerMessages;

end.

image.png.2fb7834afab14ce9e7528068bd1e0427.pngimage.png.558dbe301de683dda45070ba979b3047.png

Share this post


Link to post
On 6/25/2021 at 5:05 PM, Der schöne Günther said:

I had the same use case a few months ago, and I was glad to find out that you can at least easily select, copy & paste the compiler output as text lines. Writing yourself a tool that filters the output (for example, by unit or severity) should be trivial. The extra step to select, copy & paste might be annoying, but better than nothing.

This is the way I am doing it right now. Though, I do not use a "special" tool ;) Instead I use Notepad++. It is enough for small projects but I am going to cleanup a significantly larger project and I need a better tool.

Share this post


Link to post
On 6/25/2021 at 6:43 PM, Ondrej Kelle said:

Years ago I wrote the "JEDI Uses Wizard" which scanned compiler messages to "catch" unresolved symbol errors and offer adding appropriate units to the uses clause. With no official OpenTools API available, it had to use a hack to retrieve the compiler output from the message window's treeview.
The code is very old and perhaps a bit dangerous (although back then it seemed stable) and I have no idea if it still works today (the IDE internals might have changed). See if it helps you:
https://github.com/project-jedi/jcl/blob/master/jcl/experts/useswizard/JCLUsesWizard.pas

Hello Ondrej,
Has there been any new work on Jedi Uses WIZARD ? How do you use it exactly ?
I tried compiling it (D11 JEDI 2.8 and 3.5) but it mentioned something about first getting  a DOC-O-MATIC filename.... What does that entail ?

Edited by Blavatsky

Share this post


Link to post
8 hours ago, Blavatsky said:

Hello Ondrej,
Has there been any new work on Jedi Uses WIZARD ? How do you use it exactly ?
I tried compiling it (D11 JEDI 2.8 and 3.5) but it mentioned something about first getting  a DOC-O-MATIC filename.... What does that entail ?

Hi. Sorry, I haven't used it for years now and I have no idea.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×