使用 SWIG 从 Fortran 源代码创建 Python 模块
Creating a Python module from Fortran source code using SWIG
我从事的项目涉及为用 Fortran 编写的程序创建 Python 界面。我做了一些研究并决定使用 SWIG,首先将 Fortran 例程暴露给 C++,然后用 SWIG 包装它们。但是,我无法使 Python 模块正常工作。
例如,我有这个 Fortran 函数:
function sum_array(input_array, length) result(sum)
implicit none
integer, value, intent(in) :: length
real(kind=8), intent(in), dimension(length) :: input_array
real(kind=8) :: sum
integer :: i
sum = 0.0
do i=1, length
sum = sum + input_array(i)
end do
end function sum_array
使用 C 声明:
double sum_array(double* input_array, int length);
我使用的 SWIG 接口文件是:
%module sum_array
%{
#define SWIG_FILE_WITH_INIT
#include "sum_array.h"
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY1, int DIM1) {(double* input_array, int length)};
%include "sum_array.h"
此接口文件使用 numpy.i 接口。
我正在将此代码(使用 make)编译成共享对象,如下所示:
$ swig -python -c++ -o sum_array_wrap.cpp sum_array.i
$ gfortran -c sum_array.f90 -o sum_array.o -fpic -fno-underscoring
$ gcc -I/usr/include/python2.7 -c sum_array_wrap.cpp -o sum_array_wrap.o -fpic -std=c++0x
$ gfortran sum_array_wrap.o sum_array.o -o _sum_array.so -shared -Wl,-soname,_sum_array.so -lstdc++
当我尝试在 Python 中导入模块时,我得到 "NameError: name 'sum_array' is not defined",来自:
from numpy.random import rand
from _sum_array import *
input_array = rand(5)
sum = sum_array(input_array)
根据我从解释器中的 help() 获得的信息,我认为链接器不包括库中的 sum_array 函数,我认为这是问题所在。
关于如何让它工作的任何想法?
顺便说一下,非常欢迎关于其他工具而不是 SWIG 的建议,因为这是我第一次这样做,而且我尝试这样做的唯一方法就是这个。
这次问题出在name mangling。 Fortran sompiler 不使用它,所以导出符号名称是 sym_array
,但稍后你用 C++ 编译接口,所以链接器希望看到类似 _Z9sum_arrayPdi
的东西。解决方法是把header内容包装成
#ifdef __cplusplus
extern "C" {
#endif
double sum_array(double* input_array, int length);
#ifdef __cplusplus
}
#endif
我从事的项目涉及为用 Fortran 编写的程序创建 Python 界面。我做了一些研究并决定使用 SWIG,首先将 Fortran 例程暴露给 C++,然后用 SWIG 包装它们。但是,我无法使 Python 模块正常工作。
例如,我有这个 Fortran 函数:
function sum_array(input_array, length) result(sum)
implicit none
integer, value, intent(in) :: length
real(kind=8), intent(in), dimension(length) :: input_array
real(kind=8) :: sum
integer :: i
sum = 0.0
do i=1, length
sum = sum + input_array(i)
end do
end function sum_array
使用 C 声明:
double sum_array(double* input_array, int length);
我使用的 SWIG 接口文件是:
%module sum_array
%{
#define SWIG_FILE_WITH_INIT
#include "sum_array.h"
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY1, int DIM1) {(double* input_array, int length)};
%include "sum_array.h"
此接口文件使用 numpy.i 接口。
我正在将此代码(使用 make)编译成共享对象,如下所示:
$ swig -python -c++ -o sum_array_wrap.cpp sum_array.i
$ gfortran -c sum_array.f90 -o sum_array.o -fpic -fno-underscoring
$ gcc -I/usr/include/python2.7 -c sum_array_wrap.cpp -o sum_array_wrap.o -fpic -std=c++0x
$ gfortran sum_array_wrap.o sum_array.o -o _sum_array.so -shared -Wl,-soname,_sum_array.so -lstdc++
当我尝试在 Python 中导入模块时,我得到 "NameError: name 'sum_array' is not defined",来自:
from numpy.random import rand
from _sum_array import *
input_array = rand(5)
sum = sum_array(input_array)
根据我从解释器中的 help() 获得的信息,我认为链接器不包括库中的 sum_array 函数,我认为这是问题所在。
关于如何让它工作的任何想法?
顺便说一下,非常欢迎关于其他工具而不是 SWIG 的建议,因为这是我第一次这样做,而且我尝试这样做的唯一方法就是这个。
这次问题出在name mangling。 Fortran sompiler 不使用它,所以导出符号名称是 sym_array
,但稍后你用 C++ 编译接口,所以链接器希望看到类似 _Z9sum_arrayPdi
的东西。解决方法是把header内容包装成
#ifdef __cplusplus
extern "C" {
#endif
double sum_array(double* input_array, int length);
#ifdef __cplusplus
}
#endif