勝手にmakeでMonaの開発効率を上げよう

昨日のDevelopment Environment Conferenceで最速の中の人がCSSを編集したら即座にブラウザに反映するってのをデモしていて「待ち時間が少ない方が効率が良い」的な話をしていました。


僕みたいなLLでない人は、冷静に考えると開発時間の10%位はビルドに要していて、しかもその時間は「ぼーっ」としているのが現状です
ちょこちょこスクリプトを書いてこれを改善できれば、かなり開発の効率があがるのではないかと思いやってみました。

分析

まずは現在の作業を洗い出してみます。


1.~/mona/contrib-fast-gui/Misc/test/test.cppを編集します。


2.キリの良いタイミングで make && make installします。


3.エラーがあれば修正後、make しエラーがなくなるまでこれをくり返します。


4.~/mona/contrib-fast-gui/で make します。これは最終的に mona.iso を作ります。


5.qemuMonaを起動


6.Mona のシェルで BAYGUI 起動


7.BAYGUIのランチャで TEST を起動


8.動作確認


コード編集から動作確認までがかなり遠いですね。

Mona側で改善

6.は AUTOEXEC.MSHにBAYGUIと書いておけば良いです。
7.は BAYGUI.INIの Run にアプリケーションのフルパスを書いておけば良いでしょう。


ちなみに Run項目は , で区切ればいくつもアプリケーションの指定が出来ます。知ってました?

ビルド改善

ビルドの改善ですが、ファイルの保存時にこっそり裏で make を可能な限り進めてしまうという戦略が良いと思いました。
保存の度に make が走ると思うと、重いし無駄だという印象があると思いますがマシンパワーも余っていますし、多少無駄でもそれが開発効率アップにつながるならば良いでしょう。

さっそくファイルの保存に hook して make のやりかたを調べました。

(add-hook 'after-save-hook
   (lambda () (compile "make")))

のように書けます。


これが基本ですが、とにかくいろいろ不満があります。

  • バッファと同じディレクトリにMakefileがない場合は動作させたくない
  • compilationウィンドウがひろがるのが邪魔。結果だけが知りたい
  • (compile)は非同期なので、compile終了に hook して結果を表示したい

これらをがんばって改善したのは以下の Emacs Lisp です。
エラー処理とか手を抜いていますが期待の動作が得られています。

;; 編集中のアプリのpathから contrib/Makefileのpathを返す
(defun mona-build-contrib-makefile-path (filename)
  (string-match "\\(.+contrib[^\/]*\\)" filename)
  (format "%s/Makefile" (match-string 0 filename)))

;; compile windowを小さくして compile
(defun mona-build-silent-compile (command)
  (let ((save-height compilation-window-height))
    (setq compilation-window-height 1)
    (message "compiling") 
    (compile command)
    (setq compilation-window-height save-height)))

;; 改行削除(絶対既にあるだろうな)
(defun mona-build-chop (str)
  (replace-regexp-in-string "\n" "" str))

;; カレントバッファを保存すると勝手にmakeしてあわよくば mona.iso までつくってしまう
(add-hook 'after-save-hook 'mona-build-auto-make)
(defun mona-build-auto-make ()
  (if (file-exists-p (expand-file-name "Makefile"))
      (progn
        (message (expand-file-name "Makefile"))
        (setq compilation-finish-function
              (lambda (buffer result)
                (if (string-match "abnormally" result)
                    (progn
                      (setq compilation-finish-function nil)
                      (message
                       (format "%s result %s" (current-buffer) (mona-build-chop result))))
                  (progn
                    (setq compilation-finish-function
                          (lambda (b r)
                            (message
                             (format "mona.iso result %s" (mona-build-chop r)))))
                    (message
                     (format "%s result %s" (current-buffer) (mona-build-chop result)))
                    (save-current-buffer
                      (progn
                        (set-buffer (find-file-noselect (mona-build-contrib-makefile-path (expand-file-name (buffer-name(current-buffer))))))
                        (mona-build-silent-compile "make")))))))
        (mona-build-silent-compile "make install"))))


実際に動かしてみましたが、予想以上に効率が上がります。
ファイルを無意識に保存すると、数秒「mona.iso 出来たよ」とか「エラーだよ」って言われます。
エラーであればエラーの詳細を見て保存すれば良いですし、エラーがないのであれば好きなときにQEMUを起動すれば良いだけです。


しかしこのTipsは、世界中で僕一人にしか役に立たない気がしてきたなぁ。
Mona開発者で Emacs 使いは他にいたっけか。

蛇足1

Emacs Lispの開発をしていて思ったのですが、何度も書き直して試行錯誤する際に「 add-hook をなかったことにしたい」とか「add-hookに登録していたメソッドを今のメソッドと入れ換えたい」とか思うんですが、ついついEmacs再起動で済ませてしまいます。
何か良い方法ないかな。

蛇足2

Development Environment Conference宮川さんQEMUの事を 「けむ」「きぇむ」みたいに発音されてたんですが、僕は今まで「きゅーえみゅ」って発音してました。
ひょっとして海外では「きぇむ」なのかな。どきどき。