Ghostty GTK uygulaması baştan yazıldı
(mitchellh.com)- Ghostty ekibi GTK uygulamasını tamamen baştan yazdı ve GObject tür sistemini yoğun biçimde kullanmaya başladı
- Bu süreçte Zig dili ile entegrasyon ve Valgrind ile bellek sorunlarının doğrulanması önemli rol oynadı
- GObject sisteminin benimsenmesiyle önceye kıyasla bellek yönetimi ve özel widget geliştirme basitleşti
- Valgrind kullanımının sonucunda Ghostty'nin bellek güvenliğinin büyük ölçüde iyileştiği görüldü
- Yeni Ghostty GTK, kaynak koddan derlemelerde varsayılan hale geldi ve 1.2 sürümünde yer alacak
Giriş
- Ghostty, macOS, Linux, FreeBSD destekleyen çapraz platform bir terminal emülatörüdür
- Her platformda yerel GUI framework'lerini kullanarak farklılaşır
- macOS: Swift ve Xcode tabanlı büyük ölçekli uygulama
- Linux ve BSD: GTK tabanlı uygulama, X11/Wayland gibi sistemlerle doğrudan entegrasyon
- Ortak çekirdek Zig ile yazılmıştır ve C ABI uyumlu API sunar
- Mevcut yapıda GTK uygulamasının neden yeniden yazıldığına dair ayrıntılar için özgün PR'a bakılabilir
- Bu yazı özellikle GObject tür sistemiyle entegrasyon ve Valgrind ile doğrulanan bellek sorunları üzerine odaklanır
GObject tür sistemi ve Zig
- GTK kullanıldığında yapı gereği GObject tür sistemiyle arayüz kurmak gerekir
- Geçmişte GObject sisteminden kaçınılarak referans sayımı olmayan Zig nesneleri ile GObject nesnelerinin yaşam döngüsü elle eşleştirilmeye çalışıldı, ancak bellek serbest bırakmanın düzgün çalışmaması sorunu tekrar tekrar ortaya çıktı
- Örneğin Zig tarafındaki bellek serbest bırakılmışken GTK tarafındaki bellek yaşamaya devam ediyor ya da bunun tersi oluyordu
- Bu yaklaşım yalnızca doğruluk sorunları yaratmakla kalmadı, aynı zamanda GTK'ye özgü özelliklerin (event signals, property binding, actions) kullanımını da zorlaştırdı
- Somut bir örnek olarak, ayar (
config) yapısı yeniden yüklendiğinde bağlı tüm GUI öğelerinin tutarlı şekilde güncellenmesi gerekiyordu; bu süreç karmaşık ve hataya açıktı- Artık Zig
Configyapısı, onu saran referans sayımlıGhosttyConfigGObject ile yönetiliyor ve özellik değişikliği bildirimleri sayesinde değişiklikler uygulamanın geneline doğal biçimde yayılıyor
- Artık Zig
- Özel GObject widget'ları oluşturmak da kolaylaştı; böylece Blueprint gibi modern GTK UI teknolojilerini kullanmak mümkün oldu
- Son dönemde Blueprint'in devreye alınmasıyla GTK titlebar sekmeleri, animasyonlu zil çerçevesi gibi yeni özellikleri eklemek kolaylaştı
Valgrind, GTK ve Zig
- Tüm geliştirme süreci boyunca Valgrind, bellek sızıntıları ve tanımsız bellek erişimleri gibi sorunları sistematik olarak doğrulamak için kullanıldı
- GTK uygulamalarında Valgrind kullanmak zordur ve büyük boyutlu suppression dosyaları gerekir (yaklaşık %80'i GTK'nin kendisi, kalanı 3rd party kütüphaneler ve GPU sürücüleri içindir)
- Tekrarlanan kontroller sayesinde yalnızca bazı durumlarda ortaya çıkan karmaşık bellek hataları önceden tespit edilebildi
- Örneğin GObject
WeakRefdoğru başlatılmazsa hedef nesne daha sonra serbest bırakıldığında tanımsız bellek erişimi oluşur; bu durum Valgrind ile önceden yakalandı
- Örneğin GObject
- Fiili deneyime göre, Zig kod tabanının içindeki sorunlar toplam yalnızca 2 adetti (1 sızıntı, 1 tanımsız erişim) ve bunlar da 3rd party C API entegrasyonu sırasında ortaya çıktı
- Zig'in hata ayıklama amaçlı allocator'ü ve Valgrind entegrasyonu da işe yaradığını kanıtladı
- Bulunan diğer bellek sorunlarının çoğu C API sınırlarında ve GObject sisteminin karmaşık yaşam döngüsü yönetiminden kaynaklandı
- Sonuç olarak, karmaşık kütüphanelerin C API'lerini güvenli kullanmak için Valgrind benzeri araçlar gereklidir
- Zig'in bellek güvenliğini destekleyen özelliklerinin etkisi yalnızca teorik tartışmalarla değil, somut proje deneyimiyle de doğrulandı
Sonuç
- Bu, Ghostty'nin GUI bölümünü beşinci kez sıfırdan yeniden yapma deneyimi oldu
- GLFW, macOS SwiftUI, macOS AppKit+SwiftUI, Linux GTK (prosedürel), Linux GTK+GObject tür sistemi sırasıyla
- Tekrarlanan yeniden yazım sürecinde her seferinde yeni dersler ve teknik gelişim kazanıldı
- Bu deneyimin bir kısmının macOS projesine de uygulanması planlanıyor
- Ghostty GTK sisteminin bakım ekibinin aktif iş birliği de özellikle vurgulanıyor
- Baştan yazılan yeni Ghostty GTK uygulaması artık kaynak koddan derlemelerin varsayılanı oldu ve 1.2 kararlı sürümünde yer alacak
1 yorum
Hacker News yorumu
GTK ile doğrudan çalışma deneyimim yok, ama anlattıklarınız kulağıma Zig ile Godot binding'leri yaparken yaşadığım sorunlara çok benzer geliyor. Godot'da sınıflar, sanal metotlar, property'ler, signal'lar gibi çok fazla OOP kavramı var. Ayrıca tüm bu kavramları ele almanıza ve kullanıcı tanımlı nesnelerle özellikler oluşturmanıza izin veren bir C API sunuyor. Engine nesnelerinin yaşam döngüsünü doğrudan yönetmeniz gerekiyor ve referans sayımlı nesnelerin ağaç yapısı da var. Özellikle yaşam döngüsü sorunlarını Zig deyimlerine uygun, en iyi API hâline getirmeye çalışınca iş aşırı karmaşıklaşıyor. Bu dertlerle uğraşırken oopz kütüphanesini de yaptım. API şu an hâlâ bu seviyede ve gerçek örnekleri burada görebilirsiniz. Ghostty frontend'ini bir Godot extension'ı olarak da yapmayı denemek isterim
İyi programlamanın sonuçta sistemin sunduğu biçime uyum sağlamak olduğunu gösteren güzel bir örnek. OOP ya da bellek yönetimi hakkında ne düşünürseniz düşünün, GTK kullanıyorsanız GObject tip sistemiyle bir şekilde arayüz kurmak zorundasınız. İstemeseniz de bundan kaçış yok. Biz ise bundan kaçınmaya çalıştık ve sonuç olarak referans sayımlı nesnelerle referanssız nesnelerin ömürlerini birbirine bağlarken tam bir karmaşa çıktı. Ghostty GTK uygulamasında Zig belleğini serbest bırakınca GTK belleğinin serbest kalmaması ya da tersinin olması gibi hatalar tekrar tekrar yaşandı
OOP ve bellek yönetimi konusundaki görüşlerimi bir kenara bırakırsak, GTK kullanınca GObject tip sistemine dolanmanın kaçınılmaz olduğuna katılıyorum. Bu yüzden ben doğrudan GTK kullanmamayı seçtim. Tek tip bir UI temasının değerini görüyorum ama bana göre GTK'nın avantajları, onun bedeline katlanmaya yetecek kadar büyük değil. Açık kaynak uygulamalarda GTK çevresinde biraz uğraşmış biri olarak, GTK ve GObject'in bakış açısının benim eğilimlerimle pek örtüşmediğine ikna oldum. GTK'nın var olmasından rahatsız değilim. Ben kullanmamayı seçtiğim sürece sorun yok ama bazı insanların bunun benim seçim hakkım olduğunu düşünmemesi tuhaf geliyor. Sonuçta o, sayısız GUI toolkit'inden sadece biri ve teknik olarak oldukça rafine bir toolkit olmasına rağmen, keşke GTK'nın payı biraz daha az olsaydı da o cilalama başka, yapısal olarak daha iyi toolkit'lere gidebilseydi diye düşünüyorum. Tabii benim iyi bulduğum şey herkes için iyi olmak zorunda değil. GTK kullananların ne kadarı mecburen kullanıyor, ne kadarı bunun en iyi araç olduğunu düşünüyor merak ediyorum
İlginç bir bilgi: Ghostty ve bazı diğer GTK uygulamalarında fare pencerenin dışına çıkıp yeniden girince ilk scroll tıklaması yok sayılıyor. Bunun sebebi 2015'te ilk kez raporlanan çok eski bir hata. Hata bağlantısı. Bugüne kadar da düzeltme planı yok; bakımcıların tavrı Wayland'i beklemek yönünde
“Valgrind ile her adımı doğruladım” kısmında, aslında bu kadar bariz olmasına rağmen benim hiç düzenli yaptığım bir şey olmadı ve başka geliştiricilerde de pek görmedim. Genelde Valgrind ancak belirli bir bug ya da performans düşüşü ortaya çıkınca devreye giriyordu. Geliştirme süreci boyunca Valgrind'i, özellikle Memcheck ve Helgrind'i, proaktif biçimde kullanmak aracın güvenilirliğini çok artırır ve bug'ları sonradan yüzlerce commit'i taramadan, ortaya çıktıkları anda yakalamayı sağlayabilir gibi geliyor
Ghostty kullanırken Mac'te nano'ya çok satırlı yapıştırma yapamamak beni çok rahatsız ediyor. Galiba terminalin “bracketed pasting”i nasıl ele aldığıyla ilgili ama nedense iterm2 ya da Term'de bu sorun yok
Zig yerine Rust kullanılsaydı bellek hataları önlenir miydi diye merak ediyorum. Sorunların çoğu Zig/C etkileşiminden çıkmış gibi duruyor, bu yüzden Rust'ta da benzer olurdu sanırım. Go geliştiricisi olarak tahmin yürütüyorum ama C ile büyük ölçekte entegrasyonda gerçekten daha fazla güvenlik aracı sunan bir dil var mı merak ediyorum
Ghostty gibi GPU tabanlı uygulamaları, ayrıca Alacritty, WezTerm, Zed gibi araçları kullanınca daha hızlı ve daha iyi hissettim. Ama ironik biçimde bu tür uygulamalar Nvidia sürücülerinin sınırlarını daha görünür hâle getiriyor. Eskiden GPU'yu pek kullanmadığım için fark etmemiştim ama Regolith i3wm gibi compositorsuz ortamlarda da, sway/Wayland tarafında da ekran paylaşımı, uykudan dönüş, crash gibi konularda Nvidia sürücüleri gerçekten berbattı. Farklı sürümleri de denedim, 550/560/575/580, hepsi aynıydı. Meğer uzun zamandır durum böyleymiş, ben yeni fark etmişim
GTK tip sisteminin koda nüfuz etmesine izin vermeden büyük bir uygulama yazabildim. Ama bunun karşılığında sınıf kalıtımı ya da extension yerine, tüm bileşenleri birbirine lambda bağlayarak ilişkilendirdim. Sonuç çok da dağınık olmadı ama klasik GTK tarzına alışkın geliştiriciler için kafa karıştırıcı olabilirdi
Ghostty etrafındaki abartılı ilgiyi pek anlayamıyorum. Arayüzünde sekmeler ve context menu dışında pek bir şey yok; böyle entegrasyon işleri ve yeniden yazımlar buna gerçekten değer mi emin değilim. Belki iterm2 gibi daha güçlü bir GUI ortamı kurmak istiyorlardır diye düşünüyorum. Kitty, sekmeleri OpenGL ile kendisi çiziyor, yani tamamen özelleştirilebilir ve karmaşık framework'lere entegrasyonla vakit kaybetmeyip çok pratik özellikleri daha hızlı ekliyor; örneğin son komut çıktısını pager içinde sarmalama gibi. Uzak kullanım tarafı da Kitty'de iyi