使用 meson
#
注意
本文件的大部分內容現已過時,可以執行帶有 --build-dir
的 f2py
,以取得具有基本相依性設定的骨架 meson
專案。
在 1.26.x 版本中變更:f2py
的預設建置系統現在是 meson
,如需更多詳細資訊,請參閱 numpy.distutils 的狀態與遷移建議。
藉由利用 meson
相較於 使用 numpy.distutils 中描述的技術所獲得的主要優勢在於,它可以輕鬆地應用於現有系統和更大的專案。meson
具有相當 Python 風格的語法,這使得 python
使用者更容易上手並適合擴充。
Fibonacci 逐步解說 (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_
回想一下,如下所示的原始範例是以 SCREAMCASE 格式呈現
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.]
要點#
值得記住以下幾點
在此情境中無法使用 SCREAMCASE,因此
.f
檔案的內容或產生的包裝器.c
需要轉換為小寫字母;這可以透過F2PY
的--lower
選項來實現