第13回
エラーメッセージと対処方法(3)~開発手順の効率化

コンパイルとソース修正の自動化

コンパイルでエラーが出たらソースの修正、そしてまたコンパイル……と、プログラムが完成するまで同じような処理を繰り返します。単純な作業は自動化しましょう。

コマンドラインでのコンパイルは面倒

プログラムの完成まで、エラーを確認しては怪しい箇所を探してソースを修正し、再コンパイル……というサイクルを繰り返していく訳ですが、修正するたびにエディタを起動し、次いでコンパイルのコマンドを入力するのは面倒です。

この
コンパイル→エラー→ソース修正→再コンパイル
という繰り返しを自動的に実行できれば、最も重要なソースの修正に集中できます。

統合環境であれば、エラーが発生すれば修正して再ビルド……と、効率的な作業が行えます。面倒なのはコマンドラインでの処理です。コマンドラインで同じような作業環境を作ってみましょう。

処理の流れを把握する

コマンドライン版のコンパイラ・ドライバでは、コンパイラやリンカのエラーメッセージが標準出力(ディスプレイ)に出力されます。プログラマーはそれを手がかりに、ソースファイルをエディタで開いて、修正しなければなりません。

前回紹介したように、コンパイラやリンカの出力したエラーメッセージは、リダイレクトによってテキストファイルに記録できます。さらに多くのエディタでは、エラーメッセージを元にタグジャンプ機能を使い、指摘されたソースの行に移動できます。

そこで、上述したコンパイルからエディタによるソース編集……という流れを、自動的にこなせるようにしてみます。プログラムの実行を制御するには、DOSではバッチファイル、UNIX系OSではシェルスクリプトを使います。

処理の流れは以下のようになります。

(1)エディタでソースを入力
(2)コンパイル
(処理分岐)
 (2-1)エラーなし→実行ファイル生成
   (3-1)終了
 (2-2)コンパイルまたはリンクエラー発生
   (3-2)エラーメッセージをエディタで表示
   (4)ソースを修正
   (5)→(2)に戻る

終了コードを調べる

プログラムは終了時に終了コードと呼ばれる数値を、その呼び出し元(シェル──DOSならCOMMAND.COM)に返します。終了コードは、一般に正常終了すれば0、エラーで終了すれば0以外(-1、あるいは各種エラーの内容を示す数値)となっています。

LSI-Cのコンパイラ・ドライバLCCやLinux系OSのGCCも同じで、エラーなく終了して実行ファイルが生成できれば0、エラーがあって実行ファイルを生成できなければ0以外の数値を返します。これを利用し、
コンパイラの終了コードが0でなければ
エディタでエラーメッセージをリダイレクトした
テキストファイルを開く
ようにすれば、自動処理ができ上がります。

エラーメッセージを参照してソースを修正したら、続けて再度コンパイルを行います。このとき、無条件にコンパイラを動かすと、場合によっては延々と同じ処理を繰り返すループとなるため、「再コンパイルするか」ユーザーに確認を求めるプログラムが必要になります。

Y/N入力を処理するプログラムを作る

ユーザーに確認を求めるため、
 「はい」(Yes)なら“Y”(または“y”)を  「いいえ」(No)ならそれ以外の1文字を 受け取って、  “Y”(または“y”)の場合は0  それ以外なら1を終了コードとして返す
プログラムが必要になります。

リスト1のようなソースです。動作の詳細は回を追って説明しましょう。今の段階では、このツールをそのまま使用してください。なお、リスト1のソースはLSI-CでもGCCでもコンパイルできます。もちろんVisual C++でも可能ですが、その場合はこれまでに説明したように#includeで取り込むヘッダファイルとmain関数の先頭を書き換えることに注意してください。

ソースファイルは“yesno.c”とします(DOSでは実行ファイル名が“yesno.exe”となります)。

リスト1:プロンプトを表示して'y'または'n'の入力を受け付ける~(yesno.c)
/* -----------------------------------------------------------------------
   yesno.c -- メッセージを表示してY/Nの入力を待つ。
              [Y]なら0、[N]なら1を終了コードとして返す。
   ----------------------------------------------------------------------- */

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
  char strMessage[255] = "Are you ready?";
  int chAnswer;

  if (argc > 1)
    strcpy(strMessage, argv[1]);

  strcat(strMessage, " <y/n>");

  puts(strMessage);
  chAnswer = getchar();
  if (chAnswer == 'y' || chAnswer == 'Y')
    return(0);
  else
    return(1);
}