I would like to use pFUnit in my project and download using FetchContent
in extern/pFunit/CMakeLists.txt
. My project structure is as follows:
broken/
├── CMakeLists.txt
├── extern
│ ├── CMakeLists.txt
│ └── pFUnit
│ └── CMakeLists.txt
├── src
│ ├── CMakeLists.txt
│ └── square.f90
└── test
├── CMakeLists.txt
└── test_square.pf
when attempting cmake -S . -B build -DCMAKE_Fortran_COMPILER=mpif90
, pFUnit
does not configure correctly (maybe I open an issue in their github, but since i'm new to cmake, my issue could be a more basic misunderstanding) and throws the error preceded by some debugging information from variable_watch(PFUNIT_DRIVER)
:
CMake Debug Log at build/_deps/pfunit-src/CMakeLists.txt:223 (set):
Variable "PFUNIT_DRIVER" was accessed using MODIFIED_ACCESS with value
"/home/jf01/dev/minimal-fetch-content-pfunit/broken/build/_deps/pfunit-src/include/driver.F9
0".
CMake Debug Log at build/_deps/pfunit-src/include/add_pfunit_ctest.cmake:70 (configure_file):
Variable "PFUNIT_DRIVER" was accessed using UNKNOWN_READ_ACCESS with value
"".
Call Stack (most recent call first):
test/CMakeLists.txt:1 (add_pfunit_ctest)
CMake Error: File /home/jf01/dev/minimal-fetch-content-pfunit/broken/test/.in does not exist.
CMake Error at build/_deps/pfunit-src/include/add_pfunit_ctest.cmake:70 (configure_file):
configure_file Problem configuring file
Call Stack (most recent call first):
test/CMakeLists.txt:1 (add_pfunit_ctest)
It's odd to me that PFUNIT_DRIVER
is correctly read and set in one file, but is an empty string in the other. Any suggestions for resolving this error?
Below are the contents of the files in my broken example, but for convenience, you can also pull my code from jfdev001/minimal-fetch-content-pfunit and reproduce a working (yet not ideally structured) and broken example as needed.
###########################
# @file CMakeLists.txt
###########################
cmake_minimum_required(VERSION 3.15)
project(
TestPFUNIT
VERSION 0.1.0
LANGUAGES Fortran
)
variable_watch(PFUNIT_DRIVER)
add_subdirectory(src)
enable_testing()
add_subdirectory(extern)
add_subdirectory(test)
###########################
# @file extern/CMakeLists.txt
###########################
add_subdirectory(pFUnit)
###########################
# @file extern/pFUnit/CMakeLists.txt
###########################
include(FetchContent)
set(PFUNIT_VERSION "v4.9.0")
FetchContent_Declare(
PFUNIT
GIT_REPOSITORY "https://github.com/Goddard-Fortran-Ecosystem/pFUnit"
GIT_TAG ${PFUNIT_VERSION}
)
FetchContent_MakeAvailable(PFUNIT)
###########################
# @file src/CMakeLists.txt
###########################
add_library(sut
square.f90
)
set_target_properties(sut
PROPERTIES
Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
# Allows successful linking of sut in the tests/CMakeLists.txt
target_include_directories(sut
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}
)
###########################
# @file src/square.f90
###########################
MODULE Square_mod
IMPLICIT NONE
CONTAINS
PURE REAL FUNCTION square(x)
REAL, INTENT(in) :: x
square = x**2
END FUNCTION square
END MODULE Square_mod
###########################
# @file test/CMakeLists.txt
###########################
add_pfunit_ctest (test_square
TEST_SOURCES test_square.pf
LINK_LIBRARIES sut
LABELS "myproject"
)
###########################
# @file test/test_square.pf
###########################
@test
SUBROUTINE test_square()
USE Square_mod
USE funit
@assertEqual(9., square(3.), 'square(3)')
END SUBROUTINE test_square
A working example can be compiled by placing the pfunit fetch content in the toplevel CMakeLists.txt
and structuring the project as shown below, but for organizational purposes, it seems like it would be a better practice to put such dependencies in a separate folder (see e.g., fortran-lang/fftpack, jchristopherson/dynamics).
working/
├── CMakeLists.txt
├── src
│ ├── CMakeLists.txt
│ └── square.f90
└── test
├── CMakeLists.txt
└── test_square.pf
Turns out this was a bug in the library itself and not just a basic misunderstanding of cmake. The problem is addressed in https://github.com/Goddard-Fortran-Ecosystem/pFUnit/pull/485
As pointed out by @Tsyvarev, the scoping of PFUNIT_DRIVER
was the source of the problem. The sledgehammer solution was to cache this variable (i.e., using the CACHE
) so that the variable is visible at all scopes.