由于这是调试HPC代码的有用方法,因此这里提供了一个简单的Fortran“hello world”程序,可以从Python中调用。
使用GNU Fortran (GCC) 9.3.0
和Python 3.7.3
您需要至少:
- 一个Fortran代码,具有C绑定(即每个子例程/函数都有
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. 一个 Cython 模块,允许从 Python 调用 C 函数(或者,您可以使用 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
如需有关Intel、OpenMP和OpenMP链接方法的信息,请在评论中提问。