Görev Tabanlı Derleme Sistemleri

Sorun bildirin Kaynağı göster

Bu sayfada göreve dayalı derleme sistemleri, nasıl çalıştıkları ve göreve dayalı sistemlerde ortaya çıkabilecek bazı sorunlar ele alınmaktadır. Kabuk komut dosyalarından sonra, görev tabanlı derleme sistemleri, derlemenin bir sonraki mantıksal evrimidir.

Görev tabanlı derleme sistemlerini anlama

Görev tabanlı bir derleme sisteminde, temel çalışma birimi görevdir. Her görev, her türlü mantığı yürütebilen bir komut dosyasıdır. Görevler, kendilerinden önce çalışması gereken diğer görevleri bağımlılık olarak belirler. Günümüzde kullanılan Ant, Maven, Gradle, Grunt ve Rake gibi büyük derleme sistemlerinin çoğu göreve dayalıdır. Modern derleme sistemlerinin çoğu, kabuk komut dosyaları yerine derlemenin nasıl yapılacağını açıklayan derleme dosyaları oluşturmalarını gerektirir.

Ant kılavuzundaki şu örneği ele alalım:

<project name="MyProject" default="dist" basedir=".">
   <description>
     simple example build file
   </description>
   <!-- set global properties for this build -->
   <property name="src" location="src"/>
   <property name="build" location="build"/>
   <property name="dist" location="dist"/>

   <target name="init">
     <!-- Create the time stamp -->
     <tstamp/>
     <!-- Create the build directory structure used by compile -->
     <mkdir dir="${build}"/>
   </target>
   <target name="compile" depends="init"
       description="compile the source">
     <!-- Compile the Java code from ${src} into ${build} -->
     <javac srcdir="${src}" destdir="${build}"/>
   </target>
   <target name="dist" depends="compile"
       description="generate the distribution">
     <!-- Create the distribution directory -->
     <mkdir dir="${dist}/lib"/>
     <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
     <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
   </target>
   <target name="clean"
       description="clean up">
     <!-- Delete the ${build} and ${dist} directory trees -->
     <delete dir="${build}"/>
     <delete dir="${dist}"/>
   </target>
</project>

Derleme dosyası XML'de yazılır ve derlemeyle ilgili bazı basit meta verileri ve görev listesiyle (XML'deki <target> etiketleri) tanımlar. (Karınca bir görevi temsil etmek için hedef kelimesini, komutları ifade etmek için de görev kelimesini kullanmaktadır.) Her görev, Ant tarafından tanımlanan olası komutların bir listesini yürütür. Bu komutlar arasında dizin oluşturma ve silme, javac komutunu çalıştırma ve JAR dosyası oluşturma bulunur. Bu komut grubu, kullanıcı tarafından sağlanan eklentilerle her tür mantığı kapsayacak şekilde genişletilebilir. Her görev, bağımlı özelliği aracılığıyla bağlı olduğu görevleri de tanımlayabilir. Bu bağımlılıklar Şekil 1'de görüldüğü gibi siklik bir grafik oluşturur.

Bağımlılıkları gösteren akrilik grafik

Şekil 1. Bağımlılıkları gösteren döngüsel grafik

Kullanıcılar, Ant'ın komut satırı aracına görev vererek derlemeleri gerçekleştirir. Örneğin, bir kullanıcı ant dist yazdığında Karınca aşağıdaki adımları uygular:

  1. Geçerli dizinde build.xml adlı bir dosyayı yükler ve Şekil 1'de gösterilen grafik yapısını oluşturmak için bu dosyayı ayrıştırır.
  2. Komut satırında sağlanan dist adlı görevi arar ve compile adlı göreve bağımlılığı olduğunu keşfeder.
  3. compile adlı görevi arar ve init adlı göreve bağımlılığı olduğunu keşfeder.
  4. init adlı görevi arar ve herhangi bir bağımlılığı olmadığını keşfeder.
  5. init görevinde tanımlanan komutları yürütür.
  6. Tüm bağımlılıkları çalıştırıldığı için compile görevinde tanımlanan komutları yürütür.
  7. Tüm bağımlılıkları çalıştırıldığı için dist görevinde tanımlanan komutları yürütür.

Sonuç olarak, dist görevini çalıştırırken Ant tarafından yürütülen kod, aşağıdaki kabuk komut dosyasına eşdeğerdir:

./createTimestamp.sh
mkdir build/
javac src/* -d build/
mkdir -p dist/lib/
jar cf dist/lib/MyProject-$(date --iso-8601).jar build/*

Söz dizimi kaldırıldığında, derleme dosyası ve derleme komut dosyası aslında çok farklı olmaz. Ama bu sayede zaten büyük kazanç elde ettik. Diğer dizinlerde yeni derleme dosyaları oluşturabilir ve bunları birbirine bağlayabiliriz. Mevcut görevlere bağlı olan yeni görevleri rastgele ve karmaşık yöntemlerle kolayca ekleyebiliyoruz. ant komut satırı aracına tek bir görevin adını iletmemiz yeterlidir. Bu ad, çalıştırılması gereken her şeyi belirler.

Karınca, ilk olarak 2000'de piyasaya sürülen eski bir yazılımdır. Maven ve Gradle gibi diğer araçlar da aralar içinde Ant'ı iyileştirmiş ve dış bağımlılıkların otomatik yönetimi ve XML olmadan daha net bir söz dizimi gibi özellikler ekleyerek Ant'ın yerini almıştır. Ancak bu yeni sistemlerin doğası değişmemiştir: Mühendislerin derleme komut dosyalarını görev şeklinde ilkeli ve modüler bir şekilde yazmalarına olanak tanımanın yanı sıra bu görevleri yürütmek ve aralarındaki bağımlılıkları yönetmek için araçlar sağlar.

Görev tabanlı derleme sistemlerinin karanlık tarafı

Bu araçlar temelde mühendislerin herhangi bir komut dosyasını görev olarak tanımlamasına olanak tanıdığından son derece güçlüdür. Bu araçlar, mühendislerle hayal edebileceğiniz hemen her şeyi yapabilmenizi sağlar. Ancak bu güç bazı dezavantajları da beraberinde getirir ve oluşturma komut dosyaları daha karmaşık hale geldikçe göreve dayalı derleme sistemleriyle çalışmak zorlaşabilir. Bu tür sistemlerdeki sorun, bu sistemlerin aslında mühendislere çok fazla güç verirken sisteme yeterli güç vermemesidir. Sistem, komut dosyalarının ne yaptığı konusunda fikir sahibi olmadığından, derleme adımlarını planlar ve yürütürken çok dikkatli olması gerekir. Bu nedenle performansta düşüş yaşanır. Sistemin her bir komut dosyasının olması gerekeni yaptığını teyit etmenin bir yolu da yoktur. Bu nedenle komut dosyaları genelde karmaşık bir şekilde büyür ve hata ayıklama gerektiren bir başka unsur haline gelir.

Derleme adımlarını paralel yapma zorluğu

Paralel olarak birkaç derleme adımı yürütebilen çok sayıda çekirdek içeren modern geliştirme iş istasyonları oldukça güçlüdür. Ancak görev tabanlı sistemler, yürütmesi gereken gibi görünse bile genellikle görev yürütülmesini paralel hale getiremez. A görevinin B ve C görevlerine bağlı olduğunu varsayalım. B ve C görevlerinin birbirine bağımlılığı olmadığından, sistemin A görevine daha hızlı ulaşması için bunları aynı anda çalıştırmak güvenli midir? Belki de aynı kaynakların hiçbirine dokunmuyorlarsa olabilirler. Ancak belki de değil; her ikisi de durumlarını izlemek için aynı dosyayı kullanır ve bunları aynı anda çalıştırmak bir çakışmaya neden olur. Sistemin genel olarak bunu bilmesi mümkün değildir. Bu nedenle sistem, bu çakışmaları riske atar (nadir bulunan ancak hata ayıklaması çok zor derleme sorunlarına yol açar) ya da tüm derlemeyi tek bir işlemde tek bir iş parçacığında çalışacak şekilde kısıtlamalıdır. Bu, güçlü bir geliştirici makinesi için büyük bir israfa yol açabilir ve derlemenin birden fazla makineye dağıtılması olasılığını tamamen ortadan kaldırır.

Artımlı derlemeleri gerçekleştirme zorluğu

İyi bir derleme sistemi, mühendislerin güvenilir artımlı derlemeler yapmasına olanak tanır. Böylece küçük bir değişiklik, tüm kod tabanının sıfırdan yeniden oluşturulmasını gerektirmez. Bu, özellikle derleme sistemi yavaşsa ve yukarıda belirtilen nedenlerden dolayı derleme adımlarını paralel hale getiremiyorsa önemlidir. Ama ne yazık ki görev tabanlı derleme sistemleri bu noktada da zorlanıyor. Görevler her şeyi yapabileceğinden, görevlerin zaten yapılıp yapılmadığını kontrol etmenin genel bir yolu yoktur. Birçok görev, bir kaynak dosyası grubunu alıp bir dizi ikili program oluşturmak için bir derleyici çalıştırır. Böylece, temel kaynak dosyaları değişmediyse bu görevlerin yeniden çalıştırılması gerekmez. Ancak ek bilgi olmadan sistem bunu kesin olarak söyleyemez. Belki görev, değişmiş olabilecek bir dosya indirir veya her çalıştırmada farklı olabilecek bir zaman damgası yazar. Doğruluğu garanti etmek için sistemin genellikle her derleme sırasında her görevi yeniden çalıştırması gerekir. Bazı derleme sistemleri, mühendislerin bir görevin yeniden çalıştırılması gereken koşulları belirtmesine izin vererek artımlı derlemeleri mümkün kılmaya çalışır. Bu bazen uygulanabilir olsa da genellikle göründüğünden çok daha karmaşık bir sorundur. Örneğin, dosyaların diğer dosyalar tarafından doğrudan eklenmesine izin veren C++ gibi dillerde, giriş kaynaklarını ayrıştırmadan, değişiklikler için izlenmesi gereken dosya grubunun tamamını belirlemek mümkün değildir. Mühendisler çoğu zaman kısayolları kullanır. Bu kısayollar, bir görev sonucunun olmaması gerektiği halde tekrar kullanıldığı nadir ve sinir bozucu sorunlara yol açabilir. Bu durum sık sık yaşandığında mühendisler yeni bir durum elde etmek için her derlemeden önce temizlik çalıştırma alışkanlığı kazanır. Bu da başlangıçta artımlı bir derlemeye sahip olma amacını tamamen ortadan kaldırır. Bir görevin ne zaman tekrar çalıştırılması gerektiğini belirlemek şaşırtıcı derecede zordur ve insanlardan çok makineler tarafından daha iyi yönetilir.

Komut dosyalarını yönetme ve hata ayıklama konusunda zorluk

Son olarak, görev tabanlı derleme sistemlerinin uyguladığı derleme komut dosyalarıyla çalışmak genellikle oldukça zordur. Derleme komut dosyaları, genellikle daha az incelik gösterse de aynı sistem üzerinde çalışır ve hataların kolayca gizlenebildiği yerlerdir. Görev tabanlı bir derleme sistemiyle çalışırken çok yaygın olarak görülen hatalara bazı örnekler:

  • A görevi, çıkış olarak belirli bir dosya üretmesi için B görevine bağlıdır. B görevinin sahibi, başka görevlerin de buna bağlı olduğunun farkında değildir; bu nedenle, görevi farklı bir yerde çıktı üretmek üzere değiştirir. Bu durum, bir kişi A görevini yürütmeye çalışıp başarısız olduğunu görene kadar tespit edilemez.
  • A görevi, B görevine bağlıdır. Bu görev C görevine bağlıdır. C görevi, A görevi için gereken çıktı olarak belirli bir dosya üreten C görevidir. B görevinin sahibi artık C görevine bağımlı olmadığına karar verir. Bu da B görevi C görevini hiç umursamasa bile A görevinin başarısız olmasına neden olur.
  • Yeni bir görevin geliştiricisi, görevi çalıştıran makine hakkında bir aracın konumu veya belirli ortam değişkenlerinin değeri gibi bir varsayımda bulunabilir. Görev, kullanıcıların makinesinde çalışır ancak başka bir geliştirici bunu denediğinde başarısız olur.
  • Görevler, internetten dosya indirme veya derlemeye zaman damgası ekleme gibi deterministik olmayan bir bileşen içerir. Artık kullanıcılar derlemeyi her çalıştırdıklarında potansiyel olarak farklı sonuçlar alıyor. Diğer bir deyişle, mühendisler otomatik bir derleme sisteminde oluşan arızaları veya arızaları her zaman yeniden üretip düzeltemez.
  • Birden çok bağımlılığı olan görevler yarışma koşulları oluşturabilir. A görevi hem B görevi hem de C görevine bağlıysa ve B görevi ile C görevi aynı dosyayı değiştiriyorsa, A görevi B ve C görevlerinden hangisinin önce bittiğine bağlı olarak farklı bir sonuç alır.

Bu performans, doğruluk veya sürdürülebilirlik sorunlarını burada belirtilen göreve dayalı çerçevede çözmenin genel amaçlı bir yolu yoktur. Mühendisler derleme sırasında rastgele çalışan kod yazabildiği sürece sistem, derlemeleri her zaman hızlı ve doğru bir şekilde çalıştırabilmek için yeterli bilgiye sahip olamaz. Sorunu çözmek için mühendislerin elinden bir miktar güç alıp bunu sistemin ellerine geri vermeli ve sistemin rolünü çalıştırmak yerine işlerin üretilmesi olarak yeniden kavramamız gerekiyor.

Bu yaklaşım, Blaze ve Bazel gibi yapı tabanlı derleme sistemlerinin oluşturulmasını sağladı.