みしょのねこごや

Diary - 2010年7月

みしょの今後の予定について

各位

みしょの8月から10月にかけての予定がまとまりましたので御連絡申し上げます。東京にいない日々が続きますので,御注意下さい。

  • 8月5日~8月11日は,原子核三者若手 夏の学校のため,長野県に滞在しています。
  • 8月12日~8月19日は,SI2010のため,山梨県に滞在しています。
  • 8月20日~9月10日は,東京にいます。
  • 9月11日~9月14日は,日本物理学会 2010年秋季大会のため,福岡県にいます。
  • 9月15日~9月23日は,大分県の実家に帰省しています。
  • 9月26日~10月1日は,東京にいますが,COSMO/CosPA 2010に参加しているため時間はありません。
  • 10月3日~10月中旬にかけては,欧州にいます。

というわけで,8月20日~9月10日と9月24・25日以外は全て予定が埋まっておりますので,御注意下さい。

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