この記事に書いてあること
指がVimに慣れきってしまっている筆者は、Vimを 「エミュレート」 する他のエディタのプラグインでは満足できなくなってしまいました。Fortran, R, Python, bash, 。。。全て Vim (Neovimではない) で編集しているのですが、この記事はFortranをVimで編集する際の環境を徒然なるままに記録した記事です。(特定のツールや手法を推奨する意図はありません。)
VimとLSP
Vimは、.vimrcに syntax on
と書くだけでfortranのシンタックスハイライトが可能です。
その他にも、開いたファイルに記述済みの文字列に対しては Ctl+N, Ctl+P などで補完が効きます。
一方、デフォルトでは、ライブラリで定義されたサブルーチンや、Fortran言語自身で定義済みのモジュール変数などは初出箇所で補完することができません。そこで、最近流行りのLSPを導入し、ソースコードの編集を便利にしてみます。
自動補完環境を導入
導入方法の一例は昔の記事に書きましたが、OSなどの環境によって変わると思います。
Ubuntu20.04だとaptでfortlsを導入できるようです。
なお、2021/12時点の私の.vimrc (一部抜粋)は次のようになっています。
"--- vim plug settings ---
call plug#begin('~/.vim/plugged')
Plug 'majutsushi/tagbar'
Plug 'kshenoy/vim-signature'
Plug 'Yggdroot/indentLine'
"--- languadge server protocol
Plug 'prabirshrestha/asyncomplete.vim'
Plug 'prabirshrestha/asyncomplete-lsp.vim'
Plug 'prabirshrestha/vim-lsp'
Plug 'mattn/vim-lsp-settings'
Plug 'mattn/vim-lsp-icons'
"--- Outliner
Plug 'vim-voom/voom'
call plug#end()
"--- Language server protocol の設定
let g:lsp_diagnostics_enabled=1
let g:lsp_diagnostics_echo_cursor=1
let g:lsp_text_edit_enabled=1
let g:asyncomplete_auto_popup=1
"let g:asyncomplete_auto_completeopt=0
let g:asyncomplete_popup_delay=200
LSPの機能を使ってみる
カレントディレクトリのソースファイルに定義された関数類はLSPによる補完対象となりますが、設定ファイルを適切に編集すれば、その他のフォルダに保存されたソースコードも補完対象とすることができます。
ここでは、基本的な線形代数演算を行うBLASに定義された関数を補完対象に追加してみます。
mkdir sample-fortls
cd sample-fortls
wget http://www.netlib.org/blas/blas-3.10.0.tgz
tar xvzf blas-3.10.0.tgz
なお、上記でダウンロードしたコードはリファレンス実装なので、ここでは定義を参照するためだけに使います。
実際のアプリケーションをビルドする際には、OpenBLASやベンダ製のライブラリを使う方が速いです。
カレントディレクトリ以外の場所をLSPに認識させるためには、.fortls
ファイルを編集します。
下記のようにBLASのソースコードの場所を指定します。
{
"source_dirs": ["./BLAS-3.10.0/", "./"],
"include_dirs": ["./BLAS-3.10.0/"]
}
-
source_dirs
はインターフェイス定義やサブルーチン本体などが記述されたソースコードの場所です。 -
include_dirs
は、コンパイラで生成される.mod
ファイルの置き場所です1。
すると、下の図のように、関数名の先頭数文字を記入するだけで補完候補が現れるようになりました。
今回はBLASを例にとりましたが、自作ライブラリや、NAG数値計算ライブラリなどでも、関数のインターフェイス定義ファイルの場所を指定すれば同様のことが可能です。
画面分割とターミナルの活用
Vimは、ノーマルモードで K
を入力すると、OS付属のマニュアルを表示することができます。
Linuxでは man daxpy
とすると下図のようなドキュメントを表示されるので、調べたいキーワード上にカーソルを合わせて K
を押すことで、ソースコードとBLAS関数のリファレンスを行き来しながらコーディングが可能です。
画面分割の片方をターミナルにして、ターミナル上でmanコマンドなども良く使います(下図参照)。
短時間で終わるプログラムなら、:terminal
でターミナルを開き、結果をプロットさせることも、エディタを抜けずに(キーボードから手を離す事無く)実施可能です。
> p "< ./a.out" u 1:2 w l
Fortranに限った話ではありませんが、Vimの画面分割でターミナルを表示させることで、エディタを抜けず、かつマウスへ手を伸ばす必要なく、出来る事は無限に広がります。
-
htop
で並列実行の様子をリアルタイムモニタリング。 -
time
コマンドで時間計測。 -
make
orcmake
orconfigure
orctest
ormake check
などのコマンド実行。 -
ranger
でファイルのコピー、移動、シンボリックリンクの作成など2。
Modern Fortranのデバッグ
fortranとデバッグという記事では、普通の配列を用いた例のみを示していました。今回は、拡張型を使った場合の表示結果を例示します。
module deftype
use iso_fortran_env
implicit none
type t_base
real(real64),allocatable :: x(:),y(:)
contains
procedure :: vecsum => vecsum_base
end type
type,extends(t_base) :: t_ex1
real(real64),allocatable :: z(:)
contains
procedure :: vecsum => vecsum_ex1
end type
contains
function vecsum_base(self)result(vout)
class(t_base) :: self
real(kind=real64) :: vout
vout=sum(self%x)+sum(self%y)
end function
function vecsum_ex1(self)result(vout)
class(t_ex1) :: self
real(kind=real64) :: vout
vout=sum(self%x)+sum(self%y)+sum(self%z)
end function
end module deftype
!==============================================
program modern_test
use deftype
implicit none
type(t_base) :: bs
type(t_ex1) :: ex1
integer,parameter :: n=10
allocate(bs%x(n),bs%y(n),source=1d0)
allocate(ex1%x(n),ex1%y(n),ex1%z(n),source=1d0)
print*, "bs :",bs%vecsum()
print*, "ex1:",ex1%vecsum()
end program
!==============================================
下図は、次の手順を実施した時の画面例です。上段がgdb入出力、中段が標準出力、下段がソースコードで、これらが連携されて表示されます。(Ubuntu20.04,Vim8.1,gdb9.2の組み合わせ)
- ソースコード35行目まで実行。
- メインプログラムのスコープで
bs
とex1
を表示。 - 36行目のprint文に入り、18行目の
vecsub_base
関数に入る。 - 引数の
self
を表示。
プログラム実行中のスコープ如何により、self
(データが定義されているスコープではbs
)のデータ成分が値として表示されていたり、アドレス(?)で表示されていたりします。データの定義部分のスコープに移動すれば値が表示されることがあり、gdb内でup
やdown
を繰り返していくことで、目的のデータの値を知ることができる場合もあります。
アドレスから値を知る方法については詳しくないので、上記写真のp self
の結果を値で表示させる方法をご存知の方、コメントいただけると有り難いです。
おわりに
Vimで:help fortran
とすると、Fortranに関する文法ハイライトやシンタックスフォールディングの設定項目に関する説明があります。好みに応じて.vimrc
に設定を追記することで、より幸せなFortranライフを送ることができると思います。