目录
在python中,调用fortran封装的函数。
目前我使用miniconda创建了py39的环境。
在 Ubuntu 24.04 上实现 Python 调用 Fortran 函数的工作流(Python -> Cython -> C -> Fortran)涉及配置多个工具和库。
通过这种方式,你实现了从 Python 调用 Fortran 的工作流。这个工作流的关键步骤是:
- 用 Fortran 编写函数。
- 用 C 编写 Fortran 函数的封装器。
- 用 Cython 调用 C 函数,并生成 Python模块。
- 用 Python 直接调用 Cython 模块。
环境安装
1 安装Fortran和C编译器
确保已经安装了Fortran编译器(如 gfortran)、C编译器(如 gcc)和Python环境管理工具(如 Miniconda)。
sudo apt install gfortran gcc make
2 安装Cython
在py39 Conda 环境中,安装 Cython:
conda activate py39
conda install cython
代码分析
文件夹组成:
project_directory/
│
├── fortran/
│ └── example.f90 # Fortran 源代码
├── c/
│ └── wrapper.c # C 源代码
├── cython/
│ └── cython_wrapper.pyx # Cython 源代码
├── python/
│ └── test.py # Python 测试代码
├── build/ # 编译生成的文件放置目录
│ └── (wrapper.o, example.o, .so 文件等)
├── makefile # 一键完成整个编译和测试流程
├── setup.py # 编译和打包配置
└── README.md # 软件包说明文件
Fortran代码
! example.f90
subroutine add_numbers(a, b, result) bind(C, name="add_numbers")
implicit none
double precision, intent(in) :: a, b
double precision, intent(out) :: result
result = a + b
end subroutine add_numbers
C代码
// wrapper.c
#include <stdio.h>
extern void add_numbers(double* a, double* b, double* result);
void c_add_numbers(double a, double b, double* result) {
add_numbers(&a, &b, result);
}
Cython代码
# cython_wrapper.pyx
cdef extern void c_add_numbers(double a, double b, double* result)
def add_numbers(double a, double b):
cdef double result
c_add_numbers(a, b, &result)
return result
Python代码
import sys
import os
# 动态获取项目根目录
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 添加 build 目录到模块搜索路径
sys.path.append(os.path.join(project_root, 'build'))
from cython_wrapper import add_numbers
result = add_numbers(2.5, 3.7)
print(f"The result is: {result}")
setup代码
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
import os
# 设置环境变量,使用 gfortran 作为链接器
os.environ["LDSHARED"] = "gfortran -shared"
extensions = [
Extension(
name="cython_wrapper",
sources=["cython/cython_wrapper.pyx"],
extra_objects=["build/wrapper.o", "build/example.o"], # 放入 build 目录
libraries=["gfortran"], # 链接 Fortran 库
library_dirs=['/usr/lib/gcc/aarch64-linux-gnu/13'], # Fortran 运行时库的位置
)
]
setup(
ext_modules=cythonize(extensions, compiler_directives={'language_level': "3"}),
script_args=["build_ext", "--build-lib", "build"], # 指定编译输出目录为 build
)
makefile代码
# Makefile
# 设置变量
FORTRAN_SRC = fortran/example.f90
C_SRC = c/wrapper.c
CYTHON_SRC = cython/cython_wrapper.pyx
BUILD_DIR = build
PYTHON_TEST = python/test.py
SO_FILE = $(BUILD_DIR)/cython_wrapper*.so
# 设置编译器和编译选项
GFORTRAN = gfortran
GCC = gcc
PYTHON = python
CYTHON = cython
SETUP = python setup.py build_ext --build-lib $(BUILD_DIR)
# 默认执行所有编译和测试
all: build_dir fortran c cython run_test
# 创建 build 目录
build_dir:
mkdir -p $(BUILD_DIR)
# 编译 Fortran 文件
fortran: build_dir
$(GFORTRAN) -c $(FORTRAN_SRC) -o $(BUILD_DIR)/example.o
# 编译 C 文件
c: build_dir
$(GCC) -c $(C_SRC) -o $(BUILD_DIR)/wrapper.o
# 编译 Cython 文件,生成 .so 文件
cython: build_dir fortran c
$(SETUP)
# 运行 Python 测试
run_test: $(SO_FILE)
$(PYTHON) $(PYTHON_TEST)
# 清理生成的文件
clean:
rm -rf $(BUILD_DIR)/*.o $(BUILD_DIR)/*.so
.PHONY: all build_dir fortran c cython run_test clean
编译和运行步骤
1. 编译 Fortran 文件
进入项目的根目录,并编译 Fortran 文件:
gfortran -c fortran/example.f90 -o fortran/example.o
2. 编译 C 文件
继续编译 C 文件:
gcc -c c/wrapper.c -o c/wrapper.o
3. 编译 Cython 模块
使用 setup.py
文件来编译 Cython 模块:
python setup.py build_ext --inplace
4. 运行 Python 测试
一切编译成功后,运行 Python 文件来测试调用:
python python/test.py
你应该看到输出:
The result is: 6.2