PC パソコン

Fortranで外部ライブラリを使う方法|導入・コンパイル・リンクの基本

Fortranで外部ライブラリを使う方法|導入・コンパイル・リンクの基本

Fortranには、数値計算、配列処理、ファイル入出力など多くの機能が標準で用意されています。
一方で、より高度な線形代数、特殊な数値計算、グラフ描画、並列計算などを行う場合は、
外部ライブラリを利用することがあります。

この記事では、Fortranを学び始めた人向けに、
外部ライブラリとは何か、
「コンパイル」「リンク」とは何をしているのか、
そしてWindows・Mac・Linuxで外部ライブラリを導入して使う基本的な方法を解説します。

具体例として、科学技術計算で長く利用されている
BLASLAPACKを扱います。

外部ライブラリとは

ライブラリとは、
よく使う計算や処理をあらかじめプログラムとしてまとめたものです。

例えば、連立一次方程式を自分ですべて実装することもできますが、
既に十分に検証されたLAPACKのルーチンを利用すれば、
その機能を自分のFortranプログラムから呼び出すことができます。

イメージとしては次のようになります。

自分のFortranプログラム
        ↓
外部ライブラリの機能を呼び出す
        ↓
BLAS / LAPACKなどが計算
        ↓
結果を自分のプログラムで受け取る

標準機能と外部ライブラリの違い

例えば、Fortran標準のsqrtは、
追加のライブラリをインストールしなくても使えます。

answer = sqrt(x)

一方、LAPACKのDGESVなどはFortran標準機能ではありません。
LAPACKを導入し、コンパイル時にそのライブラリをリンクする必要があります。

BLASとは

BLAS(Basic Linear Algebra Subprograms)は、
ベクトルや行列の基本的な計算を行うためのライブラリ群です。

代表的な処理には次のようなものがあります。

  • ベクトルの加算
  • 内積
  • 行列とベクトルの積
  • 行列積

LAPACKとは

LAPACK(Linear Algebra PACKage)は、
BLASを利用しながら、より高度な線形代数計算を行うためのライブラリです。

例えば次のような処理に利用されます。

  • 連立一次方程式
  • 最小二乗法
  • 固有値・固有ベクトル
  • LU分解
  • QR分解
  • 特異値分解(SVD)

コンパイルとリンクの違い

外部ライブラリを使うときに、
初学者がつまずきやすい言葉がリンクです。

通常のFortranプログラムでは、
例えば次のようにコンパイルします。

gfortran sample.f90 -o sample

この処理では、Fortranのソースコードを機械が実行できる形へ変換し、
最終的な実行ファイルを作っています。

外部ライブラリを使う場合は、
自分のプログラムとライブラリを結び付ける必要があります。
これをリンクと呼びます。

自分のコード
    +
外部ライブラリ
    ↓
リンク
    ↓
実行ファイル

-lオプションとは

gfortranでは、-lを使ってリンクするライブラリを指定できます。

例えば、LAPACKとBLASを利用する場合、
環境によっては次のように指定します。

gfortran sample.f90 -llapack -lblas -o sample

-llapackはLAPACK、
-lblasはBLASをリンクする指定です。

なお、実際のライブラリ名や必要なオプションは、
OSや導入方法によって異なる場合があります。

-Lオプションとは

ライブラリが標準の場所にない場合は、
-Lでライブラリが保存されているフォルダを指定できます。

gfortran sample.f90 -L/path/to/library -lmylibrary -o sample

ここでは、/path/to/libraryというフォルダから
mylibraryというライブラリを探すよう指定しています。

-Iオプションとは

Fortranの外部ライブラリには、
moduleファイルを読み込んで使うものもあります。

その場合、必要なモジュールファイルが標準の場所にないときは、
-Iで検索するフォルダを指定します。

gfortran sample.f90 -I/path/to/modules -L/path/to/library -lmylibrary -o sample

Windows|MSYS2でLAPACKを導入する

WindowsでMSYS2 UCRT64を使ってgfortranを導入している場合、
LAPACKもMSYS2のパッケージ管理機能から導入できます。

MSYS2 UCRT64を開き、次のように実行します。

pacman -S mingw-w64-ucrt-x86_64-lapack

BLASを個別に導入する場合は、
次のパッケージも利用できます。

pacman -S mingw-w64-ucrt-x86_64-blas

OpenBLASを使用したい場合は、
次のパッケージがあります。

pacman -S mingw-w64-ucrt-x86_64-openblas

MSYS2ではUCRT64向けパッケージを利用している場合、
mingw-w64-ucrt-x86_64-で始まるパッケージ名を使用します。

Mac|HomebrewでLAPACKを導入する

MacでHomebrewを利用している場合、
LAPACKは次のようにインストールできます。

brew install lapack

OpenBLASを利用したい場合は次のコマンドです。

brew install openblas

HomebrewでインストールされたLAPACKやOpenBLASは、
環境によって標準のライブラリ検索場所とは異なる場所へ入る場合があります。

その場合はbrew –prefixを使って
インストール場所を確認できます。

brew --prefix lapack

例えば、表示された場所を使って
-Lオプションや-Iオプションを指定することがあります。

Linux|Ubuntu・Debian系でLAPACKを導入する

UbuntuやDebian系Linuxでは、
次のようにBLASとLAPACKの開発用パッケージを導入できます。

sudo apt update
sudo apt install libblas-dev liblapack-dev

OpenBLASを利用する場合は、
環境によってlibopenblas-devを利用できます。

sudo apt install libopenblas-dev

LAPACKで連立一次方程式を解いてみる

ここでは、LAPACKのDGESVを使って
2元連立一次方程式を解く簡単な例を紹介します。

DGESVは、実数の連立一次方程式
A × X = B
を解くためのLAPACKルーチンです。

program lapack_example
    implicit none

    ! 方程式の数
    integer, parameter :: n = 2

    ! 右辺ベクトルの本数
    integer, parameter :: nrhs = 1

    ! 行列A
    double precision :: a(n, n)

    ! 右辺B
    ! DGESV実行後は、ここに解Xが入ります。
    double precision :: b(n, nrhs)

    ! ピボット情報を保存します。
    integer :: ipiv(n)

    ! LAPACKから返される状態コードです。
    integer :: info

    ! 行列Aを設定します。
    !
    ! 方程式:
    ! 2x + y = 5
    ! x + 3y = 7
    !
    ! Fortranの配列は列方向を先に格納するため、
    ! reshapeの並びに注意します。
    a = reshape([2.0d0, 1.0d0, &
                 1.0d0, 3.0d0], shape(a))

    ! 右辺を設定します。
    b(1,1) = 5.0d0
    b(2,1) = 7.0d0

    ! DGESVを呼び出します。
    !
    ! n     : 方程式数
    ! nrhs  : 右辺の本数
    ! a     : 係数行列
    ! n     : Aの先頭次元
    ! ipiv  : ピボット情報
    ! b     : 右辺。計算後は解になります。
    ! n     : Bの先頭次元
    ! info  : 計算結果の状態
    call dgesv(n, nrhs, a, n, ipiv, b, n, info)

    ! info = 0なら正常終了です。
    if (info == 0) then

        print *, "x =", b(1,1)
        print *, "y =", b(2,1)

    else

        print *, "計算に失敗しました。"
        print *, "info =", info

    end if

end program lapack_example

LAPACKをリンクしてコンパイルする

UbuntuなどでLAPACKとBLASを導入済みなら、
環境によって次のようにコンパイルできます。

gfortran lapack_example.f90 -llapack -lblas -o lapack_example

実行します。

./lapack_example

WindowsのMSYS2では、
実行ファイル名に.exeが付きます。

./lapack_example.exe

OpenBLASをリンクする場合

OpenBLASを導入している環境では、
次のような形でリンクできる場合があります。

gfortran lapack_example.f90 -lopenblas -o lapack_example

OpenBLASはBLASの高速実装で、
環境によってはLAPACK機能も含まれています。

ただし、配布方法やビルド設定によって利用できる機能が異なることがあるため、
実際の環境のパッケージ情報を確認してください。

Macでライブラリの場所を指定する例

HomebrewでインストールしたLAPACKが
標準の検索場所から見つからない場合は、
インストール先を明示できます。

LAPACK_DIR=$(brew --prefix lapack)

gfortran lapack_example.f90 \
    -L"$LAPACK_DIR/lib" \
    -llapack -lblas \
    -o lapack_example

環境によって必要なオプションは異なるため、
Homebrewが表示するインストール後の案内も確認してください。

なぜ「undefined reference」というエラーが出る?

外部ライブラリを使うときによくあるエラーが、
undefined referenceです。

これは簡単にいうと、
「プログラム内で呼び出している関数やサブルーチンの実体を
リンク時に見つけられない」という意味です。

例えば、DGESVを呼び出しているのに
LAPACKをリンクしていない場合などに発生します。

gfortran lapack_example.f90 -o lapack_example

この場合はライブラリ指定がありません。
LAPACKを使用するなら、例えば次のようにします。

gfortran lapack_example.f90 -llapack -lblas -o lapack_example

「cannot find -l○○」とは

次のようなエラーが表示されることがあります。

cannot find -lmylibrary

これは、リンクしようとしているライブラリを
コンパイラが見つけられないという意味です。

主な原因は次のとおりです。

  • ライブラリをインストールしていない
  • ライブラリ名が間違っている
  • ライブラリの保存場所が標準検索場所にない
  • -Lで正しい場所を指定していない

「Cannot open module file」とは

外部ライブラリがFortranのMODULEを提供している場合、
次のようなエラーが出ることがあります。

Cannot open module file 'example.mod'

これは、必要な.modファイルを
コンパイラが見つけられない場合に発生します。

その場合は、モジュールファイルが保存されている場所を
-Iで指定します。

gfortran sample.f90 -I/path/to/modules ...

ライブラリファイルの代表的な形式

外部ライブラリを調べていると、
次のような拡張子を見かけることがあります。

形式 主な意味
.a 静的ライブラリ
.so Linuxなどの共有ライブラリ
.dylib macOSの共有ライブラリ
.dll Windowsの動的ライブラリ
.mod Fortran MODULEのコンパイル済み情報

静的リンクと動的リンク

外部ライブラリの利用方法には、
大きく分けて静的リンク動的リンクがあります。

静的リンク

必要なライブラリコードを実行ファイルへ組み込む方式です。
実行ファイルは大きくなりやすい一方、
配布先でライブラリを別に用意しなくてよい場合があります。

動的リンク

実行時に共有ライブラリを読み込む方式です。
実行ファイルを小さくできますが、
実行する環境にも必要な共有ライブラリが存在する必要があります。

初心者の段階では、
まずパッケージ管理ツールでライブラリを導入し、
通常の-l指定で動かすところから始めれば十分です。

リンクする順番が重要な場合がある

Unix系環境のリンカでは、
ライブラリを指定する順番によって
リンク結果が変わることがあります。

例えばLAPACKがBLASの機能を利用する場合、
一般的には次の順で指定します。

gfortran sample.f90 -llapack -lblas -o sample

エラーが出る場合は、
ライブラリの公式ドキュメントに記載されたリンク方法を確認してください。

外部ライブラリを使うときの基本手順

外部ライブラリを初めて利用するときは、
次の順番で考えると整理しやすくなります。

  1. 使いたいライブラリを決める
  2. 自分のOSへライブラリをインストールする
  3. Fortranから呼び出す方法を確認する
  4. 必要なら-Iでモジュールの場所を指定する
  5. 必要なら-Lでライブラリの場所を指定する
  6. -lでライブラリをリンクする
  7. コンパイルして実行する

コンパイルコマンドを分解して理解する

例えば次のコマンドを見てみます。

gfortran sample.f90 -I/usr/local/include \
    -L/usr/local/lib -lmylibrary -o sample
部分 意味
gfortran Fortranコンパイラを起動する
sample.f90 コンパイルするソースコード
-I/usr/local/include モジュールなどを探す場所
-L/usr/local/lib ライブラリを探す場所
-lmylibrary mylibraryをリンクする
-o sample 実行ファイル名をsampleにする

外部ライブラリは必ず必要?

いいえ。
基本的なFortran学習では外部ライブラリは必要ありません。

Fortran標準だけでも、
次のような処理はできます。

  • 四則演算
  • 三角関数・平方根・指数・対数
  • 配列計算
  • 行列積
  • ファイル入出力
  • 数値積分の自作
  • 簡単な方程式の数値解法

外部ライブラリは、
より高度な処理を効率よく、信頼性の高い既存実装で行いたいときに使います。

外部ライブラリを利用するメリット

  • 複雑な計算を自分で一から実装しなくてよい
  • 長年利用されている実績ある計算ルーチンを使える
  • 高速化された実装を利用できる場合がある
  • 大規模な科学技術計算へ発展しやすい

外部ライブラリを利用するときの注意点

  • ライブラリごとに導入方法が異なる
  • OSによってパッケージ名や保存場所が異なる
  • コンパイラとの互換性を確認する必要がある
  • 32bit / 64bitや整数サイズの違いに注意する場合がある
  • 配布するときはライセンスを確認する
  • APIやルーチンの引数を公式ドキュメントで確認する

BLAS・LAPACK以外にもライブラリはある

Fortranから利用できるライブラリはBLAS・LAPACKだけではありません。
用途に応じてさまざまなものがあります。

  • FFTなどの高速フーリエ変換
  • 乱数・統計計算
  • 常微分方程式・偏微分方程式
  • 並列計算
  • グラフ描画
  • ファイル形式の読み書き

さらにModern FortranにはC言語との相互運用機能もあり、
Cで作られたライブラリをFortranから利用することもできます。

初心者はどこまで覚えればよい?

最初から静的リンク、動的リンク、
ライブラリ検索パスなどをすべて暗記する必要はありません。

まずは次の4点を理解できれば十分です。

  1. 外部ライブラリはFortran標準以外の機能を追加するもの
  2. ライブラリは先にOSへインストールする
  3. コンパイル時に-lでリンクすることがある
  4. 見つからない場合は-Iや-Lで場所を指定する

実際に1つのライブラリを導入して動かしてみると、
「コンパイル」と「リンク」の違いが理解しやすくなります。

まとめ

Fortranでは、
標準機能だけで多くの数値計算ができますが、
外部ライブラリを利用するとさらに高度な処理が可能になります。

科学技術計算では、
BLASやLAPACKが代表的な外部ライブラリです。
LAPACKでは連立一次方程式、固有値、最小二乗法、特異値分解など、
高度な線形代数計算を行えます。

gfortranで外部ライブラリを使うときは、
-lでリンクするライブラリ、
-Lでライブラリの検索場所、
-Iでモジュールなどの検索場所を指定することがあります。

WindowsではMSYS2、
MacではHomebrew、
Ubuntu・Debian系Linuxではaptなどを使って、
必要なライブラリを導入できます。

初学者は、
まずLAPACKなどの代表的なライブラリを1つ実際に動かし、
「自分のFortranコードから外部の計算機能を呼び出す」
という流れを体験すると理解しやすいでしょう。

参考資料