Bu eğitimde, hazır bir Bazel projesini kullanarak kodunuzdaki bağımlılıkları izlemek için Bazel ile nasıl çalışacağınız açıklanmaktadır.
Dil ve --output
işareti ayrıntıları için Bazel sorgusu referansı ve Bazel sorgu referansı kılavuzlarına bakın. Komut satırına bazel help query
veya bazel help cquery
yazarak IDE'nizde yardım alın.
Hedef
Bu kılavuzda, projenizin dosya bağımlılıkları hakkında daha fazla bilgi edinmek için kullanabileceğiniz bir dizi temel sorgu açıklanmaktadır. Bu sürüm, Bazel ve BUILD
dosyalarının işleyişiyle ilgili temel bilgilere sahip yeni Bazel geliştiricileri için tasarlanmıştır.
Ön koşullar
Henüz yapmadıysanız Bazel'i yükleyerek başlayın. Bu eğitimde kaynak kontrolü için Git kullanılır. En iyi sonuçlar için Git'i de yükleyin.
Bağımlılık grafiklerini görselleştirmek için Graphviz adlı araç kullanılır. Bu aracı, adımları takip etmek için indirebilirsiniz.
Örnek projeyi alma
Ardından, tercih ettiğiniz komut satırı aracında aşağıdakileri çalıştırarak örnek uygulamayı Bazel'in Örnekler deposundan alın:
git clone https://github.com/bazelbuild/examples.git
Bu eğitim için örnek proje examples/query-quickstart
dizinindedir.
Başlarken
Bazel sorguları nedir?
Sorgular, BUILD
dosyaları arasındaki ilişkileri analiz ederek ve elde edilen çıkışı faydalı bilgiler açısından inceleyerek bir Bazel kod tabanı hakkında bilgi edinmenize yardımcı olur. Bu kılavuzda bazı temel sorgu işlevlerinin önizlemesi sunulmaktadır. Daha fazla seçenek için sorgu kılavuzuna bakın. Sorgular, BUILD
dosyalarında manuel olarak gezinmeden büyük ölçekli projelerdeki bağımlılıkları öğrenmenize yardımcı olur.
Sorgu çalıştırmak için komut satırı terminalinizi açıp şunu girin:
bazel query 'query_function'
Senaryo
Cafe Bazel ile şefi arasındaki ilişkiyi derinlemesine inceleyen bir senaryo düşünün. Bu kafede yalnızca pizza ve makarna satılır. Projenin nasıl yapılandırıldığına aşağıdan göz atın:
bazelqueryguide
├── BUILD
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ ├── customers
│ │ ├── Jenny.java
│ │ ├── Amir.java
│ │ └── BUILD
│ ├── dishes
│ │ ├── Pizza.java
│ │ ├── MacAndCheese.java
│ │ └── BUILD
│ ├── ingredients
│ │ ├── Cheese.java
│ │ ├── Tomatoes.java
│ │ ├── Dough.java
│ │ ├── Macaroni.java
│ │ └── BUILD
│ ├── restaurant
│ │ ├── Cafe.java
│ │ ├── Chef.java
│ │ └── BUILD
│ ├── reviews
│ │ ├── Review.java
│ │ └── BUILD
│ └── Runner.java
└── WORKSPACE
Bu eğitim boyunca, aksi yönde bir talimat olmadığı sürece, ihtiyacınız olan bilgileri bulmak için BUILD
dosyalarına bakmamaya çalışın. Bunun yerine yalnızca sorgu işlevini kullanın.
Proje, bir kafeyi oluşturan farklı paketlerden oluşur. Bunlar restaurant
, ingredients
, dishes
, customers
ve reviews
olarak ayrılır. Bu paketlerdeki kurallar, farklı etiketlere ve bağımlılıklara sahip farklı kafe bileşenlerini tanımlar.
Derleme çalıştırma
Bu proje, Runner.java
içinde, kafenin menüsünü yazdırmak için yürütebileceğiniz bir ana yöntem içerir. Projeyi bazel build
komutuyla Bazel'ı kullanarak oluşturun ve hedefin runner
olarak adlandırıldığını belirtmek için :
yönergesini kullanın. Hedeflere nasıl referans vereceğinizi öğrenmek için hedef adlarına bakın.
Bu projeyi derlemek için aşağıdaki komutu bir terminale yapıştırın:
bazel build :runner
Derleme başarılı olursa çıkışınız aşağıdaki gibi görünecektir.
INFO: Analyzed target //:runner (49 packages loaded, 784 targets configured).
INFO: Found 1 target...
Target //:runner up-to-date:
bazel-bin/runner.jar
bazel-bin/runner
INFO: Elapsed time: 16.593s, Critical Path: 4.32s
INFO: 23 processes: 4 internal, 10 darwin-sandbox, 9 worker.
INFO: Build completed successfully, 23 total actions
Uygulama başarıyla oluşturulduktan sonra aşağıdaki komutu yapıştırarak uygulamayı çalıştırın:
bazel-bin/runner
--------------------- MENU -------------------------
Pizza - Cheesy Delicious Goodness
Macaroni & Cheese - Kid-approved Dinner
----------------------------------------------------
Bu işlem, kısa bir açıklamayla birlikte verilen menü öğelerinin listesini gösterir.
Hedefleri keşfetme
Projede, malzemeler ve yemekler kendi paketlerinde listelenir. Bir paketin kurallarını görüntülemek için sorgu kullanmak istiyorsanız bazel query package/…
Bu örnekte, aşağıdaki komutu çalıştırarak bu kafenin malzemelerini ve yemeklerini incelemek için kullanabilirsiniz:
bazel query //src/main/java/com/example/dishes/...
bazel query //src/main/java/com/example/ingredients/...
Malzeme paketinin hedeflerini sorgularsanız çıkış aşağıdaki gibi görünmelidir:
//src/main/java/com/example/ingredients:cheese
//src/main/java/com/example/ingredients:dough
//src/main/java/com/example/ingredients:macaroni
//src/main/java/com/example/ingredients:tomato
Bağımlılıkları bulma
Koşucunuzun koşmak için hangi hedeflere ihtiyacı var?
Dosya sistemine girmeden (büyük projeler için uygun olmayabilir) projenizin yapısına daha ayrıntılı bir şekilde göz atmak istediğinizi varsayalım. Cafe Bazel hangi kuralları kullanıyor?
Bu örnekte olduğu gibi koşucu hedefiniz runner
ise şu komutu çalıştırarak hedefin temel bağımlılıklarını keşfedin:
bazel query --noimplicit_deps "deps(target)"
bazel query --noimplicit_deps "deps(:runner)"
//:runner
//:src/main/java/com/example/Runner.java
//src/main/java/com/example/dishes:MacAndCheese.java
//src/main/java/com/example/dishes:Pizza.java
//src/main/java/com/example/dishes:macAndCheese
//src/main/java/com/example/dishes:pizza
//src/main/java/com/example/ingredients:Cheese.java
//src/main/java/com/example/ingredients:Dough.java
//src/main/java/com/example/ingredients:Macaroni.java
//src/main/java/com/example/ingredients:Tomato.java
//src/main/java/com/example/ingredients:cheese
//src/main/java/com/example/ingredients:dough
//src/main/java/com/example/ingredients:macaroni
//src/main/java/com/example/ingredients:tomato
//src/main/java/com/example/restaurant:Cafe.java
//src/main/java/com/example/restaurant:Chef.java
//src/main/java/com/example/restaurant:cafe
//src/main/java/com/example/restaurant:chef
Çoğu durumda, belirli bir hedefin bağımsız çıkış bağımlılıkları görmek için deps()
sorgu işlevini kullanın.
Bağımlılık grafiğini görselleştirme (isteğe bağlı)
Bu bölümde, belirli bir sorgunun bağımlılık yollarını nasıl görselleştirebileceğiniz açıklanmaktadır. Graphviz, yolun düzleştirilmiş liste yerine yönlendirilmiş bir döngüsel grafik resmi olarak görülmesine yardımcı olur. Çeşitli --output
komut satırı seçeneklerini kullanarak Bazel sorgu grafiğinin görünümünü değiştirebilirsiniz. Seçenekler için Çıkış Biçimleri bölümüne bakın.
İlk olarak istediğiniz sorguyu çalıştırın, ardından aşırı araç bağımlılıklarını kaldırmak için --noimplicit_deps
işaretini ekleyin. Ardından, çıktı işaretiyle sorguyu takip edin ve grafiğin metin temsilini oluşturmak için grafiği graph.in
adlı bir dosyaya kaydedin.
Hedef :runner
'ün tüm bağımlılıkları için arama yapmak ve çıktıyı grafik olarak biçimlendirmek için:
bazel query --noimplicit_deps 'deps(:runner)' --output graph > graph.in
Bu işlem, yapı grafiğinin metin gösterimi olan graph.in
adlı bir dosya oluşturur. Graphviz, png oluşturmak için metni görselleştirmeye dönüştüren bir araç olan dot
'i kullanır:
dot -Tpng < graph.in > graph.png
graph.png
uygulamasını açarsanız şuna benzer bir şey görürsünüz. Aşağıdaki grafik, bu kılavuzda önemli yol ayrıntılarını daha net hale getirmek için basitleştirilmiştir.
Bu, bu kılavuzda farklı sorgu işlevlerinin çıktılarını görmek istediğinizde işinize yarayacaktır.
Ters bağımlılıkları bulma
Bunun yerine, diğer hedeflerin hangi hedefleri kullandığını analiz etmek isterseniz, hangi hedeflerin belirli bir kurala bağlı olduğunu incelemek için bir sorgu kullanabilirsiniz. Buna "ters bağımlılık" denir. rdeps()
'ü kullanmak, aşina olmadığınız bir kod tabanındaki bir dosyayı düzenlerken faydalı olabilir ve size bu dosyaya bağlı diğer dosyaları bilmeden bozmaktan kurtarabilir.
Örneğin, cheese
bileşeninde bazı düzenlemeler yapmak istiyorsunuz. Cafe Bazel'de sorun yaşamamak için hangi yemeklerin cheese
kullandığını kontrol etmeniz gerekir.
Belirli bir hedefe/pakete bağlı hedefleri görmek için rdeps(universe_scope, target)
değerini kullanabilirsiniz. rdeps()
sorgu işlevi en az iki bağımsız değişken alır: ilgili dizin olan bir universe_scope
ve bir target
. Bazel, sağlanan universe_scope
içinde hedefin ters bağımlılıklarını arar. rdeps()
operatörü isteğe bağlı üçüncü bir bağımsız değişkeni kabul eder: arama derinliğinin üst sınırını belirten bir tam sayı değişmezi.
Projenin tamamının kapsamı olan "//…" içinde hedef cheese
'nin ters bağımlılıklarını aramak için şu komutu çalıştırın:
bazel query "rdeps(universe_scope, target)"
ex) bazel query "rdeps(//... , //src/main/java/com/example/ingredients:cheese)"
//:runner
//src/main/java/com/example/dishes:macAndCheese
//src/main/java/com/example/dishes:pizza
//src/main/java/com/example/ingredients:cheese
//src/main/java/com/example/restaurant:cafe
//src/main/java/com/example/restaurant:chef
Sorgu sonucu, hem pizza hem de makarna için peynirin kullanıldığını gösterir. Ne sürpriz!
Etiketlere göre hedef bulma
Bazel Cafe'ye iki müşteri geliyor: Emir ve Jale. Adları dışında onlar hakkında bilinen bir şey yok. Neyse ki siparişleri "customers" BUILD
dosyasında etiketlenmiş. Bu etikete nasıl erişebilirsiniz?
Geliştiriciler, genellikle test amacıyla Bazel hedeflerini farklı tanımlayıcılarla etiketleyebilirler. Örneğin, testlerdeki etiketler, özellikle de çalışma zamanında ek açıklama özelliği bulunmayan C++ ve Python testleri için bir testin hata ayıklama ve yayınlama işleminizdeki rolünü ek açıklamayla belirtebilir. Etiketler ve boyut öğeleri kullanmak, kod tabanının check-in politikasına göre test paketleri oluşturma konusunda esneklik sağlar.
Bu örnekte, etiketler menü öğelerini temsil etmek için pizza
veya macAndCheese
değerlerinden biridir. Bu komut, belirli bir pakette tanımlayıcınızla eşleşen etiketlere sahip hedefleri sorgulayarak bulur.
bazel query 'attr(tags, "pizza", //src/main/java/com/example/customers/...)'
Bu sorgu, "customers" paketindeki "pizza" etiketine sahip tüm hedefleri döndürür.
Kendinizi test etme
Cansu'nun ne sipariş etmek istediğini öğrenmek için bu sorguyu kullanın.
Yanıtla
Peynirli Makarna
Yeni bağımlılık ekleme
Cafe Bazel, menüsünü genişletti. Müşteriler artık smoothie siparişi verebilir. Bu smoothie Strawberry
ve Banana
bileşenlerinden oluşuyor.
Öncelikle smoothie'nin bağlı olduğu malzemeleri ekleyin: Strawberry.java
ve Banana.java
. Boş Java sınıflarını ekleyin.
src/main/java/com/example/ingredients/Strawberry.java
package com.example.ingredients;
public class Strawberry {
}
src/main/java/com/example/ingredients/Banana.java
package com.example.ingredients;
public class Banana {
}
Ardından Smoothie.java
dosyasını uygun dizine (dishes
) ekleyin.
src/main/java/com/example/dishes/Smoothie.java
package com.example.dishes;
public class Smoothie {
public static final String DISH_NAME = "Smoothie";
public static final String DESCRIPTION = "Yummy and Refreshing";
}
Son olarak, bu dosyaları uygun BUILD
dosyalarına kural olarak ekleyin. Her yeni bileşen için adı, herkese açık görünürlük ve yeni oluşturulan "src" dosyası da dahil olmak üzere yeni bir Java kitaplığı oluşturun. Güncellenen BUILD
dosyasını aşağıdaki gibi göreceksiniz:
src/main/java/com/example/ingredients/BUILD
java_library(
name = "cheese",
visibility = ["//visibility:public"],
srcs = ["Cheese.java"],
)
java_library(
name = "dough",
visibility = ["//visibility:public"],
srcs = ["Dough.java"],
)
java_library(
name = "macaroni",
visibility = ["//visibility:public"],
srcs = ["Macaroni.java"],
)
java_library(
name = "tomato",
visibility = ["//visibility:public"],
srcs = ["Tomato.java"],
)
java_library(
name = "strawberry",
visibility = ["//visibility:public"],
srcs = ["Strawberry.java"],
)
java_library(
name = "banana",
visibility = ["//visibility:public"],
srcs = ["Banana.java"],
)
Yemeklerin bulunduğu BUILD
dosyasında Smoothie
için yeni bir kural eklemek istiyorsunuz. Bu işlem, "src" dosyası olarak Smoothie
için oluşturulan Java dosyasını ve smoothie'nin her bir malzemesi için belirlediğiniz yeni kuralları içerir.
src/main/java/com/example/dishes/BUILD
java_library(
name = "macAndCheese",
visibility = ["//visibility:public"],
srcs = ["MacAndCheese.java"],
deps = [
"//src/main/java/com/example/ingredients:cheese",
"//src/main/java/com/example/ingredients:macaroni",
],
)
java_library(
name = "pizza",
visibility = ["//visibility:public"],
srcs = ["Pizza.java"],
deps = [
"//src/main/java/com/example/ingredients:cheese",
"//src/main/java/com/example/ingredients:dough",
"//src/main/java/com/example/ingredients:tomato",
],
)
java_library(
name = "smoothie",
visibility = ["//visibility:public"],
srcs = ["Smoothie.java"],
deps = [
"//src/main/java/com/example/ingredients:strawberry",
"//src/main/java/com/example/ingredients:banana",
],
)
Son olarak, smoothie'yi şefin BUILD
dosyasına bağımlılık olarak eklemeniz gerekir.
src/main/java/com/example/restaurant/BUILD
java\_library(
name = "chef",
visibility = ["//visibility:public"],
srcs = [
"Chef.java",
],
deps = [
"//src/main/java/com/example/dishes:macAndCheese",
"//src/main/java/com/example/dishes:pizza",
"//src/main/java/com/example/dishes:smoothie",
],
)
java\_library(
name = "cafe",
visibility = ["//visibility:public"],
srcs = [
"Cafe.java",
],
deps = [
":chef",
],
)
Hata olmadığını onaylamak için cafe
öğesini tekrar oluşturun. Derleme başarılı olursa tebrikler. "Cafe" için yeni bir bağımlılık eklediniz. Aksi takdirde yazım hatalarına ve paket adlarına dikkat edin. BUILD
dosyası yazma hakkında daha fazla bilgi için BUILD Stil Kılavuzu'na bakın.
Şimdi, öncekiyle karşılaştırmak için yeni bağımlılık grafiğini Smoothie
ekleyerek görselleştirin. Anlaşılır olması için grafik girişini graph2.in
ve graph2.png
olarak adlandırın.
bazel query --noimplicit_deps 'deps(:runner)' --output graph > graph2.in
dot -Tpng < graph2.in > graph2.png
graph2.png
'e baktığınızda Smoothie
'un diğer yemeklerle ortak bağımlılıkları olmadığını, yalnızca Chef
'nin kullandığı başka bir hedef olduğunu görebilirsiniz.
somepath() ve allpaths()
Bir paketin neden başka bir pakete bağlı olduğunu sorgulamak isterseniz ne olur? Bu ikisi arasında bir bağımlılık yolunu göstermek cevabı sağlar.
Bağımlılık yollarını bulmanıza yardımcı olabilecek iki işlev vardır: somepath()
ve allpaths()
. S başlangıç hedefi ve E bitiş noktası verildiğinde somepath(S,E)
kullanarak S ile E arasında bir yol bulun.
"Şef" ve "Peynir" hedefleri arasındaki ilişkilere bakarak bu iki işlev arasındaki farkları araştırın. Bir hedeften diğerine gidilebilecek farklı yollar vardır:
- Şef → Peynirli Makarna → Peynir
- Şef → Pizza → Peynir
somepath()
, iki seçenekten tek bir yol sağlarken "allpaths()" her olası yolu döndürür.
Cafe Bazel'i örnek olarak kullanarak aşağıdakileri çalıştırın:
bazel query "somepath(//src/main/java/com/example/restaurant/..., //src/main/java/com/example/ingredients:cheese)"
//src/main/java/com/example/restaurant:cafe
//src/main/java/com/example/restaurant:chef
//src/main/java/com/example/dishes:macAndCheese
//src/main/java/com/example/ingredients:cheese
Çıkış, Cafe → Şef → MacAndCheese → Peynir ilk yolunu izler. Bunun yerine allpaths()
kullanırsanız:
bazel query "allpaths(//src/main/java/com/example/restaurant/..., //src/main/java/com/example/ingredients:cheese)"
//src/main/java/com/example/dishes:macAndCheese
//src/main/java/com/example/dishes:pizza
//src/main/java/com/example/ingredients:cheese
//src/main/java/com/example/restaurant:cafe
//src/main/java/com/example/restaurant:chef
Bağımlılıkların düzleştirilmiş bir listesi olduğu için allpaths()
işlevinin çıktısının okunması biraz daha zordur. Bu grafiği Graphviz kullanarak görselleştirmek, ilişkiyi daha net bir şekilde anlamamızı sağlar.
Kendinizi test edin
Cafe Bazel'in müşterilerinden biri restoranın ilk yorumunu yazdı. Yorumda maalesef yorum sahibinin kimliği ve hangi yemeğe atıfta bulunduğu gibi bazı ayrıntılar eksik. Neyse ki Bazel ile bu bilgilere erişebilirsiniz. reviews
paketi, gizemli bir müşterinin yorumunu yazdıran bir program içeriyor. Aşağıdakilerle derleyip çalıştırın:
bazel build //src/main/java/com/example/reviews:review
bazel-bin/src/main/java/com/example/reviews/review
Yalnızca Bazel sorgularının dışında, yorumu kimin yazdığını ve hangi yemeği açıkladığını öğrenmeye çalışın.
İpucu
Faydalı bilgiler için etiketleri ve bağımlılıkları kontrol edin.
Yanıtla
Bu yorumda pizza tarifi açıklanıyordu ve yorumu Amir yazmıştı. Bu kuralın hangi bağımlılıklara sahip olduğunu görmek için bazel query --noimplicit\_deps 'deps(//src/main/java/com/example/reviews:review)'
simgesini kullanın. Bu komutun sonucu, Amir'in inceleme uzmanı olduğunu gösterir.
Ardından, yorum yapan kişinin Amir olduğunu bildiğiniz için Amir'in "BUILD" dosyasında hangi etiketi kullandığını bulmak için sorgu işlevini kullanarak yemeğin ne olduğunu görebilirsiniz.
bazel query 'attr(tags, "pizza", //src/main/java/com/example/customers/...)'
komutu, Amir'in pizza sipariş eden tek müşteri olduğunu ve bize yanıt veren yorumcu olduğunu gösterir.
Özet
Tebrikler! Artık kendi projelerinizde deneyebilirsiniz. Sorgu dili söz dizimi hakkında daha fazla bilgi edinmek için Sorgu referans sayfasına bakın. Daha gelişmiş sorgular mı istiyorsunuz? Sorgu kılavuzu, bu kılavuzda ele alınanlardan daha fazla kullanım alanının ayrıntılı bir listesini sunar.