窓を作っては壊していた人のブログ

この謎のブログタイトルの由来を知るものはもういないだろう

Visual Studio for Mac 7.4 でC# 7.2 を使ってみたい!

タイトル通りでネタです.

先日リリースされた Visual Studio for Mac 7.4.0.1033C# 7.1に正式に対応しました:clap: 非常に喜ばしいことではありますが,新しいものをどんどん触ってみたいおじさんの私としては,あれっ,C# 7.2は?という感じになっています.

なんとかVisual Studio for MacC# 7.2の機能が使えないか調べてみたので,その結果をまとめてみます.

注意

先に答えを言うとMonoのバージョンを上げるだけなのですが,Visual Studio for Mac 7.4での安定性が保証されていないバージョンを導入することになります. 試してみる程度の用途に留めるのが良いかと思われます.

環境

実験方法

[C#] Add language version 7.2 to supported languages UI by Therzok · Pull Request #3911 · mono/monodevelop · GitHub

このコミットでC# 7.2の言語バージョンを用いてビルドするUIのリストが追加されましたが,現在のStableにはまだ入っていないので,自分でcsprojを書き換えることでプロジェクトをC# 7.2でビルドするように指定します.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>7.2</LangVersion>
  </PropertyGroup>

</Project>

こんな感じですね. 一度ビルドを試してみましょう.

失敗しましたね. 理由としてはビルドにはcsc(Roslyn compiler)を使っているのですが,VS4MのStableと同時に配信されたMonoではそのRoslyn Compilerのバージョンが2.3.2になっているからです.

これを最新の2.6.0にすることが出来ればC# 7.2でもビルドが出来るのですが,さてどうやって変えればいいのだろうかと考えてみます. Monoのコミットログを探ってみると Bump Roslyn · mono/mono@c763b4a · GitHub のコミットでRoslynのバージョンが2.6.0に変更されていることが確認できます.

それではこのバージョンに変わったのはいつかというと,Mono 5.10に入ってからということもわかります. あっさり答えが見つかりましたので,Mono 5.10を導入してみましょう.

Download - Stable | Mono このあたりのリンクから5.10のインストーラーを探してインストールします.

その後VS4Mを一度再起動し先ほどのプロジェクトをビルドしてみるとビルドが通ると思います(エディタ上ではエラーの赤波があるのにビルドが通る楽しい状況になります).

これでVisual Studio for MacでもC# 7.2が使えるようになりました.

おきもち

正直な所今すぐに対応させる必要がないかぎりは公式に対応するまで待つのが吉かと思いました.

Xamarin SDKのPinningを行う ~MSBuildと仲良くなる~

本日Twitter

Xamarin SDK複数バージョン入れて、指定したバージョンビルドって可能なんだっけ?

みたいな書き込みがあり,そういえば前Currentを書き換えてiOSSDKの変更をしたことがあったなと思い,他にやり方がないか試してみました. 以下に挙げるテクニックなどを使用したSDKのPinningを行うことで出来ることとしては,

  • OSSになったXamarin SDKを自前ビルドして最新版を試してみること
  • あるバージョンから入ったバグ探しをすること
  • macのバージョンが低く,Xcodeのバージョンなどが上げられない時の対処(たぶん)

などが挙げられるかと思います. どんな仕組みでビルドが走っているのかの一端を見ることも出来るので,興味のある人は読んでみてください.

今回提案する方法は3つあります.

実験環境

  • macOS 10.12.6
  • mono 5.8.0.108
  • Visual Studio Community 2017 for Mac (Preview) Version 7.4 Preview (7.4 build 884)
  • Xamarin.Android Version: {8.1.0.25,8.2.0.1,8.2.0.6}
  • Xamarin.Mac Version: 4.2.0.8
  • Xamarin.iOS Version: 11.8.0.8

その1,Currentの書き換え

デフォルトではmacOSの場合 /Library/Frameworks/Xamarin.{Android,iOS,Mac}.framework/Versions/Current/のバージョンを使用します. あなたがもしsudoを使える立場なのであれば,シンボリックリンクを張り直すことでバージョンのPinningが行えます.

メリット:

  • 以降のビルドが基本的にはそのバージョンで行われ続ける

デメリット:

  • sudoを行う権限が必要
  • 新しいバージョンのSDKがインストールされるとCurrentが新しい方に移り,再度修正が必要
  • 全プロジェクトでそのバージョンが使われてしまい,使い勝手が悪かったりする

その2,csprojを書き換える

Android, iOS, macOSのプロジェクトのcsprojを見てみると,いくつか.targetファイルをImportしているのが確認できるかと思います. macOSだと

<Import Project="$(MSBuildExtensionsPath)\Xamarin\Mac\Xamarin.Mac.CSharp.targets" />

こんな感じのものです.

それをどんどん遡っていくと,

macの場合は /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/Mac/Xamarin.Mac.ObjCBinding.CSharp.propsXamarinMacFrameworkRoot

Androidの場合は /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/Android/Xamarin.Android.Common.propsXamarinAndroidVersion (未検証です...)

iOSの場合は /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/iOS/Xamarin.iOS.ObjCBinding.CSharp.propsMonoTouchSdkRoot

というプロパティにたどり着きます. これらのプロパティが設定されていない場合,Currentを指すような仕組みになっているようです.

決して面倒だからと言って上記のpropsファイルを書き換えるようなことはしないでください

ということで,このプロパティを指定することでSDKのPinningが行えそうです. macOSのプロジェクトの場合,プロジェクトのcsprojを開いて

<PropertyGroup>
  <XamarinMacFrameworkRoot>/Library/Frameworks/Xamarin.Mac.framework/Versions/4.2.0.8/</XamarinMacFrameworkRoot>
</PropertyGroup>

こんな感じでパスを指定してあげます. こうすることでsudoなどを使わずとも良くなりました. PropertyGroupのConditionをいい感じに変えてあげればCurrentを使うときや,Pinningしたバージョンでビルドするといったことが切り替えることが出来るので,そちらも試してみてください.

その際のビルドログを載せておきます.(179行目ぐらいから指定したバージョンを使っていることが見える)

macOSでSDKを指定した場合とそうでない場合のビルドログ(VS4Mに出力されてるやつのコピペなので見づらい) · GitHub

メリット:

  • csprojを見ればどのバージョンでビルドしたいのかがはっきりわかる
  • 他のプロジェクトに影響を与えない

デメリット:

  • csprojファイルを自分で書き換えるのが面倒

その3,コマンドラインでビルドする

この条件は少し特殊です. 自前でCI環境などを作っていて,cscだったりmsbuildを自分で叩く人のみに関係してきます. この場合も その2 と変わらずプロパティを指定してあげるだけです.

csc /p:XamarinMacFrameworkRoot=/Library/Frameworks/Xamarin.Mac.framework/Versions/4.2.0.8/ ... some_project.csproj

みたいな感じでしょうか. これはcsprojに書いてなくてもプロパティを外部から与えてあげる際に使用されるような場合に用いられます.

詳しくはこちら

MSBuild コマンド ライン リファレンス | Microsoft Docs

まとめ

3つの方法でSDKのPinningが可能であることがわかりました. 一番オススメなのが私としてはcsprojを書き換え,SDKのPathを指定してあげることです.

今回はmacOSをターゲットとする場合でしたが,iOSでも同様の手順で可能のはずです.

また今回はAndroidの検証が行えていません. Android

<XamarinAndroidVersion>8.2.0-6</XamarinAndroidVersion>

の様に指定されているので,このプロパティに対象のバージョンを指定することで可能になりそうです. どなたか試していただければと...

またこれ以外に簡単な手段があればぜひともコメントやTwitterなどで教えていただければと思います(普通にシェルとかの環境変数で出来たら楽そう...)


追記(2018/02/07 13:40)

このようなリプをいただいたので

XamarinMacFrameworkRoot=/Library/Frameworks/Xamarin.Mac.framework/Versions/4.2.0.8/ /Applications/Visual\ Studio.app/Contents/MacOS/VisualStudio

みたいな方法でVS4Mを起動してみた所,SDKに関する変数を反映した状態でVS4Mが起動でき,またビルドを走らせることが出来ました. 情報ありがとうございました.

とすると,コマンドラインでビルドを走らせる場合はある程度プロファイルを作ってシェルを叩いてしまってもいいし,MSBuildにパラメータとして与えても問題ないって感じですね. CI環境では同時に環境変数を与えることが出来るものも多いので(Visual Studio App Centerとかもそうだし),そういう感じで条件変えながらビルドのテストが出来そうです.