gfortran + Flymake
最近,仕事の都合で,Fortranで数値計算をしている。CompilerとしてはGNU Fortranを使っているのだけど,GNU Fortranのerror出力が
test2.f:8.72:
COMMON/PYDAT1/MSTU(200),PARU(200),MSTJ(200),PARJ(200)
1
Error: Unexpected COMMON statement at (1)
test2.f:10.72:
CALL PY3ENT(0,1,21,-1,30D0,0.9D0,0.7D0)
1
Warning: Procedure 'py3ent' called with an implicit interface at (1)
みたいな破滅したカンジになっているので,あの有名なFlymakeが使えない。いや,使えるんだけど,警告がerror扱いされてしまって非常に困る。
と言うわけで,このメッセージをいわゆる「Flymake的に正しい」形,具体的にはgccのエラー出力
foobar.c:1: error: expected identifier or ‘(’ before ‘%lt;’ token
foobar.c:98:46: warning: unknown escape sequence '\c'
みたいに翻訳してくれるscriptを書いた。
#!/usr/bin/perl
our @hold;
our ($fname,$line,$ch);
foreach(<STDIN>){
if($_ =~ "^ " || $_ =~ /^\s*$/){ # ignore
push(@hold,$_);
}
elsif($_ =~ /^(Warning|Error):/ and $fname && $line && $ch){ # The last line of Message-block
chomp($_);
print "$fname:$line: $_ (ch.$ch)\n";
&clear_all;
}
elsif($_ =~ /^(.+?):(\d+?)\.(\d+):(\s*)/){ # The first line of Message-block
push(@hold,$_);
($fname,$line,$ch) = ($1,$2,$3);
}
else{ # just print the line if it seems not in a Message-block
push(@hold,$_);
print @hold;
&clear_all;
}
}
print @hold; # print rest lines
exit 0;
sub clear_all{
undef(@hold);
undef($fname);
undef($line);
undef($ch);
}
これをerrwrapper.plとかで保存して,g77の標準error出力を標準出力に持っていった上でpipe使ってこいつに食わせてやると幸福が実現するんじゃないかと思います。つまりg77 -fsyntax-only test1.f 2>&1 | perl errwrapper.plとか。
で,こいつをflymakeに設定してやれば良いわけですね!
Fortran + Flymakeの設定をもう少し詳しく説明してみる
さて,Flymakeを使うには,makefileを使う方法と,.emacs中で直接commandを指定する方法の2通りが在りますが,このwrapperを使う方法はmakefileによる方法でしか使えません!!!
まぁもちろんみなさん当然makefileを使っているはずなので大丈夫でしょうが。
基本的に,.emacsの中に
;makefileがある場合にどういうcommandで文法確認をするかの設定
(defun flymake-fortran-get-make-cmdline (source base-dir)
(setq source source)
(list "make"
(list "-s"
"-C"
base-dir
(concat "CHK_SOURCES=" source)
"LANG=C"
check-syntax-f)))
(defun flymake-fortran-init ()
(setq buffer-dir (file-name-directory buffer-file-name))
(if (file-readable-p (expand-file-name (concat buffer-dir "makefile")))
;makefileがある場合
(flymake-simple-make-init-impl
'flymake-create-temp-inplace t t "makefile" 'flymake-fortran-get-make-cmdline)
;makefileが無い場合
(let*
(
(temp-file (flymake-init-create-temp-buffer-copy 'flymake-create-temp-inplace))
(local-dir buffer-dir)
(local-file (file-relative-name temp-file local-dir)))
(list "gfortran" (list "-Wall" "-Wextra" "-fsyntax-only" local-file)))))
(defconst flymake-allowed-fortran-file-name-masks
'(("\\.f$" flymake-fortran-init flymake-simple-cleanup flymake-get-real-file-name)))
(setq flymake-allowed-file-name-masks flymake-allowed-fortran-file-name-masks)
(flymake-mode t)
のような形でflymakeの設定をしていると思います。makefileがある場合にはcheck-syntax-fにより文法を確認する,という設定ですね。だから,makefileの中のこいつを,通常の
check-syntax-f:
$(FC) -fsyntax-only $(FFLAGS) -S ${CHK_SOURCES}
から
check-syntax-f:
$(FC) -fsyntax-only $(FFLAGS) -S ${CHK_SOURCES} 2>&1 | perl errwrapper.pl
に変更してやればよいだけです!簡単ですww
Comments
名無しさん 2010/07/19(Mon) 16:37:43
その様子だと今年度の国1は落ちたな
みしょ 2010/07/19(Mon) 17:18:03
あ,受かってますw
もうすぐ人事院から成績が届くのでそれと一緒に書こうと思って……。