BEACHSIDE BLOG

Azure と GitHub と C# が好きなエンジニアの個人メモ ( ・ㅂ・)و ̑̑

C#: ビルドした exe や dll が AnyCPU / x86 / x64 かを確認する

ビルドして出力された 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 しかありませんが、構成マネージャー から x86x64 を追加することができます。

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 の ConfigurationPlatform にデフォルトの値が定義されているからです。

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 が書かれていない場合のみ上書きされる。