Использование через meson#
Примечание
Большая часть этого документа теперь устарела, можно запустить f2py с
--build-dir чтобы получить каркас meson проект с базовыми зависимостями
настройка.
Изменено в версии 1.26.x: Система сборки по умолчанию для f2py теперь meson, см.
Статус numpy.distutils и рекомендации по миграции для некоторых дополнительных деталей.
Ключевое преимущество, полученное за счет использования meson над методами, описанными
в Использование через numpy.distutils заключается в том, что это легко интегрируется в существующие системы и более крупные проекты. meson имеет довольно питонический синтаксис, что делает его более
удобным и подходящим для расширения python пользователи.
Пошаговое руководство по Фибоначчи (F77)#
Нам понадобится сгенерированный C обёртку, прежде чем мы сможем использовать универсальную систему сборки, такую как meson. Мы получим это следующим образом:
python -m numpy.f2py fib1.f -m fib2
Теперь рассмотрим следующее meson.build файл для fib и scalar
примеры из Три способа обертки - начало работы раздел:
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 "" , line 1, in
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необходимо понизить до обычных букв; что может быть облегчено с помощью--lowerопцияF2PY