5. Construindo Extensões C e C++ no Windows
*******************************************

Este capítulo explica brevemente como criar um módulo de extensão do
Windows para Python usando o Microsoft Visual C++ e segue com
informações mais detalhadas sobre como ele funciona. O material
explicativo é útil para o programador do Windows aprender a construir
extensões Python e o programador Unix interessado em produzir software
que possa ser construído com sucesso no Unix e no Windows.

Os autores de módulos são encorajados a usar a abordagem distutils
para construir módulos de extensão, em vez daquele descrito nesta
seção. Você ainda precisará do compilador C que foi usado para
construir o Python; normalmente o Microsoft Visual C++.

Nota:

  Este capítulo menciona vários nomes de arquivos que incluem um
  número de versão do Python codificado. Esses nomes de arquivos são
  representados com o número da versão mostrado como "XY"; na prática,
  "'X'" será o número da versão principal e "'Y'" será o número da
  versão secundária da versão do Python com a qual você está
  trabalhando. Por exemplo, se você estiver usando o Python 2.2.1,
  "XY" será "22".


5.1. Uma abordagem de livro de receitas
=======================================

Existem duas abordagens para construir módulos de extensão no Windows,
assim como no Unix: use o pacote "distutils" para controlar o processo
de construção ou faça as coisas manualmente. A abordagem distutils
funciona bem para a maioria das extensões; documentação sobre o uso de
"distutils" para construir e empacotar módulos de extensão está
disponível em Distribuindo Módulos Python (Versão legada). Se você
achar que realmente precisa fazer as coisas manualmente, pode ser
instrutivo estudar o arquivo do projeto para o módulo de biblioteca
padrão winsound.


5.2. Diferenças entre o Unix e o Windows
========================================

O Unix e o Windows usam paradigmas completamente diferentes para o
carregamento do código em tempo de execução. Antes de tentar construir
um módulo que possa ser carregado dinamicamente, esteja ciente de como
o seu sistema funciona.

No Unix, um arquivo de objeto compartilhado (".so") contém código a
ser usado pelo programa e também os nomes de funções e dados que ele
espera encontrar no programa. Quando o arquivo é associado ao
programa, todas as referências a essas funções e dados no código do
arquivo são alteradas para apontar para os locais reais no programa em
que as funções e os dados são colocados na memória. Isso é basicamente
uma operação de vinculação.

No Windows, um arquivo de biblioteca de vínculo dinâmico (".dll") não
possui referências pendentes. Em vez disso, um acesso a funções ou
dados passa por uma tabela de pesquisa. Portanto, o código DLL não
precisa ser corrigido no tempo de execução para se referir à memória
do programa; em vez disso, o código já usa a tabela de pesquisa da DLL
e a tabela de pesquisa é modificada em tempo de execução para apontar
para as funções e dados.

No Unix, existe apenas um tipo de arquivo de biblioteca (".a") que
contém código de vários arquivos de objetos (".o"). Durante a etapa da
vinculação para criar um arquivo de objeto compartilhado (".so"), o
vinculador pode achar que não sabe onde um identificador está
definido. O vinculador procurará nos arquivos de objeto nas
bibliotecas; se encontrar, incluirá todo o código desse arquivo de
objeto.

No Windows, existem dois tipos de biblioteca, uma biblioteca estática
e uma biblioteca de importação (ambas chamadas ".lib"). Uma biblioteca
estática é como um arquivo Unix ".a"; contém código a ser incluído
conforme necessário. Uma biblioteca de importação é basicamente usada
apenas para garantir ao vinculador que um determinado identificador é
legal e estará presente no programa quando a DLL for carregada.
Portanto, o vinculador usa as informações da biblioteca de importação
para construir a tabela de pesquisa para o uso de identificadores que
não estão incluídos na DLL. Quando uma aplicação ou uma DLL é
vinculado, pode ser gerada uma biblioteca de importação, que precisará
ser usada para todas as DLLs futuras que dependem dos símbolos na
aplicação ou DLL.

Suponha que você esteja construindo dois módulos de carregamento
dinâmico, B e C, que devem compartilhar outro bloco de código A. No
Unix, você *não* passaria "A.a" ao ligador para "B.so" e "C.so"; isso
faria com que fosse incluído duas vezes, para que B e C tivessem sua
própria cópia. No Windows, a construção "A.dll" também construirá
"A.lib". Você *passa* "A.lib" ao ligador para B e C. "A.lib" não
contém código; apenas contém informações que serão usadas em tempo de
execução para acessar o código de A.

No Windows, usar uma biblioteca de importação é como usar "import
spam"; fornece acesso aos nomes de spam, mas não cria uma cópia
separada. No Unix, vincular a uma biblioteca é mais como "from spam
import *"; ele cria uma cópia separada.


5.3. Usando DLLs na prática
===========================

O Python para Windows é criado no Microsoft Visual C++; o uso de
outros compiladores pode ou não funcionar. O restante desta seção é
específico do MSVC++.

Ao criar DLLs no Windows, você deve passar "pythonXY.lib" para o
ligador. Para construir duas DLLs, spam e ni (que usa funções C
encontradas em spam), você pode usar estes comandos:

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

O primeiro comando criou três arquivos: "spam.obj", "spam.dll" e
"spam.lib". O "spam.dll" não contém nenhuma função Python (como
"PyArg_ParseTuple()"), mas sabe como encontrar o código Python graças
a "pythonXY.lib".

O segundo comando criou "ni.dll" (e ".obj" e ".lib"), que sabe como
encontrar as funções necessárias do spam e também do executável do
Python.

Nem todo identificador é exportado para a tabela de pesquisa. Se você
deseja que outros módulos (incluindo Python) possam ver seus
identificadores, é necessário dizer "_declspec(dllexport)", como em
"void _declspec(dllexport) initspam(void)" ou "PyObject
_declspec(dllexport) *NiGetSpamData(void)".

O Developer Studio incluirá muitas bibliotecas importadas que você
realmente não precisa, adicionando cerca de 100K ao seu executável.
Para se livrar delas, use a caixa de diálogo de configurações do
projeto, na aba vincular, para especificar *ignorar bibliotecas
padrão*.  Adicione o "msvcrt*xx*.lib" correto à lista de bibliotecas.
