【gtags】GLOBAL (gtags) の導入【SW】

gtags (GLOBAL) の導入

C++ のコードを Vim にて ctags を使ってジャンプをしても精度が悪いので、 gtags を導入する。

 

gtags とは

山口志義夫さん作成のタグジャンププログラム。公式サイト関連書籍

サポートしている言語は「C, C++, Yacc, Java, PHP4 and assembly」とある。
さらに、Python3 にも対応しているらしい。(山口さんのページ)

gtags は global と gtags という2つのコマンドから成り立っている。
いまひとつ関係性が分からなかったので、man コマンドで global と gtags を見てみたところ以下のような関係らしい。

global

  • 与えられたシンボル名から、そのシンボルの定義位置等を特定するプログラム="地図"を見て探索する人

gtags

  • global がシンボルを特定するためのヒントファイルを作成するプログラム="地図"を作る人

つまり、「gtags がシンボルの配置場所を示した地図を作り」、「global がその地図を見てシンボルを探す」ということ。

 

gtags のインストールをする

以下、Cygwin 上での操作だが、Linux/Unix 環境でもほぼ同手順かと思う。

1. 下記より gtags のソースコードをダウンロードする

% wget  tamacom.com/global/global-6.5.5.tar.gz
[ Getting GLOBAL ]

2. ビルドする

% tar xvfz global-6.5.5.tar.gz
% cd  global-6.5.5
% ./configure
% make

とりあえず、これで gtags コマンドと global コマンドが作成出来たので、$HOME/bin 等に展開する。
(あと、HTML 化する htags.exe も作成されているので、必要に応じて展開する)

もしもシステムにインストール可能なら、make install をする。

% make install

インストール完了。パスも通った。

$ which global
/usr/local/bin/global

$ which gtags
/usr/local/bin/gtags

$ which htags
/usr/local/bin/htags



3. Emacs や Vim に gtags を使うためのファイルをコピーする。

.emacs や vimrc に以下のファイルの内容をコピーして使用する。

  • emacs の場合
    • gtags.el を .emacs ファイルからロードする
  • vim の場合
    • gtags.vim を C:\tool\vim80-kaoriya-win32\vim80\plugin\. に配置する



使用方法

 

emacs で使用する

下記ページを参照。
【emacs】Emacs で gtags を使う【SW】 - 4f938672-cb1c-4c5a-8233-192c4ec901df
 

vim で使用する

保留。 (∵ Emacs のような操作性がないことと、大規模なコードを閲覧する際は Vim よりも Emacs の方が使い易いため)

 

HTML形式

 
htags コマンドを使うことで HTML としてコードを探索できるようになる。
(OpenSSL のコードで実行したところ、約10分ほど要した。また、HTML ファイルの総サイズは 300MBだった)。
 

オプションについて

「htags --help」とするとオプション一覧が表示される。ただ、オプションが色々あって難しかったので、ビギナー向けとあった suggest と suggest2 に絞って使用してみた。

実際に HTTPサーバを動かしていれば、HTML ページの CGI による検索機能が使用できるようなので、ぜひ HTTP サーバを動かしておきたいところではあるが、たとえ HTTP サーバが動いていない環境でも「--suggest2」の方が「--suggest」よりも使用し易いと思う。

--suggest による生成手順と結果例
CGI による検索機能なし。

% htags --suggest

 

画面上部
f:id:dnkrnka:20161203143411p:plain:w700

画面下部
f:id:dnkrnka:20161203143427p:plain:w700

 

--suggest2 による生成手順と結果例
CGI による検索機能あり。

% htags --suggest2


画面左にインデックス、右にソースコード表示であり、個人的にはこちらの方が使いやすいかと思う。
f:id:dnkrnka:20161203144252p:plain:w700
 
 

CLI形式

手順の概要としては、最初に gtags -v によりタグファイルを作成し、次に global コマンドによって関数の呼び出し元や実装部分を洗い出すことになる。
結論から言うと、コマンドラインから global を使う意味(メリット)は余り無い。(やはりエディタから使用するのが効果大)

呼び出し元を洗い出す

「-r」(Print reference tags)
丁度 grep -l のような感じで特定の文字を含むファイル名のみ表示する。

$ global -r SSL_do_handshake
apps/s_server.c
fuzz/server.c
include/openssl/ssl.h
ssl/bio_ssl.c
ssl/ssl_lib.c
test/bad_dtls_test.c
test/handshake_helper.c


「-x」(ctags -x 形式で表示=Use standard ctags cxref (with -x) format)
「-r」のみではソースファイルのみしか表示されないので、「-x」と組み合わせる

$ global -r -x SSL_do_handshake
SSL_do_handshake 2231 apps/s_server.c                      i = SSL_do_handshake(con);
SSL_do_handshake 2244 apps/s_server.c                      i = SSL_do_handshake(con);
SSL_do_handshake 2749 apps/s_server.c                  i = SSL_do_handshake(con);
SSL_do_handshake  233 fuzz/server.c        if (SSL_do_handshake(server) == 1) {
SSL_do_handshake 1634 include/openssl/ssl.h __owur int SSL_do_handshake(SSL *s);
SSL_do_handshake  349 ssl/bio_ssl.c            ret = (int)SSL_do_handshake(ssl);
SSL_do_handshake 1457 ssl/ssl_lib.c        return SSL_do_handshake(s);
SSL_do_handshake 1467 ssl/ssl_lib.c        return SSL_do_handshake(s);
SSL_do_handshake  518 test/bad_dtls_test.c     ret = SSL_do_handshake(con);
SSL_do_handshake  532 test/bad_dtls_test.c     ret = SSL_do_handshake(con);
SSL_do_handshake  545 test/bad_dtls_test.c     ret = SSL_do_handshake(con);
SSL_do_handshake  554 test/bad_dtls_test.c     ret = SSL_do_handshake(con);
SSL_do_handshake  509 test/handshake_helper.c     ret = SSL_do_handshake(peer->ssl);


「-t」(ctags 形式で表示=Use standard ctags format)
「-x」ほど詳しくしないで出力する。

$ global -r -x -t SSL_do_handshake
SSL_do_handshake        apps/s_server.c 2231
SSL_do_handshake        apps/s_server.c 2244
SSL_do_handshake        apps/s_server.c 2749
SSL_do_handshake        fuzz/server.c   233
SSL_do_handshake        include/openssl/ssl.h   1634
SSL_do_handshake        ssl/bio_ssl.c   349
SSL_do_handshake        ssl/ssl_lib.c   1457
SSL_do_handshake        ssl/ssl_lib.c   1467
SSL_do_handshake        test/bad_dtls_test.c    518
SSL_do_handshake        test/bad_dtls_test.c    532
SSL_do_handshake        test/bad_dtls_test.c    545
SSL_do_handshake        test/bad_dtls_test.c    554
SSL_do_handshake        test/handshake_helper.c 509


「-g」(grep の実施)
grep を実施する。が、grep し直すので、パフォーマンスが遅い。

具体的には「GPATH」ファイルからソースファイルのパスを取り出し、そのパスに存在するファイルに対して
grep を実施している。

よって、GPATH 内に存在しないファイルについては grep してくれないので注意すること。

$ global -r -x -t SSL_do_handshake
SSL_do_handshake        apps/s_server.c 2231
SSL_do_handshake        apps/s_server.c 2244
SSL_do_handshake        apps/s_server.c 2749
SSL_do_handshake        fuzz/server.c   233


「-a」(Print absolute path names)
ファイルパスを絶対パスで表示してくれる。

$ global -r -x -a SSL_do_handshake
SSL_do_handshake 2231 /home/Neko/work/openssl-1.1.0a/apps/s_server.c                     i = SSL_do_handshake(con);
SSL_do_handshake 2244 /home/Neko/work/openssl-1.1.0a/apps/s_server.c                     i = SSL_do_handshake(con);
SSL_do_handshake 2749 /home/Neko/work/openssl-1.1.0a/apps/s_server.c                 i = SSL_do_handshake(con);
SSL_do_handshake  233 /home/Neko/work/openssl-1.1.0a/fuzz/server.c     if (SSL_do_handshake(server) == 1) {
SSL_do_handshake 1634 /home/Neko/work/openssl-1.1.0a/include/openssl/ssl.h __owur int SSL_do_handshake(SSL *s);
SSL_do_handshake  349 /home/Neko/work/openssl-1.1.0a/ssl/bio_ssl.c         ret = (int)SSL_do_handshake(ssl);
SSL_do_handshake 1457 /home/Neko/work/openssl-1.1.0a/ssl/ssl_lib.c     return SSL_do_handshake(s);
SSL_do_handshake 1467 /home/Neko/work/openssl-1.1.0a/ssl/ssl_lib.c     return SSL_do_handshake(s);
SSL_do_handshake  518 /home/Neko/work/openssl-1.1.0a/test/bad_dtls_test.c     ret = SSL_do_handshake(con);
SSL_do_handshake  532 /home/Neko/work/openssl-1.1.0a/test/bad_dtls_test.c     ret = SSL_do_handshake(con);
SSL_do_handshake  545 /home/Neko/work/openssl-1.1.0a/test/bad_dtls_test.c     ret = SSL_do_handshake(con);
SSL_do_handshake  554 /home/Neko/work/openssl-1.1.0a/test/bad_dtls_test.c     ret = SSL_do_handshake(con);
SSL_do_handshake  509 /home/Neko/work/openssl-1.1.0a/test/handshake_helper.c     ret = SSL_do_handshake(peer->ssl);