This is an interesting issue I recently encountered. Consider this example of defining a number Fortran-C intercompatible function.
module m_api
use, intrinsic :: iso_c_binding
implicit none
character(len=*), parameter :: namespace = "m_"
contains
function info_api() result(stat) bind(C, name=namespace//"info")
integer(c_int) :: stat
! ...
end function info_api
end module m_api
Because I’m lazy (and want to avoid mistyping the namespace in one of the bind(C)
declaration) I define a character constant in the module scope and concatenate it with the actual function name. This works surprisingly well with most compilers I tested (only failed in NVHPC 21.3 so far).
Having learnt about this useful feature I tried to use it for C-Fortran bindings as well, especially to avoid mixing preprocessor into the interface declarations like here:
module m_os
use, intrinsic :: iso_c_binding
implicit none
interface
function chdir(path) result(stat) &
#ifndef _WIN32
& bind(C, name="chdir")
#else
& bind(C, name="_chdir")
#endif
import :: c_char, c_int
character(kind=c_char, len=1), intent(in) :: path(*)
integer(c_int) :: stat
end function chdir
end interface
end module m_os
Moving out the symbol name could greatly improve the readability here:
module m_os
use, intrinsic :: iso_c_binding
implicit none
#ifndef _WIN32
character(len=*), parameter :: chdir_symbol = "chdir"
#else
character(len=*), parameter :: chdir_symbol = "_chdir"
#endif
interface
function chdir(path) result(stat) bind(C, name=chdir_symbol)
import :: c_char, c_int, chdir_symbol
character(kind=c_char, len=1), intent(in) :: path(*)
integer(c_int) :: stat
end function chdir
end interface
end module m_os
As it turns out, this is not accepted by the compiler:
❯ gfortran -c os.F90
os.F90:11:51:
11 | function chdir(path) result(stat) bind(C, name=chdir_symbol)
| 1
Error: Parameter ‘chdir_symbol’ at (1) has not been declared or is a variable, which does not reduce to a constant expression
os.F90:12:13:
12 | import :: c_char, c_int, chdir_symbol
| 1
Error: IMPORT statement at (1) only permitted in an INTERFACE body
os.F90:13:21:
13 | character(kind=c_char, len=1), intent(in) :: path(*)
| 1
Error: Parameter ‘c_char’ at (1) has not been declared or is a variable, which does not reduce to a constant expression
os.F90:14:14:
14 | integer(c_int) :: stat
| 1
Error: Parameter ‘c_int’ at (1) has not been declared or is a variable, which does not reduce to a constant expression
os.F90:15:7:
15 | end function chdir
| 1
Error: Expecting END INTERFACE statement at (1)
What am I missing here? Is this a scoping issue due to the interface having a separated scope from the module and therefore cannot see the chdir_symbol
parameter? Is there a way to make this work or is this usage indeed not possible?