emacs and mg

Table of Contents

切っ掛けは etags

この所Debianでapt updateがさっぱりやってこないんで、i386のサポートは終了しちゃったかと思っていた。そしたら噂をすれば影ってやつで、emacs一式に新しいのが降ってきた。よかったねと思っていたら、丁度やってたetagsがご機嫌斜めになっちゃった。

GNU Emacs 27.1 (build 1, i686-pc-linux-gnu, GTK+ Version 3.24.24, 
cairo version 1.16.0) of 2023-01-06, modified by Debian

sakae@deb:/tmp/t$ etags etags.c
Segmentation fault

いきなりのセグフォ。こういう時は、検死だな。

Core was generated by `etags etags.c'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0041f83b in ?? ()
(gdb) bt
#0  0x0041f83b in ?? ()
#1  0x00418f8a in ?? ()
#2  0x00415611 in ?? ()
#3  0x00414967 in ?? ()
#4  0xb7adce46 in __libc_start_main (main=0x414940, argc=2, argv=0xbfb912b4,
    init=0x4afa20, fini=0x4afa80, rtld_fini=0xb7f03230 <_dl_fini>,
    stack_end=0xbfb912ac) at ../csu/libc-start.c:308
#5  0x004149b1 in ?? ()

死因不明社会。

new emacs

これはもう、自分でemacs-worldを作りあげろって言う、神の思し召しかな。ならばやってやろうじゃん。どうせ新しくするなら、JIT版がいいかな。

ネイティブコンパイルEmacsの登場 を参考に libgccgit-10-dev なんてのを入れてから、新しい仕様でレシピを作成。

sakae@deb:/tmp/emacs$ ./configure --with-native-compilation --with-x-toolkit=lucid

待つ事、およそ45分。ELNてのがネイティブ用らしいから、順調みたい。

make[3]: Entering directory '/tmp/emacs/lisp'
  ELC+ELN  emacs-lisp/comp.elc
  ELC+ELN  emacs-lisp/comp-cstr.elc

そして、出来上がったのがこれ。ヘッドは随分先のバージョン番号になってるな。

GNU Emacs 30.0.50 (build 1, i686-pc-linux-gnu, X toolkit, cairo version 1.16.0,
 Xaw scroll bars) of 2023-01-14

久し振りなんで、どんなアプリがインストールされたか、確認してみる。

-rwxr-xr-x 1 root  root    791440 Jan 14 07:46 etags*
-rwxr-xr-x 1 root  root    800660 Jan 14 07:46 ctags*
-rwxr-xr-x 1 root  root    221456 Jan 14 07:46 emacsclient*
-rwxr-xr-x 1 root  root    208196 Jan 14 07:46 ebrowse*
-rwxr-xr-x 1 root  root  29090580 Jan 14 07:46 emacs-30.0.50*
lrwxrwxrwx 1 root  root        13 Jan 14 07:46 emacs -> emacs-30.0.50*

ネイティブにコンパイルされた物は、今迄と違う場所に入った。

sakae@deb:/usr/local/lib/emacs/30.0.50/native-lisp/30.0.50-dcdd4d6e$ ls
bytecomp-12882072-18e0ca75.eln    ja-dic-283bfd77-a5e4a1e7.eln
byte-opt-9c5f25f5-e9c39fdd.eln    loaddefs-gen-e8a3ad9c-00161efc.eln
charscript-600dca1a-50cd3215.eln  preloaded/
comp-7672a6ed-d7431afe.eln        radix-tree-669a468d-a0a70c74.eln
comp-cstr-ef162ef7-34596d4c.eln   titdic-cnv-765ac3be-dff341f9.eln
emoji-zwj-4f682c68-8845604c.eln

ユーザー固有の物は ~/.emacs.d/eln-cache/30.0.50-dcdd4d6e こんな所に鎮座するんだな。ユーザーパッケージをアクセスすると、jitで変換されてキャッシュが増加してく。重いと評判のorgも、初回のアクセス時はコンパイルの影響で黙りこんでしまうけど、次回からはスイスイと動く。これがjitの威力なんだな。実感出来てよかったな。

そして、付属品のコンパイル。詳細を省略しちゃうのは、いかがなものかと思うぞ。もっと生々しいログが欲しいんだけどな。

sakae@deb:/tmp/emacs/lib-src$ make
make -C ../lib all
make[1]: Entering directory '/tmp/emacs/lib'
  GEN      alloca.h
  GEN      dirent.h
  :
  CC       fingerprint.o
  CC       mktime.o
  :
  CC       save-cwd.o
  AR       libgnu.a
make[1]: Leaving directory '/tmp/emacs/lib'
  CCLD     etags
  CCLD     ctags
  CCLD     emacsclient
  CCLD     ebrowse
  CCLD     hexl
  CCLD     make-docfile
  CCLD     make-fingerprint

これでもCのソースです。本当にctagsとetagsは兄弟と言うか双子だな。育ちはちょいと違うけど。これぞ、デジタル・ツインです。

sakae@deb:/tmp/emacs/lib-src$ cat ctags.c
#define CTAGS 1
#include "etags.c"

それはそうと、configure時に指定したやつ –with-x-toolkit=lucid は何?

--with-x-toolkit=KIT    use an X toolkit (KIT one of: yes or gtk, gtk2,
                        gtk3, lucid or athena, motif, no)

という説明。Xの一番初期のやつがathenaでその次がmotifでその次ぐらいがlucidとかになるのかな。後はひたすら重いgtkシリーズか。さすがにqt5とかは無いな。だってGNUですものか。

Emacs をいろんな X ツールキットでビルドしてみた

--with-native-compilation[=TYPE]
                        compile with Emacs Lisp native compiler support. The
                        TYPE 'yes' (or empty) means to enable it and compile
                        natively preloaded Lisp files; 'no' means to disable
                        it; 'aot' will make the build process compile all
                        the Lisp files in the tree natively ahead of time.
                        (This will usually be quite slow.)

libgccjitが有る環境(なんて言う説明は無いけど)で、このオプションを指定すると、ターボチャージャーが働くようになるんだな。GNU特有な環境が必要ですって、ことさら断らないのは、虚偽広告ではなかろうか?

sakae@deb:~$ ldd /usr/local/bin/emacs-30.0.50 | grep jit
        libgccjit.so.0 => /lib/i386-linux-gnu/libgccjit.so.0 (0xb4960000)

config結果を見ると、こんな所に目がいった。

What compiler should emacs be built with?               gcc -g3 -O2
Does Emacs support sound?                               yes
Does Emacs use -lsqlite3?                               yes

巨大になってfirefoxとかを、追い越したいんだな。オイラーの希望はPDFを閲覧出来るようにな、お願いしますよ。

ああ、 『らじる★らじる』の聴き逃しサービス(1) を読むと、ブラウザーの拡張は、何でもjavascriptにお任せって風。そのスクリプトも、その都度DLするってんだから、ネットワーク資源の無駄使いも甚しい。こんな事でいいのか。 で、この記事で知ったのだけど、NHK+ が一週間と切っているのは、あの権利団体のせいか。成程ね。

連鎖反応

折角ヘッドを取ってきたので、エクスプローラーしてたら、leimにSKKな辞書が有った。昔から同梱されてたのかなあ? そう言えば、思い出したぞ。 DDSKK のインストール

;; for SKK -------------------------------
(global-set-key (kbd "C-x j") 'skk-auto-fill-mode)
(setq skk-egg-like-newline t)
(setq skk-sticky-key ";")
(setq skk-user-directory "~/.ddskk")
(setq skk-inhibit-ja-dic-search t)   ;; disable ja-dic.el
(setq skk-large-jisyo "/usr/local/share/skk/SKK-JISYO.L")
(setq skk-extra-jisyo-file-list
      (list "/usr/local/share/skk/SKK-JISYO.JIS2"
            "/usr/local/share/skk/SKK-JISYO.notes"
                :
            "/usr/local/share/skk/SKK-JISYO.office.zipcode"))		

こんなコードを書いてみる。SKKは変換のタイミングを大文字で指定する事になっている。シフトキーを多用する事になるんで、小指の負担が大きい。上のsticyを設定しておくと、へんかんってのを、Henkan と指定(Hのためにシフトキーが必要)するのを避けて、;henkan と入力出来る。

辞書は、skk-getすれば、一式取寄せられるんだけど、そのままでは有効にならない。少なくともlarge-jisyoだけは設定しておくべし。これが有効になってるかどうかは、大丈夫 が変換出来れば、大丈夫である。

それから、Windowsに入っているemacsも新しいのにした。

GNU Emacs 28.2 (build 2, x86_64-w64-mingw32) of 2022-09-14

ものの説明によればjitがサポートされているようだけど、それを有効にするには、かなり色々な物を取り込まなければいけないようなので、諦めた。

emacs 28.2になったおかげでorg-modeで、<e した時に、ブロックの用意が出来無かった。

(require 'org-tempo)

を追加した。微妙に変化してるのね。

msys2

Windowsに入れたemacsは、どうやら MSYS2 な環境で構築されてるっぽい。pacmanでパッケージを入れるって、ArchLinuxみたいな通の人達だな。

そういえば、ArchLinuxのemacsはjitが有効になってないな。jitって、まだ市民権を得ていない、アーリーなものか。

mg

前回からの続きでmgのデータ構造を追跡。だって本物のemacsじゃ規模が大き過ぎて大変だもの。なに、大きくても小くても、そんなに大差は無いだろう。

funmap_add

最初に目が行ったのは、mg語の関数銘とC言の関数名の対比を登録する手続。ご多分に洩れず、リスト構造になってる。呼出関係は下記のようだ。モード毎に登録されてくんだな。

(gdb) bt
#0  funmap_add (fun=0x149949e0 <dired>, fname=0x149624c0 "dired", fparams=1)
    at funmap.c:258
#1  0x149946fb in dired_init () at dired.c:208
#2  0x14980e46 in main (argc=0, argv=0xcf7ca998) at main.c:138

結果のリストをトラバースって、Lispで言う、 cadrじゃないですか。それじゃaddしてく方は、これまたLisp用語に直せばconsだな。

(gdb) p *funs
$2 = {
  fn_funct = 0x15eb38e0 <yank>,
  fn_name = 0x15e82d9e "yank",
  fn_nparams = 1,
  fn_next = 0x35e80028 <functnames+2800>
}
(gdb) p *$.fn_next
$3 = {
  fn_funct = 0x15e9b300 <filewrite>,
  fn_name = 0x15e83df2 "write-file",
  fn_nparams = 1,
  fn_next = 0x35e80018 <functnames+2784>
}
:
$24 = {
  fn_funct = 0x15eb0f10 <splitwind>,
  fn_name = 0x15e81786 "split-window-vertically",
  fn_nparams = 0,
  fn_next = 0x35e7fec8 <functnames+2448>
}
:
$57 = {
  fn_funct = 0x15ea64b0 <re_queryrepl>,
  fn_name = 0x15e82f22 "query-replace-regexp",
  fn_nparams = -1,
  fn_next = 0x35e7fcb8 <functnames+1920>
}
:
$178 = {
  fn_funct = 0x15e9f0e0 <apropos_command>,
  fn_name = 0x15e82808 "apropos",
  fn_nparams = 1,
  fn_next = 0x0
}

引数の数も一緒に登録してる。不定個の引数は、-1 って表現してるけど、これもLispでは定番の構造だな。まあ、Lispが陽に表れていないけど、内部はあれだな。全体が180個ぐらいの関数で、出来上がっている。ミニと言うかマイクロを名乗る資格が十分に有るよ。

complete_function_list

complete_function_list なんて言う楽しそうな関数を見付たので、試してみる。 M-x tag TAB したら、引掛ってきた。

(gdb) bt
#0  complete_function_list (fname=0xcf7fc8c0 "tag") at funmap.c:307
#1  0x19b1e40c in complt (flags=9, c=9, buf=0xcf7fc8c0 "tag", nbuf=64, cpos=3, \
nx=0xcf7fc83c) at echo.c:556
#2  0x19b1c8e6 in veread (fp=0x19b0ad50 "M-x ", buf=0xcf7fc8c0 "tag", nbuf=64, \
flag=9, ap=0xcf7fc8a4 "3") at echo.c:240
#3  0x19b1c5b0 in eread (fmt=0x19b0ad50 "M-x ", buf=0xcf7fc8c0 "tag", nbuf=64, \
flag=9) at echo.c:181
#4  0x19b1f8dc in extend (f=0, n=1) at extend.c:536
#5  0x19b27b5b in mgwrap (funct=0x19b1f880 <extend>, f=0, n=1) at kbd.c:461
#6  0x19b27a61 in doin () at kbd.c:167
#7  0x19b2b380 in main (argc=0, argv=0xcf7fca18) at main.c:244

etc