Bağımlılıklar

Sorun bildir Kaynağı görüntüle Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Bir hedef A, derleme veya yürütme zamanında A tarafından B'e ihtiyaç duyuluyorsa bir hedef B'e A bağlıdır. Bağlıdır ilişkisi, hedefler üzerinde bir Yönlü Düz Ağaç (DAG) oluşturur ve buna bağımlılık grafiği adı verilir.

Bir hedefin doğrudan bağımlılıkları, bağımlılık grafiğinde uzunluğu 1 olan bir yolla ulaşılabilen diğer hedeflerdir. Bir hedefin geçişli bağımlılıkları, grafikteki herhangi bir uzunluktaki yol üzerinden bağlı 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 bildirilmiş bağımlılıklar grafiği. Çoğu zaman iki grafik o kadar benzerdir ki bu ayrımın yapılması gerekmez ancak aşağıdaki tartışma için faydalıdır.

Gerçek ve beyan edilen bağımlılıklar

X hedefinin doğru şekilde oluşturulması için Y hedefinin mevcut, oluşturulmuş ve güncel olması gerekiyorsa X hedefi Y hedefiyle gerçekten bağımlıdır. Oluşturuldu; oluşturma, işleme, derleme, bağlama, arşivleme, sıkıştırma, yürütme veya oluşturma sırasında rutin olarak gerçekleşen diğer görev türlerinden herhangi biri anlamına gelebilir.

X paketinde X öğesinden Y öğesine bir bağımlılık kenarı varsa X hedefi, Y hedefi üzerinde 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ın grafiğinin D alt grafiği olmalıdır. Yani A'daki her doğrudan bağlı düğüm çifti x --> y D'de de doğrudan bağlı olmalıdır. D'nin, A'nın aşırı yaklaşımı olduğu söylenebilir.

BUILD dosya yazıcıları, derleme sistemi için her kuralın gerçek doğrudan bağımlılıklarının tümünü açıkça bildirmelidir.

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

Yürütme sırasında A tarafından gerekli olsa bile dolaylı olarak içe aktarılan her şeyi listelemeye çalışmanız gerekmez (ve çalışmamalısınız).

Hedef X oluşturulurken, oluşturma aracı, bu hedeflerdeki değişikliklerin nihai sonuca yansıtıldığından emin olmak için X bağımlılıklarının tüm geçişli kapanışını inceler ve gerektiğinde ara öğeleri yeniden oluşturur.

Bağımlılıkların geçişli yapısı, yaygın bir hataya yol açar. Bazen bir dosyadaki kod, dolaylı bağımlılık tarafından sağlanan kodu kullanabilir. Bu, bildirilen bağımlılık grafiğinde geçişli ancak doğrudan olmayan bir kenardır. 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şiklikleri izlemenin bir yolu yoktur:

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

Başlangıçta her şey çalışır. a paketindeki kod, b paketindeki kodu kullanıyor. b paketindeki kod, c paketindeki kodu kullandığı için c'e geçişli olarak a 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
Bildirilmiş bağımlılık grafiği
Bildirilen bağımlılık grafiğiyle eşleşen, a, b ve c'yi bağlayan okların bulunduğu gerçek bağımlılık grafiği
Gerçek bağımlılık grafiği

Bildirilen bağımlılıklar, gerçek bağımlılıkları fazla tahmin ediyor. Her şey yolunda.

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

Bir kullanıcı, a öğesine c üzerinde doğrudan gerçek bağımlılık oluşturan bir kod eklediğinde ancak bunu derleme dosyasında a/BUILD bildirmeyi unuttuğunda 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
Bildirilmiş bağımlılık grafiği
a, b ve c'yi bağlayan okların bulunduğu gerçek bağımlılık grafiği. Bir ok artık A'yı C'ye de bağlıyor. Bu, beyan edilen bağımlılık grafiğiyle eşleşmiyor
Gerçek bağımlılık grafiği

Bildirilen bağımlılıklar artık gerçek bağımlılıkları aşırı tahmin etmiyor. Bu, iki grafiğin geçişli kapanımları eşit olduğundan sorunsuz bir şekilde oluşturulabilir ancak bir sorunu gizler: a, c üzerinde gerçek ancak bildirilmemiş bir bağımlılığa sahiptir.

3. Bildirilen ve gerçek bağımlılık grafikleri arasındaki farklılık

Bir kullanıcı b kodunu yeniden düzenleyerek c öğesine bağımlılığını kaldırdığında tehlike ortaya çıkar. Bu durumda, a öğesi kullanıcının hatası olmaksızın yanlışlıkla bozulur.

  b/BUILD
 
rule(
    name = "b",
    srcs = "b.in",
    deps = "//d:d",
)
      
  b / b.in
 
      import d;
      function foo() {
        d.baz();
      }
      
a ve b'yi bağlayan okların bulunduğu, bildirilmiş bağımlılık grafiği.
                  b artık c'ye bağlanmıyor. Bu durum, a'nın c'ye bağlantısını kesiyor.
Bildirilmiş bağımlılık grafiği
a ile b ve c'nin bağlantısını gösteren gerçek bağımlılık grafiği,
                  ancak b artık c'ye bağlanmıyor
Gerçek bağımlılık grafiği

Bildirilen bağımlılık grafiği artık geçişli olarak kapatıldığında bile gerçek bağımlılıkların eksik bir yaklaşımıdır. Derlemenin başarısız olması muhtemeldir.

2. adımda a ile c arasında oluşturulan gerçek bağımlılığın BUILD dosyasında düzgün şekilde tanımlanmasıyla sorun önlenebilirdi.

Bağımlılık türleri

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

Birçok kuralda, kurala özgü bağımlılık türleri için ek özellikler de bulunur. Örneğin, compiler veya resources. Bunlar Build Encyclopedia'da ayrıntılı olarak açıklanmıştır.

srcs bağımlılıkları

Doğrudan kural veya kaynak dosyaları oluşturan kurallar tarafından kullanılan dosyalar.

deps bağımlılıkları

Üstbilgi dosyaları, semboller, kitaplıklar, veriler vb. sağlayan ayrı derlenmiş modülleri gösteren kural.

data bağımlılıkları

Bir derleme hedefinin doğru şekilde çalışması için bazı veri dosyalarına ihtiyacı olabilir. Bu veri dosyaları kaynak kodu değildir ve hedefin nasıl oluşturulduğunu etkilemez. Örneğin, bir 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 başlatılan araçlar için de geçerlidir.

Derleme sistemi, testleri yalnızca data olarak listelenen dosyaların bulunduğu yalıtılmış bir dizinde çalıştırır. Bu nedenle, bir ikili/kitaplık/testin çalışması için bazı dosyalar gerekiyorsa bunları (veya bunları içeren bir derleme kuralını) data içinde 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 yollarını ve çalışma alanına göre yolu birleştirerek bu dosyalara başvurabilirsiniz. Örneğin, ${TEST_SRCDIR}/workspace/path/to/data/file.

Dizinlere referans vermek için etiketleri kullanma

BUILD dosyalarımıza göz atarken bazı BUILD etiketlerinin dizinlere referans verdiğini fark edebilirsiniz.data Bu etiketler, aşağıdaki örneklerde olduğu gibi /. veya / ile bitiyor. Bu etiketleri kullanmamalısınız:

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

Önerilmeyendata = ["testdata/."]

Önerilmeyendata = ["testdata/"]

Bu, özellikle testler için kullanışlıdır. Çünkü bir testin dizindeki tüm veri dosyalarını kullanmasına olanak tanır.

Ancak bunu yapmamaya çalışın. Bir değişiklikten sonra doğru artımlı yeniden derlemelerin (ve testlerin yeniden yürütülmesinin) sağlanması için derleme sisteminin, derlemenin (veya testin) girişleri olan tüm dosyaları bilmesi gerekir. Bir dizin belirttiğinizde derleme sistemi yalnızca dizinin kendisi değiştiğinde (dosya ekleme veya silme nedeniyle) yeniden derleme gerçekleştirir ancak bu değişiklikler kapsayan dizini etkilemediğinden tek tek dosyalarda yapılan düzenlemeleri algılayamaz. Dizinleri derleme sistemine giriş olarak belirtmek yerine, bu dizinlerde bulunan dosyaları açıkça veya glob() işlevini kullanarak numaralandırmanız gerekir. (** kullanarak glob() öğesinin yinelemeli olmasını zorlayın.)

Önerilendata = glob(["testdata/**"])

Maalesef dizin etiketlerinin kullanılması gereken bazı durumlar vardır. Örneğin, testdata dizini, adları etiket söz dizimine uymayan dosyalar içeriyorsa dosyaların açıkça numaralandırılması veya glob() işlevinin kullanılması geçersiz etiketler hatasına neden olur. Bu durumda dizin etiketlerini kullanmanız gerekir ancak yukarıda açıklanan yanlış yeniden oluşturma riskine dikkat edin.

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

Birden fazla dosya kullanması gereken test gibi tüm harici kurallar, bu dosyaların tümüne bağımlı olduğunu açıkça belirtmelidir. filegroup() kullanarak BUILD dosyasındaki dosyaları gruplandırabilirsiniz:

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

Ardından, testinizde veri bağımlılığı olarak my_data etiketine başvurabilirsiniz.

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