Bu eğitimde, önceden hazırlanmış bir Bazel projesi kullanarak kodunuzdaki bağımlılıkları izlemek için Bazel ile nasıl çalışabileceğiniz ele alınmaktadır.
Dil ve --output
işaret ayrıntıları için Bazel sorgu referansı ve Bazel BigQuery referansı kılavuzlarına bakın. Komut satırına bazel help query
veya bazel help cquery
yazarak IDE'nizle ilgili 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çıklanmıştır. Bu program, Bazel ve BUILD
dosyalarının nasıl çalıştığıyla 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ğitim, kaynak kontrolü için Git kullanır. Bu nedenle, 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. Daha sonra bu aracı indirebilirsiniz.
Örnek projeyi alma
Daha sonra, seçtiğiniz komut satırı aracında aşağıdaki kodu çalıştırarak Bazel's Örnekler deposundan örnek uygulamayı alın:
git clone https://github.com/bazelbuild/examples.git
Bu eğitim için örnek proje, examples/query-quickstart
dizinindedir.
Kullanmaya başlama
Bazel sorguları nedir?
Sorgular, BUILD
dosyaları arasındaki ilişkileri analiz ederek ve elde edilen çıkışı faydalı bilgiler açısından inceleyerek Bazel kod tabanı hakkında bilgi edinmenize yardımcı olur. Bu kılavuzda bazı temel sorgu işlevleri önizlenmektedir. Ancak daha fazla seçenek için sorgu kılavuzuna göz atın. Sorgular, BUILD
dosyalarında manuel olarak gezinmeden büyük ölçekli projelerde bağımlılıklar hakkında bilgi edinmenize yardımcı olur.
Sorgu çalıştırmak için komut satırı terminalinizi açın ve şunu girin:
bazel query 'query_function'
Senaryo
Cafe Bazel ile şefi arasındaki ilişkinin ayrıntılarına inen bir senaryo hayal edin. Bu kafede özel olarak pizza, mac ve peynir satılıyor. Projenin nasıl yapılandırıldığına 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
└── MODULE.bazel
Bu eğitim boyunca, aksi belirtilmediği sürece ihtiyacınız olan bilgileri bulmak için BUILD
dosyalarına bakmayı deneyin, bunun yerine yalnızca sorgu işlevini kullanın.
Proje, bir kafeyi oluşturan farklı paketlerden oluşur. Bunlar şu şekilde ayrılmıştır: restaurant
, ingredients
, dishes
, customers
ve reviews
. Bu paketlerdeki kurallar, çeşitli etiketler ve bağımlılıklarla birlikte kafenin farklı bileşenlerini tanımlar.
Derleme çalıştırma
Bu proje, Runner.java
içinde bir kafe menüsünü yazdırmak için çalıştırabileceğiniz bir ana yöntem içerir. bazel build
komutunu kullanarak Bazel'i kullanarak projeyi oluşturun ve hedefin runner
olarak adlandırıldığını belirtmek için :
kodunu kullanın. Hedeflere nasıl başvuracağınızı öğrenmek için hedef adlarına bakın.
Bu projeyi derlemek için şu komutu bir terminale yapıştırın:
bazel build :runner
Derleme başarılı olursa çıktınız aşağıdaki gibi görünmelidir.
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 derlendikten 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
----------------------------------------------------
Böylece kısa bir açıklamayla birlikte menü öğelerinin bir listesi size sunulur.
Hedefleri keşfetme
Projede, malzemeler ve yemekler kendi paketlerinde listeleniyor. Paketin kurallarını görüntülemek amacıyla sorgu kullanmak için bazel query package/…
komutunu çalıştırın.
Bu durumda, aşağıdaki komutu çalıştırarak kafedeki malzemeler ve yemeklere göz atabilirsiniz:
bazel query //src/main/java/com/example/dishes/...
bazel query //src/main/java/com/example/ingredients/...
Malzeme paketinin hedeflerini sorgularsanız çıktı ş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
Koşucunuz koşmak için hangi hedeflere güveniyor?
Dosya sistemine geçmeden projenizin yapısını daha ayrıntılı olarak incelemek istediğinizi varsayalım (büyük projeler için bu ayar etkinleştirilemeyebilir). Cafe Bazel hangi kuralları kullanıyor?
Bu örnekte olduğu gibi, çalıştırıcınızın 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 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 sorgu için bağımlılık yollarını nasıl görselleştirebileceğiniz açıklanmaktadır. Grafik grafiği, yolu düzleştirilmiş bir liste yerine yönlendirilmiş çembersel bir grafik resmi olarak görmeye yardımcı olur. Çeşitli --output
komut satırı seçeneklerini kullanarak Bazel sorgu grafiğinin görüntüsünü değiştirebilirsiniz. Seçenekler için Çıktı Biçimleri bölümüne bakın.
İstediğiniz sorguyu çalıştırarak başlayın ve aşırı sayıda araç bağımlılığını kaldırmak için --noimplicit_deps
işaretini ekleyin. Ardından, çıktı işaretiyle sorguyu izleyin ve grafiğin metin şeklinde temsilini oluşturmak için grafiği graph.in
adlı bir dosyaya kaydedin.
Hedef :runner
öğesinin tüm bağımlılıklarını aramak 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 dot
aracını kullanır:
dot -Tpng < graph.in > graph.png
graph.png
uygulamasını açarsanız şunun gibi bir şey görürsünüz. Aşağıdaki grafik, bu kılavuzdaki temel yol ayrıntılarını daha net hale getirmek için basitleştirilmiştir.
Bu kılavuz, farklı sorgu işlevlerinin çıkışlarını görmek istediğinizde işinize yarayacaktır.
Ters bağımlılıkları bulma
Bunun yerine, başka hangi hedeflerin onu kullandığını analiz etmek istediğiniz bir hedefiniz varsa, hangi hedeflerin belirli bir kurala bağlı olduğunu incelemek için bir sorgu kullanabilirsiniz. Buna "ters bağımlılık" denir. rdeps()
kullanımı, aşina olmadığınız bir kod tabanında dosya düzenlerken faydalı olabilir ve sizi buna bağlı olan diğer dosyaları farkında olmadan bozmaktan kurtarabilir.
Örneğin, cheese
malzemesinde bazı düzenlemeler yapmak istiyorsunuz. Cafe Bazel ile ilgili sorun yaşamamak için hangi yemeklerin cheese
güvenilir olduğunu kontrol etmeniz gerekir.
Hangi hedeflerin belirli bir hedefe/pakete bağlı olduğunu görmek için rdeps(universe_scope, target)
öğesini kullanabilirsiniz. rdeps()
sorgu işlevi en az iki bağımsız değişken alır: bir universe_scope
- ilgili dizin - 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: Aramanın derinliğindeki üst sınırı belirten bir tam sayı değişmez değeri.
"//..." projesinin tamamı kapsamında cheese
hedefinin 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 macAndCheese'de peynirin kullanıldığını gösterir. Ne sürpriz!
Etiketlere göre hedefler bulma
İki müşteri Bazel Cafe'ye giriyor: Emir ve Canan. Adları dışında bilinen hiçbir şey yoktur. Neyse ki, müşterilerinin siparişleri "müşteriler" BUILD
dosyasında etiketlenmiştir. Bu etikete nasıl erişebilirsiniz?
Geliştiriciler, genellikle test amacıyla Bazel hedeflerini farklı tanımlayıcılarla etiketleyebilirler. Örneğin, testlerdeki etiketler, hata ayıklama ve yayınlama sürecinizde, özellikle de çalışma zamanı notu özelliği olmayan C++ ve Python testlerinde testin rolüne ek açıklama ekleyebilir. Etiketlerin ve boyut öğelerinin kullanılması, test paketlerinin bir kod tabanının check-in politikasına göre derlenmesinde esneklik sağlar.
Bu örnekte etiketler, menü öğelerini temsil etmek için pizza
veya macAndCheese
etiketlerinden biridir. 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, "müşteriler" paketinde bulunan ve "pizza" etiketine sahip tüm hedefleri döndürür.
Kendinizi test edin
Ceyda'nın ne sipariş etmek istediğini öğrenmek için bu sorguyu kullanın.
Yanıtla
Mac ve Peynir
Yeni bir bağımlılık ekleme
Cafe Bazel menüsünü genişletti; müşteriler artık Smoothie sipariş edebilir. Bu smoothie, Strawberry
ve Banana
malzemelerinden oluşur.
Ö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 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. Her yeni bileşen için adı, herkese açık görünürlüğü ve yeni oluşturulan 'src' dosyasını içeren yeni bir Java kitaplığı oluşturun. Şu güncellenmiş BUILD
dosyasıyla çalışmanız gerekir:
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"],
)
Yemeklerle ilgili BUILD
dosyasında Smoothie
için yeni bir kural eklemek istiyorsunuz. Bu işlem sonucunda, Smoothie
için oluşturulan Java dosyası "src" dosyası olarak ve smoothie'nin her bir malzemesi için oluşturduğunuz yeni kurallar dahil edilir.
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ına bir bağımlılık 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",
],
)
Herhangi bir hata olmadığını onaylamak için cafe
uygulamasını tekrar oluşturun. Başarıyla oluşturulduysa tebrikler! "Kafe" için yeni bir bağımlılık eklediniz. Doğru değilse yazım hatalarına ve paket adlandırma kurallarına dikkat edin. BUILD
dosyalarını yazma hakkında daha fazla bilgi için DERLEME Stil Kılavuzu'na bakın.
Şimdi, öncekiyle karşılaştırmak için yeni bağımlılık grafiğini, eklenen Smoothie
ile 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
verilerine baktığınızda, Smoothie
adlı müşterinin diğer yemeklerle ortak bağımlılıkları olmadığını, ancak Chef
için kullanılan başka bir hedefin olduğunu görebilirsiniz.
somepath() ve allpaths()
Bir paketin neden başka bir pakete bağlı olduğunu sorgulamak isterseniz ne olur? İkisi arasında bir bağımlılık yolu görüntülemek cevabı sağlar.
Şu iki işlev bağımlılık yollarını bulmanıza yardımcı olabilir: somepath()
ve allpaths()
. Bir başlangıç hedefi S ve bir bitiş noktası E verildiğinde, somepath(S,E)
işlevini 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 gitmek için kullanılabilecek farklı yollar vardır:
- Şef → MacAndCheese → Peynir
- Şef → Pizza → Peynir
somepath()
size iki seçenekten tek bir yol sunarken "allpaths()" olası her yolu sağlar.
Örnek olarak Cafe Bazel'i kullanarak aşağıdaki komutu ç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 bölümünün ilk yolunu izler. Bunun yerine allpaths()
kullanırsanız şu avantajları elde edersiniz:
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 birleştirilmiş bir listesi olduğundan allpaths()
çıktısının okunması biraz daha zordur. Bu grafiği Graphviz kullanarak görselleştirmek, ilişkinin anlaşılmasını daha net hale getirir.
Kendinizi test edin
Restoranın ilk yorumunu Cafe Bazel'in müşterilerinden biri yaptı. Maalesef 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, gizli bir müşterinin yorumunu yazdıran bir program içerir. Şununla derleyin ve ç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ından çıkarak 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 Pizzacı, yorumcunun Emir olduğu açıklanıyor. Bu kuralın bazel query --noimplicit\_deps 'deps(//src/main/java/com/example/reviews:review)'
kullanarak sahip olduğu bağımlılıklara bakarsanız
Bu komutun sonucu Emir'in incelemeci olduğunu gösterir.
Ardından, yorumcunun Emir olduğunu bildiğiniz için sorgu işlevini kullanarak Emir'in "BUILD" dosyasındaki hangi etikete sahip olduğunu araştırarak orada hangi yemeğin olduğunu görebilirsiniz.
bazel query 'attr(tags, "pizza", //src/main/java/com/example/customers/...)'
komutu, Emir'in pizza siparişi veren tek müşteri olduğunu ve yanıtı inceleyen kişi olduğunu söyler.
Ö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ılavuzu, bu kılavuzda ele alınandan daha fazla kullanım alanının ayrıntılı bir listesini gösterir.