SyntaxHighlighter

Wednesday 17 July 2013

Day 28: MSBuild and building .xnb's from the command line!

Building .xnb's from the command line

So the process to make an .xnb out of an .fbx goes something like: generate an MSBuild project that invokes the content pipeline, and then run it using MSBuild.

"MSwhat??" I hear you say? Well this overview of MSBuild explains all: http://msdn.microsoft.com/en-us/library/ms171452(v=vs.90).aspx

Taken from said overview: MSBuild is basically Microsoft's universal building thing, i.e.
The Microsoft Build Engine (MSBuild) is the new build platform for Microsoft and Visual Studio. MSBuild is completely transparent with regards to how it processes and builds software, enabling developers to orchestrate and build products in build lab environments where Visual Studio is not installed
So Visual Studio uses a hosted instance of MSBuild to build it's projects. In other words it means you can build a VS project from the command line (even on a machine with no VS installation) using MSBuild, and get exactly the same results as if you had built the project from within VS itself.

Perfect for our uses.

The MSBuild project file that I need to generate will be an xml file looking something like the example on this page: http://xboxforums.create.msdn.com/forums/t/77371.aspx. It fully describes what items need to be built as well as how they need to be built with different platforms and configurations.

Key features of the project files:
  • Items: represent inputs into the build system, grouped into item collections based on their user-defined collection names. Use these collections as parameters for tasks, which use the individual items contained in the collection to perform the steps of the build process.
<ItemGroup>
    <Compile Include = "file1.cs"/>
    <Compile Include = "file2.cs"/>
</ItemGroup>
...
$(Compile) <- to reference the item later on
  • Properties: represent key/value pairs that can be used to configure builds.
<PropertyGroup>
    <BuildDir>Build</BuildDir>
</PropertyGroup>
...
$(BuildDir) <- to reference the property later on
  • Tasks: reusable units of executable code used by MSBuild projects to perform build operations. e.g. a task might compile input files or run an external tool. Once created, tasks can be shared and reused by different developers in different projects. Example below calls the MakeDir task, passes it parameter which is the value of the BuildDir property (a task parameter can be a property or item collection).
<Target Name="MakeBuildDirectory">
    <MakeDir
        Directories="$(BuildDir)" />
</Target>
  • Targets: group tasks together in a particular order and expose sections of the project file as entry points into the build process. E.g. above, the target MakeBuildDirectory contains the task MakeDir.
To build a project file, use something like:
MSBuild.exe MyProj.proj /property:Configuration=Debug


So I made myself one of them:
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <UsingTask TaskName="BuildContent" AssemblyName="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" /> 
    <PropertyGroup> 
      <XnaInstall>C:\Program Files (x86)\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86</XnaInstall> 
    </PropertyGroup> 
    <ItemGroup> 
      <PipelineAssembly Include="$(XnaInstall)\Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll" /> 
    </ItemGroup> 
    <ItemGroup> 
      <Content Include="*.fbx"> 
        <Importer>FbxImporter</Importer>   
        <Processor>ModelProcessor</Processor> 
      </Content> 
    </ItemGroup> 
    <Target Name="Build"> 
      <BuildContent SourceAssets="@(Content)" PipelineAssemblies="@(PipelineAssembly)" TargetPlatform="Xbox360" /> 
        <BuildContent SourceAssets="@(Content)" PipelineAssemblies="@(PipelineAssembly)"  TargetPlatform="Windows" /> 
    </Target> 
  </Project> 
And I added the msbuild.exe directory to the %PATH% environment variable, opened a cmd prompt, and tried to build my new project file (with an fbx in the same directory). Nothing I try seems to get this thing to build, the error is:
C:\Users\ARdemo\Desktop\ARDemo\MSBuild Projects\process_fbx.proj(16,7): error MSB4062: The "BuildContent" task could not be loaded from the assembly Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d. Could not load file or assembly 'Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d' or one of its dependencies. The system cannot find the file specified. Confirm that the <UsingTask> declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.
Frankly, this makes no sense. The Microsoft.Xna.Framework.Content.Pipeline.dll is in the right place, Visual Studio Express builds correctly, I've installed all of the latest service packs and updates for VS and everything else, I'm using the 32-bit and the 64-bit version of msbuild (tried both, neither of them worked), I used dependency walker to check for dll dependencies of Microsoft.Xna.Framework.Content.Pipeline.dll and installed the missing dll's, still no luck. Reinstalled XNA, .NET4.5, installed the DirectX SDK, anything else I could find.

So... the assembly "Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d". Is it parsing that correctly?

Google turns up nothing. Can't believe no one wants to build fbx files outside of Visual Studio.

So it seems there is an issue with the dll or one of its dependencies. MSBuild can't see the Microsoft.Xna.Framework.Content.Pipeline assembly at all. I've even added the directory of it to the path. I'm using 32 bit MSBuild and .NET, 32 bit XNA (tried 64 bit MSBuild but no difference still get this error). I've told MSBuild to use .NET 4.0 - I do have .NET 4.5 installed maybe that's a factor?




Possible alternative to all this jazz: http://xbox.create.msdn.com/en-US/education/catalog/sample/winforms_series_2
(A tutorial that shows you how to import arbitrary 3D models at run time by running the Content Pipeline importers and processors dynamically on the fly as opposed to building all the content ahead of time in the usual way)

Will look into it because this MSBuild stuff is getting nowhere.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.