Bu eğitimde, önceden oluşturulmuş bir Bazel projesi 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 sorgu referansı ve Bazel cquery 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 doküman, Bazel ve BUILD
dosyalarının nasıl çalıştığına dair temel bilgilere sahip yeni Bazel geliştiricileri için hazırlanmış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ıyor. En iyi sonuçları elde etmek 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ı indirerek adımları takip edebilirsiniz.
Örnek projeyi alma
Ardından, tercih ettiğiniz komut satırı aracında aşağıdakileri çalıştırarak Bazel'in örnekler deposundan örnek uygulamayı alın:
git clone https://github.com/bazelbuild/examples.git
Bu eğitimdeki örnek proje examples/query-quickstart
dizinindedir.
Başlarken
Bazel sorguları nedir?
Sorgular, BUILD
dosyaları arasındaki ilişkileri analiz ederek ve sonuçtaki çıktıyı faydalı bilgiler için inceleyerek Bazel kod tabanı hakkında bilgi edinmenize yardımcı olur. Bu kılavuzda bazı temel sorgu işlevleri önizlenmektedir. Daha fazla seçenek için sorgu kılavuzuna bakın. Sorgular, BUILD
dosyaları arasında manuel olarak gezinmeden büyük ölçekli projelerdeki bağımlılıklar hakkında bilgi edinmenize 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 ele alan bir senaryo hayal edin. Bu kafede yalnızca pizza ve mac & cheese satılıyor. Projenin nasıl yapılandırıldığına dair bilgileri aşağıda bulabilirsiniz:
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ğitimin tamamında, aksi belirtilmedikçe ihtiyacınız olan bilgileri bulmak için BUILD
dosyalarına bakmamaya çalışın ve bunun yerine yalnızca sorgu işlevini kullanın.
Bir proje, bir kafeyi oluşturan farklı paketlerden oluşur. Bunlar restaurant
, ingredients
, dishes
, customers
ve reviews
olarak ayrılır. Bu paketlerdeki kurallar, çeşitli etiketler ve bağımlılıklarla Cafe'nin farklı bileşenlerini tanımlar.
Derleme çalıştırma
Bu proje, Runner.java
içinde bir ana yöntem içerir. Bu yöntemi çalıştırarak kafenin menüsünü yazdırabilirsiniz. bazel build
komutuyla Bazel'i kullanarak projeyi oluşturun ve hedefin runner
olarak adlandırıldığını belirtmek için :
kullanın. Hedeflere nasıl referans vereceğinizi öğrenmek için hedef adlarına bakın.
Bu projeyi oluşturmak 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ünür.
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
Başarıyla oluşturulduktan sonra, bu 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 sonucunda, menü öğelerinin listesi ve kısa açıklamaları gösterilir.
Hedefleri keşfetme
Proje, içerikleri ve yemekleri kendi paketlerinde listeler. Bir paketin kurallarını görüntülemek için sorgu kullanmak üzere bazel query package/…
komutunu çalıştırın.
Bu durumda, aşağıdaki kodu çalıştırarak bu kafenin malzemelerini ve yemeklerini inceleyebilirsiniz:
bazel query //src/main/java/com/example/dishes/...
bazel query //src/main/java/com/example/ingredients/...
Malzemeler paketinin hedeflerini sorgularsanız çıkış şu şekilde 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
Çalıştırıcınızın çalışmak için kullandığı hedefler nelerdir?
Örneğin, dosya sistemini incelemeden (büyük projeler için uygun olmayabilir) projenizin yapısını daha ayrıntılı bir şekilde incelemek istiyorsunuz. Cafe Bazel hangi kuralları kullanır?
Bu örnekte olduğu gibi koşucunuzun hedefi 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ını görmek için sorgu işlevini deps()
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, yolu düzleştirilmiş bir liste yerine yönlendirilmiş döngüsüz grafik görüntüsü olarak görmenize 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.
İstediğiniz sorguyu çalıştırarak başlayın ve gereksiz araç bağımlılıklarını kaldırmak için --noimplicit_deps
işaretini ekleyin. Ardından, sorguyu çıkış işaretiyle birlikte kullanın ve grafiğin metin gösterimini oluşturmak için grafiği graph.in
adlı bir dosyada saklayın.
Hedef :runner
öğesinin tüm bağımlılıklarını aramak ve çıkışı grafik olarak biçimlendirmek için:
bazel query --noimplicit_deps 'deps(:runner)' --output graph > graph.in
Bu işlem, derleme grafiğinin metin gösterimi olan graph.in
adlı bir dosya oluşturur. Graphviz, metni görselleştirmeye dönüştüren bir araç olan dot
'ı kullanarak PNG oluşturur:
dot -Tpng < graph.in > graph.png
graph.png
simgesini açtığınızda aşağıdakine benzer bir ekran görürsünüz. Aşağıdaki grafik, bu kılavuzda temel yol ayrıntılarını daha net hale getirmek için basitleştirilmiştir.
Bu kılavuzdaki farklı sorgu işlevlerinin çıkışlarını görmek istediğinizde bu özellikten yararlanabilirsiniz.
Ters bağımlılıkları bulma
Bunun yerine, diğer hedeflerin hangi hedefi kullandığını analiz etmek istiyorsanız belirli bir kurala bağlı olan hedefleri incelemek için bir sorgu kullanabilirsiniz. Bu duruma "ters bağımlılık" adı verilir. rdeps()
, aşina olmadığınız bir kod tabanında dosya düzenlerken faydalı olabilir ve bağımlı olduğu diğer dosyaları bilmeden bozmanızı önleyebilir.
Örneğin, cheese
bileşeninde bazı düzenlemeler yapmak istiyorsunuz. Cafe Bazel'de sorun yaşanmaması için hangi yemeklerde cheese
kullanıldığını kontrol etmeniz gerekir.
Hangi hedeflerin belirli bir hedefe/pakete bağlı olduğunu görmek için rdeps(universe_scope, target)
kullanabilirsiniz. rdeps()
sorgu işlevi en az iki bağımsız değişken alır: universe_scope
(ilgili dizin) ve 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.
Hedef cheese
öğesinin tüm proje kapsamındaki ("//…") 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 pizzanın hem de macAndCheese'in peynir kullandığını gösteriyor. Ne sürpriz ama!
Etiketlere göre hedefler bulma
Bazel Cafe'ye iki müşteri giriyor: Amir ve Jenny. Adları dışında haklarında hiçbir bilgi yoktur. Neyse ki siparişleri "müşteriler" BUILD
dosyasında etiketlenmiş. Bu etikete nasıl erişebilirsiniz?
Geliştiriciler, genellikle test amacıyla Bazel hedeflerini farklı tanımlayıcılarla etiketleyebilir. Örneğin, testlerdeki etiketler, özellikle çalışma zamanı notlandırma özelliği olmayan C++ ve Python testleri için bir testin hata ayıklama ve yayınlama sürecindeki rolünü notlandırabilir. Etiket ve boyut öğeleri kullanmak, test paketlerini bir kod tabanının check-in politikasına göre oluşturma konusunda esneklik sağlar.
Bu örnekte, menü öğelerini temsil etmek için etiketler pizza
veya macAndCheese
olarak belirlenmiştir. Bu komut, belirli bir pakette tanımlayıcınızla eşleşen etiketlere sahip hedefleri sorgular.
bazel query 'attr(tags, "pizza", //src/main/java/com/example/customers/...)'
Bu sorgu, "pizza" etiketi olan "customers" paketindeki tüm hedefleri döndürür.
Kendinizi test edin
Jenny'nin ne sipariş etmek istediğini öğrenmek için bu sorguyu kullanın.
Yanıt
Peynirli Makarna
Yeni bağımlılık ekleme
Cafe Bazel menüsünü genişletti. Müşteriler artık smoothie siparişi verebilir. Bu özel smoothie, Strawberry
ve Banana
malzemelerinden oluşuyor.
Öncelikle smoothie'nin temel malzemelerini 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
öğesini uygun dizine ekleyin: dishes
.
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. Adı, herkese açık görünürlüğü ve yeni oluşturulan "src" dosyası da dahil olmak üzere her yeni bileşen için yeni bir Java kitaplığı oluşturun. Sonuç olarak şu güncellenmiş BUILD
dosyasına sahip olursunuz:
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"],
)
Yemekler için BUILD
dosyasında Smoothie
için yeni bir kural eklemek istiyorsunuz. Bu işlem, Smoothie
için "src" dosyası olarak oluşturulan Java dosyasını ve smoothie'nin her malzemesi için oluşturduğunuz 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 Chef'in BUILD
dosyasında bağımlı öğe olarak eklemek istiyorsunuz.
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ığından emin olmak için cafe
öğesini tekrar oluşturun. Başarıyla oluşturulursa tebrikler. "Kafe" için yeni bir bağımlılık eklediniz. Aksi takdirde, yazım hatalarına ve paket adlandırmasına dikkat edin. BUILD
dosyaları yazma hakkında daha fazla bilgi için BUILD Stil Kılavuzu'na bakın.
Şimdi, öncekiyle karşılaştırmak için Smoothie
eklenmiş yeni bağımlılık grafiğini görselleştirin. Netlik 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
'ya baktığınızda Smoothie
'nin diğer yemeklerle paylaşılan bağımlılıkları olmadığını ancak Chef
'nin bağlı olduğu 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 yapmanız gerekir? İkisi arasındaki bağımlılık yolunu göstermek yanıtı sağlar.
Bağımlılık yollarını bulmanıza yardımcı olabilecek iki işlev vardır: somepath()
ve allpaths()
. Başlangıç hedefi S ve bitiş noktası E 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ı inceleyin. Bir hedeften diğerine ulaşmak için farklı yollar izlenebilir:
- Chef → MacAndCheese → Cheese
- Chef → Pizza → Cheese
somepath()
, iki seçenekten tek bir yol sunarken "allpaths()" işlevi olası tüm yolları verir.
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 → Chef → MacAndCheese → Cheese şeklindeki ilk yolu 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
allpaths()
çıktısı, bağımlılıkların düzleştirilmiş bir listesi olduğundan okunması biraz daha zordur. Bu grafiği Graphviz kullanarak görselleştirmek, ilişkiyi daha net anlamanızı sağlar.
Kendinizi test edin
Cafe Bazel'in müşterilerinden biri, restoranın ilk yorumunu yaptı. Yorumda, yorumcunun kimliği ve hangi yemeğe atıfta bulunduğu gibi bazı ayrıntılar eksik. Neyse ki bu bilgilere Bazel ile 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ı kullanarak yorumu kimin yazdığını ve hangi yemeği tarif ettiğini bulmaya çalış.
İpucu
Faydalı bilgiler için etiketleri ve bağımlılıkları kontrol edin.
Yanıt
Bu yorumda pizza anlatılıyor ve yorumu yapan kişi Amir. bazel query --noimplicit\_deps 'deps(//src/main/java/com/example/reviews:review)'
komutunu kullanarak bu kuralın hangi bağımlılıkları olduğuna bakarsanız
bazel query --noimplicit\_deps 'deps(//src/main/java/com/example/reviews:review)'
Bu komutun sonucu, Amir'in inceleyici olduğunu gösterir.
Ardından, incelemeyi yapan kişinin Amir olduğunu bildiğiniz için sorgu işlevini kullanarak Amir'in hangi yemeğin olduğunu görmek üzere "BUILD" dosyasında hangi etikete sahip olduğunu arayabilirsiniz.
bazel query 'attr(tags, "pizza", //src/main/java/com/example/customers/...)'
komutunun çıktısında, pizza sipariş eden tek müşterinin Amir olduğu ve yorumu yapanın da Amir olduğu belirtiliyor.
Özet
Tebrikler! Artık kendi projelerinizde deneyebileceğiniz birkaç temel sorgu çalıştırdınız. 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ılavuzunda, bu kılavuzda ele alınanlardan daha fazla kullanım alanının ayrıntılı bir listesi yer almaktadır.