# 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 Initializing C modules 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 Multi-phase initialization, 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:file: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

When an extension has been successfully build, there are three ways to use it.

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.

If the source distribution has been build successfully, maintainers can also create binary distributions. Depending on the platform, one of the following commands can be used to do so.

    python setup.py bdist_wininst
    python setup.py bdist_rpm
    python setup.py bdist_dumb