由于这是调试 HPC 代码的有用方法,因此这里有一个简单的 Fortran 程序“hello world”,从 Python 调用。
使用GNU Fortran (GCC) 9.3.0 和Python 3.7.3
你至少需要
- 带有 c 绑定的 fortran 代码(即
bind(C) 用于每个子例程/函数,iso_c_binding 用于写入/输出的每个变量)。让我们称之为hello_fortran.f90
subroutine hello_fortran() bind(c)
print *, "Hello world from fortran"
end subroutine hello_fortran
如果您不想使用 iso_c_bindings 修改原始 Fortran 代码,您还可以在 Fortran 中编写一个简单的包装函数,直接调用原始代码。
使用-c 编译此代码以在不链接的情况下进行编译,并使用-fPIC 生成与位置无关的代码。
gfortran hello_fortran.f90 -c -fPIC -o hello_fortran.o
您可以直接链接 setup.py 中的目标文件,但我发现将所有内容捆绑到共享库中要容易得多
gfortran *.o -shared -o libhello_fortran.so
并使用export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(pwd)将当前工作目录添加到PATH
2 。允许从 Python 调用 C 函数的 Cython 模块(或者,您可以使用 CFFI——方法类似)。对于我们的示例,我们称之为“hello_cython.pyx”
cdef extern:
void hello_fortran()
def hello_cython():
print("Called hello_cython")
hello_fortran()
至关重要的是,对于您要调用的每个 Fortran 函数,您需要在 cdef extern 块中声明 C 接口。请记住,fortran 不区分大小写:此块中的所有内容都应为小写。
-
setup.py 文件用于“编译” Cython 模块。不幸的是,这些很快就会变得非常复杂,所以下面给出的是一个最小的工作示例
from distutils.core import setup, Extension
from Cython.Build import cythonize
import numpy
files = ['hello_cython.pyx']
ext_module = Extension(
name = "hello_cython_FI",
sources = files,
include_dirs = ['.'],
library_dirs=['.'],
libraries=["hello_fortran"]
)
setup(
name = "hello_cython_FI",
ext_modules = cythonize(ext_module)
)
需要注意的重要事项是name 将给出 Python 中模块的名称,files 必须包含 .pyx 文件,libraries 必须具有共享库的名称(即用于libhello_fortran.so,写hello_fortran)
用python setup.py build_ext --inplace编译它
- 标准 Python 脚本
hello_python.py 调用 hello_cython_FI
import hello_cython_FI
print("Called hello_python")
hello_cython_FI.hello_cython()
那么你应该得到
>>> python hello_python.py
Called hello_python
Called hello_cython
Hello world from fortran
在 cmets 中询问 Intel、OpenMP 和 OpenMP 链接方法。