Technically Impossible

Lets look at the weak link in your statement. Anything "Technically Impossible" basically means we haven't figured out how yet.

Xanadu Clone - ザナドゥ クローン(ザナクロ)のソースを読むための準備~Visual Studio

f:id:espio999:20210711204749p:plain
入手したザナクロのコードは、問題なくビルド、実行できることが、前回の投稿で分かった。

ソースを改変して遊ぶためには、どこに何が書いてあるのかを知る必要がある。ソースコードに目を通すわけだが、ただエディタでソースコードを開いて読んでも構わないが、それなりに効率の良い環境を整えるのが良い。
前回の投稿を踏まえれば、ビルドに利用したBCC32の統合開発環境、RAD Studio (C++ Builder)を利用するのが順当なのだが、単純にフォルダを読み込んでプロジェクトを新規作成することができなかった。新規プロジェクトに、ファイルを一つずつ登録していく煩わしさを考えると、代替可能なツールを選ぶのが良い。

この投稿では、ソースコードに効率的に目を通す環境構築を目的に、Visual Studio 2019でプロジェクトを作成するまでの手順を紹介する。

なお、この投稿での環境は、前回の投稿で紹介した手順を済ませた段階の環境を引き継いでいる。手順を実行する前に、あらかじめ前回の手順を済ませておいてほしい。
impsbl.hatenablog.jp

前提

Visual Studio 2019

visualstudio.microsoft.com
ソースに目を通す環境として、Visual Studio 2019を選択した。C/C++拡張*1をインストールしたVSCodeでも構わないのだが、ソースコード中に定義されている関数、マクロのレベルまで、ソリューションのツリー構造で一望できる、そのような見通しの良さはVisual Studioならではの機能だ。
この投稿で紹介する作業を始める前に、Visual Studio 2019のインストールを完了しておく必要がある。
f:id:espio999:20210716232601p:plain

フォルダ

この投稿では、ザナクロのソース・ファイルは、次のフォルダに収録されている。

D:\user temp\work\xanadu\src

フォルダ”xanadu”を、プロジェクト・フォルダとして登録する。つまり、次のフォルダだ。

D:\user temp\work\xanadu

新規プロジェクト作成~フォルダの読み込み

一連の作業についてのスクリーン・キャプチャは、下記「参照:一連の作業」を展開してほしい。

Visual Studioを起動し、”コード無しで続行”する。
ファイル・メニューから次の項目を実行する。

ファイル > 新規作成 > 既存のコードからプロジェクトを作成

ここから”完了”ボタン押下までの一連の画面では、次の情報を登録していく。
指示のない項目は、デフォルトのままとする。

プロジェクトファイルの場所 d:\user temp\work\xanadu
プロジェクト名 xanadu
外部のビルドシステムを使用する on

参照:一連の作業
f:id:espio999:20210716232535p:plain
f:id:espio999:20210716232619p:plain
f:id:espio999:20210716232709p:plain
f:id:espio999:20210716232724p:plain
f:id:espio999:20210716232737p:plain
f:id:espio999:20210716232751p:plain
f:id:espio999:20210716232808p:plain

リビルド

設定

ただソースコードを読むだけであれば、ここでの作業は不要だ。
ここで紹介する作業を実施することで、前回利用した”makefile”を、Visual Studioから呼び出すことができる。例えば、アイテムやステータス情報に関わるパラメータを変更し、すぐにリビルドしたい時のために設定しておくと良い。

ファイル・メニューから次の項目を実行する。

デバッグ > xanaduデバッグプロパティ

各項目へ、次の情報を登録していく。
指示のない項目は、デフォルトのままとする。

  • 全般
出力ディレクト $(SolutionDir)src
中間ディレクト src\
ビルドログファイル $(MSBuildProjectName)_build.log
コマンド $(SolutionDir)src\xanadu.exe
  • NMake
インクルードの検索パス $(SolutionDir)include
ビルドコマンドライン cd $(SolutionDir)src
make all
すべてリビルドコマンドライン cd $(SolutionDir)src
make rebuild
クリーンコマンドライン cd $(SolutionDir)src
make clean

参照:一連の作業
f:id:espio999:20210716232906p:plain
f:id:espio999:20210716232925p:plain
f:id:espio999:20210716232940p:plain

実行

ファイル・メニューから次の項目を実行する。

ビルド > xanaduのクリーン
ビルド > xanaduのリビルド

前回同様、フォルダ”src”に”xanadu.exe”が出力される。

参照:一連の作業
f:id:espio999:20210716233020p:plain
f:id:espio999:20210716233036p:plain

なお、ここまでの設定では、デバッグ実行には対応できない。Makefileデバッグ用のコンパイルオプションを定義し、RAD Studio (C++ Builder)に含まれるデバッガを特定できれば、連携できるかもしれないが、デバッガを呼び出す方法が分からない。
デバッグ実行まで考慮すれば、RAD Studioでプロジェクト作成する方が良い。

ソースコードを読む

エラーから追う

Windowsの場合、プログラムは次のファイルのソースコードから始まる。

D:\user temp\work\xanadu\src\win32\main.c

このファイルを、ソリューションエクスプローラから選択すると、エディタ画面にソースコードが表示される。その状態でしばらく待つと、画面下にエラーや警告などが表示される。
f:id:espio999:20210716233106p:plain

ソースファイルを開けません ”rgb.c”

このエラーは気になる。ソースコードの冒頭に、次の記述があるのだが、

#include "rgb.c"

"rgb.c"はフォルダ"src”に存在しており、フォルダ”include”には存在していない。そこで、次の作業を行う。

  1. ”rgb.c”をフォルダ”include”へコピーする。
  2. ファイル名を”rgb.h”へ変更する。
  3. ソースコード中の"rgb.c”も、同様に”rgb.h”へ書き換える。
  4. ソリューションエクスプローラのコンテキスト・メニュー(右クリックメニュー)から、次の操作を行い、フォルダ”include”配下の”rgb.h”を追加する。

f:id:espio999:20210716233201p:plain

Header Files > 追加 > 既存の項目
D:\user temp\work\xanadu\include\rgb.h

しばらく待つと、次のようにエラーが消える。
f:id:espio999:20210716233212p:plain

定義から追う

無事にビルドができているとはいえ、このように隠れた問題を自動的に精査、提示してくれるもの統合開発環境の良いところだ。
とはいえ、やりたいことはデバッグではなく、ソースコードを読み進めることだ。例えば、先にエラーとされていた

識別子”default_rgb”が定義されていません

について、”default_rgb”の記述個所を選択し、コンテキスト・メニューから「定義をここに表示」を選択すれば、”rgb.h”の該当箇所が表示され、「定義へ移動」を選択すれば、”rgb.h”がエディタ表示される。
また「宣言へ移動」を選択すれば、画面下部にプロジェクトに含まれるソースコードから、”default_rgb”の宣言を含むファイルが一覧表示される。この検索結果をクリックすると、該当のコードがエディタ表示される。
f:id:espio999:20210716233232p:plain

検索する

例えば、戦闘中はアイテムの使用時間としてカウントされない、というのは『XANADU』の仕様だったが、『XANADU scenario 2』では廃止された。ザナクロでは、この仕様は次の箇所で定義されている。

  • user.c > void user_time_elapse(int interval)
/* シナリオ 1 では戦闘中に時間は経過しない */
if (!in_scenario2() && in_battle())
  return;

つまり、この部分を次のように書き換えれば、シナリオ1、2に関係なく、戦闘中はアイテム使用時間としてカウントされないよう、変更することができそうなのが分かる。

if (in_battle())
  return;

”Ctrl + F”で表示される検索窓から、思い当たる単語を入力することで、プロジェクト全体のソースコードを検索することもできる。
f:id:espio999:20210716234301p:plain
このように、ロジックを追跡しながら、必要に応じて関数やパラメータの定義を参照しながら、プロジェクト全体のどこに、何が定義されており、どこを変更すれば期待通りの動作をするのか、見当をつけていくことができる。

全体像をつかむ

Visual Studioが提示するツリー構造は、全体像を得られる表現の一つだ。ただし、それはファイルと、その中に定義されている関数までの粒度を網羅した「構造」だけを取り出したものだ。
それらの関連や依存関係までをも把握するには、ファイルの範囲を超えた構造も反映する必要がある。そこまで実現してくれるのが可視化ツールだ。
次回の投稿で、可視化ツールであるSourcetrailを導入し、ザナクロのソースを可視化する。
impsbl.hatenablog.jp