1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
.. _f2py-meson:
===================
Using via ``meson``
===================
The key advantage gained by leveraging ``meson`` over the techniques described
in :ref:`f2py-distutils` is that this feeds into existing systems and larger
projects with ease. ``meson`` has a rather pythonic syntax which makes it more
comfortable and amenable to extension for ``python`` users.
.. note::
Meson needs to be at-least ``0.46.0`` in order to resolve the ``python`` include directories.
Fibonacci Walkthrough (F77)
===========================
We will need the generated ``C`` wrapper before we can use a general purpose
build system like ``meson``. We will acquire this by:
.. code-block:: bash
python -n numpy.f2py fib1.f -m fib2
Now, consider the following ``meson.build`` file for the ``fib`` and ``scalar``
examples from :ref:`f2py-getting-started` section:
.. literalinclude:: ./../code/meson.build
:language: meson
At this point the build will complete, but the import will fail:
.. code-block:: bash
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_
Recall that the original example, as reproduced below, was in SCREAMCASE:
.. literalinclude:: ./../code/fib1.f
:language: fortran
With the standard approach, the subroutine exposed to ``python`` is ``fib`` and
not ``FIB``. This means we have a few options. One approach (where possible) is
to lowercase the original Fortran file with say:
.. code-block:: bash
tr "[:upper:]" "[:lower:]" < fib1.f > fib1.f
python -n numpy.f2py fib1.f -m fib2
meson --wipe builddir
meson compile -C builddir
cd builddir
python -c 'import fib2'
However this requires the ability to modify the source which is not always
possible. The easiest way to solve this is to let ``f2py`` deal with it:
.. code-block:: bash
python -n numpy.f2py fib1.f -m fib2 --lower
meson --wipe builddir
meson compile -C builddir
cd builddir
python -c 'import fib2'
Automating wrapper generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A major pain point in the workflow defined above, is the manual tracking of
inputs. Although it would require more effort to figure out the actual outputs
for reasons discussed in :ref:`f2py-bldsys`.
.. note::
From NumPy ``1.22.4`` onwards, ``f2py`` will deterministically generate
wrapper files based on the input file Fortran standard (F77 or greater).
``--skip-empty-wrappers`` can be passed to ``f2py`` to restore the previous
behaviour of only generating wrappers when needed by the input .
However, we can augment our workflow in a straightforward to take into account
files for which the outputs are known when the build system is set up.
.. literalinclude:: ./../code/meson_upd.build
:language: meson
This can be compiled and run as before.
.. code-block:: bash
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.]
Salient points
===============
It is worth keeping in mind the following:
* ``meson`` will default to passing ``-fimplicit-none`` under ``gfortran`` by
default, which differs from that of the standard ``np.distutils`` behaviour
* It is not possible to use SCREAMCASE in this context, so either the contents
of the ``.f`` file or the generated wrapper ``.c`` needs to be lowered to
regular letters; which can be facilitated by the ``--lower`` option of
``F2PY``
|