# 5. Creación de extensiones C y C++ en Windows

Este capítulo explica brevemente cómo crear un módulo de extensión de Windows para Python usando Microsoft Visual C++, y sigue con información de fondo más detallada sobre cómo funciona. El material explicativo es útil tanto para el programador de Windows que está aprendiendo a construir extensiones de Python como para el programador de Unix interesado en producir software que se pueda construir con éxito tanto en Unix como en Windows.

Se alienta a los autores de módulos a utilizar el enfoque distutils para construir módulos de extensión, en lugar del descrito en esta sección. Aún necesitará el compilador de C que se utilizó para construir Python; típicamente Microsoft Visual C++.

Nota

Este capítulo menciona varios nombres de archivo que incluyen un número de versión codificado de Python. Estos nombres de archivo se representan con el número de versión que se muestra como `XY`; en la práctica, `'X'` será el número de versión principal y `'Y'` será el número de versión menor de la versión de Python con la que está trabajando. Por ejemplo, si está utilizando Python 2.2.1, `XY` en realidad será `22`.

## 5.1. Un enfoque de libro de cocina

Hay dos enfoques para construir módulos de extensión en Windows, al igual que en Unix: use el paquete `distutils` para controlar el proceso de construcción, o haga las cosas manualmente. El enfoque distutils funciona bien para la mayoría de las extensiones; La documentación sobre el uso de `distutils` para compilar y empaquetar módulos de extensión está disponible en Distribución de módulos de Python (versión heredada). Si encuentra que realmente necesita hacer las cosas manualmente, puede ser instructivo estudiar el archivo del proyecto para el módulo de biblioteca estándar winsound.

## 5.2. Diferencias entre Unix y Windows

Unix y Windows usan paradigmas completamente diferentes para la carga de código en tiempo de ejecución. Antes de intentar construir un módulo que se pueda cargar dinámicamente, tenga en cuenta cómo funciona su sistema.

En Unix, un archivo de objeto compartido (`.so`) contiene código para ser utilizado por el programa, y también los nombres de funciones y datos que espera encontrar en el programa. Cuando el archivo se une al programa, todas las referencias a esas funciones y datos en el código del archivo se cambian para apuntar a las ubicaciones reales en el programa donde las funciones y los datos se colocan en la memoria. Esto es básicamente una operación de enlace.

En Windows, un archivo de biblioteca de enlace dinámico (`.dll`) no tiene referencias colgantes. En cambio, un acceso a funciones o datos pasa por una tabla de búsqueda. Por lo tanto, el código DLL no tiene que repararse en tiempo de ejecución para referirse a la memoria del programa; en cambio, el código ya usa la tabla de búsqueda de la DLL, y la tabla de búsqueda se modifica en tiempo de ejecución para apuntar a las funciones y los datos.

En Unix, solo hay un tipo de archivo de biblioteca (`.a`) que contiene código de varios archivos de objeto (`.o`). Durante el paso de enlace para crear un archivo de objeto compartido (`.so`), el enlazador puede encontrar que no sabe dónde se define un identificador. El enlazador lo buscará en los archivos de objetos en las bibliotecas; si lo encuentra, incluirá todo el código de ese archivo de objeto.

En Windows, hay dos tipos de biblioteca, una biblioteca estática y una biblioteca de importación (ambas llamadas `.lib`). Una biblioteca estática es como un archivo Unix `.a`; Contiene código para ser incluido según sea necesario. Una biblioteca de importación se usa básicamente solo para asegurarle al enlazador que cierto identificador es legal y estará presente en el programa cuando se cargue la DLL. Por lo tanto, el enlazador utiliza la información de la biblioteca de importación para crear la tabla de búsqueda para usar identificadores que no están incluidos en la DLL. Cuando se vincula una aplicación o una DLL, se puede generar una biblioteca de importación, que deberá usarse para todas las DLL futuras que dependan de los símbolos en la aplicación o DLL.

Suponga que está creando dos módulos de carga dinámica, B y C, que deberían compartir otro bloque de código A. En Unix, no pasaría `A.a` al enlazador para `B.so` y `C.so`; eso haría que se incluyera dos veces, de modo que B y C tengan cada uno su propia copia. En Windows, compilar `A.dll` también compilará `A.lib`. Usted si pasa `A.lib` al enlazador para B y C. `A.lib` no contiene código; solo contiene información que se usará en tiempo de ejecución para acceder al código de A.

En Windows, usar una biblioteca de importación es como usar `importar spam`; le da acceso a los nombres de spam, pero no crea una copia separada. En Unix, vincular con una biblioteca es más como `from spam import*`; crea una copia separada.

## 5.3. Usar DLL en la práctica

Windows Python is built in Microsoft Visual C++; using other compilers may or may not work. The rest of this section is MSVC++ specific.

Al crear archivos DLL en Windows, debe pasar `pythonXY.lib` al enlazador. Para construir dos DLL, spam y ni (que usa funciones C que se encuentran en el spam), puede usar estos comandos:

    cl /LD /I/python/include spam.c ../libs/pythonXY.lib
    cl /LD /I/python/include ni.c spam.lib ../libs/pythonXY.lib

El primer comando creó tres archivos: `spam.obj`, `spam.dll` y `spam.lib`. `Spam.dll` no contiene ninguna función de Python (como `PyArg_ParseTuple()`), pero sabe cómo encontrar el código de Python gracias a `pythonXY.lib`.

El segundo comando creó `ni.dll` (y `.obj` y `.lib`), que sabe cómo encontrar las funciones necesarias del spam, y también del ejecutable de Python.

No todos los identificadores se exportan a la tabla de búsqueda. Si desea que cualquier otro módulo (incluido Python) pueda ver sus identificadores, debe decir `_declspec(dllexport)`, como en `void _declspec(dllexport) initspam(void)` o `PyObject_declspec(dllexport) *NiGetSpamData(void)`.

Developer Studio will throw in a lot of import libraries that you do not really need, adding about 100K to your executable. To get rid of them, use the Project Settings dialog, Link tab, to specify ignore default libraries. Add the correct `msvcrtxx.lib` to the list of libraries.