ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
![]() |
Oracle Solaris Studio 12.3: C ユーザーガイド Oracle Solaris Studio 12.3 Information Library (日本語) |
たとえば、プログラム prog の開始直後に 「out of storage」というエラーメッセージが表示されることがあると想定します。これを解決するには、まず cscope を使用してコード内のメッセージを発行している場所を探し出さなければいけません。この場合、次の手順で実行します。
cscope は、画面指向ツールです。使用できる端末は、端末情報ユーティリティー (terminfo) データベースに書かれているものに限られます。TERM 環境変数を自分の端末タイプに設定してあることを確認してください。 cscope は TERM 環境変数の値を見て、それが terminfo データベースに存在するか確認します。まだ設定していない場合は、次のようにして TERM に値を設定し、それをシェルに伝えます。
B シェルの場合は次のように入力します。
$ TERM=term_name; export TERM
C シェルの場合は次のように入力します。
% setenv TERM term_name
次に、EDITOR 環境変数に値を設定します。 デフォルトでは、cscope は vi エディタを起動します (本章の例も vi を使用して説明しています)。vi を使用しない場合は、EDITOR 環境変数を任意のエディタ名に変更して、EDITOR をエクスポートします。
B シェルの場合は次のように入力します。
$ EDITOR=emacs; export EDITOR
C シェルの場合は次のように入力します。
% setenv EDITOR emacs
cscope とエディタ間のインタフェースを設定しなければいけません。詳細は、「8.2.9 エディタのコマンド行構文」を参照してください。
cscope を表示するためだけに使用する (編集は使用しない) 場合は、VIEWER 環境編集を pg に設定して VIEWER をエクスポートします。cscope は vi の代わりに pg を起動します。
環境変数 VPATH には、ソースファイルの検索対象ディレクトリを指定します。「8.2.6 ビューパス (Viewpath)」を参照してください。。
デフォルトでは、cscope は現ディレクトリ内にあるすべての C、lex、および yacc のソースファイルのシンボル相互参照表、および現ディレクトリまたは標準位置内にあるすべてのインクルードヘッダーファイルのシンボル相互参照表を作成します。したがって、表示するプログラムのすべてのソースファイルが現ディレクトリにあり、かつそのヘッダーファイルが現ディレクトリまたは標準位置にある場合は、cscope を引数なしで起動します。
% cscope
特定のソースファイルを表示する場合は、そのファイルの名前を引数にして cscope を起動します。
% cscope file1.c file2.c file3.h
cscope のほかの起動方法については、「8.2.5 コマンド行オプション」を参照してください。
プログラムを表示するため、最初に cscope が使用されるときにシンボル相互参照表が作成されます。デフォルトでは、作成されたシンボル相互参照表は現ディレクトリ内の cscope.out ファイルに格納されます。そのあと cscope を再び起動すると、前回と比較してソースファイルが修正されていたとき、またはソースファイルのリストが異なるときだけ相互参照表が作成し直されます。相互参照表を再び作成する時には、変更されていないファイルのデータは前回の相互参照表からコピーされます。これによって、最初の作成時より作成速度が速くなり、起動時のスタートアップ時間も短くなります。。
本節の最初で述べた本来の作業に戻り、「out of storage」のエラーメッセージの原因となっている場所を確定します。cscope が起動され、相互参照表が作成されました。画面には、cscope の作業メニューが表示されます。
cscope の作業メニュー
% cscope cscope Press the ? key for help Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file:
Return キーを押すと、カーソルが下に移動し (画面の一番下まで移動すると、先頭に戻る)、^p (Ctrl+p キー) を押すと、上に移動します。また、上矢印 (ua) と下矢印 (da) キーも使用できます。次の単一キーコマンドを使用すれば、メニュー操作とそのほかの作業が行えます。
表 8-1 cscope メニュー操作コマンド
|
検索文字列の最初の文字が前述のいずれかのコマンドと一致する場合は、検索文字列の前にバックスラッシュ (\) を加えてコマンドと区別します。
たとえば、カーソルを 5 番目のメニュー項目「Find this text string」に移動して文字列「out of storage」を入力し、Return キーを押します。
cscope 関数: 文字列検索の要求
$ cscope cscope Press the ? key for help Find this C symbol Find this global definition Find functions called by this function Find functions calling this function Find this text string: out of storage Change this text string Find this egrep pattern Find this file Find files #including this file
注 - 6 番目の「Change this text string」項目以外のメニュー項目についても同じ手順に従ってください。6 番目の項目はほかの項目よりも多少複雑なので手順が異なります。文字列の変更方法については、「8.2.8 例」を参照してください。
cscope は指定された文字列を検索し、それを含む行を見つけ出して次のように検索結果を表示します。
cscope 関数: 文字列を含む cscope 行のリスト表示
Text string: out of storage File Line 1 alloc.c 63 (void) fprintf(stderr, "\n%s: out of storage\n", argv0); Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file:
cscope によって検索結果が正常に表示されたら、次の操作を選択します。行を変更したり、またはその行の前後をエディタで調べることができます。あるいは、cscope の検索結果のリストが一画面に収まらない場合は、リストの次の部分を見ることもできます。cscope が指定した文字列を検索したあとに使用可能なコマンドを次に示します。
表 8-2 最初の検索後に使用するコマンド
|
ここでも、検索文字列の最初の文字が前述のいずれかのコマンドと一致する場合は、検索文字列の前にバックスラッシュ (\) を加えてコマンドと区別します。
次に、新しく検索した行の前後を調べます。「1」 (リスト内の行番号) を入力してください。エディタが起動され、alloc.c ファイルが読み込まれます。カーソルは、alloc.c の 63 行目の先頭に移動します。
cscope 関数: コード行の検査
{ return(alloctest(realloc(p, (unsigned) size))); } /* check for memory allocation failure */ static char * alloctest(p) char *p; { if (p == NULL) { (void) fprintf(stderr, "\n%s: out of storage\n", argv0); exit(1); } return(p); } ~ ~ ~ ~ ~ ~ ~ "alloc.c" 67 lines, 1283 characters
変数 p が NULL のときに、エラーメッセージが出力されることがわかります。alloctest() に渡される引数がなぜ NULL になったのかを調べるには、まず alloctest() を呼び出している関数を確定する必要があります。
通常の終了方法でエディタを終了し、作業メニューに戻ります。ここで、4 番目の項目「Find functions calling this function」のあとに alloctest と入力します。
cscope 関数: alloctest() を呼び出す関数のリストの要求
Text string: out of storage File Line 1 alloc.c 63(void)fprintf(stderr,"\n%s: out of storage\n",argv0); Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: alloctest Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file:
cscope は検索を実行し、次の 3 つの関数のリストを表示します。
cscope 関数: alloctest() を呼び出す Listing 関数
Functions calling this function: alloctest File Function Line 1 alloc.c mymalloc 33 return(alloctest(malloc((unsigned) size))); 2 alloc.c mycalloc 43 return(alloctest(calloc((unsigned) nelem, (unsigned) size))); 3 alloc.c myrealloc 53 return(alloctest(realloc(p, (unsigned) size))); Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file:
今度は、mymalloc() を呼び出す関数を調べます。cscope は、次のような 10 個の関数を見つけ出します。そのうち 9 個を画面に表示し、残りの 1 個を見るにはスペースバーを押すように指示しています。
cscope 関数: mymalloc() を呼び出す Listing 関数
Functions calling this function: mymalloc File Function Line 1 alloc.c stralloc 24 return(strcpy(mymalloc (strlen(s) + 1), s)); 2 crossref.c crossref 47 symbol = (struct symbol *)mymalloc (msymbols * sizeof(struct symbol)); 3 dir.c makevpsrcdirs 63 srcdirs = (char **) mymalloc (nsrcdirs * sizeof(char*)); 4 dir.c addincdir 167 incdirs = (char **)mymalloc (sizeof(char *)); 5 dir.c addincdir 168 incnames = (char **) mymalloc(sizeof(char *)); 6 dir.c addsrcfile 439 p = (struct listitem *) mymalloc (sizeof(struct listitem)); 7 display.c dispinit 87 displine = (int *) mymalloc (mdisprefs * sizeof(int)); 8 history.c addcmd 19 h = (struct cmd *) mymalloc (sizeof(struct cmd)); 9 main.c main 212 s = mymalloc((unsigned ) (strlen(reffile) +strlen(home) + 2)); * 9 more lines - press the space bar to display more * Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file:
「out of storage」のエラーメッセージはプログラムの開始直後に出力されるので、関数 dispinit() (表示の初期化) 内で問題が発生していることが推測できます。
dispinit() はリストの 7 番目の関数なので、これを参照するには「7」と入力します。
cscope 関数: dispinit() をエディタで参照
void dispinit() { /* calculate the maximum displayed reference lines */ lastdispline = FLDLINE - 4; mdisprefs = lastdispline - REFLINE + 1; if (mdisprefs > 9) { mdisprefs = 9; } /* allocate the displayed line array */ displine = (int *) mymalloc(mdisprefs * sizeof(int)); } ^L/* display a page of the references */ void display() { char file[PATHLEN + 1]; /* file name */ char function[PATLEN + 1];/* function name */ char linenum[NUMLEN + 1]; /* line number */ int screenline; /* screen line number */ int width; /* source line display width */ register int i, j; "display.c" 622 lines, 14326 characters
mymalloc() が失敗したのは、非常に大きな数または負数を引数にして呼び出されたためです。FLDLINE と REFLINE が取り得る値を調べてみると、mdisprefs の値が負になる場合があることがわかります。この場合、mymalloc() は負数を引数にして呼び出されます。
ウィンドウ形式の端末では、任意のサイズのウィンドウを複数使用できます。「out of storage」のエラーメッセージが出力されたのは、prog を実行するウィンドウ内の行数が少なすぎたためと考えられます。つまり、mymalloc() が負数を引数にして呼び出された場合にこのような状況が発生する可能性があるということです。今後このような状況が発生した場合に、もっとわかりやすいエラーメッセージ、たとえば「Screen too small」を出力してプログラムを中止するように設定しておくとよいでしょう。それには dispinit() 関数を次のように編集します。
cscope 関数: 問題箇所の修正
void dispinit() { /* calculate the maximum displayed reference lines */ lastdispline = FLDLINE - 4; mdisprefs = lastdispline - REFLINE + 1; if (mdisprefs > 9) { mdisprefs = 9; } /* allocate the displayed line array */ displine = (int *) mymalloc(mdisprefs * sizeof(int)); } ^L/* display a page of the references */ void display() { char file[PATHLEN + 1]; /* file name */ char function[PATLEN + 1];/* function name */ char linenum[NUMLEN + 1]; /* line number */ int screenline; /* screen line number */ int width; /* source line display width */ register int i, j; "display.c" 622 lines, 14326 characters
以上で、本節の最初で調査を開始した問題箇所は修正されました。これで、行数が少なすぎるウィンドウ内で prog を実行したときに、単に意味不明のエラーメッセージ「out of storage」を出力して中止するのではなく、ウィンドウサイズを検査してわかりやすいエラーメッセージを出力したあとに終了するようになります。。
すでに述べたとおり、cscope はデフォルトでは現ディレクトリ内にある C、lex、および yacc ソースファイルのシンボル相互参照表を作成します。次に例を示します。
% cscope
これは次と同等です。
% cscope *.[chly]
指定したソースファイルを表示するには、ソースファイル名を引数に指定して cscope を起動します。
% cscope file1.c file2.c file3.h
cscope のコマンド行オプションを使用して、相互参照表に含まれるソースファイルをさらに自由に指定することもできます。それには、次のように -s オプションのあとにコンマで区切られた任意の数のディレクトリ名を指定して cscope を起動します。
% cscope– s dir1,dir2,dir3
cscope は現ディレクトリ内だけでなく、指定されたディレクトリ内にあるすべてのソースファイルを対象に相互参照表を作成します。ファイル中にリストされているソースファイル (ファイル名をスペースやタブまたは復帰改行で区切ったもの) のすべてを表示するには、– i オプションとリストを持つファイル名を指定して cscope を起動します。
% cscope– i file
ソースファイルがディレクトリツリーの中にある場合は、次のコマンドでディレクトリツリー内のすべてのソースファイルを簡単に表示できます。
% find .– name ’*.[chly]’– print | sort > file % cscope– i file
このオプションを使用しても、コマンド行でファイルが指定されている場合、cscope によって指定されたファイル以外については無視されます。
-I オプションは、cc に対する -I オプションと同じような形式で cscope にも指定できます。「2.16 インクルードファイルを指定する方法」を参照してください。
-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 オプションを使用すると、cscope は検索結果でリストされたファイルのあるパス名やそのパス名の一部を表示することができます。– p のあとの n には、パス名の中で最後から何番目までの要素を表示させたいかを指定します。デフォルト値は 1 で、これはファイル名そのものを意味します。したがって現ディレクトリが home/common の場合、次のコマンドによって
% cscope– p2
cscope によって検索結果のリストに表示されるパス名が、common/file1.c や common/file2.c のように表示されます。
表示するプログラムが大量のソースファイルを含む場合、– b オプションを使用して、相互参照表を作成したあとで cscope を終了することができます。このとき、cscope は作業メニューを表示しません。パイプラインで、cscope– b を batch(1) コマンドとともに使用する場合、cscope は相互参照表をバックグラウンドで作成します。
% echo ’cscope -b’ | batch
相互参照表がいったん作成されると、その後、ソースファイルまたはソースファイルのリストを変更しないかぎり、次のように指定するだけで
% cscope
相互参照表がコピーされ、通常どおり作業メニューが表示されます。このコマンドシーケンスを使用すると cscope の初期処理の終了を待たずに作業を続けることができます。
– d オプションは、cscope にシンボル相互参照表を更新させません。このオプションを指定すると、cscope はソースファイルの変更を検査しないため時間の節約になります。変更されていないと確信できる場合にのみ使用してください。
注 - -d オプションの使用には注意が必要です。ソースファイルが変更されていることに気付かずに – d オプションを使用すると、cscope は古いシンボル相互参照表を使用して照会に応じてしまいます。
ほかのコマンド行オプションについては、cscope(1) のマニュアルページを参照してください。。
前述のように 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 に設定してエクスポートします。
B シェルの場合は次のように入力します。
$ VPATH=/usr/you:/fs1/ofc; export VPATH
C シェルの場合は次のように入力します。
% setenv VPATH /usr/you:/fs1/ofc
次に、現ディレクトリを /usr/you/src/cmd/prog1 に移動して cscope を起動します。
% cscope
cscope はビューパスにあるすべてのファイルの位置を調べます。同じファイルが複数のディレクトリにある場合は、cscope はVPATH 内で先に現れたディレクトリの下にあるファイルを使用します。したがって、f2.c がユーザーのディレクトリにあり (3 つのファイルはすべて正式バージョン用ディレクトリの下にもある場合)、cscope は f2.c はユーザーディレクトリのものを、f1.c および f3.c は正式バージョン用のディレクトリのものを検査します。
VPATH 内の最初のディレクトリは、作業用ディレクトリの接頭辞 (通常は $HOME) でなければいけません。VPATH 内のコロンで区切られたそれぞれのディレクトリは、/ から始まる絶対パス名でなければいけません。。
cscope とエディタの呼び出しはスタックできます。たとえば、cscope がエディタを起動してシンボルへの参照を調べているときに、ほかにも参照関係を調べたいシンボルがある場合、エディタ内部から再び cscope を起動して 2 番目の参照関係を調べることができます。現在起動中の cscope やエディタを終了する必要はありません。一番最後に起動した cscope またはエディタコマンドを正常に終了すれば、1 つ前の状態に戻ることができます。
cscope が次の 3 つの作業を行うのにどのように使用されるかを見ていきます。対象とする作業は、定数をプリプロセッサシンボルに変更する、関数に引数を追加する、変数の値を変更するの 3 つです。最初の例では、文字列の変更手順を示します。この作業は、cscope メニューのほかの作業項目とは少し異なっています。変更したい文字列を入力すると、cscope はそれを置き換える新しい文字列を聞いてきます。画面には古い文字列を含む行が表示されます。ここで、どの行に含まれる文字列を変更するかを指定します。
たとえば、定数 100 をプリプロセッサシンボル MAXSIZE に変更するとします。6 番目のメニュー項目「Change this text string」を選択して \100 と入力します。1 の前にはバックスラッシュを加えて、cscope のメニュー項目番号を意味する 1 と区別します。Return キーを押すと cscope は新しい文字列を聞いてくるので、MAXSIZE と入力します。
cscope 関数: 文字列の変更
cscope Press the ? key for help Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: \100 Find this egrep pattern: Find this file: Find files #including this file: To: MAXSIZE
cscope は、指定された文字列を含む行を表示します。どの行の文字列を変更するかが選択されるまで入力待ちになります。
cscope 関数: 変更行に対するプロンプト
cscope Press the ? key for help Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: \100 Find this egrep pattern: Find this file: Find files #including this file: To: MAXSIZE
リストの 1、2、3 行目 (ソースファイル内の行番号はそれぞれ 4、26、8 行目) に含まれる定数 100 は、MAXSIZE に変更すべきだとわかります。さらに、read.c の 0100 (4 行目) と err.c の 100.0 (5 行目) は変更すべきではないこともわかります。次の単一キーコマンドを使用して、変更したい行を選択します。
表 8-3 変更する行を選択するコマンド
|
この場合、1、2、および 3 を入力します。入力した番号は画面上には表示されません。代わりに cscope は各行の行番号のあとに > (右不等号) を表示することによって、変更箇所を示します。
cscope 関数: 変更行のマーキング
Change "100" to "MAXSIZE" File Line 1>init.c 4 char s[100]; 2>init.c 26 for (i = 0; i < 100; i++) 3>find.c 8 if (c < 100) { 4 read.c 12 f = (bb & 0100); 5 err.c 19 p = total/100.0; /* get percentage */ Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file: Select lines to change (press the ? key for help):
ここで、^d を入力して選択行を変更します。cscope は変更後の各行を表示し、作業の継続を促します。
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 関数: シェルへの一時移行
Text string: 100 File Line 1 init.c 4 char s[100]; 2 init.c 26 for (i = 0; i < 100; i++) 3 find.c 8 if (c < 100) { 4 read.c 12 f = (bb & 0100); 5 err.c 19 p = total/100.0; /* get percentage */ Find this C symbol: Find this global definition: Find functions called by this function: Find functions calling this function: Find this text string: Change this text string: Find this egrep pattern: Find this file: Find files #including this file: $ vi defs.h
cscope セッションへ戻るには、エディタを終了し、^d を入力してシェルを終了させます。
関数に引数を追加するには、関数そのものを編集することとその関数が呼び出されているすべての箇所に新しい引数を追加することの 2 つのステップがあります。cscope を使用して簡単にこのステップを実行できます。
まず、2 番目のメニュー項目「Find this global definition」を使用して、関数を編集します。次に、その関数がどこで呼び出されているかを探します。4 番目のメニュー項目「Find functions calling this function」を使用すると、ある関数を呼び出しているすべての関数のリストを表示することができます。このリストを使用して、リストの各行番号を個々に入力してエディタを起動するか、または ^e を入力して、各行のすべての参照元ファイルを対象にエディタを自動的に起動することができます。このような修正処理に cscope を使用すると、修正を必要とする関数はすべて修正され、見落とすことがありません。
変更内容がコードにどのように影響するかを見たいときに、表示手段として cscope が力を発揮します。
変数の値またはプリプロセッサシンボルを変更する場合を考えてみます。実際に変更する前に、最初のメニュー項目「Find this C symbol」を使用して、変更によって影響を受ける参照箇所のリストを表示します。それから、エディタを起動して各参照箇所を調べます。これによって、変更によるすべての影響を予測できます。同様に cscope を使用して、間違いなく変更されたことも確認できます。
デフォルトでは、cscope は vi エディタを起動します。EDITOR 環境変数に任意のエディタ名を設定して EDITOR をエクスポートすると、デフォルトを変更することができます。この手順については、「8.2.1 ステップ 1: 環境設定」で述べたとおりです。ただし、cscope は、使用するエディタのコマンド行構文が次の形式であるとみなします。
% editor +linenum filename
これは vi と同じです。使用したいエディタがこのようなコマンド行構文を持っていない場合は、cscope とエディタ間のインタフェースを定義する必要があります。
ed を使用する場合を考えてみます。ed では、コマンド行内に行番号を指定することができないので、そのままでは cscope のエディタとして使用できません。そこで、次のような行を含むシェルスクリプトを作成します。
/usr/bin/ed $2
ここでは、シェルスクリプトを myedit とします。環境変数 EDITOR の値をこのシェルスクリプトに設定して EDITOR をエクスポートします。
B シェルの場合は次のように入力します。
$ EDITOR=myedit; export EDITOR
C シェルの場合は次のように入力します。
% setenv EDITOR myedit
cscope は、指定されたリスト項目 (たとえば、main.c の 17 行目) を読み込んでエディタを起動するとき、次のようなコマンド行を使用してシェルスクリプトを起動します。
% myedit +17 main.c
myedit は第一引数の行番号 ($1) を無視して、第二引数のファイル名 ($2) だけを使用して ed を正しく呼び出します。希望する行を表示および編集するには、適切な ed コマンドを実行する必要があります。すなわち、17 行目に自動的に移動することはありません。