4. Construindo extensões C e C++
********************************

Uma extensão C para CPython é uma biblioteca compartilhada (por
exemplo, um arquivo ".so" no Linux, ".pyd" no Windows), que exporta
uma *função de inicialização*.

Para ser importável, a biblioteca compartilhada deve estar disponível
em "PYTHONPATH", e deve ser nomeada após o nome do módulo, com uma
extensão apropriada. Ao usar distutils, o nome do arquivo correto é
gerado automaticamente.

A função de inicialização tem a assinatura:

PyObject *PyInit_modulename(void)

Ela retorna um módulo totalmente inicializado ou uma instância de
"PyModuleDef". Veja Inicializando módulos C para detalhes.

Para módulos com nomes somente ASCII, a função deve ser nomeada
"PyInit_<nomemódulo>", com "<nomemódulo>" substituído pelo nome do
módulo. Ao usar Inicialização multifásica, nomes de módulos não ASCII
são permitidos. Neste caso, o nome da função de inicialização é
"PyInitU_<nomemódulo>", com "<nomemódulo>" codificado usando a
codificação *punycode* do Python com hifenes substituídos por
sublinhados. Em 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

É possível exportar vários módulos de uma única biblioteca
compartilhada, definindo várias funções de inicialização. No entanto,
importá-los requer o uso de links simbólicos ou um importador
personalizado, porque por padrão apenas a função correspondente ao
nome do arquivo é encontrada. Veja a seção  *"Multiple modules in one
library"* na **PEP 489** para detalhes.


4.1. Construindo extensões C e C ++ com distutils
=================================================

Módulos de extensão podem ser construídos usando distutils, que está
incluído no Python. Visto que distutils também suporta a criação de
pacotes binários, os usuários não precisam necessariamente de um
compilador e distutils para instalar a extensão.

Um pacote distutils contém um script guia "setup.py". Este é um
arquivo Python simples, que, no caso mais simples, pode ter a seguinte
aparência:

   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])

Com este "setup.py" e um arquivo "demo.c", executando

   python setup.py build

vai compilar "demo.c", e produzir um módulo de extensão chamado "demo"
no diretório "build". Dependendo do sistema, o arquivo do módulo vai
terminar em um subdiretório "build/lib.system", e pode ter um nome
como "demo.so" ou "demo.pyd".

No "setup.py", toda a execução é realizada chamando a função "setup".
Isso leva um número variável de argumentos nomeados, dos quais o
exemplo acima usa apenas um subconjunto. Especificamente, o exemplo
especifica meta-informação para construir pacotes e especifica o
conteúdo do pacote. Normalmente, um pacote conterá módulos adicionais,
como módulos-fonte Python, documentação, subpacotes etc. Consulte a
documentação do distutils em Distribuindo Módulos Python (Versão
legada) para aprender mais sobre os recursos do distutils; esta seção
explica apenas a construção de módulos de extensão.

É comum pré-computar argumentos para "setup()", para melhor estruturar
o script guia. No exemplo acima, o argumento "ext_modules" para
"setup()" é uma lista de módulos de extensão, cada um dos quais é uma
instância de "Extension". No exemplo, a instância define uma extensão
chamada "demo" que é construída compilando um único arquivo fonte,
"demo.c".

Em muitos casos, construir uma extensão é mais complexo, uma vez que
definições de pré-processador adicionais e bibliotecas podem ser
necessárias. Isso é demonstrado no exemplo abaixo.

   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])

Neste exemplo, "setup()" é chamado com meta-informação adicional, o
que é recomendado quando os pacotes de distribuição precisam ser
construídos. Para a extensão em si, especifica definições de
pré-processador, diretórios de inclusão, diretórios de biblioteca e
bibliotecas. Dependendo do compilador, distutils passa essas
informações de maneiras diferentes para o compilador. Por exemplo, no
Unix, isso pode resultar nos comandos de compilação

   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

Essas linhas são apenas para fins de demonstração; Os usuários de
distutils devem confiar que distutils acertará as invocações.


4.2. Distribuindo seus módulos de extensão
==========================================

Quando uma extensão é construída com sucesso, há três maneiras de
usá-la.

Os usuários finais normalmente desejam instalar o módulo, eles fazem
isso executando

   python setup.py install

Os mantenedores do módulo devem produzir pacotes fonte; para fazer
isso, eles executam:

   python setup.py sdist

Em alguns casos, arquivos adicionais precisam ser incluídos em uma
distribuição fonte; isso é feito através de um arquivo "MANIFEST.in";
veja Specifying the files to distribute para detalhes.

Se a distribuição fonte foi construída com sucesso, os mantenedores
também podem criar distribuições binárias. Dependendo da plataforma,
um dos seguintes comandos pode ser usado para fazer isso.

   python setup.py bdist_rpm
   python setup.py bdist_dumb
