両ツールは、シンボル定義の検索、特定の関数が使われている箇所や関数間の呼び出し関係の確認、コードベース全体からの文字列やパターンの検索に活用できる。また、ソースファイル群に対して手作業でgrepをかけるよりも、目的とする検索を迅速に行えるため、時間の節約にもなる。
Cscopeを使用する
Cscopeはよく知られたユーティリティで、最近のディストリビューションにはたいてい含まれている。もともとCscopeはC言語のコードで使うことしか想定されていなかったが、実際にはC++やJavaのような言語でも十分に使える。CscopeはncursesベースのGUIを備えているが、EmacsやVimといった主要なエディタなど、フロントエンドとして使える他のアプリケーションと連携するためのコマンドラインインタフェースもサポートしている。
Cscopeを起動すると、カレントディレクトリ内にあるソースファイルのスキャンが行われ、収集された情報がCscopeの内部データベースに格納される。-Rオプションを指定することで、サブディレクトリを再帰的にスキャンすることもできる。このデータベースに対するクエリをCscopeのGUIを使わずに別のアプリケーション(以降の記述を参照)から発行する場合には、-bオプションを指定する。大規模なプロジェクトやシステム関連のプロジェクトでCscopeを使う場合は、こちらのガイドを参照し、Cscopeを最適化して大量のファイルを高速処理するための詳しい手順を確認すること。
デフォルトでは、データベースの生成が終わると(生成済みデータベースを利用する際は、-dオプションで指定)、自動的にCscopeのGUIフロントエンドが起動される。このGUIフロントエンドのインタフェースは、2つのパネルからなる。下側のパネルに検索クエリを入力すると、検索結果が上側のパネルに表示される。Tabキーを押すとパネルが切り換わり、Ctrl-Dキーでプログラムが終了する。
下部パネルでは、カーソルキーを使って検索フィールド間の移動を行う。以下に、下部パネルで可能な操作を示す。
- 指定したシンボルの検索
- グローバル定義の検索(ヒット時には直ちにエディタが起動される)
- 指定した関数から呼び出される関数の検索
- 指定した関数を呼び出す関数の検索
- 全ソースファイルを対象としたテキスト文字列の検索
- 文字列の置換
- egrepパターンの検索
- エディタによる指定ファイルのオープン
- 指定ファイルをインクルード(#include)しているファイルの検索
検索を実行するたびに、その結果が検索番号、ファイル名、関数名(該当する場合のみ)、行番号、該当するコード行とともに表示される。検索結果の1つを、カーソルキーとEnterキー、または検索番号に対応する数字キーを使って選択すると、システムのデフォルトエディタ(EDITOR環境変数で指定されているもの)が起動し、該当する検索結果の行にカーソルが置かれた状態でそのファイルが開かれる(サポート対象外のエディタではこのとおりに動作しないことがあるが、EmacsやVimであれば問題ない)。
フロントエンドとして(X)Emacsを使用する
CscopeをEmacsと連携させて使うのは難しくない。cscope-で始まるコマンドやCscopeメニューがまだEmacsで使えるようになっていない場合は、xcscope.elをインストールすることでEmacsをCscopeと連携させることができる。xcscope.elは、Cscopeのソースtarballのcontrib/xscopeサブディレクトリに入っている。まず、cscope-indexerというスクリプトを$PATHに指定された適当なディレクトリに、またxcscopeファイルをEmacsから参照できるディレクトリ(EmacsでC-h v load-pathと入力してload-path変数を確認するとよい)にそれぞれコピーする。次に、(require 'xcscope)という行を~/.emacsまたは~/.emacs.d/init.elに追加する。
xcscope.elファイルの冒頭にあるコメントが、マニュアル代わりになっている。
このパッケージにより、Cscopeの検索コマンドがすべてEmacsのCscopeサブメニューに追加され、ソースファイル編集中にEmacs風のキーバインドによって使えるようになる。例えば、シンボルを検索する場合は、メニューから「Cscope」→「Symbol」を選択するか、M-x cscope-find-this-symbolと入力するか、C-c s sとキー入力するかのいずれかを行ってからシンボル名を入力する(シンボル名の入力がない場合はカーソルの置かれている単語が検索語になる)。
検索結果は、ファイルごとにグループ化されて<関数名>[<行番号>] <行>という形で*cscope*バッファに表示される。ヒットした検索結果の1つにカーソルを移動させてSpaceキーを押すと、検索にヒットした行にカーソルが置かれた状態で該当ファイルが別のバッファで開かれる。このときSpaceキーの代わりにEnterキーを押すと(あるいは関連する検索結果をクリックしてもよい)、*cscope*バッファがこのバッファに切り換わる。また、nキーを押すと次の検索結果に、pキーを押すと1つ前の検索結果に移動する(*cscope*バッファがアクティブでない場合は、それぞれC-c s nとC-c s pがこれらに対応)。同様に、Nキーで次のファイルが、Pキーで前のファイルが選択される(それぞれC-C s N、C-c s Pでも可)。
VimからCscopeを使う
EmacsよりVimが好みだという人にもCscopeは対応している。まず何よりも現在使っているVimが--enable-cscopeオプションを有効にしてコンパイルされている必要があるが、Linuxのバイナリディストリビューションの大半ではそのようになっている。ただし、Gentooユーザの場合は、cscope USEフラグを有効にしておく必要がある。以降では、Vimの6.xまたは7.xが使われていると仮定して話を進める。Vimのリファレンスマニュアルには、Cscopeインタフェースの利用法に関する項目が含まれている。これにあたる/usr/share/vim/vim&version/doc/if_cscop.txtというファイルが見つかるはずだ。また、CscopeをVimで使うための簡単なチュートリアルも存在する。
Vimでは、:cscope find search type search string という形式でCscopeの検索コマンドを実行する(cscope findの部分は:cs fで代用可)。search type(検索タイプ)には、以下のものがある。
-
symbolors-- すべてのシンボル参照を検索 -
globalorg-- グローバル定義を検索 -
callsorc-- 指定した関数の呼び出し箇所を検索 -
calledord-- 指定した関数が呼び出す関数を検索 -
textort-- テキスト検索を実行 -
fileorf-- ファイルを開く -
includeori-- 指定ファイルをインクルードしているファイルを検索
検索結果は、Vimウィンドウの一番下にメニュー形式で表示される。検索結果の番号を入力してEnterキーを押すと、該当する検索結果の部分にジャンプできる。また、:cscopeの部分を:scscope(または:scs)にしてコマンドを実行すると、Vimウィンドウが上下に2分割され、新しいウィンドウに検索結果が表示される。
Vimでは、Cscopeクエリによる検索結果へのジャンプが、任意のタグへのジャンプによく似ている。つまり、Ctrl-Tキーを使って検索実行前の表示画面に戻り、:tnextや:tpreviousを使って検索結果の画面を切り換えることができるのだ。
カーソルの置かれている語を検索したい場合は、cscope_maps.vimプラグインをインストールする必要がある(同ファイルを$HOME/.vim/pluginディレクトリに追加するだけ)。詳しい説明は、同ファイルにコメントとして記述されている。このcscope_mapsプラグインを利用するには、:cscopeと入力する代わりにCtrl-\キーを、:scscopeの代わりにCtrl-Spaceキーを押す。すると、カーソルの置かれている語が検索される(例:「initialize」という語にカーソルを置いた状態でCtrl-\ sとすると「initialize」へのシンボル参照の検索が実行される)。
