Tuesday, July 18, 2006

I've created a project on CodePlex to hold all of the MSBuild tasks/loggers and what not from my book and my MSDN article Inside MSBuild. The project home page is at Sedodream MSBuild CodePlex project. The idea is that I'll keep all of the MSBuild related material that I discuss here there as well. If you have content that you'd like to post there thats great too.
Here is the current list of what is available there:

Tasks Included

Name

Description

AddMetadata

Allows you to add metadata to an item

FindUnder

Finds and returns all directories (empty or not) under a specified path

GetDate

Returns a string representation of the date in a specified format

GetRegKey

Returns the value of a registry key

Move

Task to move a file (or set of files)

NUnitTask

Task to run NUnit test cases as a part of the build process

TempFile

Returns the path to a new temporary file

Loggers Included

Name

Description

EmailLogger

An MSBuild logger capable of emailing the resulting log

SimpleFileLogger

A simple MSBuild file based logger

XmlLogger

An MSBuild logger which creates an Xml file

Sayed Ibrahim Hashimi

Tuesday, July 18, 2006 5:47:05 AM (GMT Daylight Time, UTC+01:00)  #    Comments [3]  | 
Thursday, June 15, 2006

A few days ago I received an email about an MSBuild visual editor! This was something that I was interested in doing a while ago, but never got around to doing it. This tool is called MSBuild Sidekick, and you can download it for free from http://www.attrice.info/msbuild/index.htm. I have downloaded it and played around with it. I think it’s a good tool for people who are getting started with MSBuild, but for those who use MSBuild on a regular basis I don’t think it can replace the productivity that is achieved with Intellisense. They have an interesting way of representing the build file visually, and after some time if the right extensions are added it may be a tool that I’d use over Visual Studio to edit my MSBuild files. One of the challenges of representing a build file is that you have to be aware of where your new declarations are being placed. For instance if you have two properties defined, lets say Property1 and Property2. If Property2 depends on Property1 then you have to make sure that it is declared after Property1. As far as I could tell there was no way to achieve this without viewing the source of the project file through the tool.

Sayed Ibrahim Hashimi

Thursday, June 15, 2006 6:14:45 AM (GMT Daylight Time, UTC+01:00)  #    Comments [2]  | 
Wednesday, June 14, 2006

In previous versions of the Visual Studio the build customizations were basically limited to a PreBuildEvent and a PostBuildEvent. Now we have MSBuild which allows for many very specific and complex build customizations. But Microsoft obvioiusly must continue to support the Pre/Post build event. It is something that already exists, many people are familiar with it, and its very simple. Let’s see how this is implemented within MSBuild. If you add a Pre or Post build event from Visual Studio, then examine yore project file you’ll find something like the following declared.

 

  <PropertyGroup>

    <PostBuildEvent>echo 'This is the post build event!'</PostBuildEvent>

  </PropertyGroup>

 

So these events are actually simple properties that will be executed when the time is right. What does this mean for you? Now lets talk about what’s funny about this. When MSBuild loads your project file it will load all of the properties contained in PropertyGroup elements, followed by that your items will be evaluated. What this means for the Pre/Post build event is that you are able to access properties that have been declared in PropertyGroup element before the Pre/Post build event declaration. After this evaluation is made the value for the Pre/Post build event will not change! What this equates to is that you are able to use properties such as OutDir or AssemblyName, but you’ll never be able to access properties that are created from tasks contained in other targets! If you need to access properties that have been created by other targets then you’ll have to extend your build process outside of the Pre/Post build event. This is outlined in my MSDN article Inside MSBuild in the Extending the Build Process section.

This entry was inspired by a post on the MSDN MSBuild forum.

 

Sayed Ibrahim Hashimi

Wednesday, June 14, 2006 5:52:03 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1]  | 
Friday, June 09, 2006

If you look around the net you'll find a few different Xml loggers for MSBuild. When I was writing my book I decided to write my own Xml Logger for a few different reasons. The source for the Xml logger that I wrote is available at apress.com. I'm currently in the process of trying to get some shared space for me to place my tasks and loggers that I've written for everyone to have a look at. Once I get that squared away I'll make sure to write an entry about it. In the mean time let's talk about my Xml logger. What is different about my Xml logger versus some others that you may find? When I was looking around for one, I noticed that the ones that I found didn't support building solution files very well. So that was a deficiency that I wasn't willing to sacrifice with. Besides that, I noticed that none of them had an append options as most file based loggers do. So I added that to my Xml logger. I think this is a good option if you are performing a nightly ( or continuous ) build. That way you have one place to go to each time you want to see how your build progressed. However this xml file can get quite large if your build is spanning many projects.
At the bottom of this blog you can download the dll for this logger (Contained in a zip file). The source will be made available soon. There are 4 logger arguments:
   

Name

Description

Append

True/false If true then if a log file exists then it will be append to, otherwise any existing log file will be replaced.

Logfile

Name of the log file to write to

Showsummary

True/false if true then a summary will be contained in the xml file for errors and warnings.

Verbosity

The verbosity level of the logger. Same as msbuild.exe values see MSBuild Command Line Reference


   Here is some sample output:

<MSBuild>

  <Build Started="6/9/2006 1:09:51 AM" Verbosity="Detailed"

Finished="6/9/2006 1:09:56 AM" Succeeded="False">

    <Message>Build started.</Message>

    <Project Name="C:\Data\Dreamcatcher_NET\Dreamcatcher\Dreamcatcher.sln"

Message="Project &quot;Dreamcatcher.sln&quot; (Rebuild target(s)):" \

Started="6/9/2006 1:09:51 AM" Finished="6/9/2006 1:09:56 AM">

      <Target Started="6/9/2006 1:09:51 AM" Name="ValidateSolutionConfiguration"

Message="Target &quot;ValidateSolutionConfiguration&quot; in project &quot;Dreamcatcher.sln&quot;" Finished="6/9/2006 1:09:51 AM" Succeeded="True">

        <Task Started="6/9/2006 1:09:51 AM" Name="Message" Finished="6/9/2006 1:09:51 AM" />

      </Target>

<MSBuild>

 

Here is what the summary section looks like:

    <Warnings>

      <Warning Code="CS0162" Subcategory="">

        <Message>Controls\DreamView.cs(450,6): warning CS0162: Unreachable code detected</Message>

      </Warning>

    </Warnings>

    <Errors>

      <Error File="Controls\DreamView.cs" Code="CS1026" Subcategory="">

        <Message>Controls\DreamView.cs(459,44): error CS1026: ) expected</Message>

        <Location Line="459" ColumnNumber="44" />

      </Error>

      <Error File="Controls\DreamView.cs" Code="CS1002" Subcategory="">

        <Message>Controls\DreamView.cs(459,45): error CS1002: ; expected</Message>

        <Location Line="459" ColumnNumber="45" />

      </Error>

      <Error File="Controls\DreamView.cs" Code="CS1525" Subcategory="">

        <Message>Controls\DreamView.cs(459,45): error CS1525: Invalid expression term ')'</Message>

        <Location Line="459" ColumnNumber="45" />

      </Error>

      <Error File="Controls\DreamView.cs" Code="CS1002" Subcategory="">

        <Message>Controls\DreamView.cs(459,46): error CS1002: ; expected</Message>

        <Location Line="459" ColumnNumber="46" />

      </Error>

    </Errors>

The syntax to use this logger at the command prompt is:

msbuild.exe /l:XmlLogger,PATH_TO_ASSEMBLY\Sedodream.MSBuild.Loggers.dll;logfile=build.xml;verbosity=detailed;append=true;showsummary=true

There is no required parameters the defaults are:

  • Logfile=build.log.xml
  • Verbosity=normal
  • Append=false
  • Showsummary=false

Sedodream.MSBuild.Loggers.zip (binaries 9.77 KB)


Sayed Ibrahim Hashimi

Friday, June 09, 2006 6:34:17 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1]  | 
Sunday, June 04, 2006

Ok, there's several posts about whats good/bad about both of these languages, this isn't one of those. At the end of the day it doesn't matter which technology is the best, but which ones are going to employ you. About a year ago, I think there were many more Java jobs here in Jacksonville (FL) then there were C# (.NET) jobs. I've noticed that there has been an increasing need for C# developers here, can't really say about the Java positions though. Recently I've been playing around with the blog search engine technorati.com, they have some really cool features. If you've never been there you should give it a shot. One of the features is to chart the number of blog entries over a period of time, based on keywords. To view the graph of MSBuild related blogs click on the link below

http://technorati.com/chart/%22MSBuild%22#taglink

I decided to compare the results of a search of "C#" and "Java", and I was really surprised to see the results. Below you can see the images that I saw. Note: These images are static and not updating.

From the technorati.com site it stated that there was 668,373 Java related posts and 17,100,527 C# posts! That is an incredible difference. There could be a few reasons for the difference:

  1. Java people arn't blogging as much
  2. Java people arn't registering with technorati.com as much as the C# folk
  3. There is something wrong with the technorati.com processor

Since this is a simple keyword search I think we can safely assume that (3) is not the culprit. I think its really a combinition of (1) and (2). Another aspect there are many Java related blog entries that don't actually have the word Java in it. But I'm sure the same goes for C#. Previously when I was doing mostly Java work, I thought one of the cool things about Java was the community effort. With the open-source side and all. I thought that C# (.NET) would lack this for sure. But now that I know better, I know that it certainly is not like that. I think the community effort for C# (.NET) is just as strong, if not stronger, then the Java side.

I'm not sure what the significance these number have, but it certainly does make be happy to be in the C# camp. :)

To get the live chart for C# visit: http://technorati.com/chart/%22C%23%22#taglink
To get the live chart for Java visti: http://technorati.com/chart/%22Java%22#taglink

Sayed Ibrahim Hashimi

Sunday, June 04, 2006 7:39:13 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1]  | 
Saturday, June 03, 2006
Frequently I hear people asking "How can we use Visual Studio 2005 for 1.1 development". If you are writing managed code (C#,J#, or VB.NET) then you are in luck. There is a toolkit that was released from the guys at Microsoft that can do this for you. Its called MSBee (MSBuild Everett Edition). You can download this toolkit at Codeplex. The creator of MSBee blogs about it at: http://blogs.msdn.com/clichten/default.aspx

Sayed Ibrahim Hashimi

Saturday, June 03, 2006 7:38:13 AM (GMT Daylight Time, UTC+01:00)  #    Comments [2]  | 
Wednesday, May 10, 2006

I received this email from a reader of my MSBuild MSDN Article, here is his question:

I have multiple projects in multiple directories on my machine, I need to compile all of those projects and copy the resulting DLLs into my application folder which id different from the projects. Can i do all this in one MSBuild file? Most the MSBuild file samples i find work only on a single project and assume that the build file is in the same directory as the .CS files.

To answer this question you can create an MSBuild project file which uses the MSBuild task to build other project files. By using this you can extract out the files that were built during the process and place them into an item to be copied to the location of your choice. To demonstrate this I have created the following directory structure:

├BuildSeveralExample

   ├───App1

      └───WindowsApplication1

          └───Properties

   ├───App2

      ├───ClassLibrary1

         └───Properties

      └───ConsoleApplication1

          └───Properties

   └───Deploy

 

The App1 and App2 folders each represent a product that is to be built. App1 contains a C# Win Forms project and App2 contains a C# Class Library and a C# Console App. The Deploy folder is the location that we would like to copy all of the output files to. In the BuildSeveralExample folder I have created a projects file, BuildAll.proj, which can be used to fulfill this need.

The first thing we need to do is to have a way to locate all of the project files, in my solution I created an Item and included all of the project files as such:
  <ItemGroup>

    <ProjectsToBuild Include="**\*proj" Exclude="$(MSBuildProjectFile)"/>

  </ItemGroup>

I include all project files in the current directory or any subdirectory, with the exception of the current project file. The MSBuildProjectFile is an MSBuild Reserved property, for a complete list see:  http://msdn2.microsoft.com/en-us/library/ms164309.aspx.

In your situation you may need to specify what files to include and exclude, to do this you can simply enter their locations separated with a semi-colon. Now that we have all the project files we’d like to build we need to actually build them. Do this by:

  <PropertyGroup>

    <Configuration>Release</Configuration>

  </PropertyGroup>

 

  <Target Name="CoreBuild">

    <MSBuild Projects ="@(ProjectsToBuild)"

             ContinueOnError ="false"

             Properties="Configuration=$(Configuration)">

        <Output ItemName="OutputFiles" TaskParameter="TargetOutputs"/>

    </MSBuild>

  </Target>

 

This is using the MSBuild Task to each of the project files. Also note the use of the Output element here, the MSBuild Task has an output of TargetOutputs which contains a list of files which were produced by the project files built. These files are placed in the OutputFiles item. Since we didn’t specify a target to be executed on each project file, the default target will be executed. This is how Visual Studio builds your project files as well. By using the MSBuild task we can also specify properties to be passed to the project file(s) in the Properties attribute. If you need to pass different properties for different project files, then you may have to call the MSBuild Task more than once.

Now all we have to do is copy these files over to another location. This is achieved like:

 

  <PropertyGroup>

    <DestFolder>Deploy\</DestFolder>

  </PropertyGroup>

 

  <Target Name="CopyFiles">

    <Copy SourceFiles="@(OutputFiles)"

          DestinationFiles="@(OutputFiles->'$(DestFolder)%(RecursiveDir)%(Filename)%(Extension)')" />

  </Target>

The location to copy the files is specified in the DestFolder property shown above.

As well as performing these actions, we’d also like to create a fresh build when this process is invoked. To do this we can either call the Rebuild target on the project files or call Clean before we build them. I prefer the second approach, but both are equally good. It also serves for a better demonstration for me to implement the second approach.

To clean the projects all we have to do is call the Clean target on each of the project files. I have written about this in more detail in my previous entry Clean many projects and Extending the Clean. As well as that we have to remove any files that have been created by a previous invocation of this process, have a look at my clean target:

  <!--

  This target can be used to clean all of the projects before you build them.

  It will also delete any dll & exe files located in the the Deploy folder. This could be accomplished

  much better than this, but this is quick and easy.

  -->

  <Target Name="CleanAll">

    <!-- Delete any files this process may have created from a previous execution -->

    <CreateItem Include="$(DestFolder)\**\*exe;$(DestFolder)\**\*dll">

      <Output ItemName="GeneratedFiles" TaskParameter="Include"/>

    </CreateItem>

    <Delete Files="@(GeneratedFiles)"/>

    <MSBuild Projects="@(ProjectsToBuild)" Targets="Clean" Properties="Configuration=$(Configuration);"/>

  </Target>

To tie it all together I’ve created a BuildAll target which is responsible for managing all of this. Here it is:

  <PropertyGroup>

    <BuildAllDependsOn>CleanAll;CoreBuild;CopyFiles</BuildAllDependsOn>

  </PropertyGroup>

  <Target Name="BuildAll" DependsOnTargets="$(BuildAllDependsOn)"/>

I took the Visual Studio approach and defined targets to perform individual steps, created one target to call them in the correct order by using a depends list derived from a property. This is a good approach because this depends on list can be modified outside of this project file to inject other required steps. For more detailed info on that see my other entry Extending the clean.

To see this in action you have to execute the BuildAll target on the BuildAll.proj file. I’ve made the project file available as well as my sample applications that go along with it. The BuildSeveralExample.zip file contains all the necessary files.

 

BuildAll.proj (Link fixed)

BuildSeveralExample.zip (25.17 KB)

 

Sayed Ibrahim Hashimi

 

Wednesday, May 10, 2006 6:39:05 AM (GMT Daylight Time, UTC+01:00)  #    Comments [11]  | 
Wednesday, May 03, 2006

This is the beginning of a new series of blogs that I plan on writing. Its called ‘MSBuild Fun’, the idea is that I’ll discuss some examples of how you might use MSBuild, outside of building applications. MSBuild is a tool that certainly is geared toward building applications, but is not limited to that. Knowledge of MSBuild can help you with some small things that come up quite often.

In this example we will consider a relatively simple task, copying a set of files from one location to another. Let’s say that you would like to locate all image files contained in a particular location and copy those files to another. There are a few options; you can use the Windows Explorer to search for all of the image files, and copy-paste them to the other location. There are many problems associated with this approach:

  • If there are files with the same name in a different folder then you will only be able to get 1 copy of it
  • If there is an error during the course of copying the files it will stop all together
  • This doesn’t preserve directory hierarchy
  • You can only include files to be copied, not exclude them

Another option is to use the xcopy command from the command prompt. This is a good method to employ to solve the problems associated wit the previous approach. Using this approach we can continue on error,  and preserve the directory hierarchy.  We can also exclude files from being copied. If you are to perform this task many times that you can simply insert the call into a .bat file to preserve the command.
The approach we will use here is to use MSBuild
Copy task to copy the files from the source to the destination. It solves all the problems associated with the first approach, and throws in a few bonuses. Those are:

  • Syntax for excluding files is very powerful, much better than that for xcopy
  • You can transform the name of the file as you copy it
  • You can skip files that already exist, and haven’t changed, in the destination location
  • In one MSBuild file you could house various different copies. With the batch file approach you are basically limited to one pre file.

From a performance perspective the xcopy and MSBuild approach are pretty much equivalent, so that is not a factor. Now lets have a look at this in action.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="CopyFiles">

    <ItemGroup>

      <FilesToCopy Include="**\*.doc;**\*.txt"

                   Exclude="**\*trash*"/>

    </ItemGroup>

 

    <PropertyGroup>

      <Dest>Dest2</Dest>

    </PropertyGroup>

 

    <Target Name="CopyFiles">

      <Copy SourceFiles="@(FilesToCopy)"

            DestinationFiles="@(FilesToCopy->'$(Dest)\%(RecursiveDir)\%(Filename)%(Extension)')"

            ContinueOnError="true"/>

    </Target>

</Project>

This simple MSBuild project file will copy all Word Documents and text files that don’t contain trash in the filename to another location maintaining the directory hierarchy. As you can see here, in the FilesToCopy item declaration, I’m using the include attribute to include a list of files to be copied, and the exclude attribute to exclude a list of files from being copied. You can place complex wildcard expressions in these attributes to select only the files you are truly interested in.

 

 

Sayed Ibrahim Hashimi

Wednesday, May 03, 2006 6:02:18 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Friday, April 21, 2006

In the June 06 issue of the MSDN magazine you'll find an article that I wrote titled "Inside MSBuild: Compile Apps Your Way With Custom Tasks For The Microsoft Build Engine". As far as I know this will be the first article in print for the release version of MSBuild. Before I wrote this article I noticed a need, that was there was no one good resource for people to go to to learn all the key things they need to really get going with MSBuild. I think this article really does meet that need decently well. The only large topic that wasn't covered in the article is writing custom loggers. There are a few reasons for this; limited number of words, most users won't be interested in writing custom loggers and there is a lot of material about writing custom loggers available. If you are interested in writing a custom logger, I've got examples on this blog and here are a few other places you can visit:
http://msdn2.microsoft.com/en-us/library/ms171471.aspx
http://blogs.msdn.com/msbuild/archive/2005/10/10/479223.aspx

Along with these in my book I present a custom XML logger. If you read the article I welcom your feedback.

Sayed Ibrahim Hashimi

Friday, April 21, 2006 3:13:06 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Wednesday, April 05, 2006
If you are using Team Foundation Server as your SCM tool, I hope you're taking advantage of using the Team Build tool to create re-producable public builds for your projects. Very cool, and very useful, especially for those Enterprise applications. As you use Team Build you'll need to make changes to how your build process is executed. You can make the customizations in the TFSBuild.proj file. This is the file that will drive your team build. In this file there are many properties declared that are generated by the New Build Type Creation Wizard. These properties are contained in the first PropertyGroup element in that file. Some of these properties include; Description, DropLocation,BuildDirectoryPath,... which are used internally by Team Build to setup the build. Of course Team Build uses MSBuild to actually execute the build, but some things need to happen before/after MSBuild gets involved. For instance creating the Build report, which require those values. In the ideal world you'd expect for those values to be gathered using the MSBuild Object Model, but this is not the case. Team Build is extracting those values as they are declared.
There has been a few posts about this particular problem on the MSBuild MSDN Forum. Those posts are at:
Post: Property Evaluation Order (beta 3)
Properties in properties
In the post Property Evaluation Order (beta 3) I provide a workaround for most situations, but its not always perfect. Here it is for you to see:

It seems like Team build is not using the msbuild object model to get those evaluated properties, but instead are simply extracting the text value from those property declarations.

I tried to overwirte it in different places in the project file as well, with no luck. It always took the first declaration. I'm guessing that the property is not able to be overwritten because it is passed in as a command line parameter to msbuild.exe by team build. But there is a workaround that solves some of the issues. In your TFSBuild.proj file, modify the DropLocation to one that doesn't use any properties and insert the following towards the bottom:

  <PropertyGroup>

    <RootProjectFolder>ProjectX</RootProjectFolder>

 

    <DropBuildDependsOn>

      FixDropLocation;

      $(DropBuildDependsOn);

    </DropBuildDependsOn>

  </PropertyGroup>

 

  <Target Name="FixDropLocation">

    <CreateProperty Value="$(DropLocation)\$(RootProjectFolder)">

      <Output TaskParameter="Value" PropertyName="DropLocation"/>

    </CreateProperty>

    <Message Text="Drop loc: $(DropLocation)" Importance="high"/>

  </Target>

This prepends the FixDropLocation to the DropBuildDependsOn list of targets, so it will be executed before the DropBuild target. This cause your project drop files to be dropped in the location tat you want. This is able to overwrite the DropLocation property becuase we are using the CreateProperty task to overwrite this instead of the normal property declaration.

This is not however a perfect solution, because your build log will always be located in the DropLocation that was originally declared (the one w/o the property embedded within it). And in the Team build type history the drop location will also have this location as well. But it does place the files where you want them :)

Unfortunately it looks like the DropLocation that is given to TFS is happening outside the scope of MSBuild so I'm not sure you have a lot of options. You can't even pass this as a command line parameter to the tfsbuild.exe utility either. Let me know if this  is not clear.


Sayed Ibrahim Hashimi


Wednesday, April 05, 2006 8:09:52 AM (GMT Daylight Time, UTC+01:00)  #    Comments [2]  | 

Theme design by Jelle Druyts