C++ dilinde yazılan bir kodu Python dilinde nasıl kullanırız?

Cengizhan Pasaoglu
5 min readMar 10, 2020

--

Bu yazıya da günümüzde oldukça popüler bir konu haline dönüşen Python — C++ ile devam edelim istedim.

Şu sıralar akademik alanda yapılan çalışmalardan, şirketlerin vizyonlarına kadar çok yaygın kullanılan bir kaç terim var: Yapay zeka, veri madenciliği, büyük veri gibi. Bu teknolojiler gelişirken, hali hazırda en çok kullanılan programlama dillerinin başında da Python geliyor. Kullanım kolaylığının yanı sıra, herkes tarafından sevilen ve pek çok alanda çok iyi işler çıkarmasına karşın performans açısından isteneni veremediği durumlar ortaya çıkabiliyor. Ya da daha önce başka bir dille yazılmış olan yapıyı kullanmak istiyor olabilirsiniz. Bu gibi durumlarda da akıllara şu soru geliyor; performansı arttırabilecek bir dille kombine edilebilir mi? Cevap evet tabi, yoksa bu yazıda işiniz ne :]

Python programlama dili temelinde C ile yazıldığı için, bu dilde yazılmış bir kod parçasının Python dilinde yorumlanması çok da yadırganmaz diye düşünüyorum. Ancak burada başka bir problem daha ortaya çıkıyor; C++ dilinde yazılan bir kod parçasının C diline dönüşümü yapılarak (sarmalayan fonksiyonlar ile) ancak Python tarafından çağrılması mümkün. Bunu bir sonraki yazıda ele alabiliriz. Bugün daha farklı bir araç SWIG ‘ten bahsedeceğim.

SWIG kendi web sayfasında bahsettiği gibi C ve C++ dilleri kullanılarak oluşturulmuş, daha önce yazılmış bir implementasyonu üst seviye başka bir dile bağlayan bir araçtır. Python, R, C# gibi yüksek seviyeli dillerle kullanılmasına olanak sağlar.

Hadi bir örnekle başlayalım. Öncelikle SWIG uygulamasını ve Python3 için gerekli olan geliştirme kütüphanelerini Ubuntu için aşağıdaki gibi indirmemiz gerekiyor.

Benim sanal makinem üzerinde Ubuntu 19.10 yer alıyor. Eğer kullandığınız versiyona uzaktan başka bir kaynak(repository) eklemediyseniz, varsayılan olarak SWIG 3.0 geliyor. Ancak websitesinden indirip kendiniz 4.0 kurabilirsiniz.

Bunun yanı sıra, Python3 için gerekli olan python3-dev kütüphanesini de indirmeniz gerekiyor. Aşağıdaki komutları bunun için kullanabilirsiniz.

Yüklenmesi zorunlu kütüphane ve uygulamalar

Hadi başlayalım. Örnek olması açısından çok basit bir sınıf örneği yazdım. Başlık dosyasını beraber inceleyelim.

Örnek için oluşturulmuş basit Date sınıfı

Örnekte görüldüğü üzere Date sınıfımızın dış dünyaya açılan tek özel olmayan fonksiyonu calculateNextDecade() olarak gözüküyor. Bu noktada parantez açmak gerekirse, aslında public anahtar kelimesi altında yer alan diğer fonksiyonlar da dış dünya tarafından kullanılabilir tabi ancak onlar daha çok sınıfa ait özel fonksiyonlar olarak düşünülmelidir.

Hadi bir de implementasyona bakalım.

Date sınıfı uygulama kısmı

Gerekli olan fonksiyonların iç kısımlarına kendi düşündüğümüz mantıkta yerleştirdiğimizden de eminsek bu çağrıları nasıl kullanacağımızı düşünelim. Burada en dikkat edilmesi gereken noktalardan birisi oluşturacağımız yapının görüldüğü üzere herhangi bir main çağrısı(main function) tarafından kullanılmıyor oluşu. Çünkü yapmak istediğimiz şey, bir uygulama yazmak değil kütüphane oluşturmak. Bu nedenle shared library dediğimiz paylaşımlı kütüphane dosyasını oluşturup Python3 ile kullanacağız.

SWIG nerede dediğiniz duyar gibiyim, şimdi mikrofon SWIG’ te. Şimdi onun için gerekli olan arayüz(interface) dosyasını hazırlayalım. SWIG aracının asıl görevi sizin vermiş olduğunuz girdileri kullanarak anlamlı çıktılar üretmek. Ürettiği bu çıktıları da sizin kullanacağınız Python3 modülü için kullanacağız.

SWIG arayüz dosyası

Buradaki söz-dizimi alışkın olduğunuzdan biraz daha farklı olabilir, kendine has bir söz-dizimine sahip SWIG için kullandığımız iki anahtar kelime var; module ve include.

Module anahtar kelimesi içerisinde yer alan kısım, SWIG tarafından oluşturulacak olan wrapper dosyasını derlememiz için gerekli olan eklemelerin yapılması gereken yer. Oluşturduğumuz sınıf date.h dosyasında bulunuyor ve bu sınıf Cengo isim uzayında yer almakta. Bu yüzden modül içerisine bu bilgileri ekliyoruz.

Bunun dışında yer alan include anahtar kelimesi ise Python3 için kullanacağımız kısımda nelere erişebileceğimizi gösteren bir arayüz aslında. Yazdığımız sınıfta kullandığımız erişim belirteçleri (access specifier) otomatik olarak bunu yapıyor. Ancak burada bile isterseniz başlık dosyasının tamamını değil, arayüz olarak vermek istediğiniz sınıfların ya da fonksiyonların bildirimlerini yazabilirsiniz. Bu kadar laf yeter, nasıl çalışıyor bakalım.

SWIG komut dosyası
  • -Wall bayrağı aslında C++ kullanıcıları için çok yabancı gelmeyebilir ama yine de açıklamak gerekirse, arayüz dosyasını derlerken karşılaşılan yanlış kullanımlar için bizi uyaran bir flag.
  • Hangi dili seçtiğini söylediğiniz başka bir argüman -c++ da bizim için önemli.
  • Eklediğiniz ya da tanımını vermiş olduğunuz fonksiyonların yerini belirtmek için ise yine alışkın olduğumuz bir sözdizimi olan -I belirlenmiş. Bu sayede SWIG kullanmak istediğiniz başlık dosyalarını çözümlemiş oluyor.
  • Arayüz dosyanızı vermeden önce de hangi dile dönüştürülmesini isterseniz onu argüman olarak gösteriyorsunuz. Bu yazıda Python incelediğimiz için -python dedik.

Bu aşamada SWIG sizin için iki tane dosyayı otomatik olarak üretiyor. Bunlardan birincisi {modulename}_wrap.cxx dosyası. Python3 nesne yapısını sizin için sarmalayarak kullanabileceğiniz bir yapı haline getiriyor. Üretilmiş karmaşık bir yapıya sahip C++ dosyası sizi yeterince korkuttuysa dosyayı kapatabilirsiniz :)

Diğer dosya ise {modulename}.py, sizin günün sonunda oluşturmuş olduğunuz paylaşımlı kütüphane dosyasını Python dosyasına yükleyerek(load işlemi) size sadece bu dosyayı import etmek kalıyor.

Derlenme aşaması

Artık SWIG tarafından üretilen dosya ve kendimize ait dosyaları derleyip nesne dosyaları ürettirebiliriz. Buradaki önemli noktalar ise şöyle:

  • Eğer oluşturacağımız dosya paylaşımlı kütüphane ise -fPIC bayrağını kullanmamız gerekiyor.
  • -c argümanı ile sadece dosyaları derleyeceğimizi onları birbirine bağlamayacağımızı belirtiyoruz. Eğer bunu unutursanız varsayılan olarak obje dosyaları birbirine bağlanmaya çalışacak ancak nesneler arasında main fonksiyonu olmadığı için hata alacaksınız, bu yüzden önemli.
  • Bir diğer nokta ise indirdiğimiz Python geliştirme ortamına ait başlık dosyasının yer aldığı dizini göstermek. Bu sayede Python.h adlı başlık dosyasını kullanabiliyoruz.

Sıra geldi elimizdeki nesneleri linker ile bağlayıp bir paylaşımlı kütüphane ortaya çıkarmaya. Bunu ld komutu kullanarak da yapabiliriz ama ben yine g++ kullanarak ilerlemek istiyorum.

Paylaşımlı kütüphane oluşturma komutu

Sonlara doğru gelirken belki en önemli detay olarak burayı göstermem gerekiyor diye düşünüyorum çünkü dökümanda dikkat edilmesi gereken bir nokta olarak gösterilmemiş. Oluşturacağınız dosyasının adı alt çizgi ile başlamalı ve modüle tanımlamış olduğunuz isimle birebir aynı olmalı.

Hazırsak artık yazdığımız Python kod örneğini paylaşalım.

Python örneği

C++ sınıfında yazmış olduğumuz algoritmayı hatırlarsak, eğer istenen tarih 1900 ve 2200 arasında değilse fonksiyonun bize -1 dönmesini bekliyoruz. Bakalım sonuç ne oldu?

Python çıktısı

Görüldüğü üzere yazmış olduğumuz C++ sınıfı, SWIG sponsorluğunda Python tarafından yorumlanıp kullanılabilir hale geldi. Yorumlarınızı ve düşüncelerinizi bana istediğiniz adresten ulaştırabilirsiniz!

--

--