最近、ソースコードを読むことが多いので、便利そうなツールを探しています。
しかし、なかなか、新しいよく出来たツールはありません。やはり、昔ながらのツールがいいのかなと思ったりしてます。GNU Global は、昔、サクラエディタで使えるようになった時期があって、少しの間使っていましたが、ctags で十分かな、と思って、いつの間にか使わなくなっていました。
あと、コールツリー(コールグラフ)も、いいツールが無いか、探して見ましたが、結局、cflow になりました。cflow は、C++ には対応していないので、注意が必要です。
GNU Global と cflow を連携させて、HTML化するのは初めて知りました。こちらも紹介したいと思います。
それでは、やっていきます。
GNU Global
GNU Global の公式サイトです。
リポジトリを見ると、数か月前に更新がありますね。
インストール
インストールは簡単です。
最新は、6.6.14 ですが、apt でインストールされたのは、6.6.9 です。そんなに古くないので、このままでいきます。
$ sudo apt install global $ global --version global (Global) 6.6.9 Powered by Berkeley DB 1.85 and SQLite3 3.40.1. Copyright (c) 1996-2022 Tama Communications Corporation License GPLv3+: GNU GPL version 3 or later <http://www.gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
チュートリアル
公式サイトのチュートリアル(https://www.gnu.org/software/global/globaldoc_toc.html)を参考に進めていきます。
まずは、gtagsコマンドで、タグファイルを作成します。
今回は、最近見ていた libusb を対象にやってみます。バージョンは、Parrot OS にデフォルトでインストールされていたバージョンに合わせました。
チュートリアルでは、gtagsコマンドだけを実行していましたが、-v を付けて、verbose mode(出力するログを多くする)で実行しました。
$ git clone https://github.com/libusb/libusb.git $ cd libusb/ $ git checkout -b v1.0.26 refs/tags/v1.0.26 $ gtags -v [Sun May 25 20:22:24 JST 2025] Gtags started. Using configuration file '/etc/gtags/gtags.conf'. Using configuration label 'default'. [Sun May 25 20:22:24 JST 2025] Creating 'GTAGS' and 'GRTAGS'. [1] extracting tags of Xcode/config.h [2] extracting tags of android/config.h [3] extracting tags of android/examples/unrooted_android.h (途中、割愛) [59] extracting tags of tests/stress.c [60] extracting tags of tests/testlib.c [61] extracting tags of tests/umockdev.c [Sun May 25 20:22:25 JST 2025] Done. $ ll G* -rw-r--r-- 1 user user 40K 5月 25 20:22 GPATH -rw-r--r-- 1 user user 592K 5月 25 20:22 GRTAGS -rw-r--r-- 1 user user 176K 5月 25 20:22 GTAGS
3つのタグファイルが出来ました。それぞれの役割は以下です。
- GTAGS:definition database(定義データベース)
- GRTAGS:reference database(参照データベース)
- GPATH:path name database(パス名データベース)
チュートリアル通り、次は、指定した関数の定義場所を表示し、その後、指定した関数の参照元を表示してみます。
$ global -x libusb_get_device_list libusb_get_device_list 816 libusb/core.c ssize_t API_EXPORTED libusb_get_device_list(libusb_context *ctx, $ global -rx libusb_get_device_list libusb_get_device_list 184 examples/fxload.c if (libusb_get_device_list(NULL, &devs) < 0) { libusb_get_device_list 62 examples/listdevs.c cnt = libusb_get_device_list(NULL, &devs); libusb_get_device_list 297 examples/testlibusb.c cnt = libusb_get_device_list(NULL, &devs); libusb_get_device_list 1362 libusb/core.c if (libusb_get_device_list(ctx, &devs) < 0) libusb_get_device_list 386 libusb/hotplug.c len = libusb_get_device_list(ctx, &devs); libusb_get_device_list 1373 libusb/libusb.h ssize_t LIBUSB_CALL libusb_get_device_list(libusb_context *ctx, libusb_get_device_list 62 tests/stress.c ssize_t list_size = libusb_get_device_list(ctx, &device_list); libusb_get_device_list 96 tests/stress.c ssize_t list_size = libusb_get_device_list(ctx, &device_lists[i]); libusb_get_device_list 440 tests/umockdev.c g_assert_cmpint(libusb_get_device_list(fixture->ctx, &devs), ==, devcount); libusb_get_device_list 490 tests/umockdev.c int count = libusb_get_device_list(fixture->ctx, &devs); libusb_get_device_list 532 tests/umockdev.c g_assert_cmpint(libusb_get_device_list(fixture->ctx, &devs), ==, 1); libusb_get_device_list 567 tests/umockdev.c g_assert_cmpint(libusb_get_device_list(NULL, &devs), ==, 1); libusb_get_device_list 572 tests/umockdev.c g_assert_cmpint(libusb_get_device_list(NULL, &devs), ==, 1); libusb_get_device_list 577 tests/umockdev.c g_assert_cmpint(libusb_get_device_list(NULL, &devs), ==, 1); libusb_get_device_list 1084 tests/umockdev.c g_assert_cmpint(libusb_get_device_list(fixture->ctx, &devs), ==, 1); libusb_get_device_list 1100 tests/umockdev.c g_assert_cmpint(libusb_get_device_list(fixture->ctx, &devs), ==, 0);
基本的な使い方は以上です。
lessコマンドでglobalを使ってみる
本来は、エディタと連携させて使うところですが、まずは、lessコマンドでやってみます。
以下を実行すると、lessコマンドで、指定した関数が表示されます。対象が複数ある場合は、t を入力すると次のタグへ移動し、T を入力すると前のタグに戻ります。
$ echo $LESSGLOBALTAGS $ export LESSGLOBALTAGS=global $ less -t libusb_get_device_list
HTMLで参照できるようにする
ソースコードを HTML化します。ブラウザ上で、ソースコードを表示することが出来て、ソースコードの中のリンクで関数の定義を確認したりできます。
やり方はとても簡単です。htagsコマンドを実行すると、HTMLディレクトリが作成されます。その中にある index.html をブラウザでアクセスすると、表示できます。
$ htags $ ll HTML/ 合計 216K drwxr-xr-x 1 user user 188 5月 25 20:48 ./ drwxr-xr-x 1 user user 534 5月 25 20:48 ../ drwxr-xr-x 1 user user 2.7K 5月 25 20:48 D/ -rw-r--r-- 1 user user 2.0K 5月 25 20:48 FILEMAP drwxr-xr-x 1 user user 32 5月 25 20:48 I/ drwxr-xr-x 1 user user 142 5月 25 20:48 J/ drwxr-xr-x 1 user user 16K 5月 25 20:48 R/ drwxr-xr-x 1 user user 880 5月 25 20:48 S/ drwxr-xr-x 1 user user 20 5月 25 20:48 defines/ -rw-r--r-- 1 user user 185K 5月 25 20:48 defines.html drwxr-xr-x 1 user user 164 5月 25 20:48 files/ -rw-r--r-- 1 user user 880 5月 25 20:48 files.html -rw-r--r-- 1 user user 922 5月 25 20:48 help.html -rw-r--r-- 1 user user 2.6K 5月 25 20:48 index.html -rw-r--r-- 1 user user 2.6K 5月 25 20:48 mains.html -rw-r----- 1 user user 555 5月 25 20:48 rebuild.sh -rwxr-xr-x 1 user user 2.0K 5月 25 20:48 style.css*

これは、とても便利だと思います。
よく使いそうなオプションを整理しておきます。
| オプション | 内容 |
|---|---|
| -a | アルファベットの一覧を作成してくれる |
| -g | 事前に gtagsコマンドを実行してくれる |
| -I | アイコンを使ってくれる(フォルダのアイコンとか) |
| -n | ソースコードに行番号を付けてくれる |
| -s | 定義と参照以外のシンボルもリンクを作ってくれる |
GNU cflow
cflow の公式ページ?です。
Git を見ると、まだ更新されてますね。
最新バージョンは、1.7 のようです。
インストール
インストールは簡単です。最新の 1.7 が入りました。
$ sudo apt install cflow $ cflow -V cflow (GNU cflow) 1.7 Copyright (C) 2005-2021 Sergey Poznyakoff License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Sergey Poznyakoff.
使ってみる
以下に、cflow のマニュアルがあります。
ここの whoami.c をそのまま使わせてもらいます。
いつものソースの貼り方だと、行番号が分からないので、画像で貼ります。画像で貼るとコピペが出来ないので、普段はやらないのですが、上のマニュアルにソースコードはあるので、今回は大丈夫とします。

では、マニュアルにあるように、実行してみます。
同じ出力が得られました。
$ cflow whoami.c main() <int main (int argc, char **argv) at whoami.c:26>: fprintf() who_am_i() <int who_am_i (void) at whoami.c:8>: getpwuid() geteuid() getenv() fprintf() printf()
出力形式は、デフォルトは gnu ですが、posix と dot も選べます。やってみます。
$ cflow -f posix whoami.c 1 main: int (int argc, char **argv), <whoami.c 26> 2 fprintf: <> 3 who_am_i: int (void), <whoami.c 8> 4 getpwuid: <> 5 geteuid: <> 6 getenv: <> 7 fprintf: <> 8 printf: <> $ cflow -f dot whoami.c digraph cflow { node [shape="box"] main [label="int main (int argc, char **argv) whoami.c:26"] main -> fprintf main -> who_am_i fprintf [label="fprintf()"] who_am_i [label="int who_am_i (void) whoami.c:8"] who_am_i -> getpwuid who_am_i -> geteuid who_am_i -> getenv who_am_i -> fprintf who_am_i -> printf getpwuid [label="getpwuid()"] geteuid [label="geteuid()"] getenv [label="getenv()"] printf [label="printf()"] } $ sudo apt install graphviz $ cflow -f dot --output=whoami.dot whoami.c $ dot -Tpng whoami.dot -o whoami.png
GraphViz を使って、dotファイルを画像ファイルに変換します。いい感じですね。

使えそうなオプションを列挙しておきます。
| オプション | 内容 |
|---|---|
| --depth=数値 | フローグラフの深さを指定した数値に制限する |
| --format=名前 | 出力形式を指定する(使用可能: gnu(デフォルト)、posix、dot) |
| -o(--output)=ファイル名 | 出力ファイル名を指定(デフォルトは -、つまり標準出力) |
| --omit-arguments | 関数定義の引数リストを表示しない |
| -T(--tree) | ASCII アートでツリーを描画する |
使い方が簡単なので、ソースコードを読むときに、まず動かしてみるのもいいですね。
GNU Globalとcflowを連携させる
以下を参考にさせて頂きました。
libusb を対象としてやってみます。
$ gtags $ cflow --tree --format=posix `global -P` > cflow.out $ cflow --tree --format=posix --reverse `global -P` > cflow-r.out $ htags -agIns --call-tree cflow.out --callee-tree cflow-r.out --fixed-guide
以下の感じになりました。




おわりに
今回は、Linux で使用するツールである tmux の紹介でした。私の場合、常に使っているツールというわけではないのですが、使用頻度が低いだけに、何をどうやって、インストールしたかを忘れてしまうので、記事にした感じです(笑)
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。