Skip to content Skip to sidebar Skip to footer

How To Build A Python Wheel With Compiled Fortran Extension Module Without Requiring A Specific Mingw Version On The User's System?

As far as I understand, one of the main advantages of distributing Python packages through wheels is that I can include extension modules in a compiled form. Then, the user of the

Solution 1:

I recently ran into this issue by writing my own f2py building tool chain by compiling and linking all the components individually. The script was finding or installing required compilers automatically if they werent already found on the path. For cases where the gfortran tools werent on the path, but were present on the machine, I was able to inject the correct environment variables to os.environ and spawn compiler calls using Popen and the set of environment variables so that the pyd would compile. But outside of that python instance the environment variables were not correct for the pyd to run, I was getting the same DLL load failed error even on the same computer that compiled the pyds but which didnt have the correct paths setup.

So, since I'm compiling all steps separately, only using f2py to generate the f and c wrappers, I simply added -static -static-libgfortran -static-libgcc to my link step, and this causes the pyd to include the required libraries to run on those machines without the correct environment variables.

Achieving the same using numpy.distutils is possible (thanks to https://github.com/numpy/numpy/issues/3405):

from numpy.distutils.core import Extension, setup


if__name__== "__main__":
    setup(
        name="this",
        ext_modules=[
            Extension("fortmod_nostatic",
                      ["src/code.f90"],
                      ),
            Extension("fortmod_withstatic",
                      ["src/code.f90"],
                      extra_link_args=["-static", "-static-libgfortran", "-static-libgcc"]
                      )
        ]
    )

I put the above in a file test.py and built with python test.py build_ext --inplace --compiler=mingw32 --fcompiler=gnu95 -f

For comparison there is a clear size difference. Inspecting the pyd's with dependency walker shows the nostatic one depends on libgfortran-4.dll whereas the extra flags generate a pyd that does not depend on this library. In my case after adding the static flags the machine without correct environment variables is able to run the pyds, and I suspect this case will be similar to yours since the dependency on libgfortran is removed.

Hope that helps! my first SO post..

Solution 2:

I can confirm that the steps described in rmar_'s answer create a pyd file that can be imported from a machine that has no MinGW installed. This is really helpful!

In order to create a binary wheel, I do the following:

  1. Follow the steps described in rmar_'s answer in order to generate statically linked pyd files in place.
  2. Run python setup.py bdist_wheel afterwards.

For the second step, I switch off the compilation of the pyd file (e.g., by removing the ext_modules keyword from the setup() call), because I want that the pyd file created in the first step is used (and not a newly created, which might be not statically linked).

I don't know if this makes sense at all, but it seems to work ...

Post a Comment for "How To Build A Python Wheel With Compiled Fortran Extension Module Without Requiring A Specific Mingw Version On The User's System?"