5. Windows’ta C ve C++ Uzantıları Oluşturmak

Bu bölüm, Microsoft Visual C++ kullanarak Python için bir Windows uzantı modülünün nasıl oluşturulacağını kısaca açıklar ve nasıl çalıştığına dair daha ayrıntılı arka plan bilgileri ile devam eder. Açıklayıcı materyal, hem Python uzantıları oluşturmayı öğrenen Windows programcısı hem de Windows üzerinde başarılı bir şekilde yazılım oluşturulabilen ve yazılım üretmekle ilgilenen Unix programcısı için yararlıdır.

Modül yazarları, bu bölümde açıklanan yaklaşım yerine, uzantı modülleri oluşturmak için distutils yaklaşımını kullanmaları önerilir. Yine de Python’u oluşturmak için kullanılan C derleyicisine ihtiyacınız olacaktır; tipik olarak Microsoft Visual C++.

Not

Bu bölümde, kodlanmış bir Python sürüm numarası içeren bir dizi dosya adından bahsedilmektedir. Bu dosya adları XY olarak gösterilen sürüm numarası ile temsil edilir; pratikte, 'X' büyük sürüm numarası ve 'Y' çalıştığınız Python sürümünün küçük sürüm numarası olacaktır. Örneğin, Python 2.2.1 kullanıyorsanız, XY aslında 22 olacaktır.

5.1. Bir Yemek Kitabı Yaklaşımı

Unix’te olduğu gibi Windows’ta da uzantı modülleri oluşturmak için iki yaklaşım vardır: oluşturma işlemini kontrol etmek için setuptools paketini kullanın veya işleri manuel olarak yapın. Setuptools yaklaşımı çoğu uzantı için iyi çalışır; uzantı modüllerini oluşturmak ve paketlemek için setuptools kullanımına ilişkin belgeler Building C and C++ Extensions with setuptools içinde mevcuttur. Eğer işleri gerçekten elle yapmanız gerektiğini düşünüyorsanız, winsound standart kütüphane modülü için proje dosyasını incelemek öğretici olabilir.

5.2. Unix ve Windows Arasındaki Farklar

Unix ve Windows, kodun çalışma zamanında yüklenmesi için tamamen farklı paradigmalar kullanır. Dinamik olarak yüklenebilen bir modül oluşturmaya çalışmadan önce, sisteminizin nasıl çalıştığının farkında olun.

Unix’te, paylaşılan bir nesne (.so) dosyası, program tarafından kullanılacak kodu ve ayrıca programda bulmayı beklediği işlevlerin ve verilerin adlarını içerir. Dosya programa eklendiğinde, dosyanın kodundaki bu işlevlere ve verilere yapılan tüm referanslar, programdaki işlevlerin ve verilerin belleğe yerleştirildiği gerçek konumları gösterecek şekilde değiştirilir. Bu temelde bir bağlantı işlemidir.

Windows’ta, bir dinamik bağlantı kitaplığı (.dll) dosyasında sarkan referanslar yoktur. Bunun yerine, işlevlere veya verilere erişim bir arama tablosundan geçer. Dolayısıyla, DLL kodunun programın belleğine başvurmak için çalışma zamanında düzeltilmesi gerekmez; bunun yerine, kod zaten DLL’nin arama tablosunu kullanır ve arama tablosu çalışma zamanında işlevlere ve verilere işaret edecek şekilde değiştirilir.

Unix’te, birkaç nesne dosyasından (.o) kod içeren yalnızca bir tür kütüphane dosyası (.a) vardır. Paylaşılan bir nesne dosyası (.so) oluşturmak için bağlantı adımı sırasında, bağlayıcı bir tanımlayıcının nerede tanımlandığını bilmediğini fark edebilir. Bağlayıcı bunu kütüphanelerdeki nesne dosyalarında arayacaktır; bulursa, o nesne dosyasındaki tüm kodu dahil edecektir.

Windows’ta iki tür kütüphane vardır: statik kütüphane ve içe aktarma kütüphanesi (her ikisi de .lib olarak adlandırılır). Statik kütüphane Unix .a dosyası gibidir; gerektiğinde dahil edilecek kodu içerir. Bir içe aktarma kitaplığı temel olarak yalnızca bağlayıcıya belirli bir tanımlayıcının yasal olduğu ve DLL yüklendiğinde programda bulunacağı konusunda güvence vermek için kullanılır. Böylece bağlayıcı, DLL’de bulunmayan tanımlayıcıları kullanmak üzere arama tablosunu oluşturmak için içe aktarma kitaplığındaki bilgileri kullanır. Bir uygulama veya DLL bağlandığında, uygulama veya DLL’deki sembollere bağlı olan gelecekteki tüm DLL’ler için kullanılması gereken bir içe aktarma kitaplığı oluşturulabilir.

Başka bir A kod bloğunu paylaşması gereken B ve C olmak üzere iki dinamik yükleme modülü oluşturduğunuzu varsayalım. Unix’te B.so ve C.so için A.a dosyasını bağlayıcıya aktarmazsınız; bu, iki kez dahil edilmesine neden olur, böylece B ve C’nin her biri kendi kopyasına sahip olur. Windows’ta, A.dll dosyasını oluşturmak aynı zamanda A.lib dosyasını da oluşturacaktır. B ve C için bağlayıcıya A.lib dosyasını geçirirsiniz. A.lib kod içermez; sadece çalışma zamanında A’nın koduna erişmek için kullanılacak bilgileri içerir.

Windows’ta, bir içe aktarma kütüphanesi kullanmak import spam kullanmak gibidir; spam’in adlarına erişmenizi sağlar, ancak ayrı bir kopya oluşturmaz. Unix’te, bir kütüphane ile bağlantı kurmak daha çok from spam import * gibidir; ayrı bir kopya oluşturur.

5.3. DLL’leri Uygulamada Kullanma

Windows Python Microsoft Visual C++ ile oluşturulmuştur; diğer derleyicileri kullanmak işe yarayabilir veya yaramayabilir. Bu bölümün geri kalanı MSVC++’a özeldir.

Windows’ta DLL oluştururken, bağlayıcıya pythonXY.lib komutunu geçirmelisiniz. İki DLL oluşturmak için, spam ve ni (spam içinde bulunan C fonksiyonlarını kullanır), şu komutları kullanabilirsiniz:

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

İlk komut üç dosya oluşturdu: spam.obj, spam.dll ve spam.lib. Spam.dll herhangi bir Python fonksiyonu içermiyor (örneğin PyArg_ParseTuple()), ancak pythonXY.lib sayesinde Python kodunu nasıl bulacağını biliyor.

İkinci komut, spam’den ve ayrıca Python çalıştırılabilir dosyasından gerekli işlevleri nasıl bulacağını bilen ni.dll (ve .obj ve .lib) oluşturdu.

Her tanımlayıcı arama tablosuna aktarılmaz. Diğer modüllerin (Python dahil) tanımlayıcılarınızı görmesini istiyorsanız, void _declspec(dllexport) initspam(void) veya PyObject _declspec(dllexport) *NiGetSpamData(void) gibi _declspec(dllexport) demeniz gerekir.

Developer Studio, gerçekten ihtiyacınız olmayan birçok içe aktarma kütüphanesi ekleyerek çalıştırılabilir dosyanıza yaklaşık 100K kütüphane ekleyecektir. Bunlardan kurtulmak için Proje Ayarları iletişim kutusunu, Bağlantı sekmesini kullanarak varsayılan kütüphaneleri yoksay seçeneğini belirleyin. Kütüphaneler listesine doğru msvcrtxx.lib dosyasını ekleyin.