はじめに
本稿は.NET Core Advent Calendar1日目の投稿です。トップバッターなので、あまり.NET Coreの深い部分には立ち入らずに済ませようと思います。
Microsoft Connect 2016();で、新しいVSブランドの製品としてVisual Studio for Mac(以下VSMac)が公開され、プレビュー版が試せるようになりました。
お分かりの方も多いかと思いますが、VSMacは概ねXamarin Studioと言っても差し支えない存在です。MonoDevelopには元々UI上の「ブランディング」を簡単に変更する仕組みが用意されており、実態においてMonoDevelopとその上のアドインの集合体であるにすぎないXamarin Studioは、簡単に表示をXamarin Studioとしていられるわけです(かつてPlayStationSuiteという開発環境もありましたね)。VSMacもおそらく同様の仕組みに基づいて、UIを変更しているのでしょう。
というわけで、VSMacについて詳しく知りたければ、Xamarin StudioひいてはMonoDevelopについて調べればよいということになるわけですが、VSMacには、少なくとも現状のXamarin Studioには搭載されていない機能がいくつか存在します。そのひとつが本稿で言及する.NET Coreサポートです。
ちなみにVSMac自体についての基本的な使い方は、既に導入記事がいくつかあるので(この辺とか)、それらを参考にしてもらえればと思います。
.NET Core toolingとバージョンの関係
2016年10月に公表されたところによると、VS2017(当該ブログで記述されているVS "15"は、VS2017となったようです)における.NET CoreプロジェクトのビルドツールはMSBuildということになって、project.jsonや.xprojファイルは.csprojファイルに移行することになったようです。古いプロジェクトはdotnet migrate
コマンドで移行できるようです。
エェー、あの.csproj
ファイルかよ…と思われたかもしれませんが、新しいファイルはだいぶすっきりしているので、そんなに悪くないかもしれませんよ?
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
</Project>
ちなみに、以下が2016年11月時点での.csproj
ファイルです。半年でだいぶ変わりましたね。
<Project>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.App" Version="1.0.0" />
<PackageReference Include="Microsoft.NET.SDK" Version="1.0.0" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
従来のMonoDevelopとこのVSMacでは、プロジェクトモデルの実装が異なるのですが(従来型のプロジェクトがいきなりプロジェクトのファイル追加・削除操作がワイルドカード ベースになったりはしない)、この辺についてはこちらのblog postで詳しく説明されています。VSMacではこの新しいモデルに対応しています。
.NET Coreをサポートするパッケージ管理
VSMacのアプリケーションの内容を見ていくと、./Contents/Resources/lib/monodevelop/AddIns 以下に、おなじみのmonodevelopのアドイン群が入っています。今回は(Xamarin.AzureMobileAppServiceなど別方面の新しいのは置いといて)、まず地味なパッケージ管理から入りましょう。
VSMacのソースコードは公開されておらず(もともとVSMacのベースとなっているXamarin Studioも非公開です)、どうやら公開されているmonodevelopとも少し異なるコードベースを持っているようです。とはいえ、今でも共通の部分が多く、パッケージ管理については公開コードにも含まれています。MonoDevelop.PackageManagementというアドインです。
これを見る限り、NuGet 3.5には対応しているようです。NuGet 3.5では、netcoreapp11やnetstandard17といったモニカで表されるtargetに対応できる状態になっています。(もっとも、後述の通り、VSMacで対応しているのはnetstandard14です。)
あと、実装がどこにあるかは分かりませんが(たぶんMonoDevelop.ProjectsとかMonoDevelop.Ide.Projectsとか、その辺だと思うのですが…)、csprojファイルに含まれるPackageReferenceビルドアクションもサポートされているので、パッケージ参照のやり方は前述のMSDN blogに書いてあるやり方と互換性があります。ただし.NET Core 1.0互換なので、実際のビルドはproject.jsonで行っているでしょう。12/1修正: ビルドは(相変わらず正確に調べてはいませんが)csprojのC#ビルドをMSBuildで行っている可能性のほうが高いと思っています。想像です。
プロジェクトモデル
MonoDevelopは、.NETまわりのプロジェクトなら何でも自動的にサポートする、魔法のようなIDEではありません。monodevelopが新しい種類のプロジェクトをサポートするには、アドインによって新しいプロジェクト モデルを定義し、そのプロジェクトがどのようにビルド処理を行うのか、実行できる場合はどのように実行するのか、デバッグできる場合はどのデバッグエンジンを使用するのか、といった情報を、必要に応じてmonodevelopに渡せるようになっていなければなりません。
(MonoDevelopの「プロジェクトモデル」については、以前にも勉強会や記事で解説したことがあるので、もう少し詳しく知りたい方は、そちらを参照してください。)
というわけで、今回の.NET Coreサポートも、例外ではありません。
VSMacには、MonoDevelop.DotNetCore
という新しいアドインのDLLが追加されています。これはどうやら.NET Coreのプロジェクトモデルを定義しているようです。このアドインのディレクトリの下にtemplatesのフォルダがあることから、それが窺えます。
monodevelopのソースでは、main/src/addins/MonoDevelop.DotNetCore
に存在しています。ちなみに、2016年11月の時点では、このアセンブリに相当するアドインのソースは存在しませんでした…と思われるかもしれませんが、実はdotnetcoreというブランチが存在しており、この中にはMonoDevelop.DotNetCoreのソースが含まれていました。Xamarinでは、このように、新機能は基本的に別ブランチで開発していき、masterにマージできるようになったらマージする、という方針で開発が進められるので、新機能はブランチを眺めていると、何かしら新しいものが見えるようになるかもしれません(!)
MonoDevelop.DotNetCoreの具体的な実装内容について、少しずつコメントしていきましょう。
まず、サポートされているフレームワークは .NETCoreApp
と.NETStandard
です。とりあえず、.NET Core開発ツールとしてサポートする範囲としては、妥当なところかと思います。NuGetパッケージを追加しようとしても、netstandard14に対応していないものは追加できません。
プロジェクト テンプレートとしては、Console App、Empty Web App、Libraryの3種類が用意されています。Web Appというのは、ASP.NET Coreアプリケーションのことです…ASP.NET Coreについては、今回ここで詳しく説明すると、もはやVSMacの話ではなくなってしまうので、今回はこの1行にとどめます。Libraryというのは、.NET Standard Libraryのことで…これも説明すると長くなるので、既にいろんな人が書いている解説を探して読んでみてください。
ビルドに関して言えば、前述の通り、VSMacの.NET Coreサポートはv1.0相当のものなので、MSBuildでcsprojベースのビルドを行っているわけではありません。実のところ、.NET Coreのプロジェクトのビルドで使われるのは、MSBuildではなくdotnetコマンドですね。というわけで、MonoDevelopでもプロジェクトビルダーではdotnetを実行します。(てか、えらいコードですね、これ… dotnet
が /usr/local/dotnet
や /usr/share/dotnet
に入っていないと無いことにされるのかよ…)
最後にデバッグ実行についてですが…これは次に節を改めて論じます。
デバッガー
さて、今回の.NET Coreサポートで一番面白いところはここです(断言)。.NET Coreアプリケーションの実行は、(通常は)dotnet run
で行いますが、デバッグ実行となると、全く別の様相を呈してきます。この意味では、.NET Coreのデバッグ実行は、--debug
を付けて実行するだけのmonoランタイムによるデバッグ実行とは大違いです。
MonoDevelopの.NET Coreデバッグのサポートは、斜め上の方向から実装されています。MonoDevelop.DotNetCoreで実装されているデバッガー バックエンドは、DotNetCoreDebuggerEngineというクラスで、このCreateSession()メソッドはDotNetCoreDebuggerSessionというクラスのインスタンスを返します。このクラスはどう定義されているでしょうか?
public class DotNetCoreDebuggerSession : VSCodeDebuggerSession
VSCode!? そう、VSCodeです。VSCodeはデバッグ プロトコルをオープンに実装しており、VSCodeをサポートするデバッガーエンジンで動作するdebuggeeアプリケーションは、VSCodeのデバッグ プロトコルをサポートする任意のエディタでデバッグできるのです。
このVSCodeのdebug protocolを実装するアドインMonoDevelop.Debugger.VSCodeDebugProtocolが、VSMacには新しく追加されています。
MonoDevelopは、もともとmonoのデバッガー(sdb)に加えてgdbなどもサポートしており、VSCode debug protocolもこのアダプターのラインアップに新しく加わった、ということです。今後、VSCode debug protocolをサポートするプログラムは、そのデバッグ実行を開始さえ出来れば、このアドインを活用して簡単にデバッグをサポートできるようになった、と考えても良いでしょう。
VSMac(というかMonoDevelop)は、UIとしてはデバッガー クライアントであり、デバッグ対象プログラムを実行するアドインは、そのクライアントにとってはサーバーであり、このアドインは実際のプログラムにとっては、debug protocolの命令を転送するだけのクライアントである、ということになります。
さて、ではそのdebuggeeである.NET Coreプログラムは、どのようにしてデバッグ実行されるのでしょうか? vscodeでは、.NET Coreサポートにはomnisharp-vscodeというVSCode拡張が使用されます。C#サポートを実装するomnisharpの一部として実装されているということですね。デバッガー接続部分はcoreclr-debugという部分で実装されていて、実際にはOpenDebugAD7
というプログラムをインストールして実行するようになっているようです。実際、MonoDevelop.DotNetCoreに含まれるDotNetCoreDebuggerSessionでも、このOpenDebugAD7
というプログラムが実行されているようです。一体この謎のプログラムは何なのでしょうか?
その答えは…まあぐぐればすぐに分かります。Microsoftが2015年にオープンソース化したMIEngineをご存知でしょうか?
The Visual Studio MI Debug Engine ("MIEngine") provides
an open-source Visual Studio Debugger extension that
works with MI-enabled debuggers such as gdb, lldb, and clrdbg.
これは、gdbのMIと呼ばれるテキストベースのプロトコルを、MicrosoftがVisual Studioのデバッガー拡張のひとつとして実装したものです。.NET Coreのデバッグエンジンであるclrdbgは、このMIEngineから起動でき、このMIEngineのVSCode上での実体がOpenDebugAD7であるようです。
MonoDevelop.DotNetCoreのDotNetCoreDebuggerSessionは、このOpenDebugAD7を必要に応じてセットアップして接続しています。こう説明すると迂遠に見えるかもしれませんが、既存の汎用的なデバッグ サーバー・クライアントの仕組みを活用した、賢い戦略だと思いませんか?
Moving Forward
VSMacの.NET Coreサポートの実装をざっくり(?)紹介しましたが、どうでしたか? 今回は特にdebug protocolについて詳しく紹介してみました。
Visual Studioの最新のトップページには、次のようなフレーズが使われています:
"Any Developer, Any App, Any Platform"
VSMacも同じことを実現しようとしている、その未来の一端をこのdebug protocolサポートが示していると思いませんか? 現状ではXamarin Studioからrebrandingしただけとも言えるVSMacですが、新しいVisual Studioの方向性を組み込んだIDEとして、今後も発展していきそうです。