LoginSignup
9
6

More than 1 year has passed since last update.

fpm (Fortran Package Manager)をBuilder兼Runnerとして利用する

Last updated at Posted at 2020-06-13

概要

本記事では,fpmのインストールと,簡単な使い方を解説します.

fpm (Fortran Package Manager)は,Fortran-langプロジェクトの一環として開発されているパッケージマネージャです.将来的には,リモートにあるリポジトリを取得して,ビルド,インストールするところまでを目指しています.また,ユーザがビルドシステムの設定で悩まないよう,プロジェクトの構造を標準化することも目指しています.

Fortran-langプロジェクトがFortranに関するプロジェクトの調査をしていますが,パッケージマネージャとして機能するのはしばらく先になりそうです.一方,fpmの機能を確認すると,プロジェクトのビルドや実行を短いコマンドで実現できる,Builder兼Runnerとしては使えることが判りました.

追記:
バージョン0.5.0での使い方を別記事にまとめました.

環境

  • Ubuntu 18.04
  • fpm prototype version
  • gfortran 7.5
  • Haskell stack 2.3.1
  • git 2.17.1

fpmのインストール

fpmはHaskellで記述されており,インストールにもHaskell (Haskell Stack)が使われます.
インストール手順は公式のREADMEに大体書いてあるのですが,必要なライブラリについては漏れがあるので,それも含めたインストール手順を記します.

fpmのインストール時にはgitを使うので,gitは事前にインストールしておいてください.また,fpmはプロジェクトのビルドにgfortranを利用するので,gfortranについても事前にインストールしておいてください.

  1. GNU Multiple Precision Arithmetic Library Developers Toolsのインストール
  2. Haskell Stackのダウンロードと展開
  3. fpmのインストール

fpmのREADMEには,必要なソフトウェアの要件が書かれていませんが,GNU Multiple Precision Arithmetic Library (GMP)がないとHaskell Stackのインストール時にエラーが出るので,予めインストールしておきます.

Linking /home/hoge/.stack/setup-exe-cache/x86_64-linux/tmp-Cabal-simple_mPHDZzAJ_2.4.0.1_ghc-8.6.5 ...
/usr/bin/ld.gold: エラー: -lgmp が見つかりませ

GNU Multiple Precision Arithmetic Library Developers Toolsのインストール

GMP Developers Toolsのインストールをインストールします.
Ubuntuを利用している場合は,aptで簡単にインストールできます.

$ sudo apt install libgmp-dev

Haskell Stackのダウンロードと展開

Haskell Stackのtar.gzファイルをダウンロードし,展開した後,パスを通しておきます.著者は,ホームディレクトリの下にlibフォルダを作り,そこにダウンロードして展開しました.

$ cd ~
$ mkdir lib
$ cd lib
$ wget https://get.haskellstack.org/stable/linux-x86_64-static.tar.gz
$ tar xaf linux-x86_64-static.tar.gz
$ cd linux-x86_64-static
$ export PATH=$PATH:`pwd`

fpmのインストール

GitHubからfpmのリポジトリをクローンし,stackを利用してbuildします.このとき,GHC (The Glasgow Haskell Compiler)のダウンロードも行われるので,かなり時間がかかります.気長に待ちましょう.

$ cd ~/lib
$ git clone https://github.com/fortran-lang/fpm
$ cd fpm
$ stack build

fpmのビルドが完了すると,実行ファイルは異様に長いパスに置かれます.それを使いやすい場所にコピーするために,次のコマンドを実行します.

$ stack install

実行すると,以下のようなメッセージが出力され,ビルドされたfpmの実行ファイルが,~/.local/binにコピーされた事が判ります.

Copied executables to /home/hoge/.local/bin:
- fpm

このフォルダにもパスを通しておきます.

$ export PATH=$PATH:~/.local/bin

これでインストールは完了です.

fpmによるビルドと実行

fpmのパッケージングレイアウト

fpmでは,用途に応じて3通りのパッケージングの方法を提供しています.

  • アプリケーション(実行ファイルのみを生成)
  • ライブラリ(静的ライブラリのみを生成)
  • アプリケーションとライブラリ

これらは,ディレクトリ構造が異なるだけです.
また,パッケージ情報をfpm.tomlファイルに記述します.
fpm.tomlファイルには,プログラムの名前やバージョン,ライセンス情報などを記述できます.プログラム名(コンパイルした際の実行ファイルの名前)は必須ですが,それ以外は必須ではありません.

fpm.toml
name = "hello"

詳しくは,公式のPreparing your package for FPMを読んでください.

アプリケーション

アプリケーションは,下記のようなディレクトリ構造で管理されます.

project dir
├── app
│   └── main.f90
└── fpm.toml

必要なのは,main.f90fpm.tomlのみです.プロジェクトのディレクトリ直下にappディレクトリとfpm.tomlを置き,ソースファイルをappディレクトリ直下に置きます.このとき,ソースファイル名は,必ずmain.f90です.

公式のサンプルと同様にhello worldを作ってみると,下記のようになります.

hello
├── app
│   └── main.f90
└── fpm.toml
fpm.toml
name = "hello"
main.f90
program main
    implicit none

    print *, "hello, world"
end program main

プログラムのビルドは,プロジェクトのディレクトリで次のコマンドを実行します.

$ fpm build
# gfortran (for build/gfortran_debug/app/main.o)
# gfortran (for build/gfortran_debug/app/hello)

プロジェクトをビルドすると,プロジェクトディレクトリ直下にbuild\gfortran_debug\appディレクトリが作られ,その中に実行ファイルが作成されます.実行ファイルの名前は,fpm.tomlnameで指定した名前です.

ビルドしたプログラムは,fpm runで実行できます.

$ fpm run
 hello, world

ライブラリ

ライブラリの場合はディレクトリ構造が若干変わります.

project dir
├── fpm.toml
└── src
    └── module source files

このとき,fpm.tomlに書いた名前は,静的ライブラリ(*.aファイル)の名前(頭にlibが追加されます)として使われます.

const
├── fpm.toml
└── src
    └── math_constants.f90
fpm.toml
name = "const"
math_constants.f90
module math_constants
    use, intrinsic :: iso_fortran_env
    implicit none

    real(real64),parameter :: PI = acos(-1d0)

end module math_constants

ビルドはアプリケーションの場合と同様に,プロジェクトのディレクトリでfpm buildを実行します.

$ fpm build
# gfortran (for build/gfortran_debug/const/math_constants.o build/gfortran_debug/const/math_constants.mod)
# ar (for build/gfortran_debug/const/libconst.a)
ar: build/gfortran_debug/const/libconst.a を作成しています

プロジェクトディレクトリ直下にbuild\gfortran_debug\constfpm.tomlnameで指定した名前の)ディレクトリが作られ,lib+nameで指定した名前.aの静的ライブラリが作成されました.

アプリケーションとライブラリ

別ファイルでモジュールを作成し,メインルーチンからそれらを読み込む場合には,このディレクトリ構造を用います.これは非常に単純で,アプリケーションとライブラリのディレクトリ構造を合わせた構造です.

project dir
├── app
│   └── main.f90
├── fpm.toml
└── src
    └── module source files

このとき,fpm.tomlnameで指定するのは実行ファイルの名前ですが,静的ライブラリの名前にも使われます.

公式に類似した,以下のようなサンプルを作ってみました.

app_and_lib
├── app
│   └── main.f90
├── fpm.toml
└── src
    └── math_constants.f90
fpm.toml
name = "app_and_lib"
main.f90
program main
    use :: math_constants, only: PI, PI05, PI2
    implicit none

    print *, "application and static library demo"
    print *, "π = ", PI
    print *, "π/2 = ", PI05
    print *, "2π = ", PI2
end program main
math_constants.f90
module math_constants
    use, intrinsic :: iso_fortran_env
    implicit none

    real(real64),parameter :: PI = acos(-1d0)
    real(real64),parameter :: PI2  = PI * 2.0_real64
    real(real64),parameter :: PI05 = PI * 0.5_real64

end module math_constants

ビルドと実行は,アプリケーションのときと何も変わりません.

$ fpm build
# gfortran (for build/gfortran_debug/app_and_lib/math_constants.o build/gfortran_debug/app_and_lib/math_constants.mod)
# ar (for build/gfortran_debug/app_and_lib/libapp_and_lib.a)
ar: build/gfortran_debug/app_and_lib/libapp_and_lib.a を作成しています
# gfortran (for build/gfortran_debug/app/app_and_lib)

$ fpm run
 application and static library demo
 π =    3.1415926535897931
 π/2 =    1.5707963267948966
 2π =    6.2831853071795862

階層化されたモジュール

複数のモジュールが関係し,モジュールに階層構造がある場合は,モジュール名に独自のルールが設けられます.

multi_level_module
├── app
│   └── main.f90
├── fpm.toml
└── src
    ├── math_constants
    │   ├── derived.f90
    │   └── fundamental.f90
    └── math_constants.f90
fpm.toml
name = "multi_level_module"
math_constants.f90
module math_constants
    use :: math_constants_fundamental, only: PI
    use :: math_constants_derived, only: PI05, PI2
end module math_constants
fundamental.f90
module math_constants_fundamental
    use, intrinsic :: iso_fortran_env
    implicit none

    real(real64),parameter :: PI = acos(-1d0)

end module math_constants_fundamental
derived.f90
module math_constants_derived
    use, intrinsic :: iso_fortran_env
    use :: math_constants_fundamental, only: PI
    implicit none

    real(real64),parameter :: PI2  = PI * 2.0_real64
    real(real64),parameter :: PI05 = PI * 0.5_real64

end module math_constants_derived

main.f90は前の例と同じです.

モジュールの名前付けにはルールがあり,math_constants.f90ではモジュール名をmath_constantsとします.
src/math_constants/derived.f90fundamental.f90は,それぞれモジュール名をmath_constants_derivedmath_constants_fundamentalにしなければなりません.

srcディレクトリのサブディレクトリに置かれたモジュールの名前は,src以下のサブディレクトリ名をアンダースコア_で順次つないでいき,最後にファイル名で終わります.
モジュールをsrc/a/b/c/d.f90で定義するとき,モジュール名はa_b_c_dになるということです.

公式のサンプルとほとんど同じなのですが,これをビルドしてみるとエラーが出ます.

$ fpm build
# gfortran (for build/gfortran_debug/multi_level_module/math_constants_derived.o build/gfortran_debug/multi_level_module/math_constants_derived.mod)
# gfortran (for build/gfortran_debug/multi_level_module/math_constants.o build/gfortran_debug/multi_level_module/math_constants.mod)
# gfortran (for build/gfortran_debug/multi_level_module/math_constants_fundamental.o build/gfortran_debug/multi_level_module/math_constants_fundamental.mod)
src/math_constants.f90:3:10:

     use :: math_constants_fundamental, only: PI
          1
Fatal Error: Can't open module file ‘math_constants_fundamental.mod’ for reading at (1): そのようなファイルやディレクトリはありません
compilation terminated.

恐らく,依存性解析に失敗し,必要なモジュールのmodファイルが作られる前に,別のモジュールのコンパイルを行おうとして,失敗したと考えられます.もう一度実行すると,ビルドに成功します.1回目のビルドでいくつかのmodファイルが作られるので,2回目は既に作られたmodファイルを参照してコンパイルできるからです.

$ fpm build
# gfortran (for build/gfortran_debug/multi_level_module/math_constants_fundamental.o build/gfortran_debug/multi_level_module/math_constants_fundamental.mod)
# gfortran (for build/gfortran_debug/multi_level_module/math_constants_derived.o build/gfortran_debug/multi_level_module/math_constants_derived.mod)
# gfortran (for build/gfortran_debug/multi_level_module/math_constants.o build/gfortran_debug/multi_level_module/math_constants.mod)
# ar (for build/gfortran_debug/multi_level_module/libmulti_level_module.a)
ar: build/gfortran_debug/multi_level_module/libmulti_level_module.a を作成しています
# gfortran (for build/gfortran_debug/app/main.o)
# gfortran (for build/gfortran_debug/app/multi_level_module)

$ fpm run
 multi-level module demo
 π =    3.1415926535897931
 π/2 =    1.5707963267948966
 2π =    6.2831853071795862

モジュールの参照エラーであれば,何回かfpm buildを実行すればそのうち成功するでしょう.

まとめ

fpmはまだまだ開発途上ですが,簡単なプログラムのビルドおよび実行に使えることは判りました.

ビルドの補助ツールとしてはcmakeもありますが,CMakeLists.txtfpm.tomlほど気軽には書けませんし,Makefileを作ったあとにmakeも必要になります.簡単な設定とコマンドで実行できるfpmは,Builder兼Runnerとしては非常に手軽で魅力的です.

今後の進展が楽しみです.fpmの進展を待つだけでなく,プロジェクトの構造についても,この機会に見直したいと思います.

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6