Compilar extensiones de Python con distutils y MinGW



Una traducción (con algunas modificaciones y adiciones) autorizada del artículo «Compiling Python extensions with distutils and MinGW» escrito por Eli Bendersky.

Este artículo se hizo en base a la versión 2.5. Particularmente con la 2.7 no tuve ningún inconveniente al compilar una extensión escrita en C con MinGW, por lo que antes de seguir esta guía te recomiendo que lo intentes normalmente, para ahorrar cualquier tipo de trabajo innecesario.

Intentando distutils con Visual Studio 2005 Express

Actualmente cuento con la instalación de la versión gratuita Visual Studio 2005 Express. Lo utilicé para compilar satisfactoriamente el intérprete de CPython con sus respectivas fuentes, y quería atarlo a distutils para compilar la extensión. Desafortunadamente, distutils es bastante restrictivo con respecto a la versión de MSVC con la que compilas extensiones, y se quejó diciendo:

running build
running build_ext
error: Python was built with Visual Studio 2003;
extensions must be built with a compiler than can generate compatible binaries.
Visual Studio 2003 was not found on this system. If you have Cygwin installed,
you can try compiling with MingW32, by passing "-c mingw32" to setup.py.

Consulté el canal IRC de Python, y recibí una recomendación de usar MinGW de todos modos, ya que mucha gente probó su compatibilidad con la distribución de Python.

distutils con MinGW, primer intento

Descargué la última versión de MinGW, e intenté llamar distutils de la manera apropiada:

python setup build -c mingw32

Pero recibí este error:

running build
running build_ext
building 'hello' extension
creating build
creating build\temp.win32-2.5
creating build\temp.win32-2.5\Release
d:\mingw\bin\gcc.exe -mno-cygwin -mdll -O -Wall -IC:\Python25\include -IC:\Python25\PC -c hellomodule.c -o build\temp.win32-2.5\Release\hellomodule.o
writing build\temp.win32-2.5\Release\hello.def
creating build\lib.win32-2.5
d:\mingw\bin\gcc.exe -mno-cygwin -shared -s build\temp.win32-2.5\Release\hellomodule.o build\temp.win32-2.5\Release\hello.def -LC:\Python25\libs -LC:\Python25\PCbuild -lpython25 -lmsvcr71 -o build\lib.win32-2.5\hello.pyd
build\temp.win32-2.5\Release\hellomodule.o:hellomodule.c:(.text+0x3e): undefined reference to _imp___Py_NoneStruct'
build\temp.win32-2.5\Release\hellomodule.o:hellomodule.c:(.text+0x46): undefined reference to_imp___Py_NoneStruct'
collect2: ld returned 1 exit status
error: command 'gcc' failed with exit status 1

Esto me desorientó, ya que no pude encontrar nada útil acerca de este error en Google. De todas maneras, llegué a esta página, en donde encontré la solución en los comentarios.

La solución

Aparentemente, la librería que exporta Python (libs/python25.lib en la distribución de Python) no es suficiente para MinGW, y quiere un archivo .a para listar las exportaciones de la DLL en la que se encuentra el intérprete.

Por esto, debes crear el archivo libpython25.a para la librería de Python. Si quieres, puedes descargar la que creé yo (de acá o acá) y saltearte todos estos pasos. Debería funcionar en Python 2.5. Aquí está (acá o acá) el archivo para Python 2.6.

Para crear libpython25.a (o la versión que sea) por tu cuenta debes:

  • Buscar pythonXY.dll (python25.dll en este caso)
  • Listar las exportaciones de esta DLL. Muchas herramientas pueden hacer esto (incluyendo dumpbin), pero pexports es la más conveniente para esta tarea. Puedes descargarla de acá, acá o acá.
  • Ejecutar pexports.exe python25.dll > python25.def
  • Si tienes instalado MinGW y has agregado su directorio bin a tu path, deberías poder simplemente llamar dlltool (una herramienta que viene con MinGW): dlltool --dllname python25.dll --def python 25.def --output-lib libpython25.a
  • Has creado libpython25.a

Ahora simplemente coloca libpython25.a en la carpeta libs de tu distribución de Python, y ejecuta distutils nuevamente:

running build
running build_ext
building 'hello' extension
creating build
creating build\temp.win32-2.5
creating build\temp.win32-2.5\Release
d:\mingw\bin\gcc.exe -mno-cygwin -mdll -O -Wall -IC:\Python25\include -IC:\Python25\PC -c hellomodule.c -o build\temp.win32-2.5\Release\hellomodule.o
writing build\temp.win32-2.5\Release\hello.def
creating build\lib.win32-2.5
d:\mingw\bin\gcc.exe -mno-cygwin -shared -s build\temp.win32-2.5\Release\hellomodule.o build\temp.win32-2.5\Release\hello.def -LC:\Python25\libs -LC:\Python25\PCbuild -lpython25 -lmsvcr71 -o build\lib.win32-2.5\hello.pyd

¡Éxito! Ahora puedes usar la extensión desde tu código Python.

El archivo hellomodule.c que utilizo como extensión escrita en C es el siguiente:

#include <Python.h>
 
static PyObject* say_hello(PyObject* self, PyObject* args)
{
    const char* name;
 
    if (!PyArg_ParseTuple(args, "s",&name))
        return NULL;
 
    printf("Hello %s!\n", name);
 
    Py_RETURN_NONE;
}
 
static PyMethodDef HelloMethods[] =
{
     {"say_hello", say_hello, METH_VARARGS, "Greet somebody."},
     {NULL, NULL, 0, NULL}
};
 
PyMODINIT_FUNC
 
inithello(void)
{
     (void) Py_InitModule("hello", HelloMethods);
}

Y aquí está el archivo setup.py:

from distutils.core import setup, Extension
 
module1 = Extension('hello', sources = ['hellomodule.c'])
 
setup (name = 'PackageName',
        version = '1.0',
        description = 'This is a demo package',
        ext_modules = [module1])

Versión

Python 2



Deja una respuesta