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(); } |
|
|
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(); |
|
|
|
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(); } |
|
|
|
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:
Önerilmeyen —
data = ["//data/regression:unittest/."]
Önerilmeyen —
data = ["testdata/."]
Önerilmeyen —
data = ["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.)
Önerilen —
data = 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 |