Yapı Tabanlı Derleme Sistemleri

Sorun bildir Kaynağı göster Gece · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

Bu sayfada, yapıya dayalı derleme sistemleri ve bunların oluşturulmasındaki felsefe ele alınmaktadır. Bazel, yapıya dayalı bir derleme sistemidir. Görev tabanlı derleme daha iyi bir adımdır; komut dosyalarına çok fazla güç kendi görevlerini tanımlamalarını sağlayarak ayrı ayrı mühendislere yardımcı olabilirler.

Yapı tabanlı derleme sistemlerinde, sistem tarafından tanımlanan az sayıda görev bulunur sınırlı bir şekilde yapılandırabileceği araçlar. Mühendisler sisteme ne oluşturulacağını söyler ancak derleme sistemi nasıl oluşturulacağını belirler. Görev tabanlı derleme sistemlerinde olduğu gibi, Bazel gibi yapıya dayalı derleme sistemlerinde de derleme dosyaları bulunur ancak bu derleme dosyalarının içeriği çok farklıdır. Paydaşlarınıza Turing'in eksiksiz kodlama dilinde zorunlu bir komut dizisi olmaktan daha çıkışının nasıl oluşturulacağını açıklayan Bazel'deki derleme dosyaları bildirim temelli bağımlılıklarını ve derlenen bir dizi yapıyı açıklayan bir manifesto dosyasıyla nasıl oluşturulduklarını etkileyen sınırlı sayıda seçenek vardır. Mühendisler komut satırında bazel çalıştırdığında, derlenecek bir dizi hedef (ne) belirtir ve Bazel derleme adımlarını (nasıl) yapılandırma, çalıştırma ve planlamaktan sorumludur. Derleme sistemi artık hangi araçların ne zaman çalışacağı üzerinde tam kontrole sahip olduğundan, doğruluğu garanti ederken çok daha verimli olmasını sağlayan çok daha güçlü garantiler verebilir.

İşlevsel bakış açısı

Yapı tabanlı derleme sistemleri ile işlevsel sistemleri kolayca karşılaştırabilir öğreneceğiz. Görev tabanlı derleme sistemlerinin programcıların yürütecekleri bir dizi adımı tanımlamasına olanak tanıdığı gibi, geleneksel zorunlu programlama dilleri (Java, C ve Python gibi) de birbiri ardına yürütülecek ifade listelerini belirtir. İşlevsel programlama dilleri (ör. Haskell ve ML), daha çok bir dizi matematik denklemi gibi yapılandırılmıştır. İşlevsel dillerde programcı, yapılacak bir hesaplamayı açıklar ancak bu hesaplamanın ne zaman ve tam olarak nasıl yürütüleceğine dair ayrıntıları derleyiciye bırakır.

Bu, yapıya dayalı bir derleme sisteminde manifest beyan etme ve sistemin derlemeyi nasıl yürüteceğini belirlemesine izin verme fikriyle eşleşir. Birçok sorun işlevsel programlama kullanılarak kolayca ifade edilemez ancak bu programlama biçiminden büyük fayda sağlayan sorunlar da vardır: Dil, genellikle bu tür programları kolayca paralelleştirebilir ve doğruluklarıyla ilgili, zorunlu bir dilde imkansız olan güçlü garantiler verebilir. Bir dil kullanarak ifade edilmesi en kolay problemler fonksiyonel programlama, bir parçayı yalnızca bir parçayı bir dizi kural veya işlev kullanarak verileri diğerine dönüştürme. İşte tam olarak bu yapı sistemi nedir? Tüm sistem, fonksiyonel olarak matematiksel bir fonksiyondur. kaynak dosyaları (ve derleyici gibi araçları) giriş olarak alıp çıkışlar olarak ikili programların kullanılması anlamına gelir. Bu nedenle, çok sayıda reklam içeren bir projeyi fonksiyonel programlamanın ilkelerine göre hareket eden bir sistemdir.

Öğe tabanlı derleme sistemlerini anlama

Google'ın derleme sistemi Blaze, yapıya dayalı ilk derleme sistemidir. Bazel Blaze'in açık kaynak sürümüdür.

Bazel'de bir derleme dosyasının (normal olarak adı BUILD) nasıl göründüğü aşağıda verilmiştir:

java_binary(
    name = "MyBinary",
    srcs = ["MyBinary.java"],
    deps = [
        ":mylib",
    ],
)
java_library(
    name = "mylib",
    srcs = ["MyLibrary.java", "MyHelper.java"],
    visibility = ["//java/com/example/myproduct:__subpackages__"],
    deps = [
        "//java/com/example/common",
        "//java/com/example/myproduct/otherlib",
    ],
)

Bazel'de BUILD dosyaları hedefleri tanımlar. Buradaki iki hedef türü java_binary ve java_library'dir. Her hedef, sistem tarafından oluşturulabilecek bir yapıya karşılık gelir: İkili hedefler, doğrudan yürütülebilen ikili programlar oluşturur ve kitaplık hedefleri, ikili programlar veya diğer kitaplıklar tarafından kullanılabilen kitaplıklar oluşturur. Her hedefte şunlar bulunur:

  • name: Hedefin komut satırında ve diğer hedefler tarafından nasıl referans verildiği
  • srcs: Hedefin yapısını oluşturmak için derlenecek kaynak dosyalar
  • deps: Bu hedeften önce oluşturulması ve bu hedefe bağlanması gereken diğer hedefler

Bağımlılıklar aynı paket içinde (ör. MyBinary :mylib) ya da aynı kaynak hiyerarşisindeki farklı bir pakette (örneğin mylib ile //java/com/example/common arasındaki bağımlılık).

Görev tabanlı derleme sistemlerinde olduğu gibi, derlemeleri Bazel'in komut satırını kullanarak gerçekleştirirsiniz. aracını kullanın. MyBinary hedefini oluşturmak için bazel build :MyBinary komutunu çalıştırırsınız. Bu komutu temiz bir depoda ilk kez girdikten sonra Bazel:

  1. Bağımlılık grafiği oluşturmak için çalışma alanındaki her BUILD dosyasını ayrıştırır ortaya çıkarır.
  2. MyBinary grafiğinin geçişli bağımlılıklarını belirlemek için grafiği kullanır. verileri bağlı olan her hedef ve bu hedefe MyBinary ve yinelemeli olarak desteklenmektedir.
  3. Bu bağımlılıkların her birini sırayla oluşturur. Bazel, inşaat işlerinde her birinin hiçbir bağımlılığı olmayan ve hangi bağımlılıkların takip edildiğini gösteren yine de her bir hedef için oluşturulması gerekir. Bir hedefin tamamı oluşturulduğunda, Bazel bu hedefi oluşturmaya başlar. Bu işlem, MyBinary'ün geçişli bağımlılıkları oluşturulana kadar devam eder.
  4. Aşağıdakilerin tümüne bağlantı veren nihai bir yürütülebilir ikili program oluşturmak için MyBinary ve 3. adımda oluşturulan bağımlılıkları inceleyeceğiz.

Temelde, burada yaşananlar o kadar da karmaşık görünmeyebilir. olanlardan farklıdır. Gerçekten de nihai sonuç aynı ikili olur ve bunu üretme süreci aralarındaki bağımlılıkları bulmak için bir dizi adımı analiz eder ve ardından bu adımları sırasıyla takip edin. Ancak kritik farklar var. İlki 3. adımda görünür: Bazel, her hedefin yalnızca bir Java kitaplığı ürettiğini bildiğinden, yapması gereken tek şeyin kullanıcı tanımlı rastgele bir komut dosyası yerine Java derleyicisini çalıştırmak olduğunu bilir. Bu nedenle, bu adımların paralel olarak çalıştırılmasının güvenli olduğunu bilir. Bu durum, derlemelere kıyasla önemli bir performans artışı sağlayabilir. tek seferde bir tane olmak üzere çok çekirdekli bir makinede hedeflenir ve yalnızca yapı temelli yaklaşımda derleme sistemi kendi yürütmesinden sorumlu olur bu yaklaşım, paralellikle ilgili daha güçlü garantiler vermesini mümkün kılar.

Ancak avantajlar paralelliğin ötesine geçiyor. Bu aşamadan sonra, yaklaşımı, geliştirici herhangi bir değişiklik yapmadan ikinci kez bazel build :MyBinary yazdığında belirginleşir. Bazel daha kısa sürede çıkar hedefin güncel olduğunu söyleyen bir mesajla 1 saniyeden daha uzun bir sürede bırakabilirsiniz. Bu, daha önce bahsettiğimiz işlevsel programlama paradigması sayesinde mümkündür. Bazel, her hedefin yalnızca bir Java derleyicisinin çalıştırılmasının sonucu olduğunu ve Java derleyicisinin çıktısının yalnızca girişlerine bağlı olduğunu bilir. Bu nedenle, girişler değişmediği sürece çıkış yeniden kullanılabilir. Bu analiz her düzeyde çalışır. MyBinary.java değişirse Bazel, MyBinary'ü yeniden oluşturmayı ancak mylib'yi yeniden kullanmayı bilir. //java/com/example/common için bir kaynak dosya değişirse Bazel, bu kitaplığı, mylib ve MyBinary'yi yeniden derlemeyi bilir ancak //java/com/example/myproduct/otherlib'ı yeniden kullanır. Bazel her adımda çalıştırdığı araçların özelliklerini bildiği için her seferinde yalnızca minimum yapı kümesini yeniden derleyebilir. eski derlemeler oluşturmayacağını garanti eder.

Derleme sürecini görevler yerine yapı olarak yeniden çerçevelendirmek, ince ama güçlü bir yaklaşımdır. Programcının maruz kaldığı esnekliği azaltarak, derleme sistemi geliştirmenin her adımında yapılan işlemler hakkında daha fazla bilgi sahibi olabiliyor. Bu bilgiyi kullanarak derleme süreçlerini paralelleştirip çıktılarını yeniden kullanarak derlemeyi çok daha verimli hale getirebilir. Ancak bu yalnızca ilk adımdır. Paralellik ve yeniden kullanmanın bu yapı taşları, dağıtılmış ve yüksek ölçeklenebilir bir derleme sisteminin temelini oluşturur.

Diğer kullanışlı Bazel püf noktaları

Öğe tabanlı derleme sistemleri, temel olarak görev tabanlı derleme sistemlerine özgü paralellik ve yeniden kullanım sorunlarını çözer. Ancak hâlâ karşılaştığımız birkaç soruna değindik. Bazel'in bu sorunların her birini çözmenin akıllıca yolları vardır. Devam etmeden önce bunları tartışmamız gerekir.

Bağımlılık aracı olarak kullanılan araçlar

Daha önce karşılaştığımız bir sorun, derlemelerin makinemize yüklenen araçlara bağlı olmasıydı. Ayrıca, farklı araç sürümleri veya konumları nedeniyle derlemeleri sistemler arasında yeniden oluşturmak zor olabilir. Projenizde, oluşturuldukları veya derlendikleri platforma (ör. Windows ve Linux) göre farklı araçlar gerektiren diller kullanıldığında ve bu platformların her biri aynı işi yapmak için biraz farklı bir araç grubu gerektirdiğinde sorun daha da karmaşık hale gelir.

Bazel, bu sorunun ilk kısmını çözmek için araçları bağımlılık olarak ele alır. her bir hedefe bakın. Çalışma alanındaki her java_library, varsayılan olarak iyi bilinen bir derleyici olan bir Java derleyiciye bağlıdır. Bazel her oluşturulduğunda java_library, belirtilen derleyicinin kullanılabilir olup olmadığını kontrol eder. bilinen bir konumda görebilirsiniz. Diğer tüm bağımlılıklarda olduğu gibi, Java derleyicisi değişirse ona bağlı her yapı yeniden oluşturulur.

Bazel, derleme yapılandırmaları ayarlayarak sorunun ikinci bölümünü (platform bağımsızlığı) çözer. Hedefler, doğrudan araçlarına bağlı olmak yerine yapılandırma türlerine bağlıdır:

  • Ana makine yapılandırması: Derleme sırasında çalışan derleme araçları
  • Hedef yapılandırma: Son olarak istediğiniz ikili dosyayı derleme

Derleme sistemini genişletme

Bazel, birçok popüler programlama dili için hazır hedefler sunar ancak mühendisler her zaman daha fazlasını yapmak ister. Görev tabanlı sistemlerin avantajlarından biri, her türlü derleme sürecini destekleme esnekliğidir ve bu avantajdan yapı tabanlı bir derleme sisteminde vazgeçmemek daha iyi olur. Neyse ki Bazel, özel kurallar ekleyerek desteklenen hedef türlerinin genişletilmesine olanak tanır.

Kural yazarı, Bazel'de bir kural tanımlamak için kuralın (BUILD dosyasında iletilen özellikler biçiminde) ve kuralın ürettiği çıkış kümesidir. Yazar, bu kural tarafından oluşturulacak işlemleri de tanımlar. Her eylem, kendi giriş ve çıkışlarını açıklar. çalıştırılabilir veya bir dosyaya belirli bir dize yazıyor olabilir. giriş ve çıkışları aracılığıyla diğer işlemlere bağlanmasını sağlar. Bu, işlemlerin derleme sistemindeki en düşük seviyeli composable birimlerdir. Bir işlem yalnızca tanımlanan giriş ve çıkışlarını kullandığı sürece istediği her şeyi ve Bazel, işlemleri planlamaya ve sonuçları uygun şekilde önbelleğe almaya dikkat eder.

Bir işlem geliştiricisinin işleminin bir parçası olarak rastgele olmayan bir işlem başlatması gibi işlemleri yapmasının önüne geçemeyeceği için sistem hatasız değildir. Ancak bu durum pratikte pek sık yaşanmaz. eylem düzeyine kadar suistimal olasılığı önemli ölçüde azalıyor. fırsatlara sahip olacaksınız. Birçok yaygın dili ve aracı destekleyen kurallar yaygın olarak kullanılır ve çoğu projenin kendi proje belgelerini kurallar. Tanımlanmış olsa bile kural tanımlarının yalnızca tek bir bu verileri depoda merkezi bir yerde tutar. Böylece çoğu mühendis Böylece, uygulama konusunda endişelenmenize gerek kalmadan bu kuralları uygulayabilirsiniz.

Ortamı izole etme

İşlemler, diğer sistemlerdeki görevlerle aynı sorunlarla karşılaşabilir. Aynı dosyaya yazma işlemi yapan ve birbiriyle çakışan işlemler yazmak mümkün mü? Bazel aslında bunları korumalı alan oluşturma kullanıldığında mümkün olmayan çakışmalar sağlar. Desteklenen sistemlerde her işlem, dosya sistemi korumalı alanı aracılığıyla diğer işlemlerden izole edilir. Böylece her işlem, dokümanın bildirdiği girişleri ve çıkışları içeren dosya sistemi üretilir. Bu, Linux'daki LXC gibi sistemler tarafından zorunlu kılınmaktadır. LXC, Docker'ın temelindeki teknolojiyle aynıdır. Bu, bildirmedikleri dosyaları okuyamadıkları için işlemlerin birbiriyle çakışmasının mümkün olmadığı anlamına gelir. Ayrıca, bildirmedikleri ancak yazdıkları dosyalar işlem sona erdiğinde silinir. Bazel, işlemlerin ağ üzerinden iletişim kurmasını kısıtlamak için korumalı alanlardan da yararlanır.

Dış bağımlılıkları belirleyici hale getirme

Ancak hâlâ çözülmemiş bir sorun var: Derleme sistemlerinin, bağımlılıkları (araç veya kitaplık fark etmeksizin) doğrudan derlemek yerine genellikle harici kaynaklardan indirmesi gerekir. Bu durum, Maven'den JAR dosyası indiren @com_google_common_guava_guava//jar bağımlılığı aracılığıyla örnekte görülebilir.

Mevcut çalışma alanının dışındaki dosyalara bağlı olarak risklidir. Bu dosyalar değiştirebilir ve derleme sisteminin, sistemdeki değişiklikleri sürekli olarak güncellikleri görebiliriz. Uzak bir dosya karşılık gelen bir değişiklik olmadan değişirse Bu durum, çalışma alanı kaynak kodunda tekrar oluşturulamayan derlemelere yol açabilir. fark edilmemiş bir nedenden dolayı bir gün başarısız olabilir ne kadar önemli olduğunu konuşalım. Son olarak, dış bağımlılıklar, büyük bir güvenlik açığı üçüncü bir tarafa ait olduğu durumlarda risk teşkil eder: bir saldırgan sızdırabilirse bağımlı bir dosya olduğu zaman, bağımlılık dosyasını ve geliştirdiğiniz yapı üzerinde tam kontrol sahibi olmalarını sağlar. ve çıktıları arasında fark yaratır.

Temel sorun, derleme sisteminin bu dosyaları kaynak denetimine eklemek zorunda kalmadan bu dosyalardan haberdar olmasını istememizdir. Bağımlılığı güncelleme Bilinçli bir seçim olmalıdır, ancak bu seçim tek bir merkezde tek bir kez tek tek mühendisler tarafından veya mühendislik ekibi tarafından bahsedeceğim. Çünkü "kafada aktif" modelinde bile olsak deterministiktir. Bu, son kayıttan bir kayda bakarsanız olduğu gibi değil, o hafta olduğu gibi .

Bazel ve diğer bazı derleme sistemleri, Çalışma alanı genelinde, her harici kullanıcı için şifreleme karmasını listeleyen bir manifest dosyası oluşturur: altını çizeceğiz. Karma, dosyanın tamamını kaynak denetiminde kontrol etmeden dosyayı benzersiz bir şekilde temsil etmenin kısa bir yoludur. Bir çalışma alanından yeni bir harici bağımlılık referans verildiğinde, söz konusu bağımlılıktaki karma oluşturma işlemi manuel olarak veya otomatik olarak manifest dosyasına eklenir. Bazel bir derleme çalıştırdığında, önbelleğe alınmış bağımlılığının gerçek karma değerini manifest dosyasında tanımlanan beklenen karma değeriyle karşılaştırır ve yalnızca karma değer farklıysa dosyayı yeniden indirir.

İndirdiğimiz yapının karması, manifest dosyasında belirtilenden farklıysa manifest dosyasındaki karma güncellenmediği sürece derleme başarısız olur. Bu yapabilirsiniz, ancak bu değişikliğin onaylanması ve kontrol kaynak denetiminin yeni bağımlılığı kabul etmesi gerekir. Bu, bir bağımlığın ne zaman güncellendiğine dair her zaman bir kayıt bulunduğu ve harici bir bağımlığın, çalışma alanı kaynağında ilgili bir değişiklik yapılmadan değişemeyeceği anlamına gelir. Aynı zamanda, kaynak kodun eski bir sürümünü kontrol ederken derlemenin o sırada kullandığı bağımlılıkları kullanması garanti edilir emin olunması gerekir (aksi takdirde, söz konusu bağımlılıklar kullanılabilir durumda değil).

Elbette uzaktaki bir sunucu kullanılamaz hale gelirse veya bozuk veriler sunmaya başlar. Bu, tüm derlemelerinizin başarısız olmaya başlamasına neden olabilir bu bağımlılığın başka bir kopyası yoksa. Bu sorunu önlemek için, önemsiz olmayan tüm projelerde bağımlılıkların tamamını güvendiğiniz ve kontrol ettiğiniz sunuculara veya hizmetlere yansıtmanızı öneririz. Aksi takdirde, kontrol edilen karmalar güvenliğini garanti etse bile derleme sisteminizin kullanılabilirliği için her zaman üçüncü tarafların insafına kalmış olursunuz.