Ошибка сегментации при попытке написать оболочку Fortran вокруг двух объектов C с использованием f2py

Я экспериментирую с использованием f2py для инкапсуляции кода C.

В качестве первого теста я подготовил два очень простых исходных файла на C:

module1.c

double multiply(double a, double b);

double multiply(double a, double b) {
        return a*b;
}

module2.c

double divide(double a, double b);

double divide(double a, double b) {
        return a/b;
}

Я компилирую оба файла следующим образом:

$ gcc -c -fPIC -o module1.o module1.c
$ gcc -c -fPIC -o module2.o module2.c

Затем я готовлю следующую оболочку модуля Fortran для обеих функций:

fortran_module.f90

! TEST FORTRAN WRAPPER

module fortran_module

        use iso_c_binding

        ! Interface to C routine
        ! double get_price_step(double price);
        interface
                real(c_double) function multiply(a, b) bind(C)
                        use iso_c_binding
                        real(c_double), value :: a,b
                end function
                real(c_double) function divide(a, b) bind(C)
                        use iso_c_binding
                        real(c_double), value :: a,b
                end function
        end interface

end module

Я компилирую модуль, используя:

$ f2py -c -m fortran_module fortran_module.f90 module1.o module2.o

И я получаю следующий результат:

running build
running config_cc
unifing config_cc, config, build_clib, build_ext, build commands --compiler options
running config_fc
unifing config_fc, config, build_clib, build_ext, build commands --fcompiler options
running build_src
build_src
building extension "fortran_module" sources
f2py options: []
f2py:> /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_modulemodule.c
creating /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7
Reading fortran codes...
        Reading file 'fortran_module.f90' (format:free)
Post-processing...
        Block: fortran_module
                        Block: fortran_module
In: :fortran_module:fortran_module.f90:fortran_module
get_useparameters: no module iso_c_binding info used by fortran_module
In: :fortran_module:fortran_module.f90:fortran_module:unknown_interface
get_useparameters: no module iso_c_binding info used by unknown_interface
                                        Block: multiply
In: :fortran_module:fortran_module.f90:fortran_module:unknown_interface:multiply
get_useparameters: no module iso_c_binding info used by multiply
                                        Block: divide
In: :fortran_module:fortran_module.f90:fortran_module:unknown_interface:divide
get_useparameters: no module iso_c_binding info used by divide
Post-processing (stage 2)...
        Block: fortran_module
                Block: unknown_interface
                        Block: fortran_module
                                Block: unknown_interface
                                        Block: multiply
                                        Block: divide
Building modules...
        Building module "fortran_module"...
                Constructing F90 module support for "fortran_module"...
Skipping interface unknown_interface
        Wrote C/API module "fortran_module" to file "/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_modulemodule.c"
        Fortran 90 wrappers are saved to "/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_module-f2pywrappers2.f90"
  adding '/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortranobject.c' to sources.
  adding '/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7' to include_dirs.
copying /usr/local/lib/python3.7/site-packages/numpy/f2py/src/fortranobject.c -> /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7
copying /usr/local/lib/python3.7/site-packages/numpy/f2py/src/fortranobject.h -> /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7
  adding '/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_module-f2pywrappers2.f90' to sources.
build_src: building npy-pkg config files
running build_ext
customize UnixCCompiler
C compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -O2 -pipe -fstack-protector-strong -fno-strict-aliasing -fPIC

creating /tmp/tmpjgjjhjtm/tmp
creating /tmp/tmpjgjjhjtm/tmp/tmpjgjjhjtm
compile options: '-MMD -MF /tmp/tmpjgjjhjtm/file.c.d -c'
cc: /tmp/tmpjgjjhjtm/file.c
customize UnixCCompiler using build_ext
get_default_fcompiler: matching types: '['gnu', 'gnu95']'
customize GnuFCompiler
Found executable /usr/local/bin/gfort

ran9
gnu: no Fortran 90 compiler found
gnu: no Fortran 90 compiler found
customize Gnu95FCompiler
customize Gnu95FCompiler
customize Gnu95FCompiler using build_ext
building 'fortran_module' extension
compiling C sources
C compiler: cc -pthread -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -O2 -pipe -fstack-protector-strong -fno-strict-aliasing -fPIC

creating /tmp/tmp9aa3w8b0/tmp
creating /tmp/tmp9aa3w8b0/tmp/tmp9aa3w8b0
creating /tmp/tmp9aa3w8b0/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7
compile options: '-I/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7 -I/usr/local/lib/python3.7/site-packages/numpy/core/include -I/usr/local/include/python3.7m -c'
cc: /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortranobject.c
cc: /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_modulemodule.c
In file included from /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_modulemodule.c:15:
In file included from /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortranobject.h:13:
In file included from /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortranobject.c:2:
In file included from /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortranobject.h:13:
In file included from /usr/local/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4:
In file included from /usr/local/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12:
In file included from /usr/local/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1822:
/usr/local/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: "Using deprecated NumPy API, disable it with "
      "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-W#warnings]
#warning "Using deprecated NumPy API, disable it with " \
 ^
In file included from /usr/local/lib/python3.7/site-packages/numpy/core/include/numpy/arrayobject.h:4:
In file included from /usr/local/lib/python3.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:12:
In file included from /usr/local/lib/python3.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1822:
/usr/local/lib/python3.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: "Using deprecated NumPy API, disable it with "
      "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-W#warnings]
#warning "Using deprecated NumPy API, disable it with " \
 ^
1 warning generated.
1 warning generated.
compiling Fortran 90 module sources
Fortran f77 compiler: /usr/local/bin/gfortran9 -Wall -g -ffixed-form -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran f90 compiler: /usr/local/bin/gfortran9 -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran fix compiler: /usr/local/bin/gfortran9 -Wall -g -ffixed-form -fno-second-underscore -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
compile options: '-I/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7 -I/usr/local/lib/python3.7/site-packages/numpy/core/include -I/usr/local/include/python3.7m -c'
extra options: '-J/tmp/tmp9aa3w8b0/ -I/tmp/tmp9aa3w8b0/'
gfortran9:f90: fortran_module.f90
compiling Fortran sources
Fortran f77 compiler: /usr/local/bin/gfortran9 -Wall -g -ffixed-form -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran f90 compiler: /usr/local/bin/gfortran9 -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran fix compiler: /usr/local/bin/gfortran9 -Wall -g -ffixed-form -fno-second-underscore -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
compile options: '-I/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7 -I/usr/local/lib/python3.7/site-packages/numpy/core/include -I/usr/local/include/python3.7m -c'
extra options: '-J/tmp/tmp9aa3w8b0/ -I/tmp/tmp9aa3w8b0/'
gfortran9:f90: /tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_module-f2pywrappers2.f90
/usr/local/bin/gfortran9 -Wall -g -Wall -g -shared /tmp/tmp9aa3w8b0/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_modulemodule.o /tmp/tmp9aa3w8b0/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortranobject.o /tmp/tmp9aa3w8b0/fortran_module.o /tmp/tmp9aa3w8b0/tmp/tmp9aa3w8b0/src.freebsd-12.2-RC1-amd64-3.7/fortran_module-f2pywrappers2.o module1.o module2.o -L/usr/local/lib/gcc9/gcc/x86_64-portbld-freebsd12.1/9.3.0 -L/usr/local/lib -lpython3.7m -lgfortran -o ./fortran_module.so
Removing build directory /tmp/tmp9aa3w8b0

Это создает fortran_module.so в каталоге.

Затем, вернувшись в Python, я пытаюсь сделать:

import fortran_module

Но я получаю ошибку сегментации:

$ /usr/local/bin/python3.7
Python 3.7.9 (default, Oct  3 2020, 01:29:35) 
[Clang 8.0.1 (tags/RELEASE_801/final 366581)] on freebsd12
Type "help", "copyright", "credits" or "license" for more information.
readline: ~/.inputrc: line 1: nobeep: unknown variable name
readline: ~/.inputrc: line 1: nobeep: unknown variable name
>>> import fortran_module
Segmentation fault (core dumped)

Приветствуется любая помощь или намек на то, что я делаю неправильно. Я использую gcc и FreeBSD (я отказался от идеи использовать clang и flang, поскольку фланец FreeBSD, похоже, не поддерживает iso_c_bindings).

Примечание. Я также пробовал использовать --fcompiler=gnu95 в качестве параметра f2py, пытаясь убедиться, что flang или clang не используются.


person M.E.    schedule 24.06.2021    source источник
comment
Не могу помочь с f2py. Но вы хотите использовать имя привязки в интерфейсе, то есть bind(c, name="multiply").   -  person steve    schedule 25.06.2021
comment
по-прежнему возникает ошибка сегментации после использования имени привязки в интерфейсе.   -  person M.E.    schedule 25.06.2021
comment
Я пробовал скомпилировать ваш модуль с помощью python3.9 + Mac и получил аналогичную ошибку сегментации. Я предполагаю, что f2py еще не поддерживает iso_c_binding (хотя массивы предполагаемой формы и т. Д. Работают хорошо). Кроме того, по умолчанию для параметров типа поддерживаются только числовые целые числа, а для именованных параметров и т. Д. Необходим отдельный файл сопоставления numpy.org/doc/stable/f2py/   -  person roygvib    schedule 26.06.2021
comment
Если целью является вызов только подпрограмм C, возможно, проще использовать другие инструменты, такие как ctypes или cffi ...? (или, возможно, используйте какой-нибудь подход к оболочке, например, здесь stackoverflow.com/questions/67516927/   -  person roygvib    schedule 26.06.2021
comment
Прелесть f2py в том, что для перемещения множества массивов вперед и назад не требуется никаких шаблонов. Насколько я знаю, это недостижимо с ctypes (вам нужен дополнительный шаг), и я не уверен, что cffi вообще допускает массивы numpy.   -  person M.E.    schedule 26.06.2021
comment
Я никогда не пробовал этого, но это может быть другой подход к использованию ctypes или cffi и f2py гибридным способом (т.е. использовать cffi для подпрограмм C с подписями, автоматически сгенерированными из файлов заголовков C (возможно ли это?), При использовании f2py для подпрограмм Fortran). Надеюсь, будут еще прямые методы ...   -  person roygvib    schedule 26.06.2021


Ответы (1)


Предполагая, чтоf2py не может сгенерировать привязку Python для подпрограмм Fortran с bind(C), обходным путем может быть определение обычной (без привязки (C)) подпрограммы и вызов подпрограмм C изнутри (что несколько похоже на эта страница для использования производных типов). Например, возможный код может выглядеть так (но явно с большими накладными расходами на вызовы функций ...)

clib.c

double multiply(double a, double b) {
    return a * b;
}

fmod.f90

module fmod
    use iso_c_binding
    implicit none
contains

    function multiply(a, b) result(res)
        real(8) :: a, b, res   !! "8" just for test
        interface
            real(c_double) function c_multiply(a, b) bind(C,name="multiply")
                import
                real(c_double), value :: a,b
            end
        end interface

        res = c_multiply(a, b)
    end
end module

Скомпилировать:

$ gcc -c -fPIC clib.c -o clib.o
$ python3.9 -m numpy.f2py -c fmod.f90 clib.o -m py_fmod

Бегать:

$ python3.9
>>> import py_fmod
>>> print( py_fmod.fmod.__doc__ )
res = multiply(a,b)

Wrapper for ``multiply``.

Parameters
----------
a : input float
b : input float

Returns
-------
res : float

>>> py_fmod.fmod.multiply( a= 2.0, b= 3.0 )
6.0

Я предполагаю, что также можно будет определить все блоки интерфейса в отдельном файле модуля Fortran, скомпилировать его независимо от f2py и use из подпрограмм, скомпилированных с f2py (так, отделив блок интерфейса iso_c_binding + от компиляции f2py). Действительно, кажется проблематичным, если такой интерфейсный блок определяется непосредственно в части заголовка модуля для f2py (что очень похоже на проблему производных типов и т. Д.).

person roygvib    schedule 26.06.2021