handmade hero day 001

続ける保証はないというか完全に一回限りの予定ですが、handmade heroを視聴し始めましたので、ノートを書こうと思います。

本記事の内容は開発環境を作るためにやったこと、つまり動画のかいつまみです。

動画ではテキストエディタについて説明していますが、ここでは取り上げません。この記事は口頭で簡単な説明を与えられる動画とは違うので、事前にある程度の知識を要求します。一応Unix系OSを使ったことのないWindowsユーザー向けに書いたつもりです(ディレクトリやパスの知識を要求している時点でけっきょく初心者向けではないのですが、あまり詳しく説明していると本当にいくら書いても足りないので、用語だけ示して調べていただくよう促しています)。

ここより常体。

事前準備

  • 64ビットコンピュータを使っている
  • Visual C++ (ビデオでは当時最新なのでVS2013だが、ここでは2016年現在最新のVS2015でいく)
  • ディレクトリ、パス(path)、コマンドラインの使い方(cd, mkdirなど)基本的な用語への理解している
  • ファイルの拡張子が表示されている
  • テキストエディタを使える

仮想ドライブを割り当てる

作業は基本的にコマンドライン上で行う。

Winキー+Rで「ファイル名を指定して実行」、cmdと入れるとすぐ起動できて便利である。ただし、あとでショートカットの引数をいじるのでこの起動方法は使えなくなる…)

まずsubstw:という仮想ドライブを作る(subst /?で使い方が出る)。わざわざ仮想ドライブを作る理由は、たくさんコマンドを打つので短いpathで書きたいとか、環境を切り離したいという意図があるのだと思う。

書き方は以下のような感じ。

subst w: c:\work

c:\workというのは別になんでもよい。これは現に存在していて作業してもよい空ディレクトリへのpathのことである。なので、コマンドを打つ前に必要に応じて作業用のディレクトリを自分で作り、場所を確保しておいてほしい。

ちなみに仮想ドライブw:に移動したいときはコマンドラインにそのままw:とだけ入力してエンターで移動できる。

バッチファイル

substは便利な機能だが、これによる仮想ドライブの割り当ては一時的なもので、コマンドプロンプト毎にしか有効にならない。試しに別のプロンプトを起動してみるとw:などないことがわかる。いちいちsubst w: なんとかかんとかと打つのは面倒くさい。

そこでバッチファイルというものを作る。バッチファイルは、batという拡張子で書かれたファイルで、中身にコマンドの内容をテキストで書いて保存し、ダブルクリックするとそのコマンドの内容を実行してくれるというものである。何度も使うコマンドを、一回限り書いて使い回すことができる便利な方法である。

startup.batというファイルを作り、次のような感じで書く(念を押すがc:\workのようなものは自分で用意する)。

@echo off
subst w: c:\work

保存し、実行するとコマンドラインw:というドライブができていると思う。ちなみにecho offはプロンプト上にうるさい表示をなくすための命令である。@をつけるのは自分自身の命令echo offを画面に表示させないため。割とめんどくさい。

スタートアップ

しかしバッチファイルをいちいちダブルクリックするのは面倒である。

そこで、Windowsにもともと備わっているスタートアップという機能を使い、startup.batを自動で実行してもらうことにする。

スタートアップはWindowsの起動時に「あるフォルダ(C:\path\to\Startup)」にあるexeファイルやbatファイルを自動的に実行してくれる。「あるフォルダ」の場所を示す\path\toの内容はWindowsのバージョンによって異なる。筆者にはバージョンごとの仕様を把握する時間がないので、windows スタートアップで調べてほしい。Windows 10の場合は以下のパスに置かれたexe, batファイルが実行される。

%USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

Winキー+Rで「ファイル名を指定して実行」、上記のpathをコピペすればフォルダが開かれる。ここに先ほど作ったstartup.batを放り込むだけで、それがスタートアッププログラムとして登録される。

フォルダ構成

そろそろプログラムを書いていきたいが、もう少しだけ下準備をする。必要なのはフォルダの構成を考えることと、Visual C++に備わっているコンパイラを呼び出す方法を知ることである。

handmade hero初日の最終的なフォルダ構成は次の通りである。手作業でこれらのフォルダを作っていく。

- w:
 |+ build
 |- handmade
  |+ code
  |+ misc

コンパイラを使えるようにする

まずhandmadeフォルダとcode, miscを作る。misc下にshell.batというバッチファイルを作り、次のように書く。

@echo off
set path=w:\handmade\misc;%path%
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"

2行目、misc自体をpathに追加している。miscにはshell.bat以外にもいろんなバッチを追加する予定なのでこうしているのだと思う。

3行目、これがコンパイラを呼び出すためのキモである。少し説明をする。

コマンドラインから一度試してみて欲しいが(動画ではそうしている)vcvarsall.batというバッチファイルを実行してみると、バッチファイルがよしなに働いてclというC++コンパイラを使えるようになってくれる。

callは外部のバッチファイルを起動するための構文である。

vcvarsall.batには次のように引数を渡すこともできる。x64は64ビットコンピュータむけのコンパイラを使うという指定である。

call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64

現在普及しているコンピュータには32ビット(x86)と64ビット(x64)があり、ターゲットとするプラットフォームごとにコンパイラを使い分ける必要がある。pathがProgram Files (x86)になっている理由は動画の26:00ごろ~を参照してほしい。といっても、歴史的経緯がある以上のことは言っていない気がするが、よく聞き取れなかったんで逃げを打っておるのです…

なにはともあれこれでVisual C++コンパイラが使えるようになった。

コンパイラを使う

いよいよプログラムを書き、コンパイルしてみる。codeディレクトリ下にwin32_handmade.cppというファイルを作り、次のプログラムを書く。

#include <windows.h>

int CALLBACK 
WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow
        ) 
{
    return 0;
}

これはなにもしないプログラムである。codeディレクトリ下に移動して以下のコマンドを打つ。

cl win32_handmade.cpp

win32_handmade.exewin32_handmade.objが生成される。

しかしながら、次のようなオプションをつけてコンパイルしたほうがより有用である。

cl /Zi win32_handmade.cpp

これはプログラムをデバッグしやすいよう、デバッグ情報を生成するようにコンパイルしている。

詳しくは/Z7, /Zi, /ZI (Debug Information Format)を参照のこと。

ただし、このオプションをつけるとごみごみしたファイルがたくさんcode下に生成されてしまう。ソースコードはコードとして、デバッグ情報やビルドファイルはそれとして、分離しておくのが望ましい。この整理整頓を遂行するためのbuild.batcode下に書く。

@echo off

mkdir ..\..\build
pushd ..\..\build
cl -Zi ..\handmade\code\win32_handmade.cpp
popd

pushdディレクトリbuildに移動しておき、移動する前のフォルダを覚えておく命令である。移動する前のフォルダに戻るにはpopdを使う。pushdpopdのあいだでコマンドを書き、コンパイルさせることによって、buildディレクトリ直下にごみごみとしたファイル群を生成し、終わったら元の場所codeに戻ることができる。

最初のWindowsプログラム

何もしないプログラムも立派なプログラムだが、それで終わりではあまりに虚しいので、ちゃんと動くものを作ってみる。

#include <windows.h>

int CALLBACK 
WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow
        ) 
{
    MessageBox(0, "This is Handmade Hero.", "Handmade Hero",
               MB_OK | MB_ICONINFORMATION);
    return 0;
}

MessageBoxは小さなダイアログを表示する命令である。第1引数にはこのメッセージボックスを所有するウィンドウのハンドル(ここでは存在しないので0)、第2引数はダイアログの内容(の文字列)、第3引数はキャプションの文字列、第4引数はダイアログボックスのふるまいを指定するUINT型の定数である。詳しくはMessageBox function (Windows)を参照。

これをコンパイルしてみる。すると、こんな感じのエラーが出る。

W:\handmade\code>build
サブディレクトリまたはファイル ..\..\build は既に存在します。
Microsoft(R) C/C++ Optimizing Compiler Version 19.00.24210 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

win32_handmade.cpp
Microsoft (R) Incremental Linker Version 14.00.24210.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:win32_handmade.exe
/debug
win32_handmade.obj
win32_handmade.obj : error LNK2019: 未解決の外部シンボル __imp_MessageBoxA が関数 WinMain で参照されました。
win32_handmade.exe : fatal error LNK1120: 1 件の未解決の外部参照

MessageBox function (Windows)のRequirementsの項を確認していただきたい。MessageBoxを使うにはUser32.libが必要なのである。なのでこれをコンパイラからリンクする必要があった。

build.batを次のように書き変える。

@echo off

mkdir ..\..\build
pushd ..\..\build
cl -Zi ..\handmade\code\win32_handmade.cpp user32.lib
popd

プログラムに問題がなければ、きちんとコンパイルされるはずである。これで、ちゃんと動くプログラムが作成された。Congratulations!