Skip to content

Commit

Permalink
Add Fypp support (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
aradi authored Aug 30, 2024
1 parent 9d572e3 commit eec759f
Show file tree
Hide file tree
Showing 18 changed files with 614 additions and 26 deletions.
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ jobs:
if: ${{ contains(matrix.compiler, 'intel') }}
uses: rscohn2/setup-oneapi@v0
with:
components: ifx
# Note: intel 2024.1 and 2024.2 fail to build Fortuno properly due to a compiler bug,
# see https://community.intel.com/t5/Intel-Fortran-Compiler/Compiler-bug-Procedure-pointer-association-status-gets-lost/m-p/1612121#M172850
components: ifx@2024.0.0

- name: Setup Intel environment
if: ${{ contains(matrix.compiler, 'intel') }}
Expand All @@ -63,7 +65,7 @@ jobs:
- name: Setup build tools
run: |
pip install cmake fpm meson ninja
pip install cmake fpm meson ninja fypp
- name: Build Fortuno with CMake
run: |
Expand All @@ -87,7 +89,8 @@ jobs:
run: |
CMAKE_PREFIX_PATH=${INSTALL_DIR} cmake -B ${BUILD_DIR} -G Ninja test/export
cmake --build ${BUILD_DIR}
${BUILD_DIR}/testapp
${BUILD_DIR}/app/testapp
${BUILD_DIR}/app/testapp_fypp
rm -rf ${BUILD_DIR}
- name: Test fpm export
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,16 @@ if (FORTUNO_INSTALL)
include(GNUInstallDirs)
endif ()

find_program(FYPP fypp)

set(BUILD_SHARED_LIBS ${FORTUNO_BUILD_SHARED_LIBS})
fortuno_setup_build_type("RelWithDebInfo")

#[=================================================================================================[
# Main definition #
]=================================================================================================]

add_subdirectory(include)
add_subdirectory(src)
if (FORTUNO_BUILD_EXAMPLES)
add_subdirectory(example)
Expand Down Expand Up @@ -141,6 +144,7 @@ if (FORTUNO_INSTALL)
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Fortuno
COMPONENT Fortuno_development
)

endif ()

# Make project available for FetchContent
Expand Down
26 changes: 15 additions & 11 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -234,21 +234,25 @@ Fortuno. We recommend to use those compilers or any newer versions of them.
+------------------------+-----------------------------------------------------+
| Compiler | Status |
+========================+=====================================================+
| Intel 2024.0 | * serial: OK |
| | * mpi: OK |
| | * coarray: OK |
| Intel 2024.0 [1] | * OK (serial, mpi, coarray) |
+------------------------+-----------------------------------------------------+
| NAG 7.2 (build 7202) | * serial: OK |
| | * mpi: OK |
| | * coarray: OK |
| NAG 7.2 (build 7202) | * OK (serial, mpi, coarray) |
+------------------------+-----------------------------------------------------+
| GNU 13.2 | * serial: OK |
| | * mpi: OK |
| | * coarray: not tested yet |
| GNU 13.2, 14.1 | * OK (serial, mpi) |
| | * untested (coarray) |
+------------------------+-----------------------------------------------------+

If you are aware of any other compilers being able to build Fortuno, open a pull
request to update the table.
If you are aware of any other compilers being able to build Fortuno, please,
open a pull request to update the table.

Notes
-----

1. Please ensure you are using Intel 2024.0, as newer versions (2024.1 and
2024.2) have a confirmed compiler bug that creates an incorrect binary,
leading to segmentation faults due to the loss of pointer association status.
For more details, refer to the `Intel community discussion
<https://community.intel.com/t5/Intel-Fortran-Compiler/Compiler-bug-Procedure-pointer-association-status-gets-lost/m-p/1612121>`_.


License
Expand Down
30 changes: 29 additions & 1 deletion cmake/FortunoHelpers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,32 @@ function (fortuno_add_thread_safe_build_flags target)
target_link_libraries(${target} PRIVATE $<BUILD_LOCAL_INTERFACE:ThreadSafeBuild>)
endif ()

endfunction ()
endfunction ()


# Preprocesses source files
#
# Args:
# preproc: preprocessor to use (e.g. Fypp)
# preprocopts: options to pass to the preprocessor (apart of input and output files)
# oldext: extension of the files to pre-process (e.g. .fypp or .F90)
# newext: extension of the pre-processed source files (e.g. .f90)
# oldfiles: list of the files to preprocess
# newfiles [out]: variable which should contain the list of the pre-processed files on return
#
function (fortuno_preprocess preproc preprocopts oldext newext oldfiles newfiles)

foreach (oldfile IN LISTS oldfiles)
# Start with an absolulte path, so that the correct relative path is calculated thereafter
get_filename_component(oldfile ${oldfile} ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR})
file(RELATIVE_PATH oldfile ${CMAKE_CURRENT_SOURCE_DIR} ${oldfile})
string(REGEX REPLACE "\\${oldext}$" "${newext}" _newfile "${oldfile}")
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_newfile}
COMMAND ${preproc} ${preprocopts} ${CMAKE_CURRENT_SOURCE_DIR}/${oldfile} ${CMAKE_CURRENT_BINARY_DIR}/${_newfile}
MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/${oldfile})
list(APPEND _newfiles ${CMAKE_CURRENT_BINARY_DIR}/${_newfile})
endforeach ()
set(${newfiles} "${_newfiles}" PARENT_SCOPE)

endfunction ()
5 changes: 5 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,8 @@ target_sources(
testapp.f90
)
target_link_libraries(fortuno_example_testapp PRIVATE fortuno_example_mylib Fortuno::fortuno_serial)


if (FYPP)
add_subdirectory(fypp)
endif ()
46 changes: 46 additions & 0 deletions example/fypp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This file is part of Fortuno.
# Licensed under the BSD-2-Clause Plus Patent license.
# SPDX-License-Identifier: BSD-2-Clause-Patent

list(APPEND CMAKE_MESSAGE_CONTEXT Fypp)

add_library(fortuno_example_fypp_mylib)
set_target_properties(
fortuno_example_fypp_mylib PROPERTIES
OUTPUT_NAME mylib
)
target_sources(
fortuno_example_fypp_mylib PRIVATE
mylib.f90
)

add_executable(fortuno_example_fypp_testapp)
set_target_properties(
fortuno_example_fypp_testapp PROPERTIES
OUTPUT_NAME testapp_fypp
)

set(
fypp-sources
fixtured_fypp_tests.fypp
parametrized_fypp_tests.fypp
simple_fypp_tests.fypp
)

get_target_property(_fortuno_incdir Fortuno::fortuno_include_dir INTERFACE_INCLUDE_DIRECTORIES)
fortuno_preprocess(
${FYPP} "-I${_fortuno_incdir};--file-var-root=${CMAKE_SOURCE_DIR}"
.fypp .f90
"${fypp-sources}" fypp-f90-sources
)

target_sources(
fortuno_example_fypp_testapp PRIVATE
${fypp-f90-sources}
testapp_fypp.f90
)
target_link_libraries(
fortuno_example_fypp_testapp
PRIVATE
fortuno_example_fypp_mylib Fortuno::fortuno_serial
)
96 changes: 96 additions & 0 deletions example/fypp/fixtured_fypp_tests.fypp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
! This file is part of Fortuno.
! Licensed under the BSD-2-Clause Plus Patent license.
! SPDX-License-Identifier: BSD-2-Clause-Patent

#:include "fortuno_serial.fypp"

module fixtured_fypp_tests
use mylib_fypp, only : factorial
use fortuno_serial, only : char_rep_int, is_equal, named_state, named_item,&
& suite => serial_suite_item, store_state => serial_store_state,&
& serial_case_base, test_item
$:FORTUNO_SERIAL_IMPORTS()
implicit none

private
public :: fixtured_fypp_test_items


! Fixtured test case creating a random number before running a test procedure.
type, extends(serial_case_base) :: random_test_case

! Test procedure to be invoked once fixture setup had been executed
procedure(test_recursion_down), pointer, nopass :: proc

contains

! Overrides run procedure to set up fixture before test procedure is invoked.
procedure :: run => random_test_case_run

end type random_test_case

contains


! TEST n! = n * (n - 1)!
$:TEST("recursion_down", args=["nn"])
integer, intent(in) :: nn
@:CHECK(is_equal(factorial(nn), nn * factorial(nn - 1)))
$:END_TEST()


! TEST (n + 1)! = (n + 1) * n!
$:TEST("recursion_up", args=["nn"])
integer, intent(in) :: nn
@:CHECK(is_equal(factorial(nn + 2), (nn + 1) * factorial(nn)))
$:END_TEST()


! Returns the tests from this module.
function fixtured_fypp_test_items() result(testitems)
type(test_item), allocatable :: testitems(:)

testitems = [&
suite("fixtured", [&
$:TEST_ITEMS(constructor="random_test")
])&
]
#! Stop if there are tests without corresponding generated test_item constructors
$:STOP_ON_MISSING_TEST_ITEMS()

end function fixtured_fypp_test_items


! Convenience function returning a random_test_case instance wrapped as test_item.
function random_test(name, proc) result(testitem)
character(*), intent(in) :: name
procedure(test_recursion_down) :: proc
type(test_item) :: testitem

testitem%item = random_test_case(name=name, proc=proc)

end function random_test


! Run procedure of the random_test_case class.
subroutine random_test_case_run(this)
class(random_test_case), intent(in) :: this

real :: rand
integer :: nn

! Set-up fixture by creating a random number
call random_number(rand)
! Note: factorial(n) with n > 13 overflows with 32 bit integers
nn = int(13 * rand) + 1
! Store internal state to aid introspection/identification later
call store_state(&
named_state([&
named_item("n", char_rep_int(nn))&
&])&
)
call this%proc(nn)

end subroutine random_test_case_run

end module fixtured_fypp_tests
34 changes: 34 additions & 0 deletions example/fypp/mylib.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
! This file is part of Fortuno.
! Licensed under the BSD-2-Clause Plus Patent license.
! SPDX-License-Identifier: BSD-2-Clause-Patent

!> Demo module/library to be tested
module mylib_fypp
implicit none

private
public :: factorial

contains

!> Calculates the factorial of a number
function factorial(nn) result(fact)

!> Number to calculate the factorial of
integer, intent(in) :: nn

!> Factorial (note, there is no check made for integer overflow!)
integer :: fact

integer :: ii

fact = 1
do ii = 2, nn
fact = fact * ii
end do
! We create a "bug" which manifests only for certain input values
if (nn == 2 .or. nn > 10) fact = fact - 1

end function factorial

end module mylib_fypp
76 changes: 76 additions & 0 deletions example/fypp/parametrized_fypp_tests.fypp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
! This file is part of Fortuno.
! Licensed under the BSD-2-Clause Plus Patent license.
! SPDX-License-Identifier: BSD-2-Clause-Patent

#:include "fortuno_serial.fypp"

module parametrized_fypp_tests
use mylib_fypp, only : factorial
use fortuno_serial, only : as_char, is_equal, serial_case_base, suite => serial_suite_item,&
& test_item
$:FORTUNO_SERIAL_IMPORTS()
implicit none

private
public :: parametrized_fypp_test_items


!> Contains argument and expected result of a factorial() invokation
type :: arg_res
integer :: arg, res
end type

!> Argument/result pairs to check for
type(arg_res), parameter :: testcaseparams(*) = [&
& arg_res(1, 1), arg_res(2, 2), arg_res(3, 6), arg_res(4, 24), arg_res(5, 120)&
& ]


!> Parametrized test checking for an individual argument/result pair.
type, extends(serial_case_base) :: parametrized_test_case
type(arg_res) :: argres
contains
procedure :: run => parametrized_test_case_run
end type parametrized_test_case

contains


!> Returns the tests of this module.
function parametrized_fypp_test_items() result(testitems)
type(test_item), allocatable :: testitems(:)

integer :: ii

testitems = [&
suite("parametrized", [&
(parametrized_test("factorial", testcaseparams(ii)), ii = 1, size(testcaseparams))&
])&
]

end function parametrized_fypp_test_items


!> Run method of the parametrized test (executing the check directly)
subroutine parametrized_test_case_run(this)
class(parametrized_test_case), intent(in) :: this

@:CHECK(is_equal(factorial(this%argres%arg), this%argres%res))

end subroutine parametrized_test_case_run


!> Convenience wrapper to generate a test case wrapped as test_item for a given argres pair.
function parametrized_test(prefix, argres) result(testitem)
character(*), intent(in) :: prefix
type(arg_res), intent(in) :: argres
type(test_item) :: testitem

character(:), allocatable :: name

name = prefix // "_" // as_char(argres%arg)
testitem%item = parametrized_test_case(name=name, argres=argres)

end function parametrized_test

end module parametrized_fypp_tests
Loading

0 comments on commit eec759f

Please sign in to comment.