本日Twitterで
Xamarin SDK複数バージョン入れて、指定したバージョンビルドって可能なんだっけ?
みたいな書き込みがあり,そういえば前Currentを書き換えてiOSのSDKの変更をしたことがあったなと思い,他にやり方がないか試してみました.
以下に挙げるテクニックなどを使用した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.props
の XamarinMacFrameworkRoot
Androidの場合は /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/Android/Xamarin.Android.Common.props
の XamarinAndroidVersion (未検証です...)
iOSの場合は /Library/Frameworks/Mono.framework/External/xbuild/Xamarin/iOS/Xamarin.iOS.ObjCBinding.CSharp.props
の MonoTouchSdkRoot
というプロパティにたどり着きます.
これらのプロパティが設定されていない場合,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を見ればどのバージョンでビルドしたいのかがはっきりわかる
- 他のプロジェクトに影響を与えない
デメリット:
この条件は少し特殊です.
自前で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とかもそうだし),そういう感じで条件変えながらビルドのテストが出来そうです.