相対パスをフルパスに

先日、親ディレクトリにMakefileを探しにいってmakeするmake.shを書いて、それを使っていると思わぬ問題に遭遇した。使い始めて5分で。

next-errorでエラーに飛べない

/foo/Makefileを作っておいて、シンタクスエラーを含む/foo/bar/baz.mlをカレントバッファに読み込んだ状態でcompileする。すると/foo/までディレクトリをさかのぼってmakeするもんだから、コンパイラのエラーメッセージではbaz.mlはbar/baz.mlとなる。しかし、baz.mlを編集しているemacsバッファのカレントディレクトリは/foo/barなもんでbar/baz.mlを/foo/bar/bar/baz.mlとしてしまい「そんなファイルはみつからないよーと」なってしまい、全然便利じゃなかったのだ。

elispでなんとかしたいところだが、ちょっと調べてめんどくさくなったので「コンパイラの出力のうちコンパイルエラーっぽいやつを検出してファイル名をフルパスにするスクリプト」を書いた。

#!/usr/bin/env ruby

def expand_path(p)
  fp = File.expand_path(p)

  if RUBY_PLATFORM == "i386-cygwin"
    `cygpath -w #{fp}`.chomp()
  else
    fp
  end
end

if ARGV.size == 0
  exit 0
end

IO.popen("#{ARGV.join(" ")} 2>&1") {|io|
  while (l = io.gets())
    if l =~ /File \"([^\"]+)\", line (\d+), characters (\d+)\-(\d+)\:/
      f = expand_path($1)
      l = $2
      c1 = $3
      c2 = $4
      print "File \"#{f}\", line #{l}, characters #{c1}-#{c2}:\n"
    else
      print l
    end
  end
}

exit $?.exitstatus

こんなん。CYGWINの処理が気持ち悪いけど、どうせMeadowLinuxemacsからしか使わないからこれでいいや。

$ full_path.rb ocamlc foo.ml

みたいに使います。

あー便利だ。これでデバッグが当社比3倍くらいの速さで進むに違いない(棒読み)。