fpm (Fortran Package Manager)の設定ファイルの解説

# 概要
fpm(Fortran Package Manager) 0.5.0（執筆時点での最新バージョン）の設定ファイル`fpm.toml`について解説します．

具体的なプロジェクトの作成例は，[次の記事](https://qiita.com/implicit_none/items/08a2d26f8288dda7b4f5)にまとめました．

# 環境
- Windows 10
- fpm 0.5.0
- gfortran 10.3.0 (TDM-GCC-64)
- Intel oneAPI 2021.1
- git 2.29.2

Windowsで実行し，動作確認をしています．パスの区切りは`\`になっています．Unix系OSで動かす場合には，パスの区切りを`/`に置き換えてください．

# fpm
[fpm](https://github.com/fortran-lang/fpm) (Fortran Package Manager)は，Fortran-langプロジェクトの一環として開発されているパッケージマネージャ兼ビルドツールです．fpmが対象とする範囲は，ビルドツールとしての範囲とパッケージマネージャとしての範囲があります．

詳しくは前の記事を確認してください．

# fpmの設定ファイル
fpmは，ビルドの設定を`fpm.toml`に記述します．この設定のことをfpmではmanifestとよんでいます．

## manifestの詳細
manifestの解説は[Fortran package manager (fpm) manifest reference](https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md)にあります．

一つずつ解説していくのも大変なので，とりあえず`fpm new`で作られる標準の`fpm.toml`の内容から解説していきます．

## 標準のfpm.toml

標準の`fpm.toml`の中を見ると，`[]`で分類分けされている設定と，されていない設定が見つかります．分類分けされていない設定は，プロジェクトの概要に関係しています．分類分けされている設定は，fpmの動作に関係しており，例えば`[build]`は`fpm build`の動作に関係した設定です．

```toml
name = "sample"
version = "0.1.0"
license = "license"
author = "Jane Doe"
maintainer = "jane.doe@example.com"
copyright = "Copyright 2021, Jane Doe"
[build]
auto-executables = true
auto-tests = true
auto-examples = true
[install]
library = false
```

### プロジェクトの概要
`fpm.toml`に書かれているプロジェクトの概要を設定する項目の意味は，下記の通りです．

- `name`<br>プロジェクトの名前
- `version`<br>プロジェクトのバージョン
- `license`<br>プロジェクトのライセンス
- `maintainer`<br>プロジェクトのメンテナ
- `author`<br>プロジェクトの作者
- `copyright`<br>プロジェクトのコピーライト

`name`はプロジェクトの名前を意味するだけでなく，fpmパッケージの名前としても用いられます．

### ビルドの設定[build]
`auto-executables`, `auto-tests`, `auto-examples`が設定されています．

これらは，標準のディレクトリ`app`, `test`, `example`内からメインルーチン（＝ターゲット）を自動で探してビルドするか否かを制御する設定です．標準では有効に設定されています．

ディレクトリに標準と異なる名前を付けるような場合，たとえば`tests`などに変更する場合は，`auto-tests`の設定を削除するか，`auto-tests=false`として無効にします．その後，ターゲットの設定でテスト用のソースが格納されているディレクトリ，テストの名前，ソースファイル名を列挙します．

### インストールの設定[install]
ここでは，`src`ディレクトリにあるモジュール群をビルドして作られるライブラリを，インストールの対象とするかを設定します．

標準では無効になっており，インストールされるのは実行ファイルのみです．ライブラリおよび`.mod`ファイルもインストールの対象とするには，`library = true`とします．

# 設定一覧
- [`name`](#プロジェクト概要)
- [`version`](#プロジェクト概要)
- [`license`](#プロジェクト概要)
- [`maintainer`](#プロジェクト概要)
- [`author`](#プロジェクト概要)
- [`copyright`](#プロジェクト概要)
- [`description`](#プロジェクト概要)
- [`categories`](#プロジェクト概要)
- [`keywords`](#プロジェクト概要)
- [`homepage`](#プロジェクト概要)
- [`[build]`](#ビルド設定build)
    - `auto-executables`
    - `auto-tests`
    - `auto-examples`
    - `external-modules`
    - `link`
- [`[dependencies]`](#依存関係設定dependencies)
- [`[library]`](#ライブラリ設定library)
    - `source-dir`
    - `include-dir`
- [`[[executable]]`](#実行ファイル設定executable)
    - `name`
    - `source-dir`
    - `main`
    - `link`
    - `[executable.dependencies]`
- [`[[test]]`](#テスト設定test)
    - `name`
    - `source-dir`
    - `main`
    - `link`
    - `[test.dependencies]`
- [`[[example]]`](#デモサンプル設定example)
    - `name`
    - `source-dir`
    - `main`
    - `link`
    - `[example.dependencies]`
- [`[install]`](#インストール設定install)
    - `library`

# プロジェクト概要
プロジェクトの概要を設定する項目がいくつかあります．これはらのほとんどは動作に直接関係しませんが，`name`はプロジェクトの名前を意味するだけでなく，fpmパッケージの名前としても用いられます．ライブラリや実行ファイルの名前としても用いられ，他のプロジェクトが利用する場合の参照名にもなるので，最も重要な設定です．

- `name`<br>プロジェクトの名前
- `version`<br>プロジェクトのバージョン<br>標準的な方法として，[Semantic Versioning](https://semver.org/lang/ja/)がある．
- `license`<br>プロジェクトのライセンス<br>標準的なライセンスの指定方法として，[SPDX License List](https://spdx.org/licenses/)のIdentifierが利用できる．
- `maintainer`<br>プロジェクトのメンテナ
- `author`<br>プロジェクトの作者
- `copyright`<br>プロジェクトのコピーライト
- `description`<br>プロジェクトの詳細
- `categories`<br>プロジェクトのカテゴリ
- `keywords`<br>プロジェクトを表すキーワード
- `homepage`<br>プロジェクトのWebページ

`name`にはプロジェクトの名前を書き，プロジェクトの詳細は，`description`に書くようにします．

`categories`は，プロジェクトのビルドに直接影響はしませんが，将来的にfpmプロジェクトをまとめたリポジトリが作成されるの可能性もあるので，分類の助けになるように付けておくとよいと思います．

# ビルド設定`[build]`
`auto-executables`, `auto-tests`, `auto-examples`以外に`[build]`では，外部ライブラリのリンクとモジュールの参照の設定を行います．

## ビルドするターゲットの自動検出
### `auto-executables`
ビルドするアプリケーションの自動検出を設定します．

標準でこの設定は有効になっており，ディレクトリ`app`を再帰的に検索し，メインルーチンを探してアプリケーションとしてビルドします．

無効にするには，`auto-executables`を`false`に設定します．

```toml
[build]
auto-executables = false
```

### `auto-tests`
ビルドするテストの自動検出を設定します．

標準でこの設定は有効になっており，ディレクトリ`teset`を再帰的に検索し，メインルーチンを探してテストとしてビルドします．

無効にするには，`auto-tests`を`false`に設定します．

```toml
[build]
auto-tests = false
```

### `auto-examples`
ビルドするデモ・サンプルの自動検出を設定します．

標準でこの設定は有効になっており，ディレクトリ`example`を再帰的に検索し，メインルーチンを探してアプリケーションとしてビルドします．

無効にするには，`auto-examples`を`false`に設定します．

```toml
[build]
auto-examples = false
```

## `external-modules`
`external-modules`では，プロジェクトが参照しているモジュールを指定します．

fpmプロジェクト内で作成したモジュールや，`[dependencies]`で設定している依存プロジェクト（およびそれらが依存しているプロジェクト）内で定義されているモジュールは，fpmが自動で参照して依存関係を解決するので指定する必要はありません．

プロジェクト外のモジュール，たとえば既にシステムにインストールされているライブラリを参照する場合に，コンパイラが参照できずにエラーを出すことを抑制します．ただし，fpmはプロジェクト外にあるライブラリや`.mod`を自動で探さないので，パスの通っていないディレクトリに置いている場合は，`--flag`オプションを利用して，コンパイラにインクルードディレクトリを指定する必要があります．

単一のモジュールを参照する場合は値として指定子，複数のモジュールを参照する場合は，リストとして記述します．

```toml
[build]
external-modules = "stdlib_error"
```

```toml
[build]
external-modules = ["stdlib_error", "stdlib_logger"]
```

このオプションは，基本的には次の`link`と併用することになります．

## `link`
`link`では，プロジェクトがリンクするライブラリを指定します．

fpmプロジェクト内で作成されるライブラリや，`[dependencies]`で設定している依存プロジェクト（およびそれらが依存しているプロジェクト）で作成されるライブラリは，指定する必要はありません．既にシステムにインストールされているライブラリを列挙するために利用します．

```toml
[build]
link = "stdlib"
```

```toml
[build]
link = ["stdlib", "json-fortran", "vtkfortran"]
```

## `external-modules`と`link`の使用例
たとえば，Fortranの標準ライブラリをシステムにインストールし，それをプロジェクト内で参照する場合には，下記のように設定します．


```toml
[build]
external-modules = ["stdlib_error", "stdlib_logger", "stdlib_strings"]
link = "stdlib"
```

fpmのプロジェクトとしてsampleを作成し，同じ階層にインストールされ，パスの通っていないstdlibを参照することを想定します．

```console
├── sample
|    ├── app\
|    ├── src\
|    ├── fpm.toml
|    └── README.md
└── stdlib
    ├── include
    │   ├── stdlib_error.mod
    │   ├── stdlib_logger.mod
    │   └── stdlib_strings.mod
    └── lib
        └── libstdlib.a
```

`fpm.toml`に参照するモジュールやライブラリを書くだけでは自動で探索されません．ビルドするには，下記のようにコンパイラオプションでインクルードディレクトリとライブラリディレクトリを指定します．

```console
sample> fpm build --profile debug --flag "-I..\stdlib\include" --link-flag "-L..\stdlib\lib"
 + mkdir build\gfortran_662B9789102B9463
 + mkdir build\gfortran_64F749E15BDD2333
 + mkdir build\gfortran_662B9789102B9463\sample\
 + gfortran -c .\src\sample.f90  -I..\stdlib\include -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build\gfortran_662B9789102B9463 -Ibuild\gfortran_662B9789102B9463 -o build\gfortran_662B9789102B9463\sample\src_sample.f90.o
 + lib /OUT:build\gfortran_662B9789102B9463\sample\libsample.a @build\gfortran_662B9789102B9463\sample\libsample.a.resp
Microsoft (R) Library Manager Version 14.00.24234.1
Copyright (C) Microsoft Corporation.  All rights reserved.

build/gfortran_662B9789102B9463/sample/src_sample.f90.o
 + gfortran -c app\main.f90  -I..\stdlib\include -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build\gfortran_662B9789102B9463 -Ibuild\gfortran_662B9789102B9463 -o build\gfortran_662B9789102B9463\sample\app_main.f90.o
 + mkdir build\gfortran_64F749E15BDD2333\app\
 + gfortran  -I..\stdlib\include -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single  -L..\stdlib\lib build\gfortran_662B9789102B9463\sample\app_main.f90.o build\gfortran_662B9789102B9463\sample\libsample.a -lstdlib -o build\gfortran_64F749E15BDD2333\app\sample.exe
```

# 依存関係設定`[dependencies]`
この項目は，主にfpmプロジェクトで開発されるライブラリが参照する依存関係の設定を行います．

## ローカルプロジェクトの参照
計算機内に存在するfpmプロジェクトを参照するには`path`でパスを指定します．

```toml
[dependencies]
stdlib = { path = "../stdlib" }
```

stdlibのfpmプロジェクトが同じ階層にある場合の設定です．Windowsでもパスの区切りは`/`です．

## オンラインのgitリポジトリの参照
ネットワーク上のgitリポジトリにあるfpmプロジェクトを参照するには，`git`でURLを指定します．

```toml
[dependencies]
json-fortran = { git = "https://github.com/jacobwilliams/json-fortran" }
```

特定のブランチを指定するには，`branch`でブランチ名を指定します．

```toml
[dependencies]
stdlib = { git = "https://github.com/fortran-lang/stdlib", branch = "stdlib-fpm" }
```

# ターゲットに関する設定
`fpm.toml`では，ターゲット（ライブラリ，実行ファイル，テスト，デモ・サンプル）に関する設定が可能です．ライブラリはディレクトリ名のみを変更しますが，実行ファイル，テスト，デモ・サンプルは，ディレクトリ名だけでなく実行ファイル名やメインルーチンのソースファイル名なども指定します．

## ライブラリ設定`[library]`
プロジェクトで参照するディレクトリを指定します．

- `source-dir`でライブラリ作成用のディレクトリ（プロジェクトで利用するモジュール群を配置するディレクトリ）を指定します．標準は`src`です．
- `include-dir`でインクルードディレクトリを指定します．標準は`include`です．

`source-dir`を`source`，`include-dir`を`inc`に変更するには，下記のように設定を記述します．

```toml
[library]
source-dir = "source"
include-dir = "inc"
```

`include-dir`は複数指定できます．

```toml
include-dir = ["include", "../stdlib/include"]
```

## 実行ファイル設定`[[executable]]`
アプリケーションのビルドに関する設定を行います．

### ディレクトリ等の指定

この項目を変更する一番の目的は，標準のディレクトリ名を変更することだと思います．例えば`app`ではなく`apps`等にする場合，下記のように設定を記述します．

```toml
[[executable]]
name = "sample1"
source-dir = "apps"
main = "main1.f90"
```

残念ながら，ディレクトリ名のみを変更することはできず，その中にあるメインルーチンが書かれたソースファイル名およびアプリケーションとしての名前を記述する必要があります．

2重の角括弧`[[]]`はテーブルの配列を意味しており，複数のアプリケーションの設定を列挙できます．

記述量は多くなりますが，その分柔軟な設定ができるようになっており，異なるディレクトリにあるメインルーチンも参照できるようになります．

```toml
[[executable]]
name = "sample1"
source-dir = "apps"
main = "main1.f90"

[[executable]]
name = "sample2"
source-dir = "apps"
main = "main2.f90"

[[executable]]
name = "tool"
source-dir = "tools"
main = "main.f90"
```

このように列挙するのが手間と感じる場合は，インラインテーブルを用いて簡潔に書くこともできます．ただし，この書き方をすると，次の項で紹介する依存関係の設定ができなくなります．

```toml
executable = [
    {name = "sample1",source-dir = "apps",main = "main1.f90"},
    {name = "sample2",source-dir = "apps",main = "main2.f90"},
    {name = "tool",source-dir = "tools",main = "main.f90"}
]
```

tomlの書式を理解できていないだけかもしれません．どなたかご存じの方はご教示ください．

### 依存関係の記述
ライブラリでは使われず，アプリケーションのみが使用する外部fpmプロジェクトが存在した場合にも，`[[executable]]`の設定が必要になります．

アプリケーションのみが依存するプロジェクトを記述するには，少なくとも一つの`[[executable]]`が必要です．これは標準のディレクトリ名`app`を用いていても，`[build]`の設定で`auto-executables=true`にしていても必要です．

`[[executable]]`に続けて，`[executable.dependencies]`の項目を記述します．書き方は，[依存関係の設定](#依存関係設定dependencies)と同じです．

```toml
[[executable]]
name = "sample"
source-dir = "app"
main = "main.f90"

[executable.dependencies]
json-fortran = { git = "https://github.com/jacobwilliams/json-fortran" }
```

複数のアプリケーションがある場合，どれか一つを`[[executable]]`として設定し，依存関係を記述すれば，その他全てのアプリケーションにもその依存関係が適用されます．

外部ライブラリとの依存関係も指定できます．それには，`[build]`の設定で用いていた`link`を利用します．

ただし，`[[executable]]`には`external-modules`の設定を記述できないため，アプリケーションのみで参照しているモジュールであっても，その名前は`[build]`に`external-modules`を設けて記述する必要があります．

```toml
[build]
external-modules = "stdlib_error"

[[executable]]
name = "sample"
source-dir = "app"
main = "main.f90"
link = "stdlib"
```

## テスト設定`[[test]]`
テストのビルドに関する設定を行います．設定の方法，設定可能な内容は[実行ファイルの設定](#実行ファイル設定executable)と全く同じです．違いは，設定項目の名前が，`[[test]]`に変わっていることだけです．

### ディレクトリ等の指定

例えば`test`ではなく`tests`等にする場合，下記のように設定を記述します．

```toml
[[test]]
name = "test-1"
source-dir = "tests"
main = "check1.f90"
```

ディレクトリ名のみを変更することはできず，その中にあるメインルーチンが書かれたソースファイル名およびテストとしての名前を記述する必要があります．異なるディレクトリにあるメインルーチンも参照できます．

```toml
[[test]]
name = "test-1"
source-dir = "tests"
main = "check1.f90"

[[test]]
name = "test-2"
source-dir = "tests"
main = "check2.f90"

[[test]]
name = "test"
source-dir = "test"
main = "check.f90"
```

インラインテーブルを用いて簡潔に書くこともできます．ただし，インラインテーブルを用いると，依存関係の設定ができなくなります．

```toml
test = [
    {name = "test-1",source-dir = "tests",main = "check1.f90"},
    {name = "test-2",source-dir = "tests",main = "check2.f90"},
    {name = "test",source-dir = "test",main = "check.f90"}
]
```

### 依存関係の記述
テストのみが必要とする外部fpmプロジェクトが存在した場合にも，`[[test]]`の設定が必要です．

テストのみが依存するプロジェクトを記述するには，少なくとも一つの`[[test]]`が必要です．これは標準のディレクトリ名`test`を用いていても，`[build]`の設定で`auto-tests=true`にしていても必要です．現状では，依存関係の記述以外の理由で`[[test]]`を設定している場合を除いて，`[dependencies]`にまとめて書いておいた方が手間がありません．

`[[test]]`に続けて，`[test.dependencies]`の項目を記述します．書き方は，[依存関係の設定](#依存関係設定dependencies)と同じです．

```toml
[[test]]
name = "test-1"
source-dir = "test"
main = "check1.f90"

[test.dependencies]
test-drive = { git = "https://github.com/fortran-lang/test-drive" }
```

複数のテストがある場合，どれか一つを`[[test]]`として設定し，依存関係を記述すれば，その他全てのテストにもその依存関係が適用されます．

`link`を利用して外部ライブラリとの依存関係も指定できます．`[[test]]`には`external-modules`の設定を記述できないため，テストのみで参照しているモジュールであっても，その名前は`[build]`に`external-modules`を設けて記述する必要があります．

```toml
[build]
external-modules = "stdlib_logger"

[[test]]
name = "test-1"
source-dir = "test"
main = "check1.f90"
link = "stdlib"
```

## デモ・サンプル設定`[[example]]`
デモ・サンプルのビルドに関する設定を行います．設定の方法，設定可能な内容は[実行ファイルの設定](#実行ファイル設定executable)と全く同じです．違いは，設定項目の名前が，`[[example]]`に変わっていることだけです．

### ディレクトリ等の指定
デモ・サンプルのディレクトリ名を`example`ではなく`examples`にする場合，下記のように設定を記述します．

```toml
[[example]]
name = "demo-1"
source-dir = "examples"
main = "demo1.f90"
```

ディレクトリ名のみを変更することはできず，その中にあるメインルーチンが書かれたソースファイル名およびデモ・サンプルとしての名前を記述する必要があります．異なるディレクトリにあるメインルーチンも参照できます．

```toml
[[example]]
name = "demo-1"
source-dir = "examples"
main = "demo1.f90"

[[example]]
name = "demo-2"
source-dir = "examples"
main = "demo2.f90"
```

インラインテーブルも利用できます．ただし，この書き方をすると，次の項で紹介する依存関係の設定ができなくなります．

```toml
example = [
    {name = "demo-1",source-dir = "examples",main = "demo1.f90"},
    {name = "demo-2",source-dir = "examples",main = "demo2.f90"}
]
```

### 依存関係の記述
デモ・サンプルのみが参照する外部fpmプロジェクトが存在した場合，`[[example]]`の設定が必要になります．依存するプロジェクトを記述するには，少なくとも一つの`[[example]]`が必要です．標準のディレクトリ名`example`を用いていても，`[build]`の設定で`auto-examples=true`にしていても必要です．テストの場合と同様，依存関係の記述以外の理由で`[[example]]`を設定している場合を除いて，`[dependencies]`にまとめて書いておいた方が手間がありません．


`[[example]]`に続けて，`[example.dependencies]`の項目を記述します．書き方は，[依存関係の設定](#依存関係設定dependencies)と同じです．

```toml
[[example]]
name = "demo-1"
source-dir = "examples"
main = "demo1.f90"

[example.dependencies]
json-fortran = { git = "https://github.com/jacobwilliams/json-fortran" }
```

複数のデモ・サンプルがある場合，どれか一つを`[[example]]`として設定し，依存関係を記述すれば，その他全てのデモ・サンプルにもその依存関係が適用されます．

`link`を利用して，外部ライブラリとの依存関係を指定できます．`[[example]]`には`external-modules`の設定を記述できないため，デモ・サンプルのみで参照しているモジュールであっても，その名前は`[build]`に`external-modules`を設けて記述する必要があります．

```toml
[build]
external-modules = "stdlib_quadrature"

[[example]]
name = "demo-1"
source-dir = "examples"
main = "demo1.f90"
link = "stdlib"
```

# インストール設定`[install]`
ライブラリをインストールの対象とするかを設定します．

標準では無効になっており，インストールされるのは実行ファイルのみです．ライブラリおよび`.mod`ファイルもインストールの対象とするには，`library = true`とします．

```toml
[install]
library = true
```

# コンパイラオプションの記述
現行バージョンでは，`fpm.toml`にはコンパイラオプションを記述できません．

しかし，[Google Summer of Code](https://summerofcode.withgoogle.com/archive/2021/organizations/6542461173760000/)でFortran-langの提案が採用され，開発が進められてきました．近い将来にはコンパイラオプションを`fpm.toml`に記述できるようになる見込みです．

[FortranCon2021](https://www.youtube.com/watch?v=g7ECnr_Q7Ck)で紹介された設定ファイルの記述方法は，下記のようになっています．

```toml
[profiles.debug.gfortran.linux]
flags="-g -Wall"
c_flags="-O1 -g"
link_time_flags="-xlinkopt"
files={"filename.f90"="-g -fcheck=all"}
```

複数のコンパイラを想定した書き方も示されていました．

```toml
name = "hello_world"

[profiles.gfortran.linux]
flags="-Wall"

[profiles.debug.gfortran.linux]
flags="-g -O1"

[profiles.debug.ifort.linux]
flags="-g -traceback"
```

# まとめ
パッケージマネージャ兼ビルドツールであるfpmの設定ファイル（マニフェスト）の解説をしました．

現状では設定項目は少なく，最低限ビルドやリンクができるくらいですが，小規模な開発に用いるには十分な機能を持っています．一方で，ディレクトリを標準の名前から変更すると設定の煩わしさが跳ね上がるなど，少し設定を凝ろうとすると使い勝手が悪いところもあるので，意見をフィードバックして行きたいと思います．

プロジェクトの作成例については，[次の記事](https://qiita.com/implicit_none/items/08a2d26f8288dda7b4f5)で取り上げます．