TargetFrameworksからビルドできそうなフレームワークだけビルドする
これから1ヶ月以上ブログ書いてなかった。というわけで、これの続き。
この記事では PCL や Xamarin 用のアセンブリを dotnet build でビルドできるようにしましたが、これだと MS の不自由アセンブリや Xamarin がインストールされていないとエラーになってしまうので、なんとかして警告レベルに落としたいので、やっていきます。
まずは対処前の状況。こんな感じのプロジェクトをビルドしていきます。
<TargetFrameworks>netstandard1.1;netstandard1.5;portable45-net45+win8+wpa81;monoandroid10;monotouch10;xamarinios10</TargetFrameworks>
するとこう。
PCL がコケたところでビルドが止まってしまっていますね。というか並列ビルドしてくれよ。
では、 TargetFrameworks
からビルドできなさそうなフレームワークを消していくコードを追加していきましょう。やり方を言葉で表すとこんな感じ。
- まとめてビルドするやつ(
DispatchToInnerBuilds
ターゲット)の実行前にフック - 次の手順をすべてのフレームワークに実行(といっても netstandard や netcoreapp は絶対ビルドできるし、次の手順には失敗するので素通りさせる)
GetReferenceAssemblyPaths
タスクを叩いてみる- 結果が空でないなら
TargetFrameworks
に追加する
以上を全フレームワークに実行します。
というわけで実際のコードはこちら。
<Target Name="CheckAvailableFrameworks" BeforeTargets="DispatchToInnerBuilds"> <ItemGroup> <!-- _TargetFramework という名前は DispatchToInnerBuilds 内で使われているので、被らないようにアンダーバー増やした --> <__TargetFramework Include="$(TargetFrameworks)" /> <!-- netcoreapp もあるならそれもちゃんと Condition に書きましょう --> <_OldTargetFramework Include="@(__TargetFramework)" Condition="!$([System.String]::Copy('%(Identity)').StartsWith('netstandard'))" /> <_NewTargetFramework Include="@(__TargetFramework)" Condition="$([System.String]::Copy('%(Identity)').StartsWith('netstandard'))" /> </ItemGroup> <!-- TargetFramework プロパティをセットして CheckCompilability を呼び出す --> <!-- TargetFramework プロパティがセットされていると、うまいこと TargetFrameworkMoniker プロパティがセットされるのを利用していきたい --> <MSBuild Projects="$(MSBuildProjectFile)" Targets="CheckCompilability" Properties="TargetFramework=%(_OldTargetFramework.Identity)"> <!-- 結果をとりあえずアイテム化しておいて --> <Output TaskParameter="TargetOutputs" ItemName="_NewTargetFramework" /> </MSBuild> <PropertyGroup> <!-- 強引にプロパティに変換する --> <TargetFrameworks>@(_NewTargetFramework)</TargetFrameworks> </PropertyGroup> </Target> <Target Name="CheckCompilability" Returns="$(CompilableFramework)"> <!-- ContinueOnError="true" によってエラーを警告化 --> <!-- これで完全勝利 --> <GetReferenceAssemblyPaths TargetFrameworkMoniker="$(TargetFrameworkMoniker)" RootPath="$(TargetFrameworkRootPath)" ContinueOnError="true"> <Output TaskParameter="ReferenceAssemblyPaths" PropertyName="_ReferenceAssemblyPaths" /> </GetReferenceAssemblyPaths> <PropertyGroup Condition="'$(_ReferenceAssemblyPaths)' != ''"> <!-- 成功したときだけ Returns に追加されるってわけ --> <CompilableFramework>$(TargetFramework)</CompilableFramework> </PropertyGroup> </Target>
これで警告になりました。めでたしめでたし。