👏

vimのソースコードを読もうとした話[準備編]

2023/11/25に公開

概要

2023/11/18にvimconfに参加してvimへの意欲が高まってきたので、勢いで記事書いてしまおうというアレです。
先人達が沢山記事書いてると思うのですが、まあダブってもええやろの気持ち。
技術記事というより体験記みたいなノリです。

筆者について

自己紹介

事故紹介(?)を書いているので、そちらをよしなに。
https://github.com/Hakkadaikon

過去歴

実は去年(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のハウスね。👀
https://github.com/vim/vim/tree/master

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だけでいっぱい関数があるようだ。
そこで、

  1. clang-formatで整形
  2. 関数単位でファイル分割(小さい関数は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