Bağımlılıklar

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. Bu ilişki, bağımlılık grafiği olarak adlandırılan, hedefler üzerinde Yönlü Döngüsel Grafik (DAG) oluşmasına neden olur ve bu duruma bağımlılık grafiği adı verilir.

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 tanımlanan bağımlılıklar

X hedefinin doğru şekilde oluşturulabilmesi için Y öğesinin mevcut olması, derlenmiş ve güncel olması gerekiyorsa hedef X, Y hedefine bağlıdır. Oluşturulan; oluşturulmuş, işlenmiş, derlenmiş, bağlantılı, arşivlenmiş, sıkıştırılmış, yürütülen veya derleme sırasında rutin olarak gerçekleşen diğer görev türlerini 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 grafiği A, bildirilen bağımlılıklar D grafiğinin 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ı yakınsaması olduğu söylenebilir.

BUILD dosya yazarları, her kural için derleme sistemine uygulanan doğrudan bağımlılıkların tümünü açıkça beyan etmeli ve bundan sonrasını yapmamalıdır.

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ı bildirir, ancak bu kontrolün her durumda tamamlanması mümkün değildir.

Yürütme anında A tarihine kadar ihtiyaç duyulsa bile, dolaylı olarak içe aktarılan her şeyi listelemeye çalışmanız gerekmez (ve listelememeniz gerekir).

X hedefi oluşturma işlemi sırasında derleme aracı, X bağımlılıklarının geçişli olarak kapatılmasını inceleyerek bu hedeflerdeki değişikliklerin nihai sonuca yansıtıldığından emin olarak ara öğeleri gerektiği şekilde 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 kullanabilir. Bu dolaylı, bildirilen bağımlılık grafiğinde geçişli ama doğrudan olmayan bir bağımlılıktı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ığından a geçişli olarak c öğesine 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
Beyan edilen 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ıklara fazla yakındır. Her şey yolunda.

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

Bir kullanıcı a dosyasına c'a doğrudan gerçek bağımlılık oluşturan kod eklediğinde ancak bunu a/BUILD derleme dosyasında belirtmeyi unuttuğunuzda gizli bir 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 birbirine bağlayan oklarla 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, bu da a'nın c ile bağlantısını koparır
Beyan edilen 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.

2. Adımda belirtilen a ile c arasındaki gerçek bağımlılığın BUILD dosyasında doğru şekilde bildirilmesi sağlanarak sorun ö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 kuralın, kurala özgü bağımlılık türleri için compiler veya resources gibi ek özellikleri de vardır. Bu bilgiler Build Encyclopedia'da ayrıntılı olarak açıklanmıştır.

srcs bağımlılıkları

Doğrudan kaynak dosyaları oluşturan kural veya kurallar tarafından kullanılan 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ıkları

Bir derleme hedefinin doğru şekilde çalışabilmesi için bazı veri dosyalarına ihtiyacı olabilir. Bu veri dosyaları kaynak kod değildir: 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 derlerken dosyaya ihtiyacınız olmaz ancak testi çalıştırırken dosyaya ihtiyacınız olur. 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 izole bir dizinde çalıştırır. Bu nedenle, bir ikili/kitaplık/testin çalışması için bazı dosyalara ihtiyacı varsa 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 ve çalışma alanına bağlı yolunun (örneğin, ${TEST_SRCDIR}/workspace/path/to/data/file) yollarını birleştirerek bu dosyalara başvurabilirsiniz.

Dizinlere başvurmak için etiketleri kullanma

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

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

Önerilmeyendata = ["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.

Ama bunu yapmamaya çalışın. Bir değişiklikten sonra doğru artımlı yeniden derlemelerin (ve testlerin yeniden yürütülmesinin) yapılması için derleme sisteminin, derlemeye (veya teste) giriş olan tüm dosyalardan 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() öğesini yinelemeli olmaya zorlamak için ** öğesini 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 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 yanlış yeniden oluşturma riskine dikkat edin.

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/*'])
)

Daha sonra, testinizde veri bağımlılığı olarak my_data etiketine referans verebilirsiniz.

dosya derleyin Görünürlük