MSBuild.Community.Tasks の TemplateFile を使ってみた

ヘルプファイルに載ってるサンプルコードで動かなかったので、書いてみる。MSBuild.Community.Tasks ってのは、MSBuild の色々なカスタムタスクを提供してくれています。msbuildtasks.tigris.org から落とせます。
まずは使い方を確認しましょう。

ヘルプファイルの記載

<ItemGroup>
  <Tokens Include="Name">
    <ReplacementValue>MSBuild Community Tasks</ReplacementValue>
  </Tokens>
</ItemGroup>

<TemplateFile TemplateFile="ATemplateFile.template" OutputFile="ReplacedFile.txt" Tokens="@(Tokens)" />

正しくはこうだと思います。

<ItemGroup>
  <Tokens Include="Name">
    <ReplacementValue>MSBuild Community Tasks</ReplacementValue>
  </Tokens>
</ItemGroup>

<TemplateFile Template="ATemplateFile.template" OutputFileName="ReplacedFile.txt" Tokens="@(Tokens)" />

違う点は、テンプレートファイルを指定するプロパティが 「TemplateFile」 -> 「Template」、出力するファイルを指定するプロパティが「OutputFile」 -> 「OutputFileName」にすると、意図した通りに動きました。
テンプレートファイルのプロパティ名は、明らかに間違っておりコンパイルエラーになります。
出力するファイルを指定する方は、ヘルプファイルの通りだと、テンプレートファイルのファイル名 + 拡張子が "out" のファイルが出来てしまいました。


MSBuild の書き方が何となくわかったので、早速使ってみましょう。※コードを全部載せるので、少し長くなります。
まずは、テンプレートファイルから

Test.template

using System;

namespace TemplateFileTaskSample
{
  public class Test
  {
    public static string GetMessage()
    {
      return "${Message1}" + "${Message2}";
    }
  }
}

置き換える場所を示す Token は、${ name } と書きます。今回は、"Message1" と "Message2" という二つの Token を指定しました。
このファイルは、置き換える2つの文字列を結合した文字列を返すメソッドを定義したクラスファイルのテンプレートです。


続いて、こいつを呼び出すファイル

Program.cs

using System;

namespace TemplateFileTaskSample
{
  static class Program
  {
    [STAThread]
    static void Main()
    {
      Console.WriteLine(Test.GetMessage());
    }
  }
}

テンプレートファイルから生成されたクラスのメソッドを呼び出して、コンソールに出力するだけのものです。


最後に、MSBuild ファイル

TemplateFileTaskSample.csproj

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>9.0.30729</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{6DDBCBA5-E511-46E9-9686-AB4BB4B6EC62}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>TemplateFileTaskSample</RootNamespace>
    <AssemblyName>TemplateFileTaskSample</AssemblyName>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <StartupObject>
    </StartupObject>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>.\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="Test.cs" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

  <!-- 大事なのはここから!! -->
  <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
  <ItemGroup>
    <Tokens Include="Message1">
      <ReplacementValue>$(ReplaceTest1)</ReplacementValue>
    </Tokens>
    <Tokens Include="Message2">
      <ReplacementValue>$(ReplaceTest2)</ReplacementValue>
    </Tokens>
  </ItemGroup>
  <Target Name="BeforeBuild">
    <TemplateFile Template="Test.template" OutputFileName="Test.cs" Tokens="@(Tokens)" />
  </Target>
</Project>

前半は、VisualStudioからプロジェクトを作成して作った物を拝借しました、大事なのは後半です。
まず、MSBuild.Community.Tasks.Targets をインポートし TemplateFile タスクを使えるようにします。
※Targets ファイルを読み込まずに、dll と Task の宣言を自前でしても問題無いです。


次に、ItemGroup にて、置き換える Token の名前と値を指定します。Token の名前は、Include に指定します。
Include に指定する名前は、テンプレートファイル内で置き換える場所を指定した名前と合わせて下さい。
置き換える値は、ReplacementValue に指定します。今回は、コマンドラインからパラメータで(プロパティ値を)受け取る様にしました。
※ItemGroup 内に Tokens という名前で要素を追加していますが、この名前は何でも良いです。


そして、BeforeBuild (Build 前) で TemplateFile タスクを呼び出し、テンプレートファイルからクラスファイルを生成する様にします。
Template は テンプレートファイル を、OutputFileName は 出力ファイル(パスの指定可能)を指定します。
Tokens には、ItemGroup で宣言した要素の名前を指定します。(今回は、Tokens という名前にした)


設定はこれでお終い。では、実行してみます。

コマンドプロンプト から以下のコマンドを実行しビルドを行い、生成された exe ファイルを実行すると、"123abc" と出力されます。

MSBuild /t:Build /p:ReplaceTest1=123;ReplaceTest2=abc TemplateFileTaskSample.csproj