cmake -S . -B build
cmake --build build
ctest --test-dir build
================= OUTPUT ==============
Test project XXXXX
Start 1: saxpy_test
1/3 Test #1: saxpy_test ....................... Passed 0.09 sec
Start 2: sgemv_test
2/3 Test #2: sgemv_test ....................... Passed 0.00 sec
Start 3: rand_mat_svd_test
3/3 Test #3: rand_mat_svd_test ................ Passed 0.08 sec
Despite its age, Fortran continues to reign as the dominant language in advanced numerical algorithms and physics simulations. Cutting-edge numerical algorithms, including BLAS3-based LU, QR, RRQR, and implementations of eigenvalue/svd with divide-and-conquer, are exclusively found in LAPACK, setting it apart from competing clones like Eigen or Armadillo. This makes Fortran the preferred choice for researchers developing new algorithms, as it provides a foundation for benchmarking against established baselines written in the language.
While Fortran lacks a standardized unit testing framework, developers have devised custom testing systems for their projects. Unfortunately, many Fortran-based unit test frameworks suffer from infrequent updates due to the language's lesser popularity, leading to their exclusion from consideration. In pursuit of solutions with minimal dependencies and robust support in major systems like CMake and CTest, pyohannes introduced a groundbreaking demo utilizing solely CMake and CTest for Fortran (link). We have further enhanced this solution by eliminating the need for platform-dependent symbol mangling and enabling the grouping of multiple unit tests within a single Fortran file.
Users can group multiple tests into a single module as follows. The test functions return 0s on success, otherwise it is treated as failures.
! my_tests.f90
module my_tests_mod
use iso_fortran_env
use iso_c_binding
implicit none
contains
integer function my_test_success() result(ret) bind(C)
ret = 0
end function my_test_success
integer function my_test_fail() result(ret) bind(C)
ret = 1
end function my_test_fail
end module my_tests_mod
Since we used bind(C)
in the Fortran code, we don't need
the symbol mangling that pyohannes used. Creating a test
binary with CMake is quite simple as follows:
project(fortran_test)
enable_language(Fortran)
set(TEST_LIST
my_test_success
my_test_fail
)
create_test_sourcelist(_ my_tests_main.c ${TEST_LIST})
add_executable(my_tests my_tests_main.c my_tests.f90)
foreach (test ${TEST_LIST})
add_test(NAME ${test} COMMAND my_tests ${test})
endforeach ()
- Begin by specifying the list of Fortran functions to be tested in a variable
named
TEST_LIST
. - Use
create_test_sourcelist
to generate a C file responsible for handling command line parsing, providing logging support, and forward declaring the test functions listed inTEST_LIST
. - Proceed to create the test executable using
add_executable
. Ensure to include all necessary source dependencies within this macro. If shared library dependencies are required, incorporatetarget_link_libraries
for linking. - Conclude by invoking
add_test
for each test to be executed.
The following snippet builds and runs the tests.
cmake -S . -B build
cmake --build build
ctest [--verbose] --test-dir build
To write your code in a clean and consistent style, we recommend to format the code with fprettify.
fprettify -i 2 --strict-indent --enable-decl --disable-indent-mod -l 80 FILE.f90
CMake support a wide range of system packages. For the packages that wasn't included by default, user may leverage the built-in pkg-config support in CMake.
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(EIGEN REQUIRED IMPORTED_TARGET eigen3)
target_link_libraries(
lapack_test
BLAS::BLAS
LAPACK::LAPACK
PkgConfig::EIGEN
)
User may further integrate with github actions for CI:
# .github/workflows/main.yml
name: CMake
on: push
jobs:
build-project:
name: Build Project
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/[email protected]
- name: Dependencies
uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: gfortran libopenblas-dev liblapack-dev
version: 1.0
- name: Configure, build, and test
uses: threeal/[email protected]
with:
run-build: true
run-test: true