Monday, November 13, 2006

There were a couple of posts in the MSBuild forum recently related to customizing the build process. The specific thread is, Forcing a Clean build. The question boils down to, "How do you force a clean each time I build?" The answer lies in adding the Clean target to the build targets dependency list. You can read details on how this works in my MSDN article Inside MSBuild.
One of the participants asked me to post a complete solution of how to do this. So that response is this entry. I created a sample Windows Application that has the build process customized. I called this BeforeBuildEx, you can download all the files at the end of this entry. I modified the WindowsApplication1.csproj file and added the following lines:

<PropertyGroup>

   <BuildDependsOn>

      Clean;

      MyBeforeBuild;

      $(BuildDependsOn);

      MyAfterBuild

   </BuildDependsOn>

</PropertyGroup>

 

<Target Name="MyBeforeBuild">

   <Message Text="This is before the build." Importance="high"/>

</Target>

 

<Target Name="MyAfterBuild">

   <Message Text="This is after the build." Importance="high"/>

</Target>

The list of targets that must be executed for a build is contained in the BuildDependsOn list. So if you change that list, you change to build process. If you want to add a target before the build process, add that target to the begining of the list. In the above statement, I'm actually extending the previous list by adding my targets. I add 2 targets before and 1 after the already existing definiton for BuildDependsOn. Much more detail about this in my article. The snippet above was inserted after the statement

<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

This is very important, otherwise your customizations may be overwritten. Now if you build this you will see that the Clean target is executed when the application is built. If you want to see this in Visual Studio you have to increase the verbosity of the MSBuild output that is shown on the Output window. Do this by: Tools->Options->Projects and Solutions->Build and Run and set the value for MSBuild project build output verbosity to atleast Normal. The link to the zip file is below. In some cases this could cause some problems for Visual Studio.

BeforeBuildEx.zip

Sayed Ibrahim Hashimi

Monday, November 13, 2006 4:11:06 AM (GMT Standard Time, UTC+00:00)  #    Comments [5]  | 
Tuesday, August 29, 2006

A twist on the previous entry. Here’s a very similar, but different scenario. You have a set of files, that you want to push to a set of folders. But you have to “discover” these folders. In this scenario there are really 2 different situations you can be in.

1.       Each folder contains a file that you are able to identify by file name

2.       Each folder contains no files, but you are able to identify the folder by its name

For 2) you’ll have to rely on a custom task to get locate these folders. This is because if the folder is empty then you are not able to put these in an Item the normal way. I’ve previously written a task FindUnder that you can use for this purpose. You can find this task, and a handful of others at http://www.codeplex.com/Wiki/View.aspx?ProjectName=Sedodream. Let’s go over scenario 2 because I think it’s a little more straight forward.

Here is the directory structure that you have to work with:

   AssemblyInfo.cs

   DeploySample.proj

   Other1.cs

   Other2.cs

├───Deploy

   ├───five.control

   ├───four.control

   ├───one.control

   ├───six.control

   ├───six.something

   ├───three.control

   ├───three.something

   └───two.control

In this example the folders that you want to copy into end with .control, and the files you want to copy include AssemblyInfo.cs, Other1.cs and Other2.cs. In this situation we want to find all folders under Deploy that end with control. So our search pattern will be *control under the Deploy folder. Here’s how we find those folders using the FindUnder task, and copy the files into them.

   <PropertyGroup>

      <DeployRoot>Deploy</DeployRoot>

      <SearchPath>*.control</SearchPath>

   </PropertyGroup>

   <ItemGroup>

      <FilesToCopy Include="AssemblyInfo.cs;Other1.cs;Other2.cs"/>

   </ItemGroup>

   <Target Name="Deploy">

      <Copy SourceFiles="" DestinationFolder=""/>

      <!-- Find all the folders we need to place the AssemblyInfo.cs file in -->

      <FindUnder Path="$(DeployRoot)" FindDirectories="true" SearchPattern="$(SearchPath)">

         <Output ItemName="DeployFolders" TaskParameter="FoundItems"/>

      </FindUnder>

     

      <Message Text="Found items: @(DeployFolders,'%0d%0a')" Importance="high"/>

      <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="%(DeployFolders.FullPath)"/>

   </Target>

Let’s talk about the Copy task above. This shows how we can copy a set of folders to a set of different folders. This is possible through batching which was discussed in more detail in the previous post. As you use batching keep in mind that batching isn’t limited to custom meta-data. But can also be used with Well-known item metadata. That is what we are doing in this example.

Now let’s see how can we handle situation 1). To review, this is the situation that we have files in a set of directories that we can identify. In this example let’s say that file is named app.config. So we want to find all folders under a given location that have a file named app.config inside of it. So here is your directory structure

   AssemblyInfo.cs

   DeploySample.proj

   Other1.cs

   Other2.cs

└───Deploy2

      ├───five.control

             app.config

      ├───four.control

             app.config

      ├───one.control

             app.config

      ├───six.control

             app.config

      ├───six.something

      ├───three.control

             app.config

      ├───three.something

      └───two.control

            app.config

So the result should actually be the same as the previous example. This is how to achieve that.

   <PropertyGroup>

      <DeployRoot2>Deploy2</DeployRoot2>

   </PropertyGroup>

  

   <ItemGroup>

      <KeyFiles Include=".\$(Deploy2)\**\app.config"/>

   </ItemGroup>

 

   <Target Name="Deploy2">

      <Message Text="Folders to deploy to:%0d%0a@(KeyFiles->'%(RecursiveDir)','%0d%0a')"/>

 

      <!-- Now copy each file to each destination -->

      <Copy SourceFiles="@(FilesToCopy)" DestinationFolder=".\%(KeyFiles.RecursiveDir)"/>

   </Target>

 

So the in this example I’m using the KeyFiles item to determine which folders to copy all the files to. From the Deploy2 target you can see that I’m using batching to copy all the FilesToCopy into each of the locations determined by the KeyFiles item. The directory that contains each KeyFile is determined by the RecursiveDir well-known meta-data value.

 

You can download the entire sample at: www.sedodream.com/content/binary/BatchingSample.zip

Or you can have a look at the project file at:  www.sedodream.com/content/binary/DeploySample.proj.txt

 

Sayed Ibrahim Hashimi

Tuesday, August 29, 2006 3:17:46 AM (GMT Daylight Time, UTC+01:00)  #    Comments [11]  | 
Tuesday, August 15, 2006

Today someone was telling me about a co-worker who was having issues with MSBuild. He told me that he was trying to copy a set of files to a set of different servers. But the issue was that he didn’t know how to achieve this without performing multiple Copy task invocations. I told him that he could achieve this using MSBuild Batching. Batching is a process of performing a task (or target) on a set of items (batches) at a time. A batch can also include a single item. So in this scenario we need to perform the copy one time for each server that he wanted to deploy to. I’ve created a simple msbuild file which demonstrates this in two different ways. The first way uses task batching, which can bee seen in the Test target. And the other uses Target batching which can be seen in the DoItCore target. I've also created a clean target, which has nothing to do with batching.

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

     

      <ItemGroup>

            <SourceFiles Include="*.txt"/>

            <Dest Include="One;Two;Three;Four;Five"/>

      </ItemGroup>

     

      <Target Name="Test">

            <Copy SourceFiles ="@(SourceFiles)" DestinationFolder="%(Dest.FullPath)"/>

            <Message Text="Fullpath: %(Dest.FullPath)"/>

      </Target>

 

      <!-- These targets demonstrate target batching -->

      <Target Name="DoIt" DependsOnTargets="DoItCore"/>

      <Target Name="DoItCore" Inputs="@(SourceFiles)" Outputs="%(Dest.FullPath)">

            <Copy SourceFiles="@(SourceFiles)" DestinationFolder="%(Dest.FullPath)"/>

      </Target>

 

      <!-- This will clean up the files -->

      <Target Name="Clean">

            <CreateItem Include="%(Dest.FullPath)\**\*">

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

            </CreateItem>

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

      </Target>

</Project>

Batching is an advanced topic of MSBuild, and is defintely neglected. I have to admit I’m guilty of not writing about it enough myself. There are some good batching resources, they are listed below.

MSBuild Batching

How To : Batch Targets with Item Metadata

Batching Brainteaser Explained

Channel 9 : Batching Examples

Channel 9 : How does MSBuild’s Batching Algorigth Work?

 

Sayed Ibrahim Hashimi

Tuesday, August 15, 2006 4:59:32 AM (GMT Daylight Time, UTC+01:00)  #    Comments [2]  | 
Wednesday, August 09, 2006

In case you haven't already heard the MSDN Library is now free to download! You can download the May 2006 version at: http://www.microsoft.com/downloads/details.aspx?FamilyId=373930CB-A3D7-4EA5-B421-DD6818DC7C41&displaylang=en

Previously you could only get the MSDN Library if you were an MSDN Subscriber. I think its great that Microsoft made the MSDN Library free to download. It's a great resource and contains all kinds of goodies for .NET developers.

Sayed Ibrahim Hashimi

Wednesday, August 09, 2006 5:32:45 AM (GMT Daylight Time, UTC+01:00)  #    Comments [2]  | 
Tuesday, July 25, 2006

Recently a chapter from my book Deploying .NET Applications: Learning MSBuild and ClickOnce has been posted. You can read the sample chapter MSBuild By Example. Here is the TOC for that chapter.

MSBuild: By Example

Introducing Well-Known Metadata

Formatting Your Output

Editing MSBuild Files with IntelliSense

Integrating MSBuild into Visual Studio

Introducing Custom Metadata

Understanding the Difference Between @ and %

Using Environment Variables in Your Project

Reusing MSBuild Project Elements

Dealing with MSBuild Errors

Summary

Thanks to the guys at Apress and C# Online for making this chapter available online for everyone to have a look at!

Sayed Ibrahim Hashimi 

 

 

Tuesday, July 25, 2006 5:31:32 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1]  | 
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]  | 

Theme design by Jelle Druyts