5. Bygga C- och C++-tillägg i Windows

Detta kapitel förklarar kortfattat hur man skapar en Windows-tilläggsmodul för Python med hjälp av Microsoft Visual C++ och följer sedan upp med mer detaljerad bakgrundsinformation om hur det fungerar. Förklaringsmaterialet är användbart för både Windows-programmerare som lär sig att bygga Python-tillägg och Unix-programmerare som är intresserade av att producera programvara som kan byggas på både Unix och Windows.

Modulförfattare uppmuntras att använda distutils metod för att bygga tilläggsmoduler, istället för den som beskrivs i detta avsnitt. Du kommer fortfarande att behöva den C-kompilator som användes för att bygga Python, vanligtvis Microsoft Visual C++.

Anteckning

I det här kapitlet nämns ett antal filnamn som innehåller ett kodat Python-versionsnummer. Dessa filnamn representeras med versionsnumret som visas som XY; i praktiken kommer 'X' att vara huvudversionsnumret och 'Y' kommer att vara det mindre versionsnumret för den Python-version du arbetar med. Om du till exempel använder Python 2.2.1 kommer XY faktiskt att vara 22.

5.1. Ett tillvägagångssätt med kokbok

Det finns två sätt att bygga tilläggsmoduler på Windows, precis som på Unix: använd paketet setuptools för att styra byggprocessen, eller gör saker manuellt. Setuptools-metoden fungerar bra för de flesta tillägg; dokumentation om hur du använder setuptools för att bygga och paketera tilläggsmoduler finns i Bygga C- och C++-tillägg med setuptools. Om du verkligen behöver göra saker manuellt kan det vara lärorikt att studera projektfilen för standardbiblioteksmodulen winsound.

5.2. Skillnader mellan Unix och Windows

Unix och Windows använder helt olika paradigm för laddning av kod i körtid. Innan du försöker bygga en modul som kan laddas dynamiskt bör du vara medveten om hur ditt system fungerar.

I Unix innehåller en shared object (.so)-fil kod som ska användas av programmet, och även namnen på funktioner och data som den förväntar sig att hitta i programmet. När filen länkas till programmet ändras alla referenser till dessa funktioner och data i filens kod så att de pekar på de faktiska platserna i programmet där funktionerna och datan placeras i minnet. Detta är i princip en länkoperation.

I Windows har en fil från ett dynamiskt länkbibliotek (.dll) inga hängande referenser. Istället går en åtkomst till funktioner eller data via en uppslagstabell. DLL-koden behöver alltså inte fixas till vid körning för att referera till programmets minne, utan koden använder redan DLL:ns uppslagstabell och uppslagstabellen modifieras vid körning för att peka på funktioner och data.

I Unix finns det bara en typ av biblioteksfil (.a) som innehåller kod från flera objektfiler (.o). Under länkningssteget för att skapa en delad objektfil (.so) kan det hända att länkaren inte vet var en identifierare är definierad. Länkaren letar efter den i objektfilerna i biblioteken och om den hittar den inkluderas all kod från den objektfilen.

I Windows finns det två typer av bibliotek, ett statiskt bibliotek och ett importbibliotek (båda kallas .lib). Ett statiskt bibliotek är som en Unix-fil .a; det innehåller kod som kan inkluderas efter behov. Ett importbibliotek används i princip bara för att försäkra länkaren om att en viss identifierare är laglig och kommer att finnas med i programmet när DLL:en laddas. Länkaren använder informationen från importbiblioteket för att bygga upp en uppslagstabell för att använda identifierare som inte ingår i DLL-filen. När ett program eller en DLL länkas kan ett importbibliotek genereras, som måste användas för alla framtida DLL:er som är beroende av symbolerna i programmet eller DLL:en.

Anta att du bygger två moduler med dynamisk laddning, B och C, som ska dela ett annat kodblock A. På Unix skulle du inte skicka A.a till länkaren för B.so och C.so; det skulle leda till att den inkluderades två gånger, så att B och C skulle få var sin kopia. I Windows kommer byggandet av A.dll också att bygga A.lib. Du överlämnar A.lib till länkaren för B och C. A.lib innehåller inte kod, utan bara information som kommer att användas vid körning för att komma åt A:s kod.

I Windows är det ungefär som att använda import spam att använda ett importbibliotek; det ger dig tillgång till spams namn, men skapar inte en separat kopia. På Unix är länkning med ett bibliotek mer som from spam import *; det skapar en separat kopia.

Stäng av den implicita, #pragma-baserade länkningen med Python-biblioteket, som utförs i CPython-huvudfiler.

Tillagd i version 3.14.

5.3. Användning av DLL:er i praktiken

Windows Python är byggt i Microsoft Visual C++; att använda andra kompilatorer kan fungera eller inte. Resten av detta avsnitt är MSVC++-specifikt.

När du skapar DLL:er i Windows kan du använda CPython-biblioteket på två sätt:

  1. Som standard utlöser inkludering av PC/pyconfig.h direkt eller via Python.h en implicit, konfigurationsmedveten länk till biblioteket. Huvudfilen väljer pythonXY_d.lib för Debug, pythonXY.lib för Release och pythonX.lib för Release med Limited API aktiverat.

    Om du vill skapa två DLL-filer, spam och ni (som använder C-funktioner som finns i spam), kan du använda följande kommandon:

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

    Det första kommandot skapade tre filer: spam.obj, spam.dll och spam.lib. Spam.dll innehåller inga Python-funktioner (t.ex. PyArg_ParseTuple()), men den vet hur man hittar Python-koden tack vare den implicit länkade pythonXY.lib.

    Det andra kommandot skapade ni.dll (och .obj och .lib), som vet hur man hittar de nödvändiga funktionerna från spam och även från den körbara Python-filen.

  2. Manuellt genom att definiera makrot Py_NO_LINK_LIB innan du inkluderar Python.h. Du måste skicka pythonXY.lib till länkaren.

    Om du vill skapa två DLL-filer, spam och ni (som använder C-funktioner som finns i spam), kan du använda följande kommandon:

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

    Det första kommandot skapade tre filer: spam.obj, spam.dll och spam.lib. Spam.dll innehåller inga Python-funktioner (t.ex. PyArg_ParseTuple()), men den vet hur man hittar Python-koden tack vare pythonXY.lib.

    Det andra kommandot skapade ni.dll (och .obj och .lib), som vet hur man hittar de nödvändiga funktionerna från spam och även från den körbara Python-filen.

Inte alla identifierare exporteras till uppslagstabellen. Om du vill att andra moduler (inklusive Python) ska kunna se dina identifierare måste du säga _declspec(dllexport), som i void _declspec(dllexport) initspam(void) eller PyObject _declspec(dllexport) *NiGetSpamData(void).

Developer Studio slänger in en massa importbibliotek som du egentligen inte behöver och som lägger till ca 100K till din körbara fil. För att bli av med dem, använd dialogrutan Projektinställningar, fliken Länk, för att ange ignorera standardbibliotek. Lägg till rätt msvcrtxx.lib i listan över bibliotek.