A common problem I have with users of Axiom is that they will mismatch the assemblies need to get the engine up and running. Axiom uses a plugin system that allows for interchanging the platform in use (Win32, SDL, etc ) and which graphics system to use ( XNA, OpenGL, DirectX ). Unfortunately, there isn’t as loose coupling as I’d like, in particular the OpenGL rendering system has to be recompiled to use S.W.F forms or SDL forms. SLD is the particularly nasty one because it has to be paired with the SDL platform manager.

A few months ago I ran across the ILMerge utility and thought that it would solve some problems. I could combine the main engine with the proper combinations of a platform manger and render system there by eliminating the mismatch. I didn’t investigate it much because a quick try just created errors. More recently a request came up on the forums to be able to do this exact thing. I took a few hours and made it so that users could use ILMerge on the assemblies and have the system behave properly. However I didn’t make the assemblies myself, as I wasn’t preparing for a release.

Fast forward to this week. I should have released a beta of Axiom 0.7.5 back in January, but because things were a bit crazy I didn’t get to it until this week. With this release I wanted to be able to ship these combined assemblies. I like to automate things so I found an implementation of some MSBuild tasks that use ILMerge to produce a single assembly.

Now this week I had also been testing Mono’s xbuild, which is an implementation of MSBuild but on mono. Knowing that I have a large percentage of my users are linux based I investigated the ability of ILMerge to run on Mono. It doesn’t.

Ok, back to the drawing board. After a quick search I found MonoMerge. I tested it out a little to see if it worked, as it didn’t have as many options as ILMerge. It seemed to do the rick.

Now I needed a MSBuild task to execute MonoMerge. Using the ILMerge task as a guide I quickly put together a new MSBuild task that can now merge assemblies on Mono and .Net.

Enjoy!

UPDATE : Added hyperlinks to various resources.

using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Mono.Cecil;
using Mono.Merge;

namespace Mathoms.MSBuild.Tasks
{
    public class MonoMerge : Task 
    {
        private string _outputFile;
        private ITaskItem[] _assemblies = new ITaskItem[0];

        [Required]
        public virtual string OutputFile
        {
            get { return _outputFile; }
            set { _outputFile = System.IO.Path.Combine(BuildEngine.ProjectFileOfTaskNode,value); }
        }

        [Required]
        public virtual ITaskItem[] InputAssemblies
        {
            get { return _assemblies; }
            set { _assemblies = value; }
        }


        public override bool Execute()
        {
            var context = new MergeContext {OutputPath = _outputFile};

            var assemblies = new string[ _assemblies.Length];
            for( var i = 0; i < assemblies.Length; i++ )
            {
                assemblies[ i ] = _assemblies[ i ].ToString();
            }

            context.Assemblies.AddRange( assemblies );

            try
            {
                var primary = AssemblyFactory.GetAssembly( context.Assemblies[ 0 ] );

                for ( int i = 1; i < context.Assemblies.Count; i++ )
                {
                    var asm = AssemblyFactory.GetAssembly( context.Assemblies[ i ] );
                    asm.Accept( new StructureMerger( context, primary, asm ) );
                }

                var fix = new FixReflectionAfterMerge( context, primary, primary );
                fix.Process();

                AssemblyFactory.SaveAssembly( primary, context.OutputPath );

            }
            catch (Exception e)
            {
                Log.LogErrorFromException(e);
                return false;
            }

            return true;
        }
    }
}