やりたいこと
-
flang-new
のインストール. - いくつかのファイルをコンパイルしてみる.
Fortran コンパイラ
たくさんあります.
Fortran コンパイラとして有名なのが gfortran
と ifx
(旧ifort
) でしょう.
gfortran
は GNU Compiler Collection のコンパイラです.
ifx
は intel fortran compiler のコンパイラです. 今は(商用でなければ?)無料で使えるはずです.
他にも lfortran
や PGI/NVIDIA, NAG, Cray, NEC などのコンパイラがあるらしいです.
また, classic flang もあり, これは pgfortran
からの派生らしいです.
今回ビルドする flang
は llvm-project によるコンパイラです.
f18 プロジェクトから始まって, 前の flang の欠陥に対処して, LLVM project に受け入れられたようです.
つまり
pgfortran
↓ ↘
↓ classic flang
↓ ↓ (修正)
↓ f18 project
↓ (買収) ↓
nvfortran flang-new(llvm)
ってことですかね?
特徴は... 外からだとLLVMを使うことしか分からないですね.
色々試してみたいです.
LLVM
ろーれべるなんちゃらのあたまもじ... ではないらしい.
C コンパイラの Clang が有名ですね.
Flang
Fortran のコンパイラ.
LLVM の力を備えているらしい.
ビルドする
環境
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.5 LTS
Release: 22.04
Codename: jammy
$ gfortran --version
GNU Fortran (Ubuntu 12.3.0-1ubuntu1~22.04) 12.3.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ifx --version
ifx (IFX) 2025.0.1 20241113
Copyright (C) 1985-2024 Intel Corporation. All rights reserved.
$ nvfortran --version
nvfortran 23.9-0 64-bit target on x86-64 Linux -tp ivybridge
NVIDIA Compilers and Tools
Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
$ flang --version
flang version 16.0.4 (https://github.com/flang-compiler/classic-flang-llvm-project.git 8d805dfcb66161beee81045a8ecd89051e919241)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/osd-yum/.local/bin
$ free -h
total used free shared buff/cache available
Mem: 7.6Gi 4.9Gi 307Mi 1.1Gi 2.4Gi 1.3Gi
Swap: 15Gi 5.1Gi 10Gi
メモリ8GBは今の時代は足りないので, もっと欲しいです.
ビルド
頻繁にバージョンが更新されるため, https://github.com/llvm/llvm-project/releases を確認しましょう.
ビルド方法は https://github.com/llvm/llvm-project/blob/main/flang/docs/GettingStarted.md です.
cmake
と ninja
が必要です.
# Ubuntu なら
$ sudo apt install build-essential cmake ninja-build
llvm-project は 3GB くらいあるので, ストレージの容量には気をつけましょう.
また, 並列ビルドする際には, メモリが貧弱だと ninja
が落ちます.
8GBメモリでは落ちるので, ninja -j 1
で1コアのビルドにしています.
$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.5/llvm-19.1.5.src.tar.xz
$ tar xvf llvm-19.1.5.src.tar.xz
$ cd llvm-19.1.5.src
$ mkdir _build
$ cd _build
$ sudo mkdir -p /opt/flang
$ INSTALLDIR="/opt/flang"
$ cmake \
-G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$INSTALLDIR \
-DCMAKE_CXX_STANDARD=17 \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DCMAKE_CXX_LINK_FLAGS="-Wl,-rpath,$LD_LIBRARY_PATH" \
-DFLANG_ENABLE_WERROR=OFF \ # OFFにしないと `-Werror=dangling-reference` に引っ掛かってしまう...
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_TARGETS_TO_BUILD=host \
-DLLVM_LIT_ARGS=-v \
-DLLVM_ENABLE_PROJECTS="clang;mlir;flang;openmp" \
-DLLVM_ENABLE_RUNTIMES="compiler-rt" \
../llvm
$ ninja -j 1 # 長い
$ ninja flang-check -j 1 # しなくても良い?
$ sudo ninja install -j 1
-
cmake
のオプションは一部変えてあります. - 何故か
-DFLANG_ENABLE_WERROR=ON
にすると-Werror=dangling-reference
に引っかかりました.- まあ, WARNING なので(使用者は)無視しても良いでしょう.
- メモリに余裕があるなら
ninja -j (CPUの数を表す数字)
に.- 並列にビルドされ, 速くなります.
- 並列ビルドしない場合は14時間くらい掛かりました...
- この設定なら,
/opt/flang/bin
に色々インストールされます.
バイナリをダウンロード
- ビルドしない場合はバイナリを取りましょう.
$ wget https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.5/LLVM-19.1.5-Linux-X64.tar.xz
$ tar xvf LLVM-19.1.5-Linux-X64.tar.xz
$ sudo mkdir -p /opt/flang
$ sudo mv LLVM-19.1.5-Linux-X64 /opt/flang
$ export PATH="/opt/flang/LLVM-19.1.5-Linux-X64/bin:$PATH"
- この設定では,
/opt/flang/LLVM-19.1.5-Linux-X64/bin
に色々インストールされます.
(追記) apt からインストール
(Louise さんより情報をいただきました. ありがとうございます)
こちらのQiita の記事によると, llvm の公式リポジトリ から apt
でインストールできるそうです.
flang を試してみる
以下, ビルドしたものではなく, バイナリの flang-new
でコンパイルしています.
出力してみた
program test
use, intrinsic :: iso_fortran_env
implicit none
integer(int64), parameter :: x = 10_int64 ** 10
print*, x
write(output_unit, '(a)') "Hello, World!"
end program
$ export PATH="/opt/flang/bin:$PATH"
$ flang-new test.f90 && ./a.out
10000000000
Hello, World!
$ gfortran test.f90 && ./a.out
10000000000
Hello, World!
うん? 何か gfortran
と違いますね.
gfortran
では整数のバイト数に依存する空白が出ます.
program hi
use, intrinsic :: iso_fortran_env
implicit none
integer(int32) :: x
integer(int64) :: x2
x = 1; x2 = 1_int64
print*, x, x2
print*, x2, x
end program
$ flang-new test2.f90 && ./a.out
1 1
1 1
$ gfortran test2.f90 && ./a.out
1 1
1 1
$ ifx test2.f90 && ./a.out
1 1
1 1
$ nvfortran test2.f90 && ./a.out
1 1
1 1
$ flang test2.f90 && ./a.out
1 1
1 1
flang-new
では整数のバイト数に依存する空白がないようです.
classic flang
と nvfortran
と異なるようです.
program hi
use, intrinsic :: iso_fortran_env
implicit none
integer(int64) :: x
x = 1000000_int64
print'(i0)', x
print'(i4)', x
end program
$ flang-new test3.f90 && ./a.out
1000000
****
$ gfortran test3.f90 && ./a.out
1000000
****
$ ifx test3.f90 && ./a.out
1000000
****
$ nvfortran test3.f90 && ./a.out
1000000
****
$ flang test3.f90 && ./a.out
1000000
****
フォーマットを指定した場合はどれも同じです.
以前書いたやつをコンパイルしてみる.
$ find . -name '*f90' | xargs -I{} bash -c 'gfortran {} 2>/dev/null && echo {}' > success_compile.txt
$ wc -l success_compile.txt
4427 success_compile.txt
$ cat success_compile.txt | xargs -I{} bash -c 'flang-new {} 2>> flang-errors.txt || echo {}' > failed_flang-new.txt
$ wc -l failed_flang-new.txt
34 failed_flang-new.txt
gfortran
でコンパイルできた 4427個(半分くらいは重複している)の .f90
を flang-new
でコンパイルすると34個はコンパイルに失敗しているようです.
といっても, ほとんどが以下の関数の引数の順番でエラーが起こっているようです.
関数の引数
test_arg1.f90
module test
use, intrinsic :: iso_fortran_env
implicit none
contains
integer function f(arr, n) result(res)
integer(int32), intent(in) :: arr(n)
integer(int32), intent(in) :: n
res = 0
end function
end module
$ flang-new -c test_arg1.f90
$ gfortran -c test_arg1.f90
$ ifx -c test_arg1.f90
$ nvfortran -c test_arg1.f90
$ flang -c test_arg1.f90
関数の引数に配列があり, その配列のサイズを引数 n
で決めている場合.
どのコンパイラでもうまくいきます.
... n
の宣言が下にあっても...
test_arg2.f90
module test
use, intrinsic :: iso_fortran_env
implicit none
contains
integer function f(arr, n, u) result(res)
integer(int32), intent(in) :: arr(n, u)
integer(int32), intent(in) :: n, u
res = 0
end function
end module
$ flang-new -c test_arg2.f90
error: Semantic errors in test_arg2.f90
./test_arg2.f90:5:30: error: No explicit type declared for 'u'
integer function f(arr, n, u) result(res)
^
$ gfortran -c test_arg2.f90
$ ifx -c test_arg2.f90
test_arg2.f90(7): error #6415: This name cannot be assigned this data type because it conflicts with prior uses of the name. [U]
integer(int32), intent(in) :: n, u
-------------------------------------^
compilation aborted for test_arg2.f90 (code 1)
$ nvfortran -c test_arg2.f90
$ flang -c test_arg2.f90
2次元配列のサイズを下に書くと, flang-new
と ifx
はエラーとなってしまいます.
test_arg3.f90
module test
use, intrinsic :: iso_fortran_env
implicit none
contains
integer function f(arr, n, u) result(res)
integer(int32), intent(in) :: u
integer(int32), intent(in) :: arr(n, u)
integer(int32), intent(in) :: n
res = 0
end function
end module
$ flang-new -c test_arg3.f90
$ gfortran -c test_arg3.f90
$ ifx -c test_arg3.f90
$ nvfortran -c test_arg3.f90
$ flang -c test_arg3.f90
配列の上で宣言すればエラーは出ません...
Fortran の仕様まで踏み込まないと分からないかもしれません...
pure
な関数の外の配列の要素を associate
できない
test_associate.f90
program hi
use, intrinsic :: iso_fortran_env
implicit none
integer(int32), allocatable :: g(:)
contains
pure recursive subroutine dfs()
associate(nv => g(1))
end associate
end subroutine dfs
end program hi
$ flang-new test_associate2.f90
error: Semantic errors in test_associate2.f90
./test_associate2.f90:7:15: error: A pure subprogram may not have a variable with the SAVE attribute
associate(nv => g(1))
^^
$ gfortran test_associate2.f90
これが正しい挙動かどうかは分かりませんが, save
属性持っているわけではないので, エラーメッセージがおかしいかもしれません.
flang で fortran-stdlib(v0.7.0) をビルドしてみよう...と思いましたができません...
試しに fortran-stdlibのv0.7.0 をビルドしてみます.
以下の方法では python3-joblib
と fypp
と fpm
が必要です.
(cmake
を使う方法もあります.)
$ wget https://github.com/fortran-lang/stdlib/archive/refs/tags/v0.7.0.tar.gz
$ tar xvf v0.7.0.tar.gz
$ cd stdlib-0.7.0
$ python3 config/fypp_deployment.py
$ fpm build --compiler="flang-new" --profile release
# (たくさん出力される)
./././src/temp/stdlib_specialfunctions_gamma.f90:384:49: error: Value of named constant 'pi' (acos(-1._16)) cannot be computed as a constant value
one = 1.0_qp, pi = acos(- one), sqpi = sqrt(pi)
^^^^^^^^^^^
# (略)
どうやら, 4倍精度実数を扱うにはビルド時に指定する必要があるようです.
また, flang-new
(19.1.5) の時点で assumed-rank-array
(select rank) に対応していないのでいくつかのファイルはコンパイルできません.
ビルドではなく, fpm.toml
の dependencies
に書く方法を使った方が良いかもしれません.
まとめ
モダンになった flang-new
を使ってみました.
gfortran
とは仕様が違いそうですが, どちらでもコンパイルできるようにしておくと良いかもしれません.
今回は flang-new
の利点が見えませんでしたが, いつか, LLVM の力を見られるようなことをしてみたいですね.
参考
flang
LLVM
fortran-stdlib