Click here to Skip to main content
12,893,816 members (53,756 online)
Click here to Skip to main content
Add your own
alternative version


10 bookmarked
Posted 20 Jun 2009

MSBuild: Factorial!

, 20 Jun 2009 Public Domain
Rate this:
Please Sign up or sign in to vote.
Using MSBuild Targets as general-purpose functions, complete with parameters and return values.

I've been doing some exploring of MSBuild as a programming language. There are some interesting results regarding mutability/immutability, but that's for another post.

This post is about functions. In particular, a Target may be invoked using the MSBuild task, so I'm exploring using Targets as functions. MSBuild can pass parameters to a Target by sending it Properties. Property changes are not propogated back to the caller, though, so getting a return value is a bit trickier.

It turns out that MSBuild does return one bit of information from a Target: its Outputs. It's possible to set the Outputs of a Target to a Property, and have that Target depend on another Target that sets that Property. In this way, it is possible to create a pair of Targets that can "calculate" the outer Target's Outputs.

By combining these approaches (setting Properties for arguments, and using the Target's Outputs as a return value), it is possible to treat a Target as a function.

To demonstrate, I wrote this program, which uses MSBuild to recursively calculate the factorial of the $(Input) property. Have fun playing!

 <Project ToolsVersion="3.5" xmlns="<a href=""></a>">
    <Import Project="$(MSBuildExtensionsPath)\ExtensionPack\MSBuild.ExtensionPack.tasks"/>

    <!--<span class="code-comment"> Factorial program using MSBuild recursively --></span>
    <Target Name="Default">

        <!--<span class="code-comment"> Display usage --></span>
        <Error Condition="'$(Input)' == ''" Text="Usage: msbuild factorial.proj [/nologo] [/clp:v=minimal] /p:Input=nnn"/>

        <!--<span class="code-comment"> Argument error checking --></span>
        <MSBuild.ExtensionPack.Science.Maths TaskAction="Compare" P1="$(Input)" P2="1" Comparison="LessThan">
            <Output TaskParameter="LogicalResult" PropertyName="InputCheck"/>
        <Error Condition="'$(InputCheck)' != 'False'" Text="Input cannot be less than 1."/>

        <!--<span class="code-comment"> Invoke the Factorial target with the current Input property --></span>
        <MSBuild Projects="$(MSBuildProjectFile)" Targets="Factorial" Properties="Input=$(Input)">
            <Output TaskParameter="TargetOutputs" ItemName="FactorialResult"/>

        <!--<span class="code-comment"> Display the result --></span>
        <Message Importance="high" Text="Result: @(FactorialResult)"/>

    <!--<span class="code-comment"> The Factorial target uses FactorialCore to do the calculation, storing the result in FactorialResult --></span>
    <Target Name="Factorial" DependsOnTargets="FactorialCore" Outputs="$(FactorialResult)" />
    <Target Name="FactorialCore">

        <!--<span class="code-comment"> If the input is 1, then the factorial is 1 --></span>
        <PropertyGroup Condition="'$(Input)' == '1'">

        <!--<span class="code-comment"> If we don't know the result yet (i.e., the input is not 1), then calculate the factorial --></span>
        <CallTarget Condition="'$(FactorialResult)' == ''" Targets="CalculateFactorial"/>
    <Target Name="CalculateFactorial">

        <!--<span class="code-comment"> Subtract 1 from $(Input) --></span>
        <MSBuild.ExtensionPack.Science.Maths TaskAction="Subtract" Numbers="$(Input);1">
            <Output TaskParameter="Result" PropertyName="InputMinus1"/>

        <!--<span class="code-comment"> Determine the factorial of $(Input) - 1 --></span>
        <MSBuild Projects="$(MSBuildProjectFile)" Targets="Factorial" Properties="Input=$(InputMinus1)">
            <Output TaskParameter="TargetOutputs" ItemName="SubResult"/>

        <!--<span class="code-comment"> Multiply !($(Input) - 1) by $(Input) to get the result--></span>
        <MSBuild.ExtensionPack.Science.Maths TaskAction="Multiply" Numbers="@(SubResult);$(Input)">
            <Output TaskParameter="Result" PropertyName="FactorialResult"/>

    <!--<span class="code-comment"> Maybe I just have way too much time on my hands... --></span>

msbuild factorial.proj /nologo /clp:v=minimal /p:Input=5

Result: 120

msbuild factorial.proj /nologo /clp:v=minimal /p:Input=7

Result: 5040

Useless, but cool nonetheless.


This article, along with any associated source code and files, is licensed under A Public Domain dedication


About the Author

Stephen Cleary
Software Developer (Senior)
United States United States
Stephen Cleary is a Christian, husband, father, and programmer living in Northern Michigan.

Personal home page (including blog):

You may also be interested in...

Comments and Discussions

GeneralNovel! Pin
Trollslayer20-Jun-09 10:27
memberTrollslayer20-Jun-09 10:27 
GeneralRe: Novel! Pin
Stephen Cleary20-Jun-09 16:49
memberStephen Cleary20-Jun-09 16:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170424.1 | Last Updated 20 Jun 2009
Article Copyright 2009 by Stephen Cleary
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid