Bzlmod, Bazel 5.0'da kullanıma sunulan yeni harici bağımlılık sisteminin kod adıdır. Eski sistemin, aşamalı olarak giderilemeyen birçok sorunu çözmek için sunulmuştur. Daha fazla ayrıntı için orijinal tasarım dokümanının Sorun Beyanı bölümüne bakın.
Bazel 5.0'da Bzlmod varsayılan olarak açık değildir; aşağıdakinin etkili olabilmesi için --experimental_enable_bzlmod
işaretinin belirtilmesi gerekir. Bayrak adının de belirttiği gibi, bu özellik şu anda deneme aşamasındadır; özellik resmi olarak kullanıma sunulana kadar API'ler ve davranışlar değişebilir.
Bazel Modülleri
EskiWORKSPACE
tabanlı harici bağımlılık sistemidepolar (veyakod depoları ), depo kuralları (veyadepo kuralları ).
Depolar yeni sistemde hâlâ önemli bir kavram olsa da modüller, temel bağımlılık birimleridir.
Modül temel olarak birden fazla sürümü olabilecek bir Bazel projesidir. Bu sürümlerin her biri, bağımlı olduğu diğer modüllerle ilgili meta verileri yayınlar. Bu, diğer bağımlılık yönetimi sistemlerindeki aşina olunan kavramlara benzer: Maven yapısı, npm paketi, Kargo sandığı, bir Go modülü vb.
Bir modül yalnızca, WORKSPACE
içindeki belirli URL'ler yerine name
ve version
çiftlerini kullanarak bağımlılıklarını belirtir. Ardından, bağımlılıklar bir Bazel kayıt otoritesinde aranır; Bazel Central Registry'dir. Çalışma alanınızda her modül bir depoya dönüştürülür.
MODÜLÜ.bazel
Her modülün her sürümü, bağımlılıklarını ve diğer meta verileri bildiren bir MODULE.bazel
dosyası içerir. Aşağıda basit bir örnek verilmiştir:
module(
name = "my-module",
version = "1.0",
)
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")
MODULE.bazel
dosyası, çalışma alanı dizininin kök dizininde (WORKSPACE
dosyasının yanında) bulunmalıdır. WORKSPACE
dosyasından farklı olarak, geçişli bağımlılıklarınızı belirtmeniz gerekmez; Bunun yerine yalnızca doğrudan bağımlılıkları belirtmeniz gerekir. Bağımlılıkların MODULE.bazel
dosyaları, geçişli bağımlılıkları otomatik olarak keşfetmek için işleme alınır.
MODULE.bazel
dosyası herhangi bir kontrol akışını desteklemediğinden BUILD
dosyalarına benzer; ayrıca load
ifadelerini de yasaklar. MODULE.bazel
dosyalarının desteklediği yönergeler şunlardır:
module
.- Diğer Bazel modüllerinde doğrudan bağımlılıkları belirtmek için
bazel_dep
; - Belirli bir doğrudan veya geçişli bağımlılığın davranışını özelleştirmek için yalnızca kök modül (yani bağımlılık olarak kullanılan bir modül tarafından değil) tarafından kullanılabilen geçersiz kılmalar:
- Modül uzantılarıyla ilgili yönergeler:
Sürüm biçimi
Bazel'in ekosistem çeşitliliği ve projeleri, çeşitli sürüm şemalarını kullanmaktadır. Şu ana kadar en popüler olan SemVer'dir, ancak sürümleri farklı olan Abseil gibi farklı şemalar kullanan önemli projeler de vardır tarih tabanlıdır, örneğin 20210324.2
).
Bu nedenle, Bzlmod SemVer spesifikasyonunun daha rahat bir sürümünü kullanır; özellikle de sürümün "yayınlama" bölümünde herhangi bir sayıda rakam dizisine izin verir (SemVer'in belirttiği şekilde tam olarak 3 yerine: MAJOR.MINOR.PATCH
).
Ayrıca, büyük, küçük ve yama sürümü artış anlamları zorunlu kılınmaz. (Bununla birlikte, geriye dönük uyumluluğu nasıl gösterdiğimize ilişkin ayrıntılar için uyumluluk düzeyi konusuna bakın.) SemVer spesifikasyonunun bir ön sürüm sürümünü gösteren bir kısa çizgi gibi diğer bölümleri değiştirilmez.
Sürüm çözünürlüğü
Elmas bağımlılığı sorunu, sürümlü bağımlılık yönetimi alanındaki bir temel sorundur. Aşağıdaki bağımlılık grafiğine sahip olduğunuzu varsayalım:
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
Hangi D sürümü kullanılmalıdır? Bzlmod, bu soruyu çözmek için Go modül sisteminde sunulan Minimal Sürüm Seçimi (MVS) algoritmasını kullanmaktadır. MVS bir modülün tüm yeni sürümlerinin geriye dönük olarak uyumlu olduğunu varsayar ve bu nedenle herhangi bir bağımlı tarafından belirtilen en yüksek sürümü seçer (örneğimizde D 1.1). Burada D 1.1, gereksinimlerimizi karşılayan minimum sürüm olduğundan, "minimal" olarak adlandırılır; D 1.2 veya daha yeni bir sürüm mevcut olsa bile biz bu seçimi yapmıyoruz. Bunun ek avantajı, sürüm seçiminin yüksek doğruluk ve yeniden oluşturulabilir olmasıdır.
Sürüm çözünürlüğü kayıt defteri tarafından değil, makinenizde yerel olarak gerçekleştirilir.
Uyumluluk düzeyi
Bir modülün geriye dönük uyumsuz sürümlerini ayrı bir modül olarak ele aldığı için MVS'nin geriye dönük uyumluluk hakkındaki varsayımının uygulanabilir olduğunu unutmayın. SemVer açısından bu, A 1.x ve A 2.x'in ayrı modüller olarak kabul edildiği ve çözülmüş bağımlılık grafiğinde bir arada olabileceği anlamına gelir. Bu da ana sürümün, Go'da paket yolunda kodlanmasıyla mümkün kılındığı için derleme süresi veya bağlantı zamanı çakışmaları yoktur.
Bazel'de bu konuda bir garantimiz yok. Bu nedenle, geriye dönük uyumsuz sürümleri tespit etmek için "ana sürüm" numarasını belirtmek için bir yönteme ihtiyacımız vardır. Bu sayıya uyumluluk düzeyi denir ve her bir modül sürümü tarafından module()
yönergesinde belirtilir. Bu bilgiler ışığında, aynı modülün farklı bağımlılık düzeylerine sahip sürümlerinin çözümlenmiş bağımlılık grafiğinde bulunduğunu tespit ettiğimizde hata verebiliriz.
Depo adları
Bazel'de her harici bağımlılığın bir depo adı vardır. Bazen aynı bağımlılık farklı veri havuzu adları (örneğin, @io_bazel_skylib
ve @bazel_skylib
Bazel skylib) veya aynı ad aracılığıyla kullanılabilir depo adı, farklı projelerde farklı bağımlılıklar için kullanılabilir.
Bzlmod'da depolar, Bazel modülleri ve modül uzantıları tarafından oluşturulabilir. Depo adı çakışmalarını çözmek için yeni sistemde depo deposu eşleme mekanizmasını benimseyiyoruz. Burada iki önemli kavram söz konusudur:
Standart kod deposu adı: Her bir kod deposu için küresel olarak benzersiz kod deposu adı. Bu, kod deposunun bulunduğu dizin adı olacaktır.
Şu şekilde oluşturulur (Uyarı: Standart ad biçimi, bağımlı olmanız gereken bir API değildir, herhangi bir zamanda değiştirilebilir):- Bazel modülü depoları için:
module_name.version
(Örnek.@bazel_skylib.1.0.3
) - Modül uzantısı depoları için:
module_name.version.extension_name.repo_name
(Örnek.@rules_cc.0.0.1.cc_configure.local_config_cc
)
- Bazel modülü depoları için:
Yerel depo adı: Depodaki
BUILD
ve.bzl
dosyalarında kullanılacak depo adı. Aynı bağımlılık, farklı depolar için farklı yerel adlara sahip olabilir.
Aşağıdaki şekilde belirlenir:
Her depo, doğrudan bağımlılıklarının yer aldığı bir depo eşleme sözlüğüne sahiptir. Bu sözlük, yerel kod deposu adından standart depo adıyla bir haritadır.
Kod deposu eşlemesini, etiket oluştururken depo adını çözmek için kullanırız. Standart depo adlarında çakışma olmadığını ve yerel kod deposu adlarının kullanımlarının MODULE.bazel
dosyasını ayrıştırarak keşfedilebileceğini unutmayın. Bu nedenle çakışmalar, diğer bağımlılıklar.
Katı değerler
Yeni bağımlılık spesifikasyonu biçimi, daha katı kontroller gerçekleştirmemizi sağlar. Özellikle, bir modülün yalnızca doğrudan bağımlılarından oluşturulan depoları kullanmasını zorunlu kılıyoruz. Bu, geçişli bağımlılık grafiğindeki bir şey değiştiğinde yanlışlıkla yapılan ve hata ayıklaması zor kesintileri önlemeye yardımcı olur.
Katı sınırlar, havuz eşlemeye göre uygulanır. Temel olarak, her bir depo için depo eşlemesi tüm doğrudan bağımlılıklarını içerir, diğer herhangi bir depo görünmez. Her deponun görünür bağımlılıkları şu şekilde belirlenir:
- Bazel modül deposu,
MODULE.bazel
dosyasında sunulan tüm depolarıbazel_dep
veuse_repo
aracılığıyla görebilir. - Modül uzantısı deposu, uzantıyı sağlayan modülün görünür tüm bağımlılıklarını ve aynı modül uzantısı tarafından oluşturulan diğer tüm kod depolarını görebilir.
Kayıtlar
Bzlmod, Bazel kayıt otoritelerinden bilgi isteyerek bağımlılıkları keşfediyor. Bazel kayıt defteri, sadece Bazel modüllerinin veritabanıdır. Desteklenen tek kayıt defteri biçimi, yerel bir dizin veya belirli bir biçimi izleyen statik bir HTTP sunucusu olan dizin kayıt defteridir. Gelecekte bu sürüme destek eklemeyi planlıyoruz.tek modüllü kayıt otoriteleri . Bu proje, bir projenin kaynağını ve geçmişini içeren basit depodur.
Dizin kaydı
Dizin kayıt defteri; ana sayfalar, korumacılar, her sürümün MODULE.bazel
dosyası ve her bir kaynağın nasıl getirileceği dahil olmak üzere bir modül listesi hakkında bilgi içeren yerel bir dizin veya statik HTTP sunucusudur
sürümü. Özellikle, kaynak arşivlerin kendisinin sunulması gerekmez.
Dizin kayıt defteri aşağıdaki biçime uymalıdır:
/bazel_registry.json
: Kayıt defteri için meta verileri içeren bir JSON dosyası. Şu anda kaynak arşivler için kullanılacak aynaların listesini belirten tek bir anahtar (mirrors
) vardır./modules
: Bu kayıt otoritesindeki her modül için bir alt dizin içeren dizindir./modules/$MODULE
: Bu modülün her bir sürümü için alt dizin içeren bir dizin ve aşağıdaki dosya:metadata.json
: Aşağıdaki alanlarla birlikte modülle ilgili bilgileri içeren bir JSON dosyasıdır:homepage
: Proje ana sayfasının URL'si.maintainers
: Her biri kayıt otoritesinde modülün koruyucusunun bilgilerine karşılık gelen JSON nesnelerinin listesi. Bunun, projenin yazarlarıyla aynı olmadığını unutmayın.versions
: Bu kayıt defterinde bulunan bu modülün tüm sürümlerinin listesidir.yanked_versions
: Bu modülün sağlanmış sürümlerinin listesi. Bu, şu anda işlemsizdir ancak gelecekte, yansıtılan sürümler atlanır veya hata verir.
/modules/$MODULE/$VERSION
: Aşağıdaki dosyaları içeren bir dizin:MODULE.bazel
: Bu modül sürümününMODULE.bazel
dosyasıdır.source.json
: Bu modülün kaynağının nasıl getirileceğine dair bilgileri içeren bir JSON dosyası ve aşağıdaki alanlar:url
: Kaynak arşivin URL'si.integrity
: Arşivin Alt Kaynak Bütünlüğü sağlaması.strip_prefix
: Kaynak arşivi çıkarılırken çıkarılacak bir dizin ön eki.patches
: Çıkarılan arşive uygulanacak her biri bir yama dosyasına verilen dizelerin listesidir. Yama dosyaları/modules/$MODULE/$VERSION/patches
dizininin altında bulunur.patch_strip
: Unix yamasının--strip
bağımsız değişkeniyle aynıdır.
patches/
: Yama dosyaları içeren isteğe bağlı bir dizin.
Bazel Merkezi Kayıt Otoritesi
Bazel Merkezi Kayıt Defteri (BCR), registry.bazel.build dizininde yer alan bir dizin kayıt defteridir. İçeriği GitHub deposu bazelbuild/bazel-central-registry
tarafından desteklenir.
BCR, Bazel topluluğu tarafından yönetilmektedir; katkıda bulunanların pull istekleri gönderebilirler. Bazel Merkezi Kayıt Defteri Politikaları ve Prosedürleri'ne göz atın.
Normal dizin kayıt defterinin biçiminin izlenmesine ek olarak, BCR her modül sürümü (/modules/$MODULE/$VERSION/presubmit.yml
) için bir presubmit.yml
dosyası gerektirir. Bu dosya, bu modül sürümünün geçerliliğini kontrol etmek için kullanılabilecek birkaç temel derleme ve test hedefi belirtir ve BCR'deki modüller arasında birlikte çalışabilirlik sağlamak için BCR'nin CI ardışık düzenleri tarafından kullanılır ,
Kayıt otoriteleri seçme
Tekrarlanabilir Bazel işareti --registry
, modül istemek için kullanılan kayıt otoritelerinin listesini belirtmek amacıyla kullanılabilir. Böylece projenizi, üçüncü taraf veya dahili kayıt otoritesinden bağımlılığı getirecek şekilde ayarlayabilirsiniz. Önceki kayıt otoriteleri öncelik alır. Kolaylık olması için projenizin .bazelrc
dosyasına --registry
işaretlerinin listesini ekleyebilirsiniz.
Modül Uzantıları
Modül uzantıları, bağımlılık grafiğindeki modüllerden gelen giriş verilerini okuyarak, bağımlılıkları çözmek için gerekli mantığı gerçekleştirerek ve son olarak depo kuralları çağırarak depo oluşturarak modül sistemini genişletmenizi sağlar. Bunlar, günümüzün WORKSPACE
makrolarına benzer işlevlere sahiptir, ancak modüller ve geçişli bağımlılıklar dünyasında daha uygundur.
Modül uzantıları, depo kuralları veya WORKSPACE
makroları gibi .bzl
dosyalarında tanımlanır. Doğrudan çağrılamaz; çünkü her modül, uzantıların okunması için etiket adı verilen veri parçalarını belirtebilir. Ardından, modül sürüm çözünürlüğü tamamlandıktan sonra modül uzantıları çalıştırılır. Her bir uzantı, modül çözünürlüğünden sonra (bir derleme gerçekleşmeden önce hala çalışır) çalışır ve ona ait tüm etiketleri tüm bağımlılık grafiğinde okur.
[ A 1.1 ]
[ * maven.dep(X 2.1) ]
[ * maven.pom(...) ]
/ \
bazel_dep / \ bazel_dep
/ \
[ B 1.2 ] [ C 1.0 ]
[ * maven.dep(X 1.2) ] [ * maven.dep(X 2.1) ]
[ * maven.dep(Y 1.3) ] [ * cargo.dep(P 1.1) ]
\ /
bazel_dep \ / bazel_dep
\ /
[ D 1.4 ]
[ * maven.dep(Z 1.4) ]
[ * cargo.dep(Q 1.1) ]
Yukarıdaki örnek bağımlılık grafiğinde, A 1.1
ve B 1.2
vb. Bazel modülleridir. Her birini bir MODULE.bazel
dosyası olarak düşünebilirsiniz. Her modül, modül uzantıları için bazı etiketler belirtebilir. bazıları "maven" uzantısı için, bazıları da "cargo" için belirtilmiştir. Bu bağımlılık grafiği kesinleştiğinde (örneğin, B 1.2
belki D 1.3
tarihinde bir bazel_dep
içeriyor ancak C
nedeniyle D 1.4
sürümüne geçirildi) "maven" uzantıları çalışır ve hangi depoların oluşturulacağına karar vermek için oradaki bilgileri kullanarak tüm maven.*
etiketlerini okur.
Benzer şekilde, "kargo" uzantısı için.
Uzantı kullanımı
Uzantılar, Bazel modüllerinin kendisinde barındırılır. Bu nedenle, modülünüzde bir uzantı kullanmak için önce bu modüle bir bazel_dep
eklemeniz ve ardından, use_extension
yerleşik işlevi vardır. Aşağıdaki örneği, rules_jvm_external
modülünde tanımlanan varsayımsal bir "maven" uzantısını kullanmak için bir MODULE.bazel
dosyasından bir snippet'i düşünün:
bazel_dep(name = "rules_jvm_external", version = "1.0")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
Uzantıyı kapsamın içine ekledikten sonra, uzantı için etiketler belirtmek üzere nokta söz dizimini kullanabilirsiniz. Etiketlerin, ilgili etiket sınıflarının tanımladığı şemaya uygun olması gerektiğini unutmayın (aşağıdaki uzantı tanımı bölümüne bakın). Aşağıda, bazı maven.dep
ve maven.pom
etiketlerinin belirtildiği bir örnek verilmiştir.
maven.dep(coord="org.junit:junit:3.0")
maven.dep(coord="com.google.guava:guava:1.2")
maven.pom(pom_xml="//:pom.xml")
Uzantı, modülünüzde kullanmak istediğiniz depoları oluşturuyorsa bunları bildirmek için use_repo
yönergesini kullanın. Bu, katı deps koşulunu karşılamak ve yerel depo adı çakışmasını önlemek içindir.
use_repo(
maven,
"org_junit_junit",
guava="com_google_guava_guava",
)
Bir uzantı tarafından oluşturulan kod depoları, kendi API'sinin bir parçasıdır. Bu nedenle, belirttiğiniz etiketlerden, "maven" uzantısının "org_junit_junit" ve "com_google_guava_guava" adlı bir kod deposu oluşturacağını bilmeniz gerekir. ". use_repo
kullanarak isteğe bağlı olarak bu modülleri modülünüzün kapsamında yeniden adlandırabilirsiniz (örneğin, burada "guava").
Uzantı tanımı
Modül uzantıları, depo kurallarına benzer şekilde module_extension
işlevi kullanılarak tanımlanır.
Her ikisinin de bir uygulama işlevi vardır; ancak depo kuralları bir dizi özelliğe sahip olsa da modül uzantılarının her biri bir dizi özelliğe sahip bir dizi tag_class
es özelliği vardır. Etiket sınıfları, bu uzantı tarafından kullanılan etiketler için şemaları tanımlar. Yukarıdaki varsayımsal "maven" uzantı örneğimizi devam edelim:
# @rules_jvm_external//:extensions.bzl
maven_dep = tag_class(attrs = {"coord": attr.string()})
maven_pom = tag_class(attrs = {"pom_xml": attr.label()})
maven = module_extension(
implementation=_maven_impl,
tag_classes={"dep": maven_dep, "pom": maven_pom},
)
Bu bildirimler, maven.dep
ve maven.pom
etiketlerinin, yukarıda tanımlanan özellik şeması kullanılarak belirtilebileceğini açıkça belirtiyor.
Uygulama işlevi, bir WORKSPACE
makrosuna benzer. Ancak bu makro, bağımlılık grafiğine ve ilgili tüm etiketlere erişim sağlayan bir module_ctx
nesnesi alır. Uygulama işlevi, depo oluşturmak için depo kurallarını çağırmalıdır:
# @rules_jvm_external//:extensions.bzl
load("//:repo_rules.bzl", "maven_single_jar")
def _maven_impl(ctx):
coords = []
for mod in ctx.modules:
coords += [dep.coord for dep in mod.tags.dep]
output = ctx.execute(["coursier", "resolve", coords]) # hypothetical call
repo_attrs = process_coursier(output)
[maven_single_jar(**attrs) for attrs in repo_attrs]
Yukarıdaki örnekte, bağımlılık grafiğindeki tüm modülleri gözden geçiriyoruz
(ctx.modules
), her biribazel_module
nesnenin değeritags
alanı, tümmaven.*
etiketlerini görebilirsiniz. Ardından Malin ile iletişime geçip çözümü gerçekleştirmesi için CLI yardımcı programı
Coursier'ı çağırırız. Son olarak, varsayımsal maven_single_jar
kod deposu kuralını kullanarak bir dizi kod deposu oluşturmak için çözüm sonucunu kullanırız.