Main menu:

Site search

December 2008
S M T W T F S
     
 123456
78910111213
14151617181920
21222324252627
28293031  

Categories

Tags

MSBuild Logger in Delphi .NET

Project: Create a custom XML logger dll for use with MSBuild using Delphi.

Starting with Delphi 2007 Codegear uses MSBuild as the build engine. There is a split in the Delphi community over this being a good thing, but I think it is. MSBuild is Microsoft’s scripting tool for the build process and is very comparable to make. The ‘dproj’ file that is created with a project in Delphi is actually an XML file that can be used with MSBuild.

I think this is a good thing because I can use the exact same tool as the IDE to automates builds. Delphi WAnt worked for years but you have to manually create the build script and keep it in sync with the project. Now Delphi keeps the MSBuild script in sync since it is the same file it uses when you compile in the IDE.

While making the switch from WAnt to MSBuild I realized I no longer had to redirect stdout and parse the output for errors during the build process. I could just tell MSBuild to use a custom logger and I could write the log as easy to parse XML. It was finally time for me to learn a little .NET. All that is needed to create a custom logger is create a class that supports the ILogger interface.

During the following steps I will create a basic logger using Delphi .NET that should be easy to extend to any format you might need. The first thing is to start a new project.

New .NET DLL

Select ‘New | Other … ‘ and then select Library under ‘Delphi for .NET Projects.

 

 

Save the new library project as “DCBuildLogger.dproj” and add the references to the .NET assemblies Microsoft.Build.Framework and Microsoft.Build.Utilities.

Add Reference

Right click References in the Project manager and select Add Reference.

 

 

MSfk_MSut

Select Microsoft.Build.Frameworkand Microsoft.Build.Utilities and click Add References

 

 

 

NewUnit

Select ‘File | New | Other’ and select Unit under Delphi for .NET projects

 

 

 

Save the new unit as BuildLogger.pas. Now that everything is setup we can get to the interesting bits. First add a uses clause and specify the proper units.

uses
  SysUtils, Classes, System.Xml, Microsoft.Build.Utilities,
  Microsoft.Build.Framework;

 

Next define a class that will implement the ILogger interface called TXMLBuildLogger. We are actually extending the Logger class which already supports the interface. Include a couple of basic functions to make the first version of the logger somewhat useful.

type
  TXMLBuildLogger = class(Logger)
  private
    FXMLWriter: XmlTextWriter;
    procedure eventSource_ProjectStarted(sender: TObject;
      e: ProjectStartedEventArgs);
    procedure eventSource_ProjectFinished(sender: TObject;
      e: ProjectFinishedEventArgs);
  public
    procedure Initialize(eventSource: Microsoft.Build.Framework.IEventSource); override;
    procedure Shutdown; override;
  end;

 

The methods eventSource_ProjectStarted and eventSource_ProjectFinished will be called by MSBuild when the a project has been started or finished. The Initialize procedure is where the XMLTextWriter is setup and Shutdown is where all the cleanup occurs. Press CTRL+C to create the stubs.

procedure TXMLBuildLogger.Initialize(
  eventSource: Microsoft.Build.Framework.IEventSource);
begin
  FXMLWriter := XmlTextWriter.Create('c:\BuildLog.xml', nil);
  FXMLWriter.Formatting := Formatting.Indented;
  FXMLWriter.WriteStartDocument;
  FXMLWriter.WriteStartElement('Build');

  Include(eventSource.ProjectStarted, eventSource_ProjectStarted);
  Include(eventSource.ProjectFinished, eventSource_ProjectFinished);
end;

 

The first step in Initialize is creating the XMLTextWriter. This example uses a hardcoded filename for the output of c:\BuildLog.xml. Setting the indented property is completely optional but makes the XML output easier to check while debugging. WriteStartDocument must be called to start ouput and WriteStartElement is called to create the XML node that contains the output from the logger. The two Include lines set the method to use for the specified event.

procedure TXMLBuildLogger.Shutdown;
begin
  FXMLWriter.WriteEndElement;
  FXMLWriter.Close;
  FXMLWriter := nil;
end;

 

In the Shutdown method cleanup after the XMLTextWriter. Write the closing tag for the Build node created in Initialize and Close the document.

procedure TXMLBuildLogger.eventSource_ProjectStarted(sender: TObject; e:
  ProjectStartedEventArgs);
begin
  FXMLWriter.WriteStartElement('Project');
  FXMLWriter.WriteAttributeString('File', e.ProjectFile);
end;

 

When MSBuild calls eventSource_ProjectStarted create a new element call Project. Write the project file as an attribute of the Project node called File.

procedure TXMLBuildLogger.eventSource_ProjectFinished(sender: TObject;
  e:ProjectFinishedEventArgs);
begin
  FXMLWriter.WriteEndElement;
end;

 

Close the Project node when eventSource_ProjectFinished is called.

ChangeDir

We could build the library using the IDE but let’s use MSBuild. Open a command prompt and navigate to the directory where DCBuildLogger.dproj was saved. Build the project one time to generate DCBuildLogger.dll.

 

 

Now that the dll has been generated we can use it in a test build. The class name for the logger and the full path to the library must be specified. Rerun msbuild but specify the /logger switch and add the needed parameters. Include the /noconsole switch to turn off the output to the command window.

msbuild /noconsole
  /logger:TXMLLogger,c:\Develop\DCBuildLogger\DCBuildLogger.dll

 

TestRun

 

 

This should have created a file named BuildLog.xml in c:\. Take a look at the output from the logger.

<?xml version="1.0"?>
<Build>
<Project File="C:\Develop\DCBuildLogger\DCBuildLogger.dproj" />
</Build>

 

While it isn’t exactly useful it is a decent proof of concept. Check back for updates on adding more features and handling other events such as TargetStarted, TargetFinished, ErrorEventRaised, WarningEventRaised, and the generic StatusEventRaised that reports every status change.

Write a comment