C ユーザーズガイド |
第 9 章
cscope
: 対話的な C プログラムの検査
cscope
は、C、lex
、またはyacc
のソースファイル内のコードの特定の要素を探し出す対話型プログラムです。cscope
ブラウザを使用すると、従来のエディタよりも効率的にソースファイルを検索、編集できます。これは、cscope
が関数呼び出し (関数がいつ呼び出され、いつその関数を実行するか) についてと、C 言語の識別子と予約語を理解しているためです。本章はcscope
ブラウザについて説明します。この章は、このリリースに付属している
cscope
ブラウザの使い方を学ぶための資料として利用できます。説明項目は次のとおりです。
cscope
プロセス
cscope
は、C、lex
、yacc
のソースファイルを読み取り、ファイル内の関数、関数呼び出し、マクロ、変数、前処理シンボルのシンボル相互参照表を作成します。次に作成した表を検索して、ユーザーが指定したシンボルの位置を探し出します。cscope
は、最初にメニューを表示し、実行したい検索のタイプを聞いてきます。たとえば、特定の関数を呼び出しているすべての関数を検索することができます。検索が終了すると、
cscope
は結果を表示します。リストの各エントリ行には、指定したコードが存在するファイル名、行番号、その行のテキストが含まれます。この例では、指定された関数を呼び出している関数名も表示されます。リストを表示した後は、新しく検索するか、あるいはリストに表示された行をエディタで調べるかを選択することができます。後者の場合、cscope
はその行があるファイルをエディタで読み込んで、その行にカーソルを移動します。ここで、その行の前後関係を調べることができます。さらに他のファイルと同じように編集することもできます。エディタを終了したら、メニューに戻って新しい検索を始めます。作業内容によって手順も変わってくるので、
cscope
の使用方法は 1 通りではありません。cscope
の詳しい使用方法や、コード全体を調べることなくプログラム内のバグを探し出す方法については、次の「基本的な使用方法」で説明します。
基本的な使用方法
たとえば、プログラム
prog
の開始直後にout
of
storage
というエラーメッセージが表示されることがあると想定します。これを解決するには、まずcscope
を使用してコード内のメッセージを発行している場所を探し出さなければなりません。この場合、次の手順で実行します。ステップ 1:環境設定
cscope
は、画面指向ツールです。使用できる端末は、端末情報ユーティリティ (terminfo
) データベースに書かれているものに限られます。TERM
環境変数を自分の端末タイプ<端末名>
に設定してあることを確認してください。cscope
はTERM
環境変数の値を見て、それがterminfo
データベースに存在するか確認します。まだ設定していない場合は、次のようにして
TERM
に値を設定し、それをシェルに伝えます。
$TERM=
<端末名>; export TERM
%setenv TERM
<端末名>次に、
EDITOR
環境変数に値を設定します。デフォルトでは、cscope
はvi
エディタを起動します (本章の例もvi
を使用して説明しています)。vi
を使用したくない場合は、EDITOR
環境変数を任意のエディタ名に変更して、EDITOR
をエクスポートします。
$EDITOR=emacs; export EDITOR
%setenv EDITOR emacs
cscope
とエディタ間のインタフェースを設定しなければなりません。詳細は、
「エディタのコマンド行構文」を参照してください。
cscope
を表示するためだけに使用したい (編集は使用しない) 場合は、VIEWER
環境変数をpg
に設定してVIEWER
をエクスポートします。cscope
はvi
の代わりにpg
を起動します。環境変数
VPATH
には、ソースファイルの検索対象ディレクトリを指定します。
「ビューパス (Viewpath)」を参照してください。ステップ 2:
cscope
プログラムの起動デフォルトでは、
cscope
は現ディレクトリ内にあるすべての C、lex
、およびyacc
のソースファイルのシンボル相互参照表、および現ディレクトリまたは標準位置内にあるすべてのインクルードヘッダーファイルのシンボル相互参照表を作成します。したがって、表示するプログラムのすべてのソースファイルが現ディレクトリにあり、かつそのヘッダーファイルが現ディレクトリまたは標準位置にある場合は、cscope
を引数なしで起動します。
%cscope
特定のソースファイルを表示する場合は、そのファイルの名前を引数にして
cscope
を起動します。
%cscope
<ファイル 1>.c
<ファイル 2>.c
<ファイル 3>.h
cscope
の他の起動方法については、「コマンド行オプション」を参照してください。プログラムを表示するため、最初に
cscope
が使用されるときにシンボル相互参照表が作成されます。デフォルトでは、作成されたシンボル相互参照表は現ディレクトリ内のcscope.out
ファイルに格納されます。その後cscope
を再び起動すると、前回と比較してソースファイルが修正されていたとき、またはソースファイルのリストが異なるときだけ相互参照表が作成し直されます。相互参照表を再び作成する時には、変更されていないファイルのデータは前回の相互参照表からコピーされます。これによって、最初の作成時より作成速度が速くなり、起動時のスタートアップ時間も短くなります。ステップ 3:コード位置の確定
本節の最初で述べた本来の作業に戻り、out of storage のエラーメッセージの原因となっている場所を確定します。
cscope
が起動され、相互参照表が作成されました。画面には、cscope
の作業メニューが表示されます。
Return キーを押すと、カーソルは下に移動し (画面の一番下まで移動すると、先頭に戻ります)、
^p
(Ctrl キーと p キー) を押すと上に移動します。また、上矢印と下矢印キーも使用できます。以下の単一キーコマンドを使用すれば、メニュー操作とその他の作業が行えます。
検索文字列の最初の文字が上記のいずれかのコマンドと一致する場合は、検索文字列の前にバックスラッシュ (\) を加えてコマンドと区別します。
たとえば、カーソルを 5 番目のメニュー項目「
Find this text string
」に移動して文字列「out of storage」を入力し、Return キーを押します。
注 - 6 番目の「Change this text string
」項目以外のメニュー項目についても同じ手順に従ってください。6 番目の項目は他の項目よりも多少複雑なので手順が異なります。文字列の変更方法については 「cscope の使用例」を参照してください。
cscope
は指定された文字列を検索し、それを含む行を見つけ出して次のように検索結果を表示します。
cscope
関数: 文字列を含むcscope
行のリスト表示
検索結果が正常に表示されたら、次の操作を選択します。行を変更したり、またはその行の前後をエディタで調べることができます。あるいは、
cscope
の検索結果のリストが一画面に収まらない場合は、リストの次の部分を見ることもできます。cscope
が指定した文字列を検索した後に使用可能なコマンドを以下に示します。
ここでも、検索文字列の最初の文字が上記のいずれかのコマンドと一致する場合は、検索文字列の前にバックスラッシュ (\) を加えてコマンドと区別します。
次に、新しく検索した行の前後を調べます。「1」(リスト内の行番号) を入力してください。エディタが起動され、
alloc.c
ファイルが読み込まれます。カーソルは、alloc.c
の 63 行目の先頭に移動します。
変数
p
がNULL
のときに、エラーメッセージが出力されることがわかります。alloctest()
に渡される引数がなぜNULL
になったのかを調べるには、まずalloctest()
を呼び出している関数を確定する必要があります。通常の終了方法でエディタを終了し、作業メニューに戻ります。ここで、4 番目の項目「
Find functions calling this function
」の後にalloctest
と入力します。
cscope
関数:alloctest()
を呼び出す関数のリストの要求
cscope
は検索を実行し、次の 3 つの関数のリストを表示します。
cscope
関数:alloctest()
を呼び出すListing
関数
今度は、
mymalloc()
を呼び出す関数を調べます。cscope
は、次のような 10 個の関数を見つけ出します。そのうち 9 個を画面に表示し、残りの 1 個を見るにはスペースバーを押すように指示しています。
cscope
関数:mymalloc()
を呼び出す関数のListing
関数
out of storage
のエラーメッセージはプログラムの開始直後に出力されるので、関数dispinit()
(表示の初期化) 内で問題が発生していることが推測できます。
dispinit()
はリストの 7 番目の関数なので、これを参照するには「
7」
と入力します。
cscope
関数:dispinit()
をエディタで参照
mymalloc()
が失敗したのは、非常に大きな数または負数を引数にして呼び出されたためです。FLDLINE
とREFLINE
が取り得る値を調べてみると、mdisprefs
の値が負になる場合があることがわかります。この場合、mymalloc()
は負数を引数にして呼び出されます。ステップ 4:コードの編集
ウィンドウ端末上では、任意のサイズで複数のウィンドウを開くことができます。
out of storage
のエラーメッセージが出力されたのは、prog
を実行するウィンドウ内の行数が少なすぎたためと考えられます。つまり、mymalloc()
が負数を引数にして呼び出された場合にこのような状況が発生する可能性があるということです。
今後このような状況が発生した場合に、もっと分かりやすいエラーメッセージ、たとえば
Screen too small
を出力してプログラムを中止するように設定しておくとよいでしょう。それには、dispinit()
関数を以下のように編集します。
以上で、本節の最初で調査を開始した問題箇所は修正されました。これで、行数が少なすぎるウィンドウ内で
prog
を実行したときに、単に意味不明のエラーメッセージout of storage
を出力して中止するのではなく、ウィンドウサイズを検査して分かりやすいエラーメッセージを出力した後に終了するようになります。コマンド行オプション
すでに述べたとおり、
cscope
はデフォルトでは現ディレクトリ内にある C、lex
、およびソースファイルのシンボル相互参照表を作成します。すなわち、次の 2 つのコマンドは等価です。
%cscope
%cscope *.[chly]
指定したソースファイルを表示するには、ソースファイル名を引数に指定して
cscope
を起動します。
%cscope
<ファイル 1>.c
<ファイル 2>.c
<ファイル 3>.h
cscope
のコマンド行オプションを使用して、相互参照表に含まれるソースファイルをさらに自由に指定することもできます。それには、次のように-s
オプションの後にコンマで区切られた任意の数のディレクトリ名を指定してcscope
を起動します。
%cscope -s
<ディレクトリ 1>,<ディレクトリ 2>,<ディレクトリ 3>
cscope
は現ディレクトリ内だけでなく、指定されたディレクトリ内にあるすべてのソースファイルを対象に相互参照表を作成します。<ファイル> 中にリストされているソースファイル (ファイル名をスペースやタブまたは復帰改行で区切ったもの) のすべてを表示するには、-i
オプションとリストを持つファイル名を指定してcscope
を起動します。
%cscope -i
<ファイル>ソースファイルがディレクトリツリーの中にある場合は、以下のコマンドでディレクトリツリー内のすべてのソースファイルを簡単に表示できます。
%find . -name '*.[chly] ' -print | sort >
<ファイル>%cscope -i
<ファイル>このオプションを使用しても、コマンド行でファイルが指定されている場合は、指定されたファイル以外については無視されるので注意してください。
-I
オプションは、cc
に対する-I
オプションと同じような形式でcscope
にも指定できます。「インクルードファイル」を参照してください。
-f
オプションを使用すると、デフォルトのcscope.out
以外のファイルを相互参照ファイルとして指定できます。このオプションは、同じディレクトリ内に異なるシンボル相互参照ファイルを保管するのに役立ちます。たとえば、2 つのプログラムが同じディレクトリ内にあるが、すべてのファイルを共有しているとは限らない場合に使用します。
$cscope -f admin.ref admin.c common.c aux.c libs.c
$cscope -f delta.ref delta.c common.c aux.c libs.c
この例では、2 つのプログラム
admin
とdelta
のソースファイルは同じディレクトリ内にありますが、プログラムを構成するファイルは異なっています。cscope
起動時に、別のシンボル相互参照ファイルを指定しておくことによって、2 つのプログラムの相互参照情報を別々に保管できます。
-p
n オプションを使用すると、検索結果でリストされたファイルのあるパス名やそのパス名の一部を表示することができます。-p
の後の n には、パス名の中で最後から何番目までの要素を表示させたいかを指定します。デフォルト値は1
で、これはファイル名そのものを意味します。したがって現ディレクトリがhome/common
の場合、以下のコマンドによって検索結果のリストに表示されるパス名は、common/
<ファイル 1>.c
やcommon/
<ファイル 2>.c
のようになります。
%cscope -p2
表示したいプログラムが大量のソースファイルを含む場合、
-b
オプションを使用して、相互参照表を作成した後でcscope
を終了することができます。このとき、作業メニューは表示されません。パイプを使用して、cscope -b
の出力をbatch
(1) コマンドの入力につなげると、cscope
は相互参照表をバックグラウンドで作成します。
%echo 'cscope -b' | batch
相互参照表がいったん作成されると、その後、ソースファイルまたはソースファイルのリストを変更しない限り、次のように指定するだけで相互参照表がコピーされ、通常どおり作業メニューが表示されます。
%cscope
このコマンドシーケンスを使用すると
cscope
の初期処理の終了を待たずに作業を続けることができます。
-d
オプションは、cscope
にシンボル相互参照表を更新させません。このオプションを指定すると、ソースファイルの変更が検査されないため時間の節約になります。変更されていないと確信できる場合にのみ使用してください。
注 --d
オプションの使用には注意が必要です。ソースファイルが変更されていることに気付かずに-d
オプションを使用すると、cscope
は古いシンボル相互参照表を使用して照会に応じてしまいます。
他のコマンド行オプションについては、
cscope
(1) のマニュアルページを参照してください。ビューパス (Viewpath)
前述のように
cscope
は、デフォルトでは現ディレクトリ内のソースファイルを検索します。環境変数VPATH
が設定されているときは、cscope
はVPATH
に指定されたディレクトリ内のソースファイルを検索します。ビューパスとは、順序付けされたディレクトリのリストで、リスト内の各ディレクトリの下は同じディレクトリ構造になっています。たとえば、ユーザーがあるソフトウェアプロジェクトのメンバーであるとします。
/fs1/ofc
下のディレクトリには、正式バージョンのソースファイルがあります。各メンバーはホームディレクトリ (/usr/you
) を持っており、ソフトウェアシステムを変更する場合は、変更するファイルだけを/usr/you/src/cmd/prog1
にコピーします。全プログラムの正式バージョンは、/fs1/ofc/src/cmd/prog1
にあります。
cscope
を使用して、prog1
を構成する 3 つのファイル (f1.c、f2.c、f3.c
) を表示します。まずVPATH
を/usr/you
と/fs1/ofc
に設定してエクスポートします。
$VPATH=/usr/you:/fs1/ofc; export VPATH
%setenv VPATH /usr/you:/fs1/ofc
次に、現ディレクトリを
/usr/you/src/cmd/prog1
に移動してcscope
を起動します。
$cscope
cscope
はビューパスにあるすべてのファイルの位置を調べます。同じファイルが複数のディレクトリにある場合は、VPATH
内で先に現れたディレクトリの下にあるファイルを使用します。したがって、f2.c
がユーザーのディレクトリにあり (3 つのファイルはすべて正式バージョン用ディレクトリの下にもある場合)、cscope
はf2.c
はユーザーのディレクトリのものを、f1.c
およびf3.c
は正式バージョン用のディレクトリのものを検査します。
VPATH
内の最初のディレクトリは、作業用ディレクトリの接頭辞 (通常は$HOME
) でなければなりません。VPATH
内のコロンで区切られたそれぞれのディレクトリは、/
から始まる絶対パス名でなければなりません。
cscope
とエディタ呼び出しのスタック
cscope
とエディタの呼び出しはスタックできます。たとえば、cscope
がエディタを起動してシンボルへの参照を調べているときに、他にも参照関係を調べたいシンボルがある場合、エディタ内部から再びcscope
を起動して 2 番目の参照関係を調べることができます。現在起動中のcscope
やエディタを終了する必要はありません。一番最後に起動したcscope
またはエディタコマンドを正常に終了すれば、1 つ前の状態に戻ることができます。
cscope
の使用例
cscope
が次の 3 つの作業を行うのにどのように使用されるかを見ていきます。対象とする作業は、定数をプリプロセッサシンボルに変更する、関数に引数を追加する、変数の値を変更するの 3 つです。最初の例では、文字列の変更手順を示します。この作業は、cscope
メニューの他の作業項目とは少し異なっています。変更したい文字列を入力すると、cscope
はそれを置き換える新しい文字列を聞いてきます。画面には古い文字列を含む行が表示されます。ここで、どの行に含まれる文字列を変更するかを指定します。例 1:定数をプリプロセッサシンボルに変更する
たとえば、定数
100
をプリプロセッサシンボルMAXSIZE
に変更するとします。6 番目のメニュー項目「Change this text string
」を選択して、\100
と入力します。1
の前にはバックスラッシュを加えて、cscope
のメニュー項目番号を意味する1
と区別します。Return キーを押すとcscope
は新しい文字列を聞いてくるので、MAXSIZE
と入力します。
cscope
は、指定された文字列を含む行を表示します。どの行の文字列を変更するかが選択されるまで入力待ちになります。
リストの 1、2、3 行目 (ソースファイル内の行番号はそれぞれ 4、26、8 行目) に含まれる定数
100
は、MAXSIZE
に変更すべきだとわかります。また、read.c
内の0100
とerr.c
内の100.0
(リストの 4、 5 行目) は、変更すべきでないこともわかります。変更する行を指定するには、以下の単一キーコマンドを使用します。
表 9-3 変更行選択コマンド 1-9
変更行をマークまたはマーク解除する *
表示されている行をすべて変更対象としてマークまたはマーク解除する スペース 次画面のリストを表示する +
次画面のリストを表示する -
前画面のリストを表示する a
すべての行を変更対象としてマークする ^d
マークされた行を変更して終了する Esc
マークされた行を変更しないで終了する
この場合、1、2、および 3 を入力します。入力した番号は画面上には表示されません。代わりに各行の行番号の後に > (右不等号) を表示することによって、変更箇所を示します。
ここで、
^d
を入力して選択行を変更します。cscope
は変更後の各行を表示し、作業の継続を促します。
Changed lines:
char s[MAXSIZE];
for (i = 0; i < MAXSIZE; i++)
if (c < MAXSIZE) {
Press the RETURN key to continue:
このプロンプトに対して Return キーを押すと、
cscope
は画面を書き換えて変更行を指定する前の画面に戻ります。次に新しいシンボル
MAXSIZE
の#define
文を追加します。#define
文を追加するヘッダーファイルは、現在表示されている行の参照元ファイルの中にはありません。したがって、!
と入力してシェルに入る必要があります。シェルプロンプトが画面の一番下に現れます。あとは、エディタを起動して#define
文を追加します。
cscope
セッションへ戻るには、エディタを終了し、^d
を入力してシェルを終了させます。例 2:関数に引数を追加する
関数に引数を追加するには、関数そのものを編集することとその関数が呼び出されているすべての箇所に新しい引数を追加することの 2 つのステップがあります。
cscope
を使用すると簡単にこのステップを実行できます。まず、2 番目のメニュー項目「
Find this global definition
」を使用して、関数を編集します。次に、その関数がどこで呼び出されているかを探します。4 番目のメニュー項目「Find function calling this function
」を使用すると、ある関数を呼び出しているすべての関数のリストを表示することができます。このリストを使用して、リストの各行番号を個々に入力してエディタを起動するかまたは^e
を入力して、各行のすべての参照元ファイルを対象にエディタを自動的に起動することができます。このような修正処理にcscope
を使用すると、修正を必要とする関数はすべて修正され、見落とすことがありません。例 3:変数の値を変更する
変更内容がコードにどのように影響するかを見たいときに、表示手段として
cscope
が力を発揮します。変数の値またはプリプロセッサシンボルを変更する場合を考えてみます。実際に変更する前に、最初のメニュー項目「Find this C symbol
」を使用して、変更によって影響を受ける参照箇所のリストを表示します。それから、エディタを起動して各参照箇所を調べます。これによって、変更によるすべての影響を予測できます。同様にcscope
を使用して、間違いなく変更されたことも確認できます。エディタのコマンド行構文
cscope
はデフォルトでvi
エディタを使用しています。EDITOR
環境変数に任意のエディタ名を設定してEDITOR
をエクスポートすると、デフォルトを変更することができます。この手順については、「ステップ 1:環境設定」で述べた通りです。ただしcscope
は、使用するエディタのコマンド行構文がvi
と同様に次のような形式であるとみなします。
%editor +<行番号> <ファイル>
使用したいエディタがこのようなコマンド行構文を持っていない場合は、
cscope
とエディタ間のインタフェースを定義する必要があります。
ed
を使用する場合を考えてみます。ed
では、コマンド行内に行番号を指定することができないので、そのままではcscope
のエディタとして使用できません。そこで、次のような行を含むシェルスクリプトを作成します。
/usr/bin/ed $2ここでは、シェルスクリプトを
myedit
とします。環境変数EDITOR
の値をこのシェルスクリプトに設定してEDITOR
をエクスポートします。
$EDITOR=myedit; export EDITOR
%setenv EDITOR myedit
cscope
は、指定されたリスト項目 (たとえば、main.c
の 17 行目) を読み込んでエディタを起動するとき、次のようなコマンド行を使用してシェルスクリプトを起動します。
%myedit +17 main.c
myedit
は第一引数の行番号 ($1
) を無視して、第二引数のファイル名 ($2
) だけを使用してed
を正しく呼び出します。希望する行を表示および編集するには、適切なed
コマンドを実行する必要があります。すなわち、17 行目に自動的に移動することはありません。不明な端末タイプのエラー
Sorry, I don't know how to deal with your "term" terminalこのメッセージは、現在ロードされている端末情報ユーティリティ (
terminfo
) データベース内に使用端末が含まれていないことを意味します。TERM
に正しい値が設定されていることを確認してください。それでもメッセージが出力される場合は、端末情報ユーティリティを再ロードしてください。次のようなメッセージも表示されることがあります。
Sorry, I need to know a more specific terminal type than "unknown"このメッセージが表示されたら、「ステップ 1:環境設定」で述べた手順に従って、
TERM
環境変数を設定しエクスポートしてください。
サン・マイクロシステムズ株式会社 Copyright information. All rights reserved. |
ホーム | 目次 | 前ページへ | 次ページへ | 索引 |