VSCodeのFortran向け拡張を整理，最新化する（2022年6月）

# 概要
- VSCodeにあるFortran向けの拡張は，Modern Fortran拡張に一本化できるようになりました．
- fortran-language-serverは，それから派生したfortlsに置き換えられます．
- Anacondaユーザは，pipではなくcondaでfortls, fprettifyをインストールできます．

# テスト環境
- Windows 10 64 bit 21H2
- Fortranコンパイラ
    - gfortran 10.3 ([quickstart fortran](https://github.com/LKedward/quickstart-fortran) bundle)
    - Intel OneAPI 2021.5.0
- conda 4.13.0
- VSCode 1.68
- VSCode拡張
    - Modern Fortran v3.1.0
    - C/C++ v1.10.5
- fortls 2.9.0
- fprettify 0.3.7
- Visual Studio 2017

# 背景
VSCodeには非常に多くの拡張が存在しており，それらを用いることでプログラミングの体験を大きく改善できます．Fortranも例外ではなく，VSCodeと拡張機能を利用することで，開発の効率化を実現できます．

一方で，Fortranには万能な拡張がなく，色々な拡張を併用する必要がありました．例えば，以下の拡張機能が有名です．

- Modern Fortran: プログラミング言語モードの設定，Lint，シンタックスハイライト，コードスニペット
- FORTRAN IntelliSense: 言語サーバの利用，コードナビゲーション
- Fortran breakpoint Support: デバッグ時のブレークポイントの設定
- vscode-modern-fortran-formatter: ソースコードの自動整形

これら以外にも，重複する拡張機能がいくつかあります．残念ながら上記の拡張より機能が少なく，開発も早期に停滞しました．

- fortran: プログラミング言語モードの設定，シンタックスハイライト，コードスニペット
- fortran - ekon: 同上
- fprettify: ソースコードの自動整形
- fixedformfortranlinter: Lint

これらの拡張のうち，[Modern Fortran](https://marketplace.visualstudio.com/items?itemName=fortran-lang.linter-gfortran)拡張は開発が続けられ，言語サーバの利用，デバッグ，ソースコードの自動整形の機能を取り込んできました．また，Modern Fortran拡張は[fortran-lang](https://fortran-lang.org)に取り込まれ，fortran-langのプロジェクトの一つして開発が継続されることになりました．そのため，今後も精力的な開発が続けられると期待されます．

この記事では，これまで複数利用していた拡張をModern Fortran拡張に一本化し，その設定について解説します．また，Modern Fortran拡張が利用していたPythonパッケージについても，最新版に変更します．

# Modern Fortran拡張が利用するPythonパッケージの更新
Modern Fortran拡張は，言語サーバの利用，およびソースコードの自動整形のためにPythonパッケージを利用します．

## 言語サーバ
言語サーバは，fortrran-language-serverという名前のパッケージを利用していました．Modern Fortran拡張の開発者は，fortran-language-serverから派生したプロジェクトを立ち上げ，[fortls](https://github.com/gnikit/fortls)という名前で開発を進めています．

fortlsは，pipまたはcondaを用いてインストールできます．

### pip
```console
pip install fortls
```

### conda
```console
conda install -c conda-forge fortls
```

fortran-language-serverはpipからしかインストールできなかったため，Anacondaユーザはpipとcondaを混ぜて利用する事に苦悩していたと思います．fortlsはcondaでインストールできるので，この苦悩から解放されます．

## 自動整形
ソースコードの自動整形には，[fprettify](https://github.com/pseewald/fprettify)および[findent](https://github.com/MFTabriz/findent)が利用できます．fprettifyはvscode-modern-fortran-formatterからも利用されていたので，利用している人は多いと思います．

fprettifyもpipまたはcondaを用いてインストールできます．

### pip
```console
pip install fprettify
```

### conda
```console
conda install -c programfan fprettify
```

# Modern Fortran拡張の最新化
Modern Fortran拡張の最新バージョンはv3.1.0です．VSCodeのバージョンが最新になっていれば，自動的に最新バージョンに更新されます．

上述のとおり，Modern Fortran拡張がfortran-langに取り込まれたことに伴い，Modern Fortran拡張に割り当てられている拡張機能IDが`krvajalm.linter-gfortran`から`fortran-lang.linter-gfortran`に変更されました．

extensions.jsonの`"recommendations"`に拡張機能IDを記述していた場合は，それを修正しないと，marketplaceに拡張機能が無いという警告を見続けることになります．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/d0a40982-726a-4d6d-b005-05e100a2c1cf.png)

また，いくつかのオプション名が変更になったため，バージョンを上げた際にdepricated optionとして表示されます．

|旧|新|
|:--|:--|
|`fortran.gfortranExecutable`|`fortran.linter.compilerPath`|
|`fortran.includePaths`|`fortran.linter.includePath`|
|`fortran.linterExtraArgs`|`fortran.linter.extraArgs`|
|`fortran.provideCompletion`|`fortran.provide.autocomplete`|
|`fortran.provideHover`|`fortran.provide.hover`|
|`fortran.provideSymbols`|`fortran.provide.symboles`|

## linterの設定
Modern Fortranは，lintにgfortranを用いていました．そのため，Intel Fortranユーザもgfortranをインストールする必要がありました．現在のModern Fortranは，gfortranに加えて，ifortおよびifxもlintに利用できるようになりました．

Modern Fortranは，ソースファイルを開いた際に，.modファイルを作成してそれをlintに利用します．Fortranの.modファイルはコンパイラ間で互換性がないため，外部ライブラリをシステムにインストールして利用する際に，当該ライブラリが持つモジュールや，定数，手続をModern Fortranに認識させるためには，不要であってもgfortranで一度ビルドして.modファイルを作成するなどの手間が必要でした．

現状では，Intel Fortran利用者はその手間がなくなりました．今はgfortranおよびIntel Fortranだけですが，NAG fortranやflangをlintに利用できるようにする開発計画があるようです．

lintに利用するコンパイラは，`Fortran › Linter: Compiler`でプルダウンメニューから選択し，その実行ファイルのフルパスを`Fortran › Linter: Compiler Path`で指定します[^linterbug]．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/b0330935-c3f8-29d3-5c92-3fe3e050d118.png)
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/fd437119-5c49-6fd4-c9e9-fe4184f265d8.png)


[^linterbug]: `v3.1.0`より前のバージョンでは，実行ファイル指定の設定が異なっており，実行ファイルが置かれているディレクトリのパスを指定しないと正しく認識されませんでした．これがバグなのか挙動を変更したのかは判りません．設定の説明が変わっていないように見えるので，私はバグだと判断しています．

gfortranとifortを切り替えてみると，表示されるエラーが変化することが確認できます．

- gfortranをlintに利用した場合
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/5c524dbe-b6d1-f835-30a1-bcb7e60bf16e.png)

- ifortをlintに利用した場合
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/a3f66dd0-6e20-3356-f135-645cb4dffe87.png)


lintのためにFortranコンパイラを実行する際のオプションは，`Fortran › Linter: Extra Args`で指定します．

## Formatterの設定
ソースの自動整形に使うFormatterも，linterと同じように設定します．

整形に利用するFormatterは，`Fortran › Formatting: Formatter`でプルダウンメニューから選択し，その**実行ファイルがあるディレクトリのパス**を`Fortran › Formatting: Path`で指定します．本記事ではfprettifyを利用します．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/0820c3af-8195-004b-eca6-b0cfec3f166a.png)
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/209ed5a7-0ea2-99a1-4daf-2b49d7fd8e4e.png)


fprettifyに渡すオプションは，`Fortran › Formatting: Fprettify Args`に記述します．設定の記述にはかなりクセがあり，スペースを区切りとして全て別々の項目として書いていきます．例えば，`--indent 4 --enable-decl --strip-comments --case 1 1 1 1`というオプションを記述するには，`"--indent","4","--line-length","256","--enable-decl","--strip-comments","--case","1","1","1","1"`と区切る必要があります．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/2ef4b2aa-bcbf-e56b-e8cc-4d1c935b8a4b.png)

- 自動整形前
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/9461794a-1108-5305-ce5f-2ae768e64026.png)
- 設定したオプションによる自動整形
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/0a3a7a2f-1ea2-151e-c8d3-df25b5c2f964.png)

自動整形を有効にするには，VSCode自体の設定も必要です．

`Editor: Format On Save`を有効（チェックボックス☑にチェックを入れる）にし，`Editor: Default Formatter`を`なし`に設定します．

## 言語サーバの設定
最後に，Modern Fortranから呼び出す言語サーバの設定を行います．

言語サーバは，`Fortran › Fortls: Path`にfortls（実行ファイル）のフルパスを指定します．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/246437b9-5d5e-10ca-1486-860a59ea6ff3.png)

その他，非常に多くの項目を設定できますが，基本的には標準設定のままで問題ありません．プリプロセスをよく利用する場合は，プリプロセスに関する設定や，ファイル拡張子に関する設定をしておくと便利です．fortlsの分析の対象にする/しないといったディレクトリの指定については，各プロジェクトに固有の設定ファイルを用意して，そこに設定を書いた方が柔軟に対応できます．設定ファイルは，標準ではプロジェクトのルートに`.fortls`という名前で置く必要があります．それ以外の名前については`Fortran › Fortls: Configure`で設定します．

## デバッグの設定
Modern Fortranは，C/C++拡張のデバッグの機能を利用して，Fortranプログラムのデバッグ実行を可能にします．デバッガには，gdbもしくはVisual Studioのデバッガが必要です．Windowsの場合，gfortranでコンパイルしたプログラムにはgdb，ifortでコンパイルしたプログラムにはVisual Studioのデバッガを利用します．

デバッグの例のために，下記のような構成でプログラムを作成します．main.f90を含むフォルダをVSCodeで開いているとします．

```console
.
└── main.f90
```

```Fortran
program main
    use, intrinsic :: iso_fortran_env
    implicit none

    real(real32) :: f(4) = [1.0, 2.0, 3.0, 4.0]

    block
        integer(int32) :: i
        do i = 1, size(f)
            f(i) = f(i)*2
        end do
    end block

    print *, f
end program main
```

VSCodeでデバッグ実行するには，`.vscode/launch.json`ファイルにデバッグ実行の設定を記述します．プロジェクトルートに`.vscode`ディレクトリを作成し，空の`launch.json`ファイルを作成します．

```console
.
├── main.f90
└── .vscode
    └── launch.json
```

VSCodeでそのファイルを開くと，[構成の追加]ボタンが現れるので，それを押すといくつかの既存構成が一覧で現れます．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/9397586b-a9d2-1acb-f486-f02870400b29.png)
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/b188e804-477d-ce50-fb14-4d5bf925c8fc.png)


gfortran用の（gdbを使う）設定は，`C/C++: (gdb) 起動`，ifort用の（Visual Studioを使う）設定は，`C/C++: (Windows) 起動`を選択します．`launch.json`には複数の構成情報を書くことができます．

### gfortran用の設定
`C/C++: (gdb) 起動`を選択して既存構成を読み込むと，下記のような内容が挿入されます．

```json
{
    "configurations": [
        {
            "name": "(gdb) 起動",
            "type": "cppdbg",
            "request": "launch",
            "program": "プログラム名を入力してください (例: ${workspaceFolder}/a.exe)",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "/path/to/gdb",
            "setupCommands": [
                {
                    "description": "gdb の再フォーマットを有効にする",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description":  "逆アセンブリ フレーバーを Intel に設定",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}
```

ここで編集する必要がある項目は，`"program"`, `"cwd"`, `"miDebuggerPath"`です．それぞれ下記のように編集します．

```diff
-            "program": "プログラム名を入力してください (例: ${workspaceFolder}/a.exe)",
+            "program": "${workspaceFolder}/a.exe",
```
```diff
-            "cwd": "${fileDirname}",
+            "cwd": "${workspaceFolder}",
```
```diff
-            "miDebuggerPath": "/path/to/gdb",
+            "miDebuggerPath": "gdb",
```

Windowsであっても，パスの区切りは`/`でよいようです．`a.exe`としているのは，gfortranを用いたときに標準で付けられる実行ファイル名だからという単純な理由です．`-o`オプションで実行ファイルの名前を指定する場合は，その指定した名前を利用してください．

```json
{
    "configurations": [
        {
            "name": "(gdb) 起動",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/a.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "miDebuggerPath": "gdb",
            "setupCommands": [
                {
                    "description": "gdb の再フォーマットを有効にする",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description":  "逆アセンブリ フレーバーを Intel に設定",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ]
        }
    ]
}
```

### ifort用の設定
`C/C++: (Windows) 起動`を選択して既存構成を読み込むと，下記のような内容が挿入されます．

```json
{
    "configurations": [
        {
            "name": "(Windows) 起動",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "プログラム名を入力してください (例: ${workspaceFolder}/a.exe)",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "console": "externalTerminal"
        }
    ]
}
```

編集する項目はgfortran用の設定とほぼ同じで，ここで編集する必要がある項目は，`"program"`, `"cwd"`です．それぞれ下記のように編集します．

```diff
-            "program": "プログラム名を入力してください (例: ${workspaceFolder}/a.exe)",
+            "program": "${workspaceFolder}/main.exe",
```
```diff
-            "cwd": "${fileDirname}",
+            "cwd": "${workspaceFolder}",
```

`main.exe`は，ファイル名（`main.f90`）から採用しており，ifortを用いたときの標準の実行ファイル名（ソースファイルと同じ名前になる）です．`/exe:`や`-o`オプションで実行ファイルの名前を指定する場合は，その指定した名前を利用してください．

```json
{
    "configurations": [
        {
            "name": "(Windows) 起動",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/main.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "console": "externalTerminal"
        }
    ]
}
```

### デバッグの実行
#### プログラムのビルド
デバッグの前に，プログラムをデバッグ用にビルドします．

```console
gfortran -g main.f90
```

```console
ifort /debug:full main.f90
```

#### ブレークポイントの設定
デバッグの最中に，変数の値を確認等を行うためのに，プログラムを一時的に停止するブレークポイントの設定も行います．ブレークポイントは，エディターウィンドウに表示されているプログラムの行番号の左側をクリックすることで設定できます．ブレークポイントが設定できていると，行番号の左側に赤い丸が付き，デバッグ実行した際にこの赤丸の行でプログラムが一時停止します．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/152db19b-ee00-89d6-2626-fde221434963.png)

#### デバッグの実行
デバッグを実行するには，上部メニューの[実行]→[デバッグの開始]を選択するか，`F5`キーを押すか，サイドバーの[実行とデバッグ]を選択します．

デバッグが無事実行されると，ブレークポイントを設定した行が黄色くハイライトされ，デバッグウィンドウに情報が表示されます．変数と書かれている項目を展開していくと，配列`f`やループカウンタ`i`の数値を見ることができます．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/dc4ae0f6-8798-c82e-04b1-bd55bc65e8f9.png)

変数名が大文字になっているのは，おそらくifortが内部的に変数を全て大文字として扱っている（FORTRAN 77までは大文字しか扱えなかった）ことに起因していると考えられます．

エディターウィンドウに重なって表示されるツールバーから，[続行]をクリックすると，次のブレークポイントまで実行され，再び停止します．何度か[続行]をクリックしていくと，ループが進み，配列の値が変化していくことが確認できます．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/4f568ae4-1643-6d4c-daac-41dd53be3640.png)

上記の画像は，ifortでビルドしたプログラムをVisual Studioのデバッガでデバッグしたときの結果です．gfortranでビルドしたプログラムをgdbでデバッグしても，同じような結果が得られます．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/03dd48fa-adf0-e777-961f-210b649fb938.png)

#### 複数のデバッグ構成がある場合
`launch.json`に複数のデバッグ構成が書かれている場合，上部メニューの[実行]→[デバッグの開始]を選択する方法と，`F5`キーを押す方法では，どうやらファイルの前の方に書かれている構成に沿ってデバッグが行われるようです．

デバッグウィンドウではプルダウンメニューから構成を選択してデバッグを実行できます．

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/1f82cc3f-fa35-6f49-e5bf-7d88217ca6ca.png)


# まとめ
VSCodeのFortran向け拡張の現状を整理し，2022年6月時点で最新の状況に情報を更新しました．これまで複数の拡張を併用していた機能

- プログラミング言語モードの設定
- Lint
- シンタックスハイライト
- コードスニペット
- 言語サーバの利用
- コードナビゲーション
- デバッグ時のブレークポイントの設定
- VSCodeのデバッグウィンドウとの統合
- ソースコードの自動整形

については，Modern Fortran拡張に一本化できました．これにより，VSCodeとFortranを併用する際の環境構築が簡略化され，よりFortranを利用しやすくなりました．

fortran-langに合流したModern Fortran拡張には今後も大いに期待しています．