vimのソースコードを読もうとした話[準備編]
概要
2023/11/18にvimconfに参加してvimへの意欲が高まってきたので、勢いで記事書いてしまおうというアレです。
先人達が沢山記事書いてると思うのですが、まあダブってもええやろの気持ち。
技術記事というより体験記みたいなノリです。
筆者について
自己紹介
事故紹介(?)を書いているので、そちらをよしなに。
過去歴
実は去年(2022)か一昨年(2021)くらい?に一度ビルドしたりソースを見ていたことがありますが、あまりのソース量に挫折しました。
検証環境
バージョン
version : v9.0.2112
commit : ab4f27e
ビルド環境
ConoHa VPS借りてます。
OS : Ubuntu 20.04.2 LTS(kernel: 5.4.0-153-generic)
CPU : Intel(R) Xeon(R) Gold 6230 CPU @ 2.10GHz
RAM : 検証時点では↓こんな感じ。
$ free -h
total used free shared buff/cache available
Mem: 964Mi 356Mi 117Mi 3.0Mi 490Mi 436Mi
Swap: 2.0Gi 631Mi 1.4Gi
検証
clone
ここがvimのハウスね。👀
2023/11/19時点で18,648commit. さすが30年選手のリポジトリだ。
とりあえずcloneしてみます。(ボリューム多いので、ひとまずdepth 1 で。)
git clone git@github.com:vim/vim.git --depth 1
ソースコードの内訳
clone出来たので、clocコマンド(ソースコードの行数計測ツール)でvimを見てみましょう。
以下は、直下でclocコマンドを実行した結果です。
$ cloc .
4369 text files.
4282 unique files.
1795 files ignored.
github.com/AlDanial/cloc v 1.82 T=4.36 s (592.2 files/s, 330010.6 lines/s)
---------------------------------------------------------------------------------------
Language files blank comment code
---------------------------------------------------------------------------------------
vim script 1957 57739 58097 383516
C 189 48491 81714 375180
PO File 40 86030 14953 218130
C/C++ Header 66 3933 5574 31526
Bourne Shell 29 2268 1585 15765
diff 42 111 1248 15750
C++ 4 1165 1145 5983
IDL 148 19 0 5557
m4 1 383 184 4138
make 14 819 1595 3833
Python 26 168 190 972
YAML 11 128 94 880
Markdown 7 240 0 779
Perl 8 194 217 777
awk 3 35 101 716
Forth 1 407 1 630
Prolog 1 386 0 609
Verilog-SystemVerilog 1 354 0 476
Smalltalk 1 354 0 458
Objective C 1 83 90 351
DAL 1 400 263 309
DOS Batch 15 47 70 255
Windows Resource File 3 36 51 203
XML 1 0 0 18
Lua 2 2 0 10
Windows Module Definition 2 4 6 8
sed 4 0 1 8
C Shell 1 0 6 7
JSON 1 0 0 1
---------------------------------------------------------------------------------------
SUM: 2580 203796 167185 1066845
---------------------------------------------------------------------------------------
かなりのボリューム。
vim scriptとC言語が多めですね。
ビルド
Ubuntu 20.04でのビルド方法を書いている方がいたので、そちらを参考にしつつビルド。
./configure \
--with-features=huge \
--enable-gui=gtk3 \
--enable-python3interp \
--enable-luainterp \
--enable-tclinterp \
--enable-rubyinterp \
--with-luajit \
--enable-fail-if-missing
make
ビルド時のコマンドをtimeで計測したら、158秒くらいでした。
Executed in 158.66 secs fish external
usr time 139.77 secs 371.00 micros 139.77 secs
sys time 17.13 secs 166.00 micros 17.13 secs
ソースコード解析準備
まずはls
src/以下に移動して、「ls」っと。
$ vim/src$ ls
alloc.c configure.ac ex_eval.c gui_x11.c if_xcmdsrv.c main.c msvc-latest.bat os_mswin.c regexp.h textobject.c vim.h
alloc.h create_cmdidxs.vim ex_getln.c gui_x11_pm.h iid_ole.c Make_all.mak msys32.bat os_qnx.c regexp_nfa.c textprop.c vim.ico
arabic.c create_nvcmdidxs.c feature.h gui_xim.c indent.c Make_ami.mak msys64.bat os_qnx.h register.c time.c vim_icon.xbm
arglist.c create_nvcmdidxs.vim fileio.c gui_xmdlg.c insexpand.c Make_cyg.mak mysign os_unix.c screen.c toolbar.phi viminfo.c
ascii.h crypt.c filepath.c gui_xmebw.c INSTALL Make_cyg_ming.mak nbdebug.c os_unix.h scriptfile.c toolcheck vim_info.ico
auto crypt_zip.c findfile.c gui_xmebw.h INSTALLami.txt Makefile nbdebug.h os_unixx.h search.c tools.bmp vim.manifest
autocmd.c debugger.c float.c gui_xmebwp.h INSTALLmac.txt Make_ming.mak netbeans.c os_vms.c session.c typemap vim_mask.xbm
beval.c dict.c fold.c GvimExt installman.sh Make_mvc.mak normal.c os_vms_conf.h sha256.c typval.c vim_quest.ico
beval.h diff.c getchar.c gvimtutor installml.sh Make_vms.mms nv_cmdidxs.h os_vms_fix.com sign.c ui.c vim.rc
bigvim64.bat digraph.c globals.h hardcopy.c INSTALLpc.txt map.c nv_cmds.h os_vms_mms.c sound.c undo.c vimrun.c
bigvim.bat dlldata.c gui_beval.c hashtab.c install-sh mark.c objects os_w32dll.c spell.c uninstall.c vim.tlb
blob.c dosinst.c gui.c help.c INSTALLvms.txt match.c ops.c os_w32exe.c spellfile.c usercmd.c vimtutor
blowfish.c dosinst.h gui_dwrite.cpp highlight.c INSTALLx.txt mbyte.c option.c os_win32.c spell.h userfunc.c which.sh
buffer.c drawline.c gui_dwrite.h if_cscope.c iscygpty.c memfile.c optiondefs.h os_win32.h spellsuggest.c version.c winclip.c
bufwrite.c drawscreen.c gui_gtk.c if_lua.c iscygpty.h memfile_test.c option.h pathdef.sh strings.c version.h window.c
change.c edit.c gui_gtk_f.c if_mzsch.c job.c memline.c optionstr.c po structs.h vim xdiff
channel.c errors.h gui_gtk_f.h if_mzsch.h json.c menu.c os_amiga.c popupmenu.c syntax.c vim9class.c xpm
charset.c evalbuffer.c gui_gtk_res.xml if_ole.cpp json_test.c message.c os_amiga.h popupwin.c tag.c vim9cmds.c xpm_w32.c
cindent.c eval.c gui_gtk_vms.h if_ole.h keymap.h message_test.c osdef1.h.in profiler.c tearoff.bmp vim9compile.c xpm_w32.h
clientserver.c evalfunc.c gui_gtk_x11.c if_ole.idl kword_test.c misc1.c osdef2.h.in proto tee vim9execute.c xxd
clipboard.c evalvars.c gui.h if_perlsfio.c libvterm misc2.c osdef.sh protodef.h term.c vim9expr.c
cmdexpand.c evalwindow.c gui_haiku.cc if_perl.xs link.390 mouse.c os_dos.h proto.h termdefs.h vim9.h
cmdhist.c ex_cmdidxs.h gui_haiku.h if_py_both.h link.sh move.c os_haiku.h pty.c terminal.c vim9instr.c
config.h.in ex_cmds2.c gui_motif.c if_python3.c list.c msvc2015.bat os_haiku.rdef.in quickfix.c termlib.c vim9script.c
config.mk.dist ex_cmds.c gui_photon.c if_python.c locale.c msvc2017.bat os_mac_conv.c README.md testdir vim9type.c
config.mk.in ex_cmds.h gui_w32.c if_ruby.c logfile.c msvc2019.bat os_mac.h regexp_bt.c testing.c vim_alert.ico
configure ex_docmd.c gui_w32_rc.h if_tcl.c macros.h msvc2022.bat os_macosx.m regexp.c textformat.c vim_error.ico
ソースが多いよ!!!!助けてお母さん!!!!!(?)
ディレクトリで分かれてないのが微妙につらいが、ビルド上の理由とか変更が大変とか
色々あるのかもしれない。
main.cを見よう
とりあえるエントリポイントみれば分かるやろ。
$ wc main.c
3748 12336 98089 main.c
想像以上にmain.cのボリュームがデカかった。
main.cをバラしてみよう
どうやら、main.cだけでいっぱい関数があるようだ。
そこで、
- clang-formatで整形
- 関数単位でファイル分割(小さい関数は1個のファイルで纏めている)
をやった。
$wc *
196 546 5219 ./getout.h
433 1505 12547 ./vim_main2.h
1381 4880 49546 ./no_vim_main.h
283 859 6693 ./func.h
187 801 8232 ./usage.h
111 367 2980 ./common_init.h
333 1318 12643 ./main_loop.h
85 280 2589 ./early_arg_scan.h
84 206 2996 ./Makefile
341 1236 9878 ./main.c
42 126 965 ./set_progpath.h
341 1236 9878 ./organize/main.c
86 321 2561 ./define.h
3903 13681 126727 total
どうやら、本当のエントリポイントは341行のようだ。
これなら追えそう。
ifdef祭り
vimのソースコードを見ていたが、あらゆるパターンでifdefが切られている。
このまま全部読むのは中々骨が折れそう。
そこでビルド時の定数をunifdefコマンドに食わせて、有効化されていない部分を削除してから読もうとした。
-> しかし、unifdefでコードを出力すると、300L以上は途切れてしまうようだった。
仕様の問題なのか設定なのか、今後もう少し調査してみる予定。
最後に
中途半端だが、このまま解析続けると結構かかりそうなので、一旦この辺で記事を投稿することにした。
ひとまず準備編ということで。
Discussion