しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Surface Pro X (ARM64) に対応したアプリケーションを作る

10 インチの Surface Go に ARM の CPU が載ることを期待していましたが、Surface Pro X に載ってしまったので検証用に買うべきか悩んでいます。本体だけなら $999 から買えるので比較的安いです。

例によって日本での発売は未定ですが、フラグシップとなる Surface Pro X に ARM が載ったことで、それなりの台数が出そうなのでアプリ側の対応をしておくと幸せになれる予感がするので調べました。

先に ARM64 で動作するアプリを作る方法を 32 行でまとめておきました。Windows 向けにアプリを作る一般的な方法を選んでいますが、別の UI Framework を使えば実現出来るかも知れません。

  • .NET Framework を使って Any CPU 向けにビルド
  • UWP を使って ARM64 向けにビルド
  • C/C++ (Win32) を使って ARM64 向けにビルド

もうちょっと具体的に書いてみると、以下のようになると思います。実機がないので細かい部分までは追えていないですが、ビルド通ってしまえば勝ちという感じがあります。

  • .NET Framework (Any CPU) はそのまま ARM64 x86 で動く
    • NuGet などで Native DLL を参照している場合は実行時エラーになる
  • .NET Core は Windows 10 ARM64 を未サポート
    • .NET Core 3.0 でもダメ
    • ARM32 向けにビルドすれば動く (WPF / Win Forms 以外)
    • WPF / Win Forms は x86 向けにビルドするとバイナリトランスレーションで動く
  • UWP (.NET Native) は 6.2.7 から ARM64 をサポート
    • 新しくプロジェクトを作ると ARM64 ターゲット付きになっている
  • C/C++ (Win32) は ARM64 向けにビルドすれば動く
    • ARM64 向け開発ツール (コンパイラ / ライブラリ) のインストールが必要

Any CPU な .NET Framework 向けアプリならすんなり動きますが、ネイティブコードが含まれているライブラリを使っているケースは厄介です。最近は NuGet からビルド済みアセンブリをインストール出来ますが、殆どは ARM64 向けのバイナリを持っていないので詰みます。

意外に思われるかも知れないですが、.NET Core は Windows の ARM64 には公式対応していないです。RID に win10-arm64 を指定するとビルドが通ることもありますが、不具合を抱えている可能性があります。

公式ドキュメントなど

非常に ARM64 に関するドキュメントは少ないです。実機を買って触ってみるのが一番早そうです。

基本的には Visual Studio 2019 と ARM64 の開発ツールを入れてビルドを頑張る、という流れです。

あと、つもりんが Windows on ARM64 の実機を持っているので、ちょいちょいブログに書いてくれてます。

.NET Framework

Windows 10 の ARM64 版には .NET Framework の ARM64 版がインストールされているので、Any CPU でビルドしているアプリケーションは問題なく動作するはずです。

パッと見た感じでは ARM64 に限定したビルドは無理のようでした。普通は Any CPU で作ると思うので問題ないですが、ネイティブ DLL を読み込む場合は ARM64 向けのビルドを用意しておかないと死にます。*1

外部ライブラリを使う場合はマネージドコード実装のものを選んでおくと安心です。

追記

Surface Pro X で確認したところ、.NET Framework でビルドしたアプリケーションは強制的に x86 として実行されました。ARM32 / ARM64 向けに JIT Compile されないようなので、全体的にエミュレーションでの動作になるようでした。

つまり .NET Framework のままでは ARM64 への対応は絶対に無理ということです。

.NET Core

.NET Core は ARM64 に対応していないので、Surface Pro X に持って行っても動きません。ただし ARM32 や x86 としてビルドすると動作するので、とりあえずは妥協するしかなさそうです。

つもりんに協力してもらって ARM64 の Windows 上でいろいろと確認してもらいました。何故か対応してないはずの ARM64 向けにビルドが出来たので、それも確認してもらいました。

コンソールアプリケーションは問題ないですが、WPF / Win Forms に関してはランタイムが x86 / x64 向けにしか公開されていないので、ARM としてビルドは絶対にできないようになっています。

なので x86 としてビルドして、バイナリトランスレーションに頼る形になります。

x86 から ARM への変換が行われて、問題なく WPF のアプリケーションが動きました。

WPF (.NET Core) の ARM64 対応は今のところ 5.0 で予定されているみたいですが、先なので妥協します。

Surface Pro X がめちゃくちゃ売れたら優先順位が上がるかも知れませんが、望みは薄いでしょう。

UWP (.NET Native)

UWP に関しては元々 Windows 10 Mobile で ARM 対応が行われていたのもあり、ARM64 の対応は比較的スムーズに行えそうな感じです。とはいえ外部ライブラリの問題は残って来ます。

新しくプロジェクトを作れば、最初から ARM64 のプラットフォーム設定が追加されています。

f:id:shiba-yan:20191003205511p:plain

ARM のターゲットは Windows 10 Mobile 以外では必要ないので、いっそ削除しても良い気がします。

アプリケーションのパッケージ作成時に ARM64 にチェックを入れれば、対応したパッケージが作られます。依存関係が少なければ非常に簡単なので、まずは UWP から対応するようにしています。

f:id:shiba-yan:20191003205407p:plain

ビルドが成功しても認定ツールを走らせたり、ストアへの申請時のチェック時にエラーとなる場合があります。原因は大体ライブラリが ARM64 に対応していないことなので、ライブラリを特定して対応をお願いしたり、コントリビュートが必要になるでしょう。

C/C++ (Win32)

Win32 API を使って書いている場合も、基本は ARM64 向けのプラットフォームを追加してビルドすれば良いです。依存するライブラリが ARM64 に対応している必要がありますが、自分でビルドすることも可能です。

プラットフォームの追加ですが、最初から ARM64 が用意されているので簡単に行えます。

f:id:shiba-yan:20191003210637p:plain

適当にビルドしてみましたが、ちゃんと ARM64 向けのコードが生成されていることが確認できます。

f:id:shiba-yan:20191003194053p:plain

ビルドしたアプリケーションを開発用のマシンから ARM64 へ展開する場合は、Remote Tools for Visual Studio 2019 の ARM64 版をインストールすれば良いです。開発者モードをオンにしても出来る気がします。

ARM64 への対応は簡単な場合はやばいぐらいすぐに終わりますが、極端に難易度が高くなるケースもあるので行うべきかの判断が難しいです。

Surface Pro X がバカ売れしたら対応せざるを得ないはずなので、もう少し様子を見ても良いとは思います。

*1:Win32 API は ARM64 なので問題なし