Finally!! MetaTask builds Pipelines in a single solution!

by justin 24. July 2009 08:59

I’ve been struggling for the last couple of weeks to try to get the MetaSharp build environment to a state where it’s not painful to debug. Since the primary system for building DSLs right now is through an MSBuild Task I have been having one heck of a time. When my Task would get loaded it would then load a supplied assembly and run the pipeline defined in it. This would cause it to get loaded into Visual Studios AppDomain and not release the assemblies, which meant you’d have to open and close Visual Studio after every build… very painful.

The obvious solution was to create an AppDomain and try to load the Pipeline assembly in that domain and do the work there. But of course, AppDomains are evil. Seriously, I’ve been chipping away at this issue for weeks to no avail… until today. I found something magical that probably everyone else in the world knew about except for me.

I found the AppDomainIsolatedTask.

Instead of having to create your own AppDomain and messing around with all that you can simply inherit from AppDomainIsolatedTask and Visual Studio will do the magic for you. Whatever assemblies you load for your Task will be definitely released. Awesome! This means you can have a task in one project, and consume it in another, both in the same solution, and build over and over. Wonderful!

To top it all off I changed my assembly loading system to use the new .NET 4.0 MEF framework (System.ComponentModel.Composition). Everything is all very elegant now.

So all you have to do is create a class that implements IPipeline, add an Export attribute and create a simple .targets file to call the MetaTask. Here is a little example of how to consume MEF in code for those who are curious:

string location = Path.GetDirectoryName(typeof(MetaTask).Assembly.Location);
using (DirectoryCatalog catalog = new DirectoryCatalog(location))
{
    using (CompositionContainer container = new CompositionContainer(catalog))
    {
        Export<IPipeline> export = container.GetExport<IPipeline>(pipelineTypeName);
        using (IPipeline pipeline = export.GetExportedObject())
        {
            // ...
            pipeline.Process();
        }
    }
}

This code will load all assemblies at the given location then find the Exported type with the provided string ‘pipelineTypeName’. This value is passed into the MetaTask based on the desired DSL. Here is a sample of how to Export a pipeline.

[Export("MetaSharp.Transformation.Lang.Builder.NodeBuilderPipeline", typeof(IPipeline))]
public class NodeBuilderPipeline : CodeDomCodeGenerationPipeline
{
    //...
}

The string is the ‘pipelineTypeName’ passed into the MetaTask. Incredibly simple. To round out the example here is the MSBuild .targets file to bring it all together.

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

    <!--Reference the assembly where our tasks are defined-->
    <PropertyGroup>
        <MetaSharpBinPath Condition="'$(MetaSharpBinPath)' == ''">.</MetaSharpBinPath>
        
        <!-- Pipelines -->
        <NodeBuilderPipeline Condition="'$(NodeBuilderPipeline)'==''">
            MetaSharp.Transformation.Lang.Builder.NodeBuilderPipeline
        </NodeBuilderPipeline>
        
    </PropertyGroup>
    
    <UsingTask TaskName="MetaSharp.Transformation.Builder.MetaTask" 
               AssemblyFile="MetaSharp.Transformation.Builder.dll" />

    <!--Compile target (this is the target that calls the compiler task)-->
    <Target Name="BeforeBuild">

        <MetaTask
            Templates="@(Node)"
            Configuration="$(Configuration)"
            Language="$(Language)"
            DefaultNamespace="$(RootNamespace)"
            Pipeline="$(NodeBuilderPipeline)">
            <Output TaskParameter="Generated" ItemName="Generated" />
        </MetaTask>

        <ItemGroup>
            <Compile Include="@(Generated)" />
        </ItemGroup>

    </Target>
</Project>

So now I’m happy, I think I can finally get past this build environment minutiae and onto the fun stuff!

Tags: , , ,

MetaSharp | MSBuild | .NET | C#

Comments are closed

About Me

sweetest hat ever

I'm a software developer from Minnesota and this blog largely focuses on various technical concepts I am thinking about at the moment. I currently work for Microsoft in the St. Paul office of the Expression product group.

RecentPosts