Visual Studio から実機用のバイナリを作る方法

実機用のバイナリを作る方法についてはstd::vector と例外と+αを使ってる状態で実機用のバイナリを作る方法を参考にして貰うとして、ここでは Visual Studio でどうやって実機用バイナリを作るかというのを説明します。


といっても単純にカスタムビルドを使って適当にビルドするだけです。また、差分ビルドすると更新してもコンパイルされなかったりとよく分からないことになっちゃったので、フルビルドだけしかできません。

注意点

自分が確認したのは Visual C++ 2008 だけです。
「ビルド→構成マネージャ」を開くとか説明していますが、もしかしたら別の名前になってたりこの項目が無かったりするかもしれませんが、その場合はフィーリングで設定してください。

必要なもの

  • 実機用バイナリを作る際に使ったもの一式
  • Visual C++ 2008(Visual C++ 2005 や、Express Edition でもいけると思います)
  • Visual C++ で作られた、シミュレータを実行できる環境

コンパイル・リンク用の via ファイルを作る

via は要するにコンパイル時の引数を別ファイルに分けて書ける仕組みです。
via ファイルの構文については ARM のマニュアルダウンロードから手に入るコンパイラ/ライブラリガイドに書かれています。まあ単に複数行に設定が書けることと、‘;’以降はコメントになるということぐらいです。
別に無理して作る必要は無いのですが、あるとフラグの設定とか結構便利だったりするので、作っておいて損は無いと思います。


実際にどんなフラグを設定したかについてはstd::vector と例外と+αを使ってる状態で実機用のバイナリを作る方法を参照してください。


ただしリンク用の via ファイルについては以下のフラグを追加しています。

--via input_file_list.txt

input_file_list.txt には、リンクしたい .o ファイルの一覧を書いておきます。こうすることでリンク時にコマンドラインを弄る必要は無くなります。


自分はコンパイル用の via ファイルを armcc_via.txt、リンク用の via ファイルを armlink_via.txt としました。

新しく構成を作る

シミュレータの実行できるプロジェクトを VC で起動して、「ビルド→構成マネージャ」を開きます。
そこの「アクティブ ソリューション構成」から一つ構成を追加します。名前は何でもいいです。コピー元は今のシミュレータの環境を指定すれば良さそうです。


新しく構成を作らなくても、シミュレータの環境は大抵は Debug ビルドでしょうから、Release ビルドに設定しても構わないです(というか自分はそうしてます)。
ただし、その場合は Release バージョンのシミュレータ用の DLL が作れなくなってしまうことに注意です。これの問題点は、Visual C++ の入っていない PC でシミュレータを動かしたいという場合、Release ビルドじゃないと起動できないことです。そういったことを行う可能性がある場合は新しく構成を作って設定してやるのが吉です。

新しく作った構成をユーティリティ用ビルドに設定する

カスタムビルドを行うための設定を行います。
以下の設定は新しく作った構成に対してのみに反映されるようにしておいてください。


プロジェクトのプロパティを開きます。
項目ツリーから「構成プロパティ→全般」を選択して、「構成の種類」の設定を「ユーティリティ」にします。こうするとリンカだの MIDL コンパイルだのマニフェストの埋め込みといったことはしなくなります。
この設定を項目ツリーに反映させるためには「適用」を選択します。そうすると項目ツリーから無駄な項目が無くなります。

コンパイル用の設定を行う

ソリューション エクスプローラから全ての .cpp ファイルを選択して、これのプロパティを出してやります。
この全て選択するのが結構面倒だったりするのですが……。あと .cpp ファイルを追加するたびに以下の設定を行う必要があります。多分「追加するファイルが .cpp だったらこの設定をデフォルトで行っておく」みたいなのがあると思うのですが、調べきれませんでした。設定する方法を知ってる方は是非教えてください。


項目ツリーの「構成プロパティ→全般」を選択して「ツール」を「カスタム ビルド ツール」に設定して「適用」します。既に「カスタム ビルド ツール」になっている場合は必要無いです。
項目ツリーの「構成プロパティ→カスタム ビルド ステップ→全般」を選択して、「コマンドライン」を以下のように設定します。

armcc --via armcc_via.txt -o $(OutDir)\$(InputName).o $(InputPath)
echo $(OutDir)\$(InputName).o>>input_file_list.txt

1行目は、armcc_via.txt の設定を使って $(InputPath) のファイルを armcc でコンパイルし、$(OutDir)\$(InputName).o に出力します。出力場所はどこでもいいのですが、$(OutDir)\$(InputName).o が一番適切かなと思います。ただし、入力ファイルが別フォルダで同名になってたりなんかすると上書きされちゃっておかしなことになりそうなので、同名ファイルはやめておいた方がよさげです。
2行目は、出力した .o ファイルのパスを input_file_list.txt に追加書き込みしています。こうすることで、リンクする際に使用する .o ファイルの一覧をリンカに教えてやることができます。
ただし、このままだとビルドするたびに input_file_list.txt の中身が増えていってファイル名が重複してしまって多重リンクになって失敗してしまうので、ビルド開始時にこのファイルを削除してやることにします。この設定は後でやります。


「出力ファイル」には以下のように設定します。

$(OutDir)\$(InputName).o

まあこれが出力されるので当たり前です。
ただ、どうせフルビルドでしかコンパイルできないようにするので、無くてもいいやと思って消したのですが、ここにちゃんと出力されるファイルを書いておかないとこのファイルがコンパイルされなくなります
なのでちゃんと設定しておきましょう。


「追加の依存ファイル」には以下のように設定します。

input_file_list.txt

これは書く必要が無かったような気もするのですが、まあとりあえずという感じで書いてます。


これで全ての .cpp ファイルについてコンパイルできる環境が設定されたはずなので、一応 .o ファイルは作れるはずです。
次はリンクのための設定を行います。

リンク用の設定を行う

プロジェクトのプロパティを開いて、項目ツリーから「構成プロパティ→ビルド イベント→ビルド前のイベント」を選択して、ここの「コマンドライン」に以下のように入力します。

del input_file_list.txt
del $(OutDir)\*.o

コンパイル用の設定で説明した input_file_list.txt をビルドを開始する前に削除します。こうすればリンクするための .o ファイルが重複することもなくなります。
あとは既存の .o ファイルを全て削除します。これは差分ビルドを行った際に確実に失敗させるためです。こうすることで「以前の .o ファイルが残っていて偶然リンクできたけど、実機で落ちた」という状況が無くなると思います。


続いて、項目ツリーから「構成プロパティ→ビルド イベント→ビルド後のイベント」を選択して、ここの「コマンドライン」に以下のように入力します。

armlink --via armlink_via.txt --output $(OutDir)\$(InputName).elf
elf2mod -output bin\arm\$(InputName)\$(InputName).mod $(OutDir)\$(InputName).elf

1行目は、armlink_via.txt の設定を使ってリンクして $(OutDir)\$(InputName).elf ファイルを作ります。armlink_via.txt の中で --via input_file_list.txt と書いてあるので、ここの .o ファイルをリンクすることになります。
2行目で elf2mod を使って .mod を作ります。elf2mod にパスを通しておく必要があります。.mod の出力先は実機に転送しやすい場所に出力するのがいいでしょう。


これで設定は完了です。

ビルドする

あとは「ビルド→ソリューションのリビルド」あたりを選択してやるとフルビルドされるので、しばらく待てば .mod ファイルが作られます。
コンパイルエラーになったときにダブルクリックでジャンプするためにはRVCT3.0 のエラー形式のような Pipe を作っておいてちょっと変換すればいけるようになると思います。

さらに使いやすく

場合によっては ARM 用のバイナリをデバッグ用とリリース用に分けたいと思うかも知れません。
その場合は構成をいくつか作ってやります。例えば arm_debug と arm_release 構成を作って、コンパイル時に指定する via ファイルを以下のようにします。

armcc --via armcc_via_$(ConfigurationName).txt -o $(OutDir)\$(InputName).o $(InputPath)

これで armcc_via_arm_debug.txt と armcc_via_arm_release.txt にそれぞれの設定を書いておいて、リンクの方も同様に設定すれば、同一の設定で両方ともコンパイルができます。

おまけ

C++0x を使うために GCC4.4 とか使ったりしているのですが、これのビルドもカスタムビルドを使ってビルドしています。
カスタムビルドは結構便利なので、いろんなところで使ってやるといいかもしれません。