Bağımlılıklar

A hedefi, derleme veya yürütme sırasında A tarafından B gerekiyorsa B hedefine bağlıdır. İlişki, hedeflere bağlı olarak Yönlendirilmiş Döngüsel Grafik'e (DAG) neden olur ve buna bağımlılık grafiği denir.

Bir hedefin doğrudan bağımlılıkları, bağımlılık grafiğinde 1 uzunluğunda bir yol ile erişilebilen diğer hedeflerdir. Bir hedefin geçişli bağımlılıkları, grafik boyunca herhangi bir uzunluktaki bir yol üzerinden bağımlı olduğu hedeflerdir.

Aslında derlemeler bağlamında iki bağımlılık grafiği vardır: gerçek bağımlılıklar grafiği ve bildirilen bağımlılıklar grafiği. Çoğu zaman, iki grafik o kadar benzer ki bu ayrımı yapmak gerekmez ama aşağıdaki tartışma için yararlıdır.

Gerçek ve bildirilen bağımlılıklar

X hedefinin doğru şekilde derlenmesi için Y öğesinin mevcut, oluşturulmuş ve güncel olması gerekiyorsa X hedefi, Y hedefine gerçekten bağımlıdır. Derleme, bir derleme sırasında düzenli olarak gerçekleşen, oluşturulan, işlenen, derlenen, bağlanılan, arşivlenen, sıkıştırılan, yürütülen, yürütülen veya diğer türde görevler anlamına gelebilir.

X paketinde X ile Y arasında bir bağımlılık sınırı varsa bir hedef X, Y hedefine bildirilmiş bir bağımlılığa sahiptir.

Doğru derlemeler için gerçek bağımlılıkların grafiği A, bildirilen bağımlılıklar D grafiğinin alt grafiği olmalıdır. Yani A bölgesinde doğrudan bağlı olan her düğüm (x --> y) aynı zamanda doğrudan D konumunda da bağlı olmalıdır. D'nin, A'ya fazla yakınlaşması olduğu söylenebilir.

BUILD dosya yazarları, her kurala ilişkin gerçek doğrudan bağımlılıkların tümünü derleme sistemine açıkça bildirmelidir ve bunu yapmaz.

Bu ilkeye uyulmaması, tanımlanmamış davranışa neden olur: Derleme başarısız olabilir ancak daha kötüsü, derleme bazı önceki işlemlere veya hedefin sahip olduğu geçişli bildirilmiş bağımlılıklara bağlı olabilir. Bazel eksik bağımlılıkları kontrol eder ve hataları bildirir. Ancak bu kontrolün her durumda tamamlanması mümkün değildir.

A tarafından yürütme sırasında ihtiyaç duyulsa bile dolaylı olarak içe aktarılan her şeyi listelemeye çalışmanız gerekmez (ve bunu yapmamanız gerekir).

X hedefinin derlemesi sırasında derleme aracı, bu hedeflerdeki değişikliklerin nihai sonuca yansıtıldığından emin olmak için X bağımlılıklarının geçişli olarak kapanmasını tamamen inceleyerek ara ürünleri gerektiği gibi yeniden oluşturur.

Bağımlılıkların geçişli yapısı sık karşılaşılan bir hataya yol açar. Bazen bir dosyadaki kod, dolaylı bir bağımlılık (bildirilen bağımlılık grafiğinde doğrudan olmayan ancak geçişli bir uç) tarafından sağlanan kodu kullanabilir. Dolaylı bağımlılıklar BUILD dosyasında görünmez. Kural doğrudan sağlayıcıya bağlı olmadığından, aşağıdaki örnek zaman çizelgesinde gösterildiği gibi değişiklikler izlenemez:

1. Bildirilen bağımlılıklar gerçek bağımlılıklarla eşleşir

İlk başta her şey çalışıyor. a paketindeki kod, b paketindeki kodu kullanıyor. b paketindeki kod, c paketindeki kodu kullandığından a, geçişli olarak c paketine bağlıdır.

a/BUILD b/BUILD
rule(
    name = "a",
    srcs = "a.in",
    deps = "//b:b",
)
      
rule(
    name = "b",
    srcs = "b.in",
    deps = "//c:c",
)
      
a / a.in b / b.in
import b;
b.foo();
    
import c;
function foo() {
  c.bar();
}
      
a, b ve c'yi bağlayan okların bulunduğu, bildirilmiş bağımlılık grafiği
Beyan edilen bağımlılık grafiği
a, b ve c'yi bağlayan oklarla belirtilen bağımlılık grafiğiyle eşleşen gerçek bağımlılık grafiği
Gerçek bağımlılık grafiği

Beyan edilen bağımlılıklar, gerçek bağımlılıklara yaklaşık olarak yaklaşıyor. Her şey yolunda.

2. Bildirilmemiş bir bağımlılık ekleme

Bir kullanıcı a öğesine c öğesine doğrudan gerçek bağımlılık oluşturan bir kod ekler ancak bunu derleme dosyasında belirtmeyi unutursa a/BUILD gizli bir tehlike ortaya çıkar.

a / a.in  
        import b;
        import c;
        b.foo();
        c.garply();
      
 
a, b ve c'yi bağlayan okların bulunduğu, bildirilmiş bağımlılık grafiği
Beyan edilen bağımlılık grafiği
a, b ve c'yi bağlayan okların yer aldığı gerçek bağımlılık grafiği. Bir ok, A'yı C'ye de bağlar. Bu, beyan edilen bağımlılık grafiğiyle eşleşmiyor
Gerçek bağımlılık grafiği

Belirtilen bağımlılıklar artık gerçek bağımlılıklara yakın değil. Bu durum sorun teşkil edebilir çünkü iki grafiğin geçişli olarak kapanmaları eşittir ancak bir sorunu maskeler: a, c üzerinde gerçek ama bildirilmemiş bir bağımlılığa sahiptir.

3. Beyan edilen ve gerçek bağımlılık grafikleri arasındaki fark

Birisi b ürününü artık c'ye bağımlı olmayacak şekilde yeniden düzenlediğinde ve istemeden a kodunu kendi hatası olmadan kırdığında tehlike ortaya çıkar.

  b/BUILD
 
rule(
    name = "b",
    srcs = "b.in",
    deps = "//d:d",
)
      
  b / b.in
 
      import d;
      function foo() {
        d.baz();
      }
      
A ile b'yi birleştiren okların bulunduğu, bildirilmiş bağımlılık grafiği.
                  b artık c'ye bağlanmaz, bu da a'nın c ile bağlantısını keser
Beyan edilen bağımlılık grafiği
b ve c'ye bağlanmayı gösteren ancak b'nin artık c'ye bağlanmadığını gösteren gerçek bağımlılık grafiği
Gerçek bağımlılık grafiği

Beyan edilen bağımlılık grafiği, geçişli olarak kapalı olsa bile artık gerçek bağımlılıkların yaklaşık bir özetidir. Derlemenin başarısız olma olasılığı yüksektir.

2. Adımda tanıtılan a ile c arasındaki gerçek bağımlılığın BUILD dosyasında düzgün şekilde tanımlanması sağlanarak bu sorun önlenebilirdi.

Bağımlılık türleri

Çoğu derleme kuralının, farklı türlerde genel bağımlılıkları belirtmek için üç özelliği vardır: srcs, deps ve data. Bunlar aşağıda açıklanmıştır. Daha fazla ayrıntı için Tüm kurallarda ortak özellikler bölümüne bakın.

Birçok kuralın, kurala özgü bağımlılık türleri için ek özellikleri de (ör. compiler veya resources) vardır. Bu konular, Ansiklopedi Oluşturma bölümünde ayrıntılı olarak açıklanmıştır.

srcs bağımlılık

Kaynak dosyaları oluşturan kurallar veya doğrudan kural tarafından tüketilen dosyalar.

deps bağımlılık

Başlık dosyaları, semboller, kitaplıklar, veriler vb. sağlayan, ayrı olarak derlenmiş modüllere işaret eden kural.

data bağımlılık

Derleme hedefinin düzgün çalışması için bazı veri dosyaları gerekebilir. Bu veri dosyaları kaynak kodu değildir: Hedefin ne şekilde oluşturulduğunu etkilemezler. Örneğin, birim testi, bir işlevin çıkışını bir dosyanın içeriğiyle karşılaştırabilir. Birim testini oluştururken dosyaya ihtiyacınız yoktur, ancak testi çalıştırırken dosyaya ihtiyacınız vardır. Aynı durum, yürütme sırasında kullanıma sunulan araçlar için de geçerlidir.

Derleme sistemi, testleri yalnızca data olarak listelenen dosyaların bulunduğu izole bir dizinde çalıştırır. Dolayısıyla, bir ikili program/kitaplık/testin çalışması için bazı dosyalar gerekiyorsa bunları data içinde (veya bunları içeren bir derleme kuralı) belirtin. Örneğin:

# I need a config file from a directory named env:
java_binary(
    name = "setenv",
    ...
    data = [":env/default_env.txt"],
)

# I need test data from another directory
sh_test(
    name = "regtest",
    srcs = ["regtest.sh"],
    data = [
        "//data:file1.txt",
        "//data:file2.txt",
        ...
    ],
)

Bu dosyalar, path/to/data/file göreli yolu kullanılarak kullanılabilir. Testlerde, testin kaynak dizininin ve çalışma alanına bağlı yolun yollarını (örneğin, ${TEST_SRCDIR}/workspace/path/to/data/file) birleştirerek bu dosyalara başvurabilirsiniz.

Dizinlere referans vermek için etiketleri kullanma

BUILD dosyalarına bakarken bazı data etiketlerinin dizinlere karşılık geldiğini fark edebilirsiniz. Bu etiketler, aşağıdaki örneklerde olduğu gibi /. veya / ile biter. Bunları kullanmamalısınız:

Önerilmeyendata = ["//data/regression:unittest/."]

Önerilmeyendata = ["testdata/."]

Önerilmeyendata = ["testdata/"]

Bu, özellikle testler açısından bir testin dizindeki tüm veri dosyalarını kullanmasına olanak tanıdığından kullanışlı görünür.

Ama bunu yapmamaya çalışın. Bir değişiklikten sonra artımlı yeniden derlemelerin (ve testlerin yeniden yürütülmesini) doğru bir şekilde yapılmasını sağlamak için derleme sistemi, derleme (veya test) girdileri olan tüm dosya grubundan haberdar olmalıdır. Bir dizin belirttiğinizde derleme sistemi yalnızca dizinin kendisi değiştiğinde (dosyaların eklenmesi veya silinmesi nedeniyle) yeniden oluşturma işlemi gerçekleştirir; ancak bu değişiklikler ilişkili dizini etkilemediği için bağımsız dosyalarda yapılan düzenlemeleri algılayamaz. Dizinleri, derleme sistemi için girişler olarak belirtmek yerine, içlerinde bulunan dosya grubunu açıkça veya glob() işlevini kullanarak numaralandırmanız gerekir. (glob() öğesini yinelemeli olmaya zorlamak için ** kullanın.)

Önerilen: data = glob(["testdata/**"])

Maalesef dizin etiketlerinin kullanılması gereken bazı senaryolar vardır. Örneğin, testdata dizini, adları etiket söz dizimine uygun olmayan dosyalar içeriyorsa dosyaların açık bir şekilde numaralandırılması veya glob() işlevinin kullanılması geçersiz etiket hatasına yol açar. Bu durumda dizin etiketlerini kullanmanız gerekir ancak yukarıda açıklanan yanlış yeniden oluşturma risklerine karşı dikkatli olun.

Dizin etiketlerini kullanmanız gerekiyorsa göreli bir ../ yoluyla üst pakete başvuruda bulunamayacağınızı unutmayın. Bunun yerine //data/regression:unittest/. gibi mutlak bir yol kullanın.

Birden fazla dosya kullanması gereken bir harici kuralın (ör. test) tümüne bağımlı olduğunu açıkça beyan etmesi gerekir. BUILD dosyasında dosyaları gruplandırmak için filegroup() kullanabilirsiniz:

filegroup(
        name = 'my_data',
        srcs = glob(['my_unittest_data/*'])
)

Daha sonra, testinizdeki veri bağımlılığı olarak my_data etiketine başvurabilirsiniz.

BUILD dosyaları Görünürlük