The Stochastic Game

Ramblings of General Geekery

Posts tagged with 'msbuild'

Target the .NET Compact Framework using Visual Studio Express

Microsoft only supports Visual Studio Professional for developing Windows Mobile applications and, more generally, code based on the .NET Compact Framework. You get nice things like application deployment and emulators and remote debugging and all. But if you just want to compile something against the .NET Compact Framework, for example to check that you’re using supported methods and classes, you can do that with Visual Studio Express.

Create a project in Visual Studio Express and open it in a text editor. In the first “<PropertyGroup>” node, add the following at the end:

   1: <NoStdLib>true</NoStdLib>

This will tell MSBuild to not include mscorlib.dll automatically, so we can make it use the Compact Framework’s version.

Next, re-open the project in Visual Studio Express, delete all the system references (System.dll, System.Xml.dll, System.Data.dll, etc.), and re-add them, only this time use the Compact Framework’s assemblies. You’ll have to directly browse to those DLLs, as they probably won’t show up in the default dialog.

Now rebuild you application. It should build against the Compact Framework. You can test that by adding an instruction that’s unsupported, like for example “Thread.Sleep(TimeSpan)”.


CreateProperty task in a skipped target

In MSBuild, you can specify inputs and outputs for target so that the target is skipped when the outputs are more recent than the inputs. However, you get a strange behaviour when you put a <CreateProperty> task inside such a target.

Let’s look at the following MSBuild project:

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

  <PropertyGroup>
    <WhyIsThisCreated>everything is okay</WhyIsThisCreated>
  </PropertyGroup>

  <Target Name="DoIt" DependsOnTargets="CreateTestFiles; DoStuffMaybe">
    <Message Text="I say: $(WhyIsThisCreated)" />
  </Target>

  <Target Name="CreateTestFiles">
    <WriteLinesToFile Lines="input" File="input.txt" Overwrite="true" />
    <WriteLinesToFile Lines="output" File="output.txt" Overwrite="true" />
  </Target>

  <Target Name="DoStuffMaybe" Inputs="input.txt" Outputs="output.txt">
    <Error Text="We shouldn't be there!" />
    <CreateProperty Value="oh my" Condition="">
      <Output TaskParameter="Value" PropertyName="WhyIsThisCreated"/>
    </CreateProperty>
  </Target>

</Project>

This project creates two files, "input.txt" and "output.txt". Then, the "DoStuffMaybe" target is tentatively run, but is skipped because "output.txt" is newer. We make super sure that this target won’t be run by adding an <Error> task in there.

But when you run this project, you get the following output:

msbuild output

Somehow, the <CreateProperty> task was processed, and the value of $(WhyIsThisCreated) was set to "oh my"!

I don’t really know what’s going on, but the solution to this problem is, as it is the case most of the time, to read the documentation. The <CreateProperty> page on MSDN informs us that another property is available on the task:

ValueSetByTask

Optional String output parameter.

Contains the same value as the Value parameter. Use this parameter only when you want to avoid having the output property set by MSBuild when it skips the enclosing target because the outputs are up-to-date.

If we replace TaskParameter="Value" by TaskParameter="ValueSetByTask" in the MSBuild project, we finally get the expected result:

msbuild output

This RTFM saying never gets old, does it?