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 "msvcrt*xx*.lib" dosyasını ekleyin.
