Share via


ビルド プロセスでテキスト変換を呼び出す

Visual Studio ソリューションのビルド プロセスの一環として、テキスト変換を呼び出すことができます。 テキスト変換に特化したビルド タスクがあります。 T4 ビルド タスクはデザイン時テキスト テンプレートを実行し、また、実行時 (前処理済み) テキスト テンプレートをコンパイルします。

使用するビルド エンジンに応じて、ビルド タスクができることには違いが生じます。 Visual Studio でソリューションをビルドすると、hostspecific="true" 属性が設定されている場合、テキスト テンプレートでは Visual Studio API (EnvDTE) にアクセスできます。 しかし、コマンド ラインからソリューションをビルドするとき、または、Visual Studio 経由でサーバー ビルドを開始するときは、これは当てはまりません。 このような場合、ビルドは MSBuild によって実行され、別の T4 ホストが使用されます。 つまり、MSBuild を使用してテキスト テンプレートをビルドすると、プロジェクト ファイル名などに同じようにアクセスできないことになります。 ただし、ビルド パラメーターを使用してテキスト テンプレートとディレクティブ プロセッサに環境情報を渡すことはできます。

コンピューターの構成

開発用コンピューターでビルド タスクを有効にするには、Visual Studio 用の Modeling SDK をインストールします。

注意

テキスト テンプレート変換コンポーネントは、Visual Studio 拡張機能の開発ワークロードの一部として自動的にインストールされます。 また、 [SDK、ライブラリ、およびフレームワーク] カテゴリの下にある Visual Studio インストーラーの [個別のコンポーネント] タブからインストールすることもできます。 [個別のコンポーネント] タブから Modeling SDK コンポーネントをインストールします。

Visual Studio がインストールされていないコンピューターで自分のビルド サーバーが実行されている場合、次のファイルを開発用コンピューターからビルド コンピューターにコピーします。

  • %ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VisualStudio\v16.0\TextTemplating

    • Microsoft.VisualStudio.TextTemplating.Sdk.Host.15.0.dll
    • Microsoft.TextTemplating.Build.Tasks.dll
    • Microsoft.TextTemplating.targets
  • %ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\VSSDK\VisualStudioIntegration\Common\Assemblies\v4.0

    • Microsoft.VisualStudio.TextTemplating.15.0.dll
    • Microsoft.VisualStudio.TextTemplating.Interfaces.15.0.dll
    • Microsoft.VisualStudio.TextTemplating.VSHost.15.0.dll
  • %ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies

    • Microsoft.VisualStudio.TextTemplating.Modeling.15.0.dll

ヒント

ビルド サーバーで TextTemplating ビルド ターゲットを実行しているときに、Microsoft.CodeAnalysis メソッドの MissingMethodException が表示された場合は、Roslyn アセンブリが、ビルド実行可能ファイルと同じディレクトリ (たとえば、msbuild.exe) 内の Roslyn という名前のディレクトリにあることを確認してください。

プロジェクト ファイルを編集する

プロジェクト ファイルを編集して、たとえばテキスト変換ターゲットをインポートして MSBuild の一部の機能を構成します。

ソリューション エクスプローラーで、プロジェクトの右クリック メニューから [アンロード] を選択します。 これにより XML エディターで .csproj または .vbproj ファイルを編集できるようになります。 編集が完了したら、 [再読み込み] を選択します。

テキスト変換ターゲットをインポートする

.vbproj または .csproj ファイルで、最後の Import Project 行を見つけます。

その行の後に (存在する場合)、テキスト テンプレートのインポートを挿入します。

<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v17.0\TextTemplating\Microsoft.TextTemplating.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v16.0\TextTemplating\Microsoft.TextTemplating.targets" />

ビルド時にテンプレートを変換する

プロジェクト ファイルに挿入して変換タスクを制御できるプロパティがいくつかあります。

  • すべてのビルドの開始時に変換タスクを実行します。

    <PropertyGroup>
        <TransformOnBuild>true</TransformOnBuild>
    </PropertyGroup>
    
  • たとえばチェックアウトされていないために、読み取り専用であるファイルを上書きします。

    <PropertyGroup>
        <OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
    </PropertyGroup>
    
  • 毎回、すべてのテンプレートを変換します。

    <PropertyGroup>
        <TransformOutOfDateOnly>false</TransformOutOfDateOnly>
    </PropertyGroup>
    

    既定では、次のものより古い場合、T4 MSBuild タスクによって出力ファイルが再生成されます。

    • テンプレート ファイル
    • 含まれているファイル
    • テンプレートによって、またはテンプレートで使用するディレクティブ プロセッサによって前に読み込まれたファイル

    これは、テンプレートと出力ファイルの日付のみを比較する Visual Studio の [すべてのテンプレートの変換] コマンドで使用されるよりも、強力な依存関係テストです。

プロジェクトでテキスト変換だけを実行するには、TransformAll タスクを呼び出します。

msbuild myProject.csproj /t:TransformAll

特定のテキスト テンプレートを変換するには、次のように実行します。

msbuild myProject.csproj /t:Transform /p:TransformFile="Template1.tt"

TransformFile ではワイルドカードを使用できます。

msbuild dsl.csproj /t:Transform /p:TransformFile="GeneratedCode\**\*.tt"

ソース管理

ソース管理システムと連携するような専用の機能は組み込まれていません。 ただし、独自の拡張機能を追加して、たとえば生成されたファイルをチェックアウトしてチェックインすることができます。 既定では、テキスト変換タスクでは、読み取り専用としてマークされているファイルの上書きを回避します。 このようなファイルが検出されると、Visual Studio のエラー一覧にエラーが記録され、タスクは失敗します。

読み取り専用ファイルを上書きするには、次のプロパティを挿入します。

<OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>

後処理のステップをカスタマイズしない限り、ファイルが上書きされるとエラー一覧に警告が記録されます。

ビルド プロセスをカスタマイズする

テキスト変換は、ビルド処理で他のタスクよりも前に実行されます。 $(BeforeTransform) プロパティと $(AfterTransform) プロパティを設定して、変換の前後に呼び出すタスクを定義できます。

<PropertyGroup>
    <BeforeTransform>CustomPreTransform</BeforeTransform>
    <AfterTransform>CustomPostTransform</AfterTransform>
</PropertyGroup>
<Target Name="CustomPreTransform">
    <Message Text="In CustomPreTransform..." Importance="High" />
</Target>
<Target Name="CustomPostTransform">
    <Message Text="In CustomPostTransform..." Importance="High" />
</Target>

AfterTransform では、ファイルのリストを参照できます。

  • GeneratedFiles: 処理中に出力されたファイルのリスト。 既存の読み取り専用ファイルを上書きしたファイルの場合、%(GeneratedFiles.ReadOnlyFileOverwritten) は true になります。 これらのファイルは、ソース管理からチェックアウトできます。

  • NonGeneratedFiles: 上書きされなかった読み取り専用ファイルのリスト。

たとえば、GeneratedFiles をチェックアウトするタスクを定義します。

OutputFilePath と OutputFileName

これらのプロパティを使用するのは MSBuild だけです。 Visual Studio のコード生成には影響しません。 これらは生成された出力ファイルを別のフォルダーまたはファイルにリダイレクトします。 対象となるフォルダーが既に存在する必要があります。

<ItemGroup>
  <None Include="MyTemplate.tt">
    <Generator>TextTemplatingFileGenerator</Generator>
    <OutputFilePath>MyFolder</OutputFilePath>
    <LastGenOutput>MyTemplate.cs</LastGenOutput>
  </None>
</ItemGroup>

リダイレクト先として便利なフォルダーは $(IntermediateOutputPath) です。

出力ファイル名を指定した場合、テンプレートの出力ディレクティブで指定された拡張子より優先されます。

<ItemGroup>
  <None Include="MyTemplate.tt">
    <Generator>TextTemplatingFileGenerator</Generator>
    <OutputFileName>MyOutputFileName.cs</OutputFileName>
    <LastGenOutput>MyTemplate.cs</LastGenOutput>
  </None>
</ItemGroup>

Visual Studio 内部でも [すべて変換] を使用してテンプレートを変換している場合、または単一ファイル ジェネレーターを実行している場合、OutputFileName または OutputFilePath を指定することはお勧めできません。 変換をどのようにして開始したのかに応じて、ファイル パスが変わります。 これはややこしい場合があります。

参照およびインクルード パスを追加する

ホストには、テンプレートで参照されているアセンブリを検索する既定のパス セットがあります。 このパス セットを追加するには、次のように指定します。

<ItemGroup>
    <T4ReferencePath Include="$(VsIdePath)PublicAssemblies\" />
    <!-- Add more T4ReferencePath items here -->
</ItemGroup>

インクルード ファイルを検索するフォルダーを設定するには、セミコロン区切りのリストを指定します。 通常は、既存のフォルダー リストに追加します。

<PropertyGroup>
    <IncludeFolders>
$(IncludeFolders);$(MSBuildProjectDirectory)\Include;AnotherFolder;And\Another</IncludeFolders>
</PropertyGroup>

テンプレートにビルド コンテキスト データを渡す

プロジェクト ファイルでパラメーター値を設定できます。 たとえば、ビルド プロパティや環境変数を渡すことができます。

<ItemGroup>
  <T4ParameterValues Include="ProjectFolder">
    <Value>$(ProjectDir)</Value>
    <Visible>false</Visible>
  </T4ParameterValues>
</ItemGroup>

テキスト テンプレートでは、template ディレクティブで hostspecific を設定します。 値を取得するには、parameter ディレクティブを使用します。

<#@template language="c#" hostspecific="true"#>
<#@ parameter type="System.String" name="ProjectFolder" #>
The project folder is: <#= ProjectFolder #>

ディレクティブ プロセッサでは、ITextTemplatingEngineHost.ResolveParameterValue を呼び出すことができます。

string value = Host.ResolveParameterValue("-", "-", "parameterName");

注意

ResolveParameterValue では、MSBuild を使用する場合に限り、T4ParameterValues からデータを取得します。 Visual Studio を使用してテンプレートを変換すると、パラメーターは既定値になります。

assembly および include ディレクティブでプロジェクト プロパティを使用する

$(SolutionDir) などの Visual Studio のマクロは、MSBuild では動作しません。 その代わりに、プロジェクト プロパティを使用できます。

.csproj または .vbproj ファイルを編集してプロジェクトのプロパティを定義します。 この例では、myLibFolder という名前のプロパティを定義します。

<!-- Define a project property, myLibFolder: -->
<PropertyGroup>
    <myLibFolder>$(MSBuildProjectDirectory)\..\libs</myLibFolder>
</PropertyGroup>

<!-- Tell the MSBuild T4 task to make the property available: -->
<ItemGroup>
    <T4ParameterValues Include="myLibFolder">
      <Value>$(myLibFolder)</Value>
    </T4ParameterValues>
  </ItemGroup>

これで、assembly ディレクティブおよび include ディレクティブでプロジェクト プロパティを使用できます。

<#@ assembly name="$(myLibFolder)\MyLib.dll" #>
<#@ include file="$(myLibFolder)\MyIncludeFile.t4" #>

これらのディレクティブは、MSBuild ホストおよび Visual Studio ホストの両方で T4parameterValues から値を取得します。

Q & A

なぜビルド サーバーでテンプレートを変換するのですか。 担当コードをチェックインする前に、既に Visual Studio でテンプレートを変換しています。

インクルード ファイル、またはテンプレートで読み込まれる別のファイルを更新した場合、Visual Studio ではそのファイルは自動的に変換されません。 ビルドの一部としてテンプレートを変換すると、すべてが最新であることが保証されます。

テキスト テンプレートを変換する方法は他にもありますか。

  • T4 MSbuild テンプレート (%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VisualStudio\v17.0\TextTemplating\Microsoft.TextTemplating.targets) にガイダンスがあります
  • T4 MSbuild テンプレート (%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Enterprise\msbuild\Microsoft\VisualStudio\v16.0\TextTemplating\Microsoft.TextTemplating.targets) にガイダンスがあります