ろぐれこーど

限界組み込みエンジニアの学習記録とちょっぴりポエム

tagsファイルをパースして関数一覧を取得する

プロジェクト内の関数一覧を取得したいとPLに言われたので、適当に方法を考えてみました。構文解析から愚直にやると地獄を見そうなので、今回はCtagsを利用し、tagsファイルをパースするスクリプトpythonで書きます。

  • Ctags == 5.8
  • python >= 3
  • C/C++のプロジェクトを想定(他言語でも設定変えれば適応可)

結論

Ctagsを入手します。以下からwindows向けCtags日本語版バイナリをダウンロードできます。

https://hp.vector.co.jp/authors/VA025040/ctags/

mac OSへの導入は以下です。

https://log.yostos.org/2017/05/22/installing-ctags-to-mac/

以下コマンドをプロジェクトのトップディレクトリで実行します。

ctags --excmd==n -R .

生成されたtagsファイルのある場所で、以下スクリプトを実行すると、関数一覧をresult.txtに抽出できます。(オーバーロードしている関数は1関数とみなし、重複分を含めない形で出力します)

funcs = []
with open("tags", mode="r") as tags_file:
    # result.txtに関数名一覧を出力
    out = open("result.txt", mode="w")
    lines = tags_file.readlines()
    for line in lines:
        symbol_info = line.strip().split("\t")
        func = symbol_info[0]
        # 関数のみ取得
        if symbol_info[-1] == "f":
            func = symbol_info[0]
            # 重複した関数は除く
            if func in funcs:
                continue
            # 新規関数はresult.txtに出力
            else:
                funcs.append(func)
                out.write(func + "\n")
    out.close()

補足説明あれこれ

Ctags

wikipediaの引用です↓

Ctags(英: Ctags)はソース及びヘッダ内にある名前のインデックス(又はタグ)ファイルを生成するプログラム。様々なプログラミング言語に対応している。言語に依存するが、サブルーチン(関数)、変数、クラスのメンバ、マクロ等がインデックス化される。これらのタグによりテキストエディタなどのツールで高速かつ容易に定義を参照できる。相互参照ファイルを出力でき、また名前についての情報を人が読みやすい形で列挙した言語ファイルを生成することもできる。

https://ja.wikipedia.org/wiki/Ctags

Ctagsが生成するtagsファイルを解釈できれば、軽量で限定的な機能しか持たないエディタでも手軽に定義元ジャンプが利用できるようになります。tagsは以下のようなフォーマットで1タグにつき1行ずつ記述されます。

tag_name <TAB> file_name <TAB> ex_cmd;" <TAB> extension_fields
記述 概要
tag_name タグ名(関数や変数など)
file_name 定義元ファイルまでの相対パス
ex_cmd ファイル内の定義位置までジャンプするためのコマンド
extension_fields exコマンドに付随するkey-value形式のコメント

extension_fieldsにはオプション次第で種々の情報が含まれますが、今回はkindで示されるタグtypeを参照して関数の定義のみを取得します。プロジェクトのトップディレクトリで以下コマンドを実行し、tagsファイルを生成します。

ctags --excmd==n -R .

--excmdにより、tagsファイルに記述されるex_cmdの内容が変わります。n(number)を指定すると行数のみで定義元へジャンプするようになり、tagsファイルのサイズを最小にできます(その分ソースファイル編集するごとにtagsを更新する必要があるという欠点もあります)。今回は関数一覧を取得したいだけなので、ファイルサイズが小さくなるようにnを指定します。-R再帰的探索のオプションです。

extension_fieldsに含まれるkindはタグの種類(関数、変数、メソッド、クラスなど)を示してくれるので、これを使えば任意の種類のタグが取得できるようになります。タグは言語によって異なるため、以下コマンドで確認できます。

ctags --list-kinds=<言語の名前>

例えばC言語のタグは以下です。(C++も同じ結果です)

$ ctags --list-kinds=c

c  classes
d  macro definitions
e  enumerators (values inside an enumeration)
f  function definitions
g  enumeration names
l  local variables [off]
m  class, struct, and union members
n  namespaces
p  function prototypes [off]
s  structure names
t  typedefs
u  union names
v  variable definitions
x  external and forward variable declarations [off]

関数定義はfで表されるので、上記のスクリプトではこれをキーとしてタグを判別しています。この部分を変更すれば他タグも取得できますが、key-valueペアとなるタグtypeもあるため適宜書き換える必要があります。

Ctagsの詳細な使用方法やtagsファイルのフォーマットは以下のドキュメントで確認できます。

http://ctags.sourceforge.net/ctags.html

まとめ

tagsファイルを使用して関数一覧を取得しました。普段はVSCodeを使用しているのでCtagsは使ったことがなかったのですが、意外な使い道を見つけられて嬉しいです。