Following program compiles(in f2py) when the subroutine doesn't contain any internal procedures but fails to compile in f2py (compiles with gfortran) when it contains any internal procedure
Fortran code:
subroutine example(array)
implicit none
real*8::array(:,:)
INTEGER::i,j
!f2py intent(inout)::array
do i=1,3
do j=1,3
array(i,j)=10*i+j
enddo
! print*,''
enddo
call tentimes(array)
RETURN
contains
subroutine tentimes(array)
implicit none
!f2py intent(inout):array
real*8::array(:,:)
array=array*10
end subroutine tentimes
end subroutine example
program dummy
implicit none
end program dummy
compiled with python -m numpy.f2py -c allocate.f90 -m ftest
and the python code :
import numpy as np
a=np.zeros((3,3),order="F")
print(a)
res=ftest.example(a)
print(a)
Why is this happening?
Error generated by f2py:
compiling Fortran sources
Fortran f77 compiler: /usr/bin/gfortran -Wall -g -ffixed-form -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran f90 compiler: /usr/bin/gfortran -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran fix compiler: /usr/bin/gfortran -Wall -g -ffixed-form -fno-second-underscore -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
compile options: '-I/tmp/tmpwd_qygau/src.linux-x86_64-3.9 -I/home/srj/.local/lib/python3.9/site-packages/numpy/core/include -I/usr/include/python3.9 -c'
gfortran:f90: allocate.f90
allocate.f90:17:31:
17 | subroutine tentimes(array_i)
| 1
Warning: Unused dummy argument ‘array_i’ at (1) [-Wunused-dummy-argument]
allocate.f90:17:23:
17 | subroutine tentimes(array_i)
| ^
Warning: ‘tentimes’ defined but not used [-Wunused-function]
gfortran:f90: /tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90
/tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90:13:17:
13 | subroutine tentimes(array_i)
| 1
Error: Unclassifiable statement at (1)
/tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90:15:39:
15 | end subroutine tentimes
| 1
Error: Expected label ‘example’ for END SUBROUTINE statement at (1)
/tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90:14:53:
14 | real*8, dimension(:,:) :: array_i
| 1
Error: Array ‘array_i’ at (1) cannot have a deferred shape
error: Command "/usr/bin/gfortran -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops -I/tmp/tmpwd_qygau/src.linux-x86_64-3.9 -I/home/srj/.local/lib/python3.9/site-packages/numpy/core/include -I/usr/include/python3.9 -c -c /tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.f90 -o /tmp/tmpwd_qygau/tmp/tmpwd_qygau/src.linux-x86_64-3.9/ftest-f2pywrappers2.o" failed with exit status 1
Similar nested procedures work well in gfortran. Why does this error happen? How to rectify this?
EDIT: The better way is to use f2py is "the smart way"
just doing this works well
python -m numpy.f2py allocate.f90 -m ftest -h ftest.pyf && \
python -m numpy.f2py -c ftest.pyf allocate.f90
Since this bypasses generating FORTRAN interface.
Okay, I confirmed it's a bug in f2py, the generated code in f2pywrappers2.f90 has an error
f2py produces:
! -*- f90 -*-
! This file is autogenerated with f2py (version:1.21.2)
! It contains Fortran 90 wrappers to fortran functions.
subroutine f2pywrapexample (array, f2py_array_d0, f2py_array_d1)
integer f2py_array_d0
integer f2py_array_d1
real*8 array(f2py_array_d0,f2py_array_d1)
interface
subroutine example(array)
real*8, dimension(:,:),intent(inout) :: array
subroutine tentimes(array)
real*8, dimension(:,:) :: array
end subroutine tentimes
end subroutine example
end interface
call example(array)
end
correct code:
subroutine f2pywrapexample (array, f2py_array_d0, f2py_array_d1)
integer f2py_array_d0
integer f2py_array_d1
real*8 array(f2py_array_d0,f2py_array_d1)
interface
subroutine example(array)
real*8, dimension(:,:),intent(inout) :: array
end subroutine example
subroutine tentimes(array)
real*8, dimension(:,:) :: array
end subroutine tentimes
end interface
call example(array)
end
the interface shouldn't actually contain nested procedures, even though the subroutine has a nested procedure
fixing this, then generating the corresponding object, placing it in the correct temp folder and manually linking with the command
/usr/bin/gfortran -Wall -g -Wall -g -shared /tmp/tmpfw0ammli/tmp/tmpfw0ammli/src.linux-x86_64-3.9/ftestmodule.o /tmp/tmpfw0ammli/tmp/tmpfw0ammli/src.linux-x86_64-3.9/fortranobject.o /tmp/tmpfw0ammli/allocate.o /tmp/tmpfw0ammli/tmp/tmpfw0ammli/src.linux-x86_64-3.9/ftest-f2pywrappers2.o -L/usr/lib/gcc/x86_64-redhat-linux/11 -L/usr/lib/gcc/x86_64-redhat-linux/11 -L/usr/lib64 -lgfortran -o ./ftest.cpython-39-x86_64-linux-gnu.so
this succeeded, and python prints correct output.