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 "msvcrt*xx*.lib" to the list of
libraries.
