ビルドして出力された exe や dll が AnyCPU / x86 / x64 を確認する方法はいくつかあります。
私は今回 Windows で Visual Studio が入ったローカル環境で試すので、手軽に確認できる corflags.exe を使っていきます。
実際に知りたいのは、諸条件下で msubuild コマンドを実行してビルドした場合の挙動ですが、手始めに csproj で PlatformTarget
を変更した際の VS でビルドした際の挙動とかも見ていきます。
今回は、.NET Framework (4.8) の ASP.NET MVC のプロジェクトを対象に調査してみました。
基礎知識
基礎 - その1
そもそもの話として AnyCPU
, x86
, x64
ってなんだっけって話は以下のドキュメントを確認しましょう。
C# コンパイラ オプション - 出力オプション | Microsoft Learn
ドキュメントにあるように今回対象の3種類以外にもいくつかありますが、今回は私が興味あるこの3つだけで検証します。
基礎 - その2
VS 上でビルドするときは以下の 構成 (下図左の赤枠) と プラットフォーム (下図右の赤枠)の2つでどれになるかが決まります。
最近の VS のデフォルトでは AnyCPU
しかありませんが、構成マネージャー から x86
や x64
を追加することができます。
Visual Studio の UI でビルドを実行して試す
準備: 開発者用 PhoweShell の起動
VS の上部メニュー 表示 → ターミナル をクリックすると 開発者用 PhoweShell が起動します。
準備: プロジェクトのプロパティを開く
csproj の <PlatformTarget>
の変更を VS の UI から変更したいので、プロジェクトのプロパティを開きます (VS Code で csproj を直接編集の方がブログで説明するのが面倒だったので...)。
VS のソリューションエクスプローラーでプロジェクトを右クリック (①)→ プロパティ (②) をクリックするとプロジェクトのプロパティが表示されます。ビルド (③) を開きましょう。対象プラットフォーム (④) と書かれている部分を変更しながら corflags.exe の挙動を確認します。
挙動の確認
色んな条件で corflags.exe を実行して出力される dll を見ていきます。前提として雑に3つ。
- ASP.NET MVC は、ソリューション名もプロジェクト名も Mvc48 というやつがある感じです。
- 基本的にコードは変えないのでビルドではなく リビルドして試していきます。
- 構成はすべて
Release
でやります。
AnyCPU の場合
構成を Release
にすると AnyCPU
がデフォルトで選ばれた状態になりますね。
これで VS の上部メニューからリビルドしましょう。リビルドが終わったら、開発者 PowerShell で以下のコマンドを実行して確かめてみましょう。
corflags.exe Mvc48\obj\Release\Mvc48.dll
もちろん結果は AnyCPU
です。AnyCPU
だと以下の結果が表示されます。
PE : PE32
32BITREQ : 0
32BITPREF : 0
x86 の場合
対象プラットフォームを x86 にしてみます。これは構成が Release
、プラットフォームが AnyCPU
が選ばれたときに対象のプラットフォームを x86 にするという、表示されていることとやってることが不整合になっていますが...簡易に検証するだけなので気にせず進みます。
VS の上部メニューから リビルド して、corflags.exe のコマンドを実行します。
corflags.exe Mvc48\obj\Release\Mvc48.dll
x86
場合、corflags.exe Mvc48\obj\Release\Mvc48.dll
を実行すると以下の結果が表示されます。
PE : PE32
32BITREQ : 1
32BITPREF : 0
x64の場合
対象プラットフォームを x64 にしてみます。
x64
場合、corflags.exe Mvc48\obj\Release\Mvc48.dll
を実行すると以下の結果が表示されます。
PE : PE32+
32BITREQ : 0
32BITPREF : 0
対象プラットフォームごとの判別はこんな感じでできます。
msbuild コマンドで試す
次は開発者用 PowerShell で、msbuild
コマンドを使って挙動を見ていきます。GitHub Actions で CI 時 msbuild がどう動きをするのか確認したいわけです。
msbuild (オプションなし) で実行
以下の場合で試します。
- ソリューションファイルがある直下で
msbuild
だけで実行 - ソリューションファイル指定 - 例:
msbuild Mvc48.sln
- プロジェクトファイルを指定 - 例:
msbuild Mvc48\Mvc48.csproj
どの場合でも Debug: AnyCPU の結果になりました。これは、csproj の Configuration
と Platform
にデフォルトの値が定義されているからです。
Configuration を指定して実行
前提として先ほどの検証からなんも変更はしていないので、Release の対象プラットフォームは x64 のままです。
つまり csproj では PlatformTarget
が明示的に指定された状態です。
今回のビルドは、構成のみを明示的に Release
を指定して実行してみます。
msbuild Mvc48.sln /p:Configuration=Release
コマンド実行後、 corflags.exe Mvc48\obj\Release\Mvc48.dll
を実行すると、Release の対象プラットフォームに設定されている x64 になりました。ここまではなんの変哲もない、構成されたとおりに動いている感じです。
Configuration と Platform を指定して実行
csproj で Release の対象プラットフォームは x64 のままです。これでビルドのコマンドは、構成は Release
、プラットフォームに Any CPU
を指定して実行してみましょう。
msbuild Mvc48.sln /p:Configuration=Release /p:Platform="Any CPU"
これで corflags.exe Mvc48\obj\Release\Mvc48.dll
を実行すると、コマンドで指定した "Any CPU" が出力されると思ってたけど、結果は x64 でした。
csproj で明示的に PlatformTarget
の指定があるとそっちが優先されるのか。
csproj で PlatformTarget を消した状態で Configuration と Platform を指定して実行
前述で csproj に <PlatformTarget>x64</PlatformTarget>
があるって図を出しましたがこれを消します。明示的な指定が無いとデフォルトで AnyCPU
になるので、その状態でビルドのコマンドに x86
を指定してみます。
msbuild Mvc48.sln /p:Configuration=Release /p:Platform=x86
🚧🚧 ちなみに x86
を指定するには、事前に 構成マネージャー から x86
のプラットフォームを作成しておく必要があります。
これで corflags.exe Mvc48\obj\x86\Release\Mvc48.dll
を実行すると、x86 の dll ができていました。csproj に明示的に書かれていない場合のみ /p:Platform=x86
はオーバーライドされるんですね。
まとめ
実は今回やりたかったことは、msbuild で /p:Platform
ってほんまにオーバーライドされるの?って疑問の検証だったんですが結果はこれ。
csproj で対象の構成 (Configuration) に明示的に PlatformTarget
が書かれていない場合のみ上書きされる。