hitode909の日記

以前はプログラミング日記でしたが、今は子育て日記です

最近のPerlでflymakeする

Cartonとplenvを使ってるときでもflymakeできるようにした.
flymakeはEmacs上でシンタックスチェックするやつ.


まず,exec-path-from-shellで環境変数を設定しておく.
これすると,.zshenvとかに書いた環境変数がEmacsに引き継がれる.(getenv "PATH")してシェルと同じくらいPATHが設定されてたらうまくいってる.MySQLを/usr/local/mysql/に入れてるときはDYLD_LIBRARY_PATHも設定する.

(exec-path-from-shell-initialize)
(exec-path-from-shell-copy-env "DYLD_LIBRARY_PATH")


flymakeの設定こんな感じ.

(defun flymake-perl-init ()
  (let* ((root (expand-file-name (or (vc-git-root default-directory) default-directory))))
    (list "perl" (list "-MProject::Libs lib_dirs => [qw(local/lib/perl5), glob(qw(modules/*/lib))]" "-wc"  buffer-file-name) root)
    ))

(push '(".+\\.p[ml]$" flymake-perl-init) flymake-allowed-file-name-masks)
(push '(".+\\.psgi$" flymake-perl-init) flymake-allowed-file-name-masks)
(push '(".+\\.t$" flymake-perl-init) flymake-allowed-file-name-masks)

(add-hook 'cperl-mode-hook (lambda () (flymake-mode t)))


PATHが設定されてれば,plenvが.per-versionを見て適切なPerl呼んでくれる.
Project::Libsを使う.local/lib/perl5を設定してるのは,Cartonでインストールするとここに入るので追加する.Project::Libsがlocal/lib/perl5以下に入ってても意味ないので,普通にcpanm Project::Libsして入れる.
globしているのは会社のリポジトリの都合で,modules/なんとか にGitのサブモジュールを置いていて,Project::Libsはmodules/なんとかにGitのサブモジュールがあれば読み込んでくれるのだけど,Gitリポジトリじゃなくて,単なるディレクトリとかを置いてると読んでくれないので,globして指定した.この設定いらない人もいると思う.
listの最後にGitのルートディレクトリを設定している.これすると,コマンドがこのディレクトリで実行される.flymakeのソースコード読んでたら見つけた.use lib;とかしてるときとか,modules/*/libをglobするときとか,リポジトリのトップから実行しないとおかしくなることがある.
Gitじゃないときもプロジェクトのトップから実行するほうがよいだろうけど,ソースコード触ることないので,手抜きで,default-directoryから実行するようにした.

雑談(1)

.zshenvにPATHの設定書いてれば,M-! which perlとかしたときに,.zshenvも読まれて,正しい環境変数が設定されて便利だった.
これでだいたいうまくいって,EmacsからPerlのテスト実行するのとか,carton exec -- perl なんとか.tとか普通に書けばテストできる..zshenvにPATHの設定書けばplenv.el使う必要ないという認識でいる.
flymakeも同じ調子でできるかと思ったけど,M-! で実行したときはシェルが実行されていて,flymakeから実行するときは単なるプロセスとして実行される点がちがう.なので,flymakeからplenvのPerlとかを呼ぶためには,Emacs側の環境変数を設定しないといけない.
PATH設定するだけではだめで,DYLD_LIBRARY_PATHとか,他にも設定しないといけないのもある.自動で設定されないからちょっと不便だと思う.
exec-path-from-shellを使わず,毎回シェルを起動する方法もあってこのほうがメンテナンスが楽だと思ったけど,見た目が不気味だった.flymakeどうせ遅いからこっちでもいい気もする.これにすればexec-path-from-shell要らない.

(defun flymake-perl-init ()
  (let* ((perl (guess-plenv-perl-path))
         (root (expand-file-name (vc-git-root default-directory))))
    (list shell-file-name (list "-c" (format "perl '-MProject::Libs lib_dirs => [qw(local/lib/perl5), glob(qw(modules/*/lib))]' -wc %s" (shell-quote-argument buffer-file-name))) root)
    ))

雑談(2)

flymakeはデフォルトでは何も言わず,中でどうなってるのかよく分からない.

(setq flymake-log-level 3)

とすると,Messagesにログが出て,ちょっと便利.


それだけでは不十分だったので,プロセスから返った内容もMessagesに出して観察してた.これは関数を上書きして観察する感じでひどい.

(defun flymake-process-filter (process output)
  "Parse OUTPUT and highlight error lines.
It's flymake process filter."
  (let ((source-buffer (process-buffer process)))

    (flymake-log 3 "received %d byte(s) of output from process %d"
                 (length output) (process-id process))
    (message "----------")
    (message output)
    (message "~~~~~~~~~~")
    (when (buffer-live-p source-buffer)
      (with-current-buffer source-buffer
        (flymake-parse-output-and-residual output)))))


あと,環境変数どうなってるか調べるために,envとかを実行させて様子を見たりしてた.envを見たらPATHが変だったとか気付けた.

(defun flymake-perl-init ()
  (let* ((root (expand-file-name (or (vc-git-root default-directory) default-directory))))
    (list "env")
    ))

雑談(3)

flymake動くようにするのなんか半日くらいかかってつらかった.週末主にEmacsの設定したら終わった.
昨日も500円ギネス飲みに行って,3日連続でギネス飲んでフィッシュ&チップス食べたら飽きてきておもしろかった.毎日食べたら主食みたいな扱いになる.その後寿司食べたらかつてない感じで寿司おいしかった.