Bağımlılıklar

Sorun bildirme Kaynağı görüntüleme Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Derleme veya yürütme zamanında A için B gerekiyorsa bir A hedefi B hedefine bağlıdır. Bağlı ilişkisi, hedefler üzerinde bir yönlü düz ağaç (DAG) oluşturur ve bu ağaca bağlılık grafiği denir.

Bir hedefin doğrudan bağımlılıkları, bağımlılıklar grafiğinde 1 uzunluğunda bir yola ulaşılarak erişilebilen diğer hedeflerdir. Bir hedefin geçişli bağımlılıkları, grafiğin herhangi bir uzunluğundaki bir yol üzerinden bağlı olduğu hedeflerdir.

Aslında derlemeler bağlamında iki bağımlılık grafiği bulunur: gerçek bağımlılıkların grafiği ve bildirilen bağımlılıkların grafiği. Çoğu zaman bu iki grafik o kadar benzerdir ki bu ayrımı yapmanın bir anlamı yoktur ancak aşağıdaki tartışma için bu ayrım faydalıdır.

Gerçek ve beyan edilen bağımlılar

X hedefinin doğru şekilde oluşturulabilmesi için Y hedefinin mevcut, oluşturulmuş ve güncel olması gerekiyorsa X hedefi Y hedefine gerçekten bağlıdır. Derlendi ifadesi, oluşturuldu, işlendi, derlendi, bağlandı, arşivlendi, sıkıştırıldı, yürütüldü veya derleme sırasında rutin olarak gerçekleşen diğer görev türlerinden herhangi birini ifade edebilir.

X paketinde X ile Y arasında bir bağımlılık kenarı varsa X hedefi, Y hedefi için belirlenmiş bir bağımlılığa sahiptir.

Doğru derlemeler için gerçek bağımlılıkların grafiği A, beyan edilen bağımlılıkların grafiğinin D bir alt grafiği olmalıdır. Yani A'da doğrudan bağlı x --> y düğümlerinin her bir çifti de D'de doğrudan bağlı olmalıdır. D'nin, A'ya fazla tahmini olduğu söylenebilir.

BUILD dosyası yazarları, her kural için derleme sistemine gerçek doğrudan bağımlılıkların tümünü açıkça belirtmelidir.

Bu ilkeye uyulmaması, tanımlanmamış davranışa 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 tanımlanmış bağımlılıklara bağlı olabilir. Bazel, eksik bağımlılıkları kontrol eder ve hataları raporlar ancak bu kontrolün her durumda eksiksiz olması mümkün değildir.

Yürütme sırasında A tarafından ihtiyaç duyulsa bile dolaylı olarak içe aktarılan her şeyi listelemeniz gerekmez (ve listelemeniz de gerekmez).

X hedefinin derlenmesi sırasında derleme aracı, bu hedeflerdeki değişikliklerin nihai sonuca yansıtıldığından emin olmak için X'nin bağımlılıkların geçişli kapatılmasının tamamı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ı bir bağımlılık tarafından sağlanan kodu (tanımlanmış bağımlılık grafiğinde geçişli ancak doğrudan olmayan bir kenar) kullanabilir. Dolaylı bağımlılar 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. Beyan edilen bağımlılıklar gerçek bağımlılıklarla eşleşiyor

Başlangıçta her şey yolunda gider. a paketindeki kod, b paketindeki kodu kullanıyor. b paketindeki kod, c paketindeki kodu kullandığından a, c'e dolaylı olarak 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 birbirine bağlayan oklarla tanımlanmış bağımlılık grafiği
Belirtilen bağımlılık grafiği
a, b ve c'yi birbirine bağlayan oklarla, beyan edilen 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ıkları fazla tahmin ediyor. Her şey yolunda.

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

Birisi a koda doğrudan gerçek bağımlılık oluşturan c ancak derleme dosyasında bunu bildirmeyi unuttuğunda bir kod eklerse a/BUILD gizli tehlike ortaya çıkar.

a / a.in  
        import b;
        import c;
        b.foo();
        c.garply();
      
 
a, b ve c'yi birbirine bağlayan oklarla tanımlanmış bağımlılık grafiği
Beyan edilen bağımlılık grafiği
a, b ve c'yi bağlayan okların olduğu gerçek bağımlılık grafiği. A ile C arasında da bir ok gösterilir. Bu, bildirilen bağımlılık grafiğiyle eşleşmiyor
Gerçek bağımlılık grafiği

Beyan edilen bağımlılıklar artık gerçek bağımlılıkları aşırı tahmin etmiyor. Bu bir sorun yaratmayabilir, çünkü iki grafiğin geçişli kapanışları eşittir, ancak bir sorunu maskeler: a, c öğesine gerçek ancak bildirilmemiş bir bağımlılığa sahiptir.

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

Bir kullanıcı b'ü artık c'e bağlı olmayacak şekilde yeniden yapılandırdığında ve kendi hatası olmadan a'yi yanlışlıkla bozduğunda tehlike ortaya çıkar.

  b/BUILD
 
rule(
    name = "b",
    srcs = "b.in",
    deps = "//d:d",
)
      
  b / b.in
 
      import d;
      function foo() {
        d.baz();
      }
      
a ve b'yi birbirine bağlayan oklarla tanımlanmış bağımlılık grafiği.
                  b artık c'ye bağlanmaz ve a'nın c ile bağlantısı kesilir
Belirtilen bağımlılık grafiği
a'nın b ve c'ye bağlandığını 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 gerçek bağımlılıkların altında bir yaklaşımdır. Derlemenin başarısız olma olasılığı yüksektir.

Sorun, 2. adımda tanıtılan a ile c arasındaki gerçek bağımlığın BUILD dosyasında doğru şekilde tanımlanmasıyla önlenebilirdi.

Bağımlılık türleri

Çoğu derleme kuralında, farklı türde 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 (ör. compiler veya resources). Bu bilgiler Build Encyclopedia'da ayrıntılı olarak açıklanmıştır.

srcs bağımlılıkları

Doğrudan kural tarafından tüketilen veya kaynak dosyaları yayınlayan kurallar.

deps bağımlılıkları

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

data bağımlılıkları

Bir derleme hedefinin düzgün çalışması için bazı veri dosyaları gerekebilir. Bu veri dosyaları kaynak kod değildir: Hedefin oluşturulma şeklini etkilemezler. Ö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, yalnızca data olarak listelenen dosyaların bulunduğu izole bir dizinde testler çalıştırır. Bu nedenle, bir ikili programın/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 dosyalara path/to/data/file göreli yolu kullanılarak erişilebilir. Testlerde, testin kaynak dizininin yollarını ve Workspace'e göreli yolu (ör. ${TEST_SRCDIR}/workspace/path/to/data/file) birleştirerek bu dosyalara referans verebilirsiniz.

Dizinlere başvurmak için etiketleri kullanma

BUILD dosyalarımıza göz atarken, bazı data etiketlerinin dizinleri ifade ettiğini fark edebilirsiniz. Bu etiketler, kullanmamanız gereken aşağıdaki örneklerde olduğu gibi /. veya / ile biter:

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

Önerilmeyen: data = ["testdata/."]

Önerilmeyen: data = ["testdata/"]

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

Ancak bunu yapmamaya çalışın. Bir değişiklikten sonra artımlı yeniden derlemelerin doğru şekilde yapılmasını (ve testlerin yeniden yürütülmesini) sağlamak için derleme sisteminin, derlemeye (veya teste) giriş olan tüm dosya grubundan haberdar olması gerekir. Bir dizin belirttiğinizde derleme sistemi yalnızca dizinin kendisi değiştiğinde (dosya ekleme veya silme nedeniyle) yeniden derleme yapar ancak bu değişiklikler kapsayıcı dizini etkilemediğinden tek tek dosyalardaki düzenlemeleri algılayamaz. Dizinleri, derleme sistemine girişler olarak belirtmek yerine, açıkça veya glob() işlevini kullanarak, içerdikleri dosya grubunu numaralandırmanız gerekir. (glob() işlevinin yinelemeli olmasını sağlamak için ** kullanın.)

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

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

Dizin etiketleri kullanmanız gerekiyorsa üst pakete göreli ../ yolu ile atıfta bulunamayacağınızı unutmayın. Bunun yerine //data/regression:unittest/. gibi mutlak bir yol kullanın.

Birden fazla dosyayı kullanması gereken harici kurallar (ör. testler) tüm dosyalara olan bağımlılığını açıkça belirtmelidir. Dosyaları BUILD dosyasında gruplandırmak için filegroup()'ü kullanabilirsiniz:

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

Ardından, testinizde veri bağımlılığı olarak my_data etiketine referans verebilirsiniz.

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