| 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の開始直後にoutofstorageというエラーメッセージが表示されることがあると想定します。これを解決するには、まず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 つのプログラムの相互参照情報を別々に保管できます。
-pn オプションを使用すると、検索結果でリストされたファイルのあるパス名やそのパス名の一部を表示することができます。-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. |
ホーム | 目次 | 前ページへ | 次ページへ | 索引 |