При попытке обернуть некоторый код Fortran в Python с помощью Cython, я обнаружил, что оператор Fortran WRITE
может заставить сгенерированный Python модуль обработать sh (ошибка сегментации).
Если быть точным, оператор WRITE
вызывает cra sh, только если он содержит строку формата. Без форматной строки он не сможет обработать sh. А именно, WRITE(*,*) "xxx"
не создает sh, а WRITE(*,"(A)") "xxx"
делает. При вызове обычной процедурой на языке Fortran или C ++ соответствующая подпрограмма работает должным образом и не имеет cra sh.
. Ниже приведен пример. Он содержит несколько файлов:
1. fortran_write.f90
2. testwrite.pyx
3. header.hpp
4. setup.py
Файл fortran_write.f90
:
module mod_write
use, intrinsic :: ISO_C_BINDING
implicit none
contains
subroutine fwrite(flag) bind(C, name="write_f")
integer*4, intent(in) :: flag
write(*, *) "In fwrite: flag=", flag
if (flag .eq. 0) then
write(*, *) "Message from fwrite (write_f)."
else if (flag .eq. 1) then
write(*, *) "MSG", 1234, 12.34
else if (flag .eq. 2) then
write(*, "(A40)") "Message from fwrite (write_f)."
else if (flag .eq. 3) then
write(*, "(I6)") 1234
else if (flag .eq. 4) then
write(*, "(F6.2)") 12.34
end if
end subroutine fwrite
end module mod_write
Файл testwrite.pyx
:
# distutils: language = c++
cdef extern from "header.hpp":
void write_f(int* flag)
cdef writef(flag):
cdef int f;
f = flag
write_f(&f)
def run():
writef(0)
writef(1)
writef(2)
writef(3)
writef(4)
Файл header.hpp
:
extern "C" {
void write_f(int* flag);
}
Файл setup.py
:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
extension = Extension(
name="testwrite",
sources=["testwrite.pyx"],
libraries=["testwrite", "gfortran"],
library_dirs=["./", "/usr/local/Cellar/gcc/9.2.0_1/lib/gcc/9/"],
include_dirs=["./"],
depends=['fortran_write.f90', 'header.hpp'],
extra_compile_args=["-std=c++11"])
setup(
name="testwrite",
ext_modules=cythonize([extension], language_level="3")
)
Процедура компиляции:
gfortran -c fortran_write.f90
ar rcs libtestwrite.a fortran_write.o
python setup.py build_ext --inplace
Процедура тестирования :
python -c "import testwrite;testwrite.run()"
Вывод:
In fwrite: flag= 0
Message from fwrite (write_f).
In fwrite: flag= 1
MSG 1234 12.3400002
In fwrite: flag= 2
[1] 7631 segmentation fault python -c "import testwrite;testwrite.run()"
Ожидаемый вывод:
In fwrite: flag= 0
Message from fwrite (write_f).
In fwrite: flag= 1
MSG 1234 12.3400002
In fwrite: flag= 2
Message from fwrite (write_f).
In fwrite: flag= 3
1234
In fwrite: flag= 4
12.34
Кстати, f2py
отлично работает.
Процедура компиляции:
f2py -c -m testwrite fortran_write.f90
Процедура тестирования:
python -c "import testwrite;testwrite.mod_write.fwrite(2)"
Системная информация
macOS Version 10.15.3
gfortran -v
:
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/9.2.0_1/libexec/gcc/x86_64-apple-darwin18/9.2.0/lto-wrapper
Target: x86_64-apple-darwin18
Configured with: ../configure --build=x86_64-apple-darwin18 --prefix=/usr/local/Cellar/gcc/9.2.0_1 --libdir=/usr/local/Cellar/gcc/9.2.0_1/lib/gcc/9 --disable-nls --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-9 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-system-zlib --with-pkgversion='Homebrew GCC 9.2.0_1' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
Thread model: posix
gcc version 9.2.0 (Homebrew GCC 9.2.0_1)
g++ -v
:
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.0 (clang-1100.0.33.16)
Target: x86_64-apple-darwin19.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
cython --version
Cython version 0.29.14
python --version
: Python 3.7.4
f2py
версия 2