4. Construyendo extensiones C y C++
***********************************

Una extensión C para CPython es una biblioteca compartida (por
ejemplo, un archivo ".so" en Linux, ".pyd" en Windows), que exporta
una *función de inicialización*.

Para que sea importable, la biblioteca compartida debe estar
disponible en "PYTHONPATH", y debe tener el nombre del módulo, con una
extensión adecuada. Cuando se usan distutils, el nombre de archivo
correcto se genera automáticamente.

La función de inicialización tiene la firma:

PyObject *PyInit_modulename(void)

It returns either a fully initialized module, or a "PyModuleDef"
instance. See Inicializando módulos en C for details.

Para los módulos con nombres solo ASCII, la función debe llamarse
"PyInit_<modulename>", con "<modulename>" reemplazado por el nombre
del módulo. Cuando se usa Inicialización multifase, se permiten
nombres de módulos que no sean ASCII. En este caso, el nombre de la
función de inicialización es "PyInitU_<modulename>", con
"<modulename>" codificado usando la codificación *punycode* de Python
con guiones reemplazados por guiones bajos. En Python:

   def initfunc_name(name):
       try:
           suffix = b'_' + name.encode('ascii')
       except UnicodeEncodeError:
           suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
       return b'PyInit' + suffix

Es posible exportar múltiples módulos desde una única biblioteca
compartida definiendo múltiples funciones de inicialización. Sin
embargo, importarlos requiere el uso de enlaces simbólicos o un
importador personalizado, porque de forma predeterminada solo se
encuentra la función correspondiente al nombre del archivo. Consulte
la sección *"Múltiples módulos en una biblioteca"* en **PEP 489** para
más detalles.


4.1. Construyendo extensiones C y C++ con distutils
===================================================

Los módulos de extensión se pueden construir utilizando distutils, que
se incluye en Python. Dado que distutils también admite la creación de
paquetes binarios, los usuarios no necesitan necesariamente un
compilador y distutils para instalar la extensión.

Un paquete distutils contiene un script de controlador, "setup.py".
Este es un archivo Python simple, que, en el caso más simple, podría
verse así:

   from distutils.core import setup, Extension

   module1 = Extension('demo',
                       sources = ['demo.c'])

   setup (name = 'PackageName',
          version = '1.0',
          description = 'This is a demo package',
          ext_modules = [module1])

Con esto "setup.py", y un archivo "demo.c", ejecutando:

   python setup.py build

compilará "demo.c", y producirá un módulo de extensión llamado "demo"
en el directorio "build". Dependiendo del sistema, el archivo del
módulo terminará en un subdirectorio "build/lib.system", y puede tener
un nombre como "demo.so" o "demo.pyd".

En "setup.py", toda la ejecución se realiza llamando a la función
"setup". Esto toma un número variable de argumentos de palabras clave,
de los cuales el ejemplo anterior usa solo un subconjunto.
Específicamente, el ejemplo especifica metainformación para construir
paquetes, y especifica el contenido del paquete. Normalmente, un
paquete contendrá módulos adicionales, como módulos fuente Python,
documentación, subpaquetes, etc. Consulte la documentación de
distutils en Distribución de módulos de Python (versión heredada) para
obtener más información sobre las características de distutils; Esta
sección explica la construcción de módulos de extensión solamente.

Es común precalcular argumentos para "setup()", para estructurar mejor
el script del controlador. En el ejemplo anterior, el argumento
"ext_modules" para "setup()" es una lista de módulos de extensión,
cada uno de los cuales es una instancia de "Extension" . En el
ejemplo, la instancia define una extensión llamada "demo" que se
construye compilando un solo archivo fuente "demo.c".

En muchos casos, construir una extensión es más complejo, ya que es
posible que se necesiten preprocesadores adicionales y bibliotecas.
Esto se demuestra en el siguiente ejemplo.

   from distutils.core import setup, Extension

   module1 = Extension('demo',
                       define_macros = [('MAJOR_VERSION', '1'),
                                        ('MINOR_VERSION', '0')],
                       include_dirs = ['/usr/local/include'],
                       libraries = ['tcl83'],
                       library_dirs = ['/usr/local/lib'],
                       sources = ['demo.c'])

   setup (name = 'PackageName',
          version = '1.0',
          description = 'This is a demo package',
          author = 'Martin v. Loewis',
          author_email = 'martin@v.loewis.de',
          url = 'https://docs.python.org/extending/building',
          long_description = '''
   This is really just a demo package.
   ''',
          ext_modules = [module1])

En este ejemplo, se llama a "setup()" con metainformación adicional,
que se recomienda cuando se deben construir paquetes de distribución.
Para la extensión en sí, especifica las definiciones de preprocesador,
incluye directorios, directorios de biblioteca y bibliotecas.
Dependiendo del compilador, distutils pasa esta información de
diferentes maneras al compilador. Por ejemplo, en Unix, esto puede
resultar en los comandos de compilación:

   gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o

   gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so

Estas líneas son solo para fines de demostración; Los usuarios de
distutils deben confiar en que distutils obtiene las invocaciones
correctas.


4.2. Distribuyendo sus módulos de extensión
===========================================

Cuando una extensión se ha creado correctamente, hay tres formas de
usarla.

Los usuarios finales generalmente querrán instalar el módulo, lo hacen
ejecutando:

   python setup.py install

Los mantenedores de módulos deben producir paquetes fuente; para
hacerlo, ejecutan:

   python setup.py sdist

En algunos casos, se deben incluir archivos adicionales en una
distribución de origen; esto se hace a través de un archivo
"MANIFEST.in"; ver Especificar los archivos a distribuir para más
detalles.

Si la distribución de origen se ha creado correctamente, los
encargados del mantenimiento también pueden crear distribuciones
binarias. Dependiendo de la plataforma, se puede usar uno de los
siguientes comandos para hacerlo.:

   python setup.py bdist_rpm
   python setup.py bdist_dumb
