最近知ったんですが、lctagsというclangを使ったソースコードタグシステムがあるそうです。
ソースコードのタグシステムというのは、変数名や関数名から定義を参照したり、関数の定義部から呼び出し元へ飛ぶような複数のファイルを跨いで内容を飛びまわるようなものを言います。メジャーどころだと、ctags, etags, GNU Globalあたりが昔から使われています。これらの昔から存在するツールは、ソースコードを読み込んで解析するパーサを自前で持っていますが、この部分を真面目に開発していくと、最終的にはコンパイラを作る羽目になることが広く知られています。*1
じゃ、実際にコンパイラを使えばいいじゃんというわけで、ClangのフロントエンドがパースしたAST木を使っているのがこちらのシステムです。
インストール方法は apt が使えるOSならmake一発でインストールしてくれるそうです。
$ make build_for_ubuntu [PROXY=http://proxy.hoge:port/] $ sudo make install
でもってmakefile(src/makefile)を確認するとbuild_for_ubntuはありませんでしたが、build_for_aptがあったのでそっちを見てみると
- libclang3.8-devのインストール
- liblua5.3-devのインストール
- libssl-devのインストール
- swig3.0のインストール
- gtagsのインストール
- luasqlite3のインストール
- lctagsのビルド
と進んでいくようです。
とのことでしたが、とりあえずubuntu20で試してみましょう。
> docker run -it --rm ubuntu /bin/bash # apt update # apt install git make python sudo curl unzip # git clone https://github.com/ifritJP/lctags.git # cd lctags # make build_for_apt (cd src; make build_for_apt) make[1]: Entering directory '/lctags/src' /bin/sh: 1: lua5.3: not found check clang-dev ... sudo apt-get -o Acquire::http::proxy="" install libclang-3.8-dev Reading package lists... Done Building dependency tree Reading state information... Done E: Unable to locate package libclang-3.8-dev E: Couldn't find any package by glob 'libclang-3.8-dev' E: Couldn't find any package by regex 'libclang-3.8-dev' make[1]: *** [makefile:637: build_for_apt] Error 100 make[1]: Leaving directory '/lctags/src' make: *** [makefile:2: all] Error 2
というわけで、libclang-3.8-dev なんてパッケージは無いと言われて止まります。
試しにapt searchしてみたらversion10なんてのが見つかりました。
# apt search libclang-dev Sorting... Done Full Text Search... Done libclang-dev/focal 1:10.0-50~exp1 arm64 clang library - Development package
もうちょっと古いのは無いかなということで探してみると
# apt search libclang |grep dev WARNING: apt does not have a stable CLI interface. Use with caution in scripts. libclang-10-dev/focal 1:10.0.0-4ubuntu1 arm64 libclang-11-dev/focal-updates 1:11.0.0-2~ubuntu20.04.1 arm64 libclang-6.0-dev/focal 1:6.0.1-14 arm64 libclang-7-dev/focal 1:7.0.1-12 arm64 libclang-8-dev/focal 1:8.0.1-9 arm64 libclang-9-dev/focal 1:9.0.1-12 arm64 libclang-common-10-dev/focal 1:10.0.0-4ubuntu1 arm64 Clang library - Common development package libclang-common-11-dev/focal-updates 1:11.0.0-2~ubuntu20.04.1 arm64 Clang library - Common development package libclang-common-6.0-dev/focal 1:6.0.1-14 arm64 clang library - Common development package libclang-common-7-dev/focal 1:7.0.1-12 arm64 Clang library - Common development package libclang-common-8-dev/focal 1:8.0.1-9 arm64 Clang library - Common development package libclang-common-9-dev/focal 1:9.0.1-12 arm64 Clang library - Common development package libclang-cpp10-dev/focal 1:10.0.0-4ubuntu1 arm64 libclang-cpp11-dev/focal-updates 1:11.0.0-2~ubuntu20.04.1 arm64 libclang-dev/focal 1:10.0-50~exp1 arm64 librust-clang-sys+clang-3-7-dev/focal 0.28.1-6 arm64 librust-clang-sys+clang-3-8-dev/focal 0.28.1-6 arm64 librust-clang-sys+clang-3-9-dev/focal 0.28.1-6 arm64 librust-clang-sys+clang-4-0-dev/focal 0.28.1-6 arm64 librust-clang-sys+clang-5-0-dev/focal 0.28.1-6 arm64 librust-clang-sys+clang-6-0-dev/focal 0.28.1-6 arm64 librust-clang-sys+clang-7-0-dev/focal 0.28.1-6 arm64 librust-clang-sys+clang-8-0-dev/focal 0.28.1-6 arm64 librust-clang-sys+libloading-dev/focal 0.28.1-6 arm64 librust-clang-sys-dev/focal 0.28.1-6 arm64
あら、rustバインディングは3.8が残ってますね。
じゃ、こいつの依存パッケージは何かしらというと
# apt depends librust-clang-sys+clang-3-8-dev/focal librust-clang-sys+clang-3-8-dev Depends: librust-clang-sys-dev (= 0.28.1-6) Depends: <librust-clang-sys+gte-clang-3-6-dev> (= 0.28.1-6) librust-clang-sys-dev Depends: <librust-clang-sys+gte-clang-3-7-dev> (= 0.28.1-6) librust-clang-sys-dev Depends: <librust-clang-sys+gte-clang-3-8-dev> (= 0.28.1-6) librust-clang-sys-dev root@e0f6d7d7f2c9:/lctags# apt depends librust-clang-sys-dev librust-clang-sys-dev Depends: <librust-glob-0.3+default-dev> librust-glob-dev Depends: <librust-libc-0.2-dev> (>= 0.2.39-~~) librust-libc-dev Depends: libclang-dev Depends: llvm Depends: clang Suggests: librust-clang-sys+clang-3-7-dev (= 0.28.1-6) Suggests: librust-clang-sys+clang-3-8-dev (= 0.28.1-6) Suggests: librust-clang-sys+clang-3-9-dev (= 0.28.1-6) Suggests: librust-clang-sys+clang-4-0-dev (= 0.28.1-6) Suggests: librust-clang-sys+clang-5-0-dev (= 0.28.1-6) Suggests: librust-clang-sys+clang-6-0-dev (= 0.28.1-6) Suggests: librust-clang-sys+clang-7-0-dev (= 0.28.1-6) Suggests: librust-clang-sys+clang-8-0-dev (= 0.28.1-6) Suggests: librust-clang-sys+libloading-dev (= 0.28.1-6)
なぜかlibclangには依存していない・・・
面倒なんで、新しいのを入れて自力でビルドしましょう。
もう一度、READMEファイルに戻ってみると
必要なライブラリ等 swig (3.0) lua, lua-dev(5.2 or 5.3) libclang-dev (r380 or r390) luasqlite3 (0.9.4) openssl
だそうなので、この辺をlibclang-devのバージョンだけ無視してインストールします。 ただし、luasqlite3はパッケージが無いようなので、lctagsのmakefileを使ってインストールします。
# apt-get install swig3.0 lua5.3 liblua5.3-dev libclang-dev openssl # make download_luasqlite3 (cd src; make download_luasqlite3) make[1]: Entering directory '/lctags/src' check luasqlite3 ... install mkdir -p ../external/luasqlite3 curl --proxy "" "http://lua.sqlite.org/index.cgi/zip/lsqlite3_fsl09x.zip?uuid=fsl_9x" -o ../external/luasqlite3/lsqlite3_fsl09x.zip % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1947k 100 1947k 0 0 1399k 0 0:00:01 0:00:01 --:--:-- 1398k (cd ../external/luasqlite3; unzip -o lsqlite3_fsl09x.zip) Archive: lsqlite3_fsl09x.zip creating: lsqlite3_fsl09x/ inflating: lsqlite3_fsl09x/HISTORY inflating: lsqlite3_fsl09x/Makefile inflating: lsqlite3_fsl09x/README creating: lsqlite3_fsl09x/doc/ inflating: lsqlite3_fsl09x/doc/lsqlite3.wiki creating: lsqlite3_fsl09x/examples/ inflating: lsqlite3_fsl09x/examples/aggregate.lua inflating: lsqlite3_fsl09x/examples/function.lua inflating: lsqlite3_fsl09x/examples/hooks_advanced.lua inflating: lsqlite3_fsl09x/examples/order.lua inflating: lsqlite3_fsl09x/examples/simple.lua inflating: lsqlite3_fsl09x/examples/smart.lua inflating: lsqlite3_fsl09x/examples/statement.lua inflating: lsqlite3_fsl09x/examples/tracing.lua inflating: lsqlite3_fsl09x/examples/update_hook.lua creating: lsqlite3_fsl09x/extras/ inflating: lsqlite3_fsl09x/extras/Makefile inflating: lsqlite3_fsl09x/extras/extension-functions.c inflating: lsqlite3_fsl09x/extras/installpath.lua inflating: lsqlite3_fsl09x/lsqlite3-0.9.4-2.rockspec inflating: lsqlite3_fsl09x/lsqlite3.c inflating: lsqlite3_fsl09x/lsqlite3complete-0.9.4-2.rockspec inflating: lsqlite3_fsl09x/sqlite3.c inflating: lsqlite3_fsl09x/sqlite3.h creating: lsqlite3_fsl09x/test/ inflating: lsqlite3_fsl09x/test/test-dyld.lua inflating: lsqlite3_fsl09x/test/test.lua inflating: lsqlite3_fsl09x/test/tests-sqlite3.lua make[1]: Leaving directory '/lctags/src'
でもって最後にmake buildすると
# make build (cd src; make build) make[1]: Entering directory '/lctags/src' swig -I/usr/lib/llvm-3.8/include -o swig/libClangLuaBase_wrap.c -lua swig/libClangLuaBase.i make[1]: swig: Command not found make[1]: *** [makefile:162: swig/libClangLuaBase_wrap.c] Error 127 make[1]: Leaving directory '/lctags/src' make: *** [makefile:2: all] Error 2
# sed -i -e '/SWIG=swig/s/swig/swig3.0/' -e '/CLANG_VER=3.8/s/3.8/10/' src/makefile # make build (cd src; make build) make[1]: Entering directory '/lctags/src' swig3.0 -I/usr/lib/llvm-10/include -o swig/libClangLuaBase_wrap.c -lua swig/libClangLuaBase.i /usr/lib/llvm-10/include/clang-c/Platform.h:45: Error: Syntax error - possibly a missing semicolon. make[1]: *** [makefile:162: swig/libClangLuaBase_wrap.c] Error 1 make[1]: Leaving directory '/lctags/src' make: *** [makefile:2: all] Error 2
ぐぬぬぬ。とりあえず一番古いlibclangを入れて再トライ
# apt install libclang-6.0-dev Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: libclang-common-6.0-dev libclang1-6.0 libllvm6.0 The following NEW packages will be installed: libclang-6.0-dev libclang-common-6.0-dev libclang1-6.0 libllvm6.0 0 upgraded, 4 newly installed, 0 to remove and 5 not upgraded. Need to get 42.9 MB of archives. After this operation, 437 MB of additional disk space will be used. ・ ・ ・ # sed -i -e '/CLANG_VER=10/s/10/6.0/' src/makefile # make build ・ ・ ・ gcc Helper.c -std=c99 -DHELPER_STAND_ALONE -o Helper -I/usr/include/lua5.3 -llua5.3 -lcrypto -lm -lpthread -lrt Helper.c:4:10: fatal error: openssl/evp.h: No such file or directory 4 | #include <openssl/evp.h> | ^~~~~~~~~~~~~~~ compilation terminated.
わーい進んだ。 でも今度はopensslのヘッダが無いとか言われてます。
よくよくこの記事を遡ってみると、opensslは入れてるけど、libssl-devは入れてませんね。 追加でインストールして再ビルドしてみると
#apt install libssl-dev # make build (cd src; make build) make[1]: Entering directory '/lctags/src' make -C lctags LUA_COMMAND=lua5.3 LUA_INC=/usr/include/lua5.3 LUA_LIB= LUA_CFLAGS="-I/usr/include/lua5.3" LUA_LDFLAGS=-llua5.3 SO=so make[2]: Entering directory '/lctags/src/lctags' gcc Helper.c -std=c99 -DHELPER_STAND_ALONE -o Helper -I/usr/include/lua5.3 -llua5.3 -lcrypto -lm -lpthread -lrt Helper.c: In function 'helper_msleep': Helper.c:322:5: warning: implicit declaration of function 'usleep'; did you mean 'sleep'? [-Wimplicit-function-declaration] 322 | usleep( ( msec % 1000 ) * 1000 ); | ^~~~~~ | sleep gcc Helper.c -std=c99 -fPIC -shared -DHELPER_STAND_ALONE -o Helper.so -I/usr/include/lua5.3 -llua5.3 -lcrypto -lm -lpthread -lrt Helper.c: In function 'helper_msleep': Helper.c:322:5: warning: implicit declaration of function 'usleep'; did you mean 'sleep'? [-Wimplicit-function-declaration] 322 | usleep( ( msec % 1000 ) * 1000 ); | ^~~~~~ | sleep make[2]: Leaving directory '/lctags/src/lctags' make[1]: Leaving directory '/lctags/src' # make install (cd src; make install) make[1]: Entering directory '/lctags/src' make -C lctags LUA_COMMAND=lua5.3 LUA_INC=/usr/include/lua5.3 LUA_LIB= LUA_CFLAGS="-I/usr/include/lua5.3" LUA_LDFLAGS=-llua5.3 SO=so make[2]: Entering directory '/lctags/src/lctags' make[2]: Nothing to be done for 'all'. make[2]: Leaving directory '/lctags/src/lctags' make install-lib make[2]: Entering directory '/lctags/src' mkdir -p /usr/local/lib/lua/5.3 mkdir -p /usr/local/lib/lua/5.3/libclanglua mkdir -p /usr/local/lib/lua/5.3/lctags mkdir -p /usr/local/share/lua/5.3 mkdir -p /usr/local/share/lua/5.3/libclanglua mkdir -p /usr/local/share/lua/5.3/lctags /usr/bin/install -c libclanglua/core.so /usr/local/lib/lua/5.3/libclanglua /usr/bin/install -c libclanglua/if.lua libclanglua/ifc.lua /usr/local/share/lua/5.3/libclanglua if [ -f lsqlite3.so ]; then /usr/bin/install -c lsqlite3.so /usr/local/lib/lua/5.3; fi mkdir -p /usr/local/share/lua/5.3/lctags /usr/bin/install -c lctags/_lctags.conf /usr/local/share/lua/5.3/lctags /usr/bin/install -c lctags/*.lua /usr/local/share/lua/5.3/lctags sed "s@.*-- replase by install@ self.clangIncPath = \"/usr/lib/llvm-6.0/lib/clang/6.0.1\"@g" lctags/config.lua > /tmp/config.lua /usr/bin/install -c /tmp/config.lua /usr/local/share/lua/5.3/lctags rm /tmp/config.lua /usr/bin/install -c lctags/*.so /usr/local/lib/lua/5.3/lctags make[2]: Leaving directory '/lctags/src' make -C lctags install INST_DIR=/usr/local/bin \ LUA_COMMAND=lua5.3 LUA_MOD_DIR=/usr/local/share/lua/5.3 make[2]: Entering directory '/lctags/src/lctags' sed "s@lua5.3@lua5.3@g" lctags | \ sed 's@${DIR}@'"/usr/local/share/lua/5.3/lctags@g" > /usr/local/bin/lctags chmod +x /usr/local/bin/lctags make[2]: Leaving directory '/lctags/src/lctags' make[1]: Leaving directory '/lctags/src'
じゃ、テストしてみましょう。
#make test (cd src; make test) make[1]: Entering directory '/lctags/src' make -C lctags LUA_COMMAND=lua5.3 LUA_INC=/usr/include/lua5.3 LUA_LIB= LUA_CFLAGS="-I/usr/include/lua5.3" LUA_LDFLAGS=-llua5.3 SO=so make[2]: Entering directory '/lctags/src/lctags' make[2]: Nothing to be done for 'all'. make[2]: Leaving directory '/lctags/src/lctags' lua5.3 lctags/lctags.lua init . /usr/include/stdio.h:33:10: fatal error: 'stddef.h' file not found please set clang inc-path at getClangIncPath() in /lctags/src/lctags.conf, and retry init. make[1]: *** [makefile:210: test] Error 1 make[1]: Leaving directory '/lctags/src' make: *** [makefile:2: all] Error 2
なんでやねん。 このissueを見てると、build-essential入れとけって話のようなので、素直に入れときましょう。
でもって、再トライ
# make test (cd src; make test) make[1]: Entering directory '/lctags/src' make -C lctags LUA_COMMAND=lua5.3 LUA_INC=/usr/include/lua5.3 LUA_LIB= LUA_CFLAGS="-I/usr/include/lua5.3" LUA_LDFLAGS=-llua5.3 SO=so make[2]: Entering directory '/lctags/src/lctags' make[2]: Nothing to be done for 'all'. make[2]: Leaving directory '/lctags/src/lctags' lua5.3 lctags/lctags.lua init . /usr/include/stdio.h:33:10: fatal error: 'stddef.h' file not found please set clang inc-path at getClangIncPath() in /lctags/src/lctags.conf, and retry init. make[1]: *** [makefile:210: test] Error 1 make[1]: Leaving directory '/lctags/src' make: *** [makefile:2: all] Error 2
うーむ駄目か。
いさぎよく、build_for_aptの説明のところで動作確認したと言われている、debian9.1で再トライしてみます。
途中、何度かDo you want to continue? [Y/n]
と聞かれるので、yes | make build_for_apt
しといた方が無難ですね。
>docker run -it --rm debian:9.1 /bin/bash # apt update # apt install git make python sudo curl unzip # git clone https://github.com/ifritJP/lctags.git # cd lctags # make build_for_apt ・ ・ ・ gcc Helper.c -std=c99 -fPIC -shared -DHELPER_STAND_ALONE -o Helper.so -I/usr/include/lua5.3 -llua5.3 -lcrypto -lm -lpthread -lrt Helper.c: In function 'helper_msleep': Helper.c:322:5: warning: implicit declaration of function 'usleep' [-Wimplicit-function-declaration] usleep( ( msec % 1000 ) * 1000 ); ^~~~~~ make[3]: Leaving directory '/lctags/src/lctags' make[2]: Leaving directory '/lctags/src' make[1]: Leaving directory '/lctags/src'
無事にインストールできました・・・orz
さっそくテストしてみましょう。
# make test (cd src; make test) make[1]: Entering directory '/lctags/src' make -C lctags LUA_COMMAND=lua5.3 LUA_INC=/usr/include/lua5.3 LUA_LIB= LUA_CFLAGS="-I/usr/include/lua5.3" LUA_LDFLAGS=-llua5.3 SO=so make[2]: Entering directory '/lctags/src/lctags' make[2]: Nothing to be done for 'all'. make[2]: Leaving directory '/lctags/src/lctags' lua5.3 lctags/lctags.lua init . sync rm -f emacs -batch -q -eval "(progn (add-to-list 'load-path \"lisp\") (load \"lctags-test.el\"))" /bin/sh: 1: emacs: not found makefile:210: recipe for target 'test' failed make[1]: *** [test] Error 127 make[1]: Leaving directory '/lctags/src' makefile:2: recipe for target 'all' failed make: *** [all] Error 2
emacsを入れてもう一度テストすると
# apt install -y emacs # make test ・ ・ ・ --- 3669,3673 ---- make test-chg-proj /usr/bin/lua lctags/lctags.lua --lctags-form json set-projDir . test@test2 > /dev/null /usr/bin/lua lctags/lctags.lua --lctags-form json dump file | grep test/ > /dev/null && (echo ==== NG set-projDir ====; exit 1) ! makefile:476: recipe for target 'test-chg-proj' failed /usr/bin/lua lctags/lctags.lua --lctags-form json set-projDir . test2@test > /dev/null makefile:210: recipe for target 'test' failed make[1]: [test] Error 1 (ignored) make[1]: Leaving directory '/lctags/src'
うむ。駄目っぽいです・・・o....rz
この後make cleanしてmake testすると、stddefが無いエラーが再発しました。 とりあえずlctagsコマンド自体はビルドできてるっぽいので、インストールして初期化してみると
#make install # lctags init . /usr/include/stdio.h:33:11: fatal error: 'stddef.h' file not found please set clang inc-path at getClangIncPath() in /lctags/lctags.conf, and retry init.
dockerイメージだと、インストーラから入れたものと比べると大幅にパッケージが減らされているんで、たぶん何かしら不足してるパッケージがあるんだと思いますが、これ以上追求していくのも大変そうなので、今回は諦めます。
これが使えると、いろいろとはかどりそうだったんで期待してたんですが、残念です。