使用 meson
#
注意
本文档的大部分内容现已过时,可以使用 f2py
和 --build-dir
来获得具有基本依赖项设置的 meson
项目框架。
版本 1.26.x 中已更改: f2py
的默认构建系统现在是 meson
,请参阅 numpy.distutils 的状态和迁移建议 以了解更多详细信息。
与 使用 numpy.distutils 中描述的技术相比,利用 meson
获得的关键优势在于,它可以轻松地融入现有系统和大型项目中。meson
具有相当 Pythonic 的语法,这使得它对 python
用户来说更舒适易用。
斐波那契数列演练 (F77)#
在使用像 meson
这样的通用构建系统之前,我们需要生成的 C
包装器。我们将通过以下方式获得它:
python -m numpy.f2py fib1.f -m fib2
现在,考虑以下来自 三种包装方式 - 入门 部分的 fib
和 scalar
例子的 meson.build
文件:
project('f2py_examples', 'c',
version : '0.1',
license: 'BSD-3',
meson_version: '>=0.64.0',
default_options : ['warning_level=2'],
)
add_languages('fortran')
py_mod = import('python')
py = py_mod.find_installation(pure: false)
py_dep = py.dependency()
incdir_numpy = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy; print(numpy.get_include())'],
check : true
).stdout().strip()
incdir_f2py = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy.f2py; print(numpy.f2py.get_include())'],
check : true
).stdout().strip()
inc_np = include_directories(incdir_numpy, incdir_f2py)
py.extension_module('fib2',
[
'fib1.f',
'fib2module.c', # note: this assumes f2py was manually run before!
],
incdir_f2py / 'fortranobject.c',
include_directories: inc_np,
dependencies : py_dep,
install : true
)
此时构建将完成,但导入将失败
meson setup builddir
meson compile -C builddir
cd builddir
python -c 'import fib2'
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: fib2.cpython-39-x86_64-linux-gnu.so: undefined symbol: FIB_
# Check this isn't a false positive
nm -A fib2.cpython-39-x86_64-linux-gnu.so | grep FIB_
fib2.cpython-39-x86_64-linux-gnu.so: U FIB_
回想一下,如下所示的原始示例是用大写字母编写的
C FILE: FIB1.F
SUBROUTINE FIB(A,N)
C
C CALCULATE FIRST N FIBONACCI NUMBERS
C
INTEGER N
REAL*8 A(N)
DO I=1,N
IF (I.EQ.1) THEN
A(I) = 0.0D0
ELSEIF (I.EQ.2) THEN
A(I) = 1.0D0
ELSE
A(I) = A(I-1) + A(I-2)
ENDIF
ENDDO
END
C END FILE FIB1.F
使用标准方法,公开给 python
的子程序是 fib
而不是 FIB
。这意味着我们有几个选择。一种方法(如果可能的话)是用例如以下命令将原始 Fortran 文件转换为小写:
tr "[:upper:]" "[:lower:]" < fib1.f > fib1.f
python -m numpy.f2py fib1.f -m fib2
meson --wipe builddir
meson compile -C builddir
cd builddir
python -c 'import fib2'
但是,这需要修改源代码的能力,而这并非总是可能的。解决这个问题最简单的方法是让 f2py
来处理它
python -m numpy.f2py fib1.f -m fib2 --lower
meson --wipe builddir
meson compile -C builddir
cd builddir
python -c 'import fib2'
自动化包装器生成#
上述工作流程中的一个主要痛点是手动跟踪输入。虽然需要付出更多努力才能找出实际输出(原因在 F2PY 和构建系统 中讨论)。
注意
从 NumPy 1.22.4
开始,f2py
将根据输入文件的 Fortran 标准(F77 或更高版本)确定性地生成包装器文件。--skip-empty-wrappers
可以传递给 f2py
以恢复以前仅在输入文件需要时才生成包装器的行为。
但是,我们可以增强我们的工作流程,以便在设置构建系统时考虑输出已知的那些文件。
project('f2py_examples', 'c',
version : '0.1',
license: 'BSD-3',
meson_version: '>=0.64.0',
default_options : ['warning_level=2'],
)
add_languages('fortran')
py_mod = import('python')
py = py_mod.find_installation(pure: false)
py_dep = py.dependency()
incdir_numpy = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy; print(numpy.get_include())'],
check : true
).stdout().strip()
incdir_f2py = run_command(py,
['-c', 'import os; os.chdir(".."); import numpy.f2py; print(numpy.f2py.get_include())'],
check : true
).stdout().strip()
fibby_source = custom_target('fibbymodule.c',
input : ['fib1.f'], # .f so no F90 wrappers
output : ['fibbymodule.c', 'fibby-f2pywrappers.f'],
command : [py, '-m', 'numpy.f2py', '@INPUT@', '-m', 'fibby', '--lower']
)
inc_np = include_directories(incdir_numpy, incdir_f2py)
py.extension_module('fibby',
['fib1.f', fibby_source],
incdir_f2py / 'fortranobject.c',
include_directories: inc_np,
dependencies : py_dep,
install : true
)
这可以像以前一样编译和运行。
rm -rf builddir
meson setup builddir
meson compile -C builddir
cd builddir
python -c "import numpy as np; import fibby; a = np.zeros(9); fibby.fib(a); print (a)"
# [ 0. 1. 1. 2. 3. 5. 8. 13. 21.]
要点#
值得记住以下几点:
在这种情况下,不能使用大写字母,因此需要将
.f
文件的内容或生成的包装器.c
转换为小写字母;这可以通过F2PY
的--lower
选项来实现。