Help us understand the problem. What is going on with this article?

Visual Studio for Macの.NET Coreサポートの実装について

More than 1 year has passed since last update.

はじめに

本稿は.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 adapter (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をご存知でしょうか?

https://github.com/Microsoft/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の最新のトップページには、次のようなフレーズが使われています:

visualstudio.com top page

"Any Developer, Any App, Any Platform"

VSMacも同じことを実現しようとしている、その未来の一端をこのdebug protocolサポートが示していると思いませんか? 現状ではXamarin Studioからrebrandingしただけとも言えるVSMacですが、新しいVisual Studioの方向性を組み込んだIDEとして、今後も発展していきそうです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした