Bu eğiticide, önceden hazırlanmış bir Bazel projesi kullanarak kodunuzdaki bağımlılıkları izlemek için Bazel ile nasıl çalışabileceğiniz 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'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 bulabilirsiniz. Bu program, Bazel ve BUILD
dosyalarının nasıl çalıştığıyla ilgili temel bilgilere sahip yeni Bazel geliştiricileri içindir.
Ön koşullar
Henüz yapmadıysanız Bazel'i yükleyerek başlayın. Bu eğitim, kaynak kontrolü için Git'i kullandığından 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ı indirebilirsiniz.
Örnek projeyi alma
Ardından, istediğiniz komut satırı aracında aşağıdaki kodu çalıştırarak Bazel'ın Örnekler deposundan örnek uygulamayı alın:
git clone https://github.com/bazelbuild/examples.git
Bu eğitim için örnek proje examples/query-quickstart
dizininde yer alıyor.
Başlarken
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. Daha fazla seçenek için sorgu kılavuzuna göz atabilirsiniz. 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şkiyi ele alan bir senaryo düşünün. Bu kafede özel olarak pizza, mak ve peynir satılır. Aşağıda 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
└── WORKSPACE
Bu eğitim süresince, aksi belirtilmediği sürece, ihtiyacınız olan bilgileri bulmak için BUILD
dosyalarına bakmayıp yalnızca sorgu işlevini kullanmayı deneyin.
Proje, bir kafeyi oluşturan farklı paketlerden oluşur. Bunlar restaurant
, ingredients
, dishes
, customers
ve reviews
olarak ayrılmıştır. Bu paketlerdeki kurallar, kafenin çeşitli etiketleri ve bağımlılıklarıyla 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 ana bir yöntem içermektedir. Projeyi, bazel build
komutuyla Bazel kullanarak oluşturun ve hedefin runner
olarak adlandırıldığını belirtmek için :
ifadesini 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 şuna benzer bir görünümde olacaktı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 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 size menü öğelerinin bir listesi sunulur.
Hedefleri keşfetme
Projede malzemeler ve yemekler kendi paketlerinde listeleniyor. Paketin kurallarını sorgu kullanarak görüntülemek için bazel query package/…
komutunu çalıştırın
Bu durumda, aşağıdaki kodu çalıştırarak bu kafenin malzemelerine ve yemeklerine göz atabilirsiniz:
bazel query //src/main/java/com/example/dishes/...
bazel query //src/main/java/com/example/ingredients/...
Bileşenler paketinin hedeflerini sorgularsanız çıktı 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şucunuz koşmak için hangi hedefleri temel alıyor?
Dosya sistemini üretmeden projenizin yapısını derinlemesine incelemek istediğinizi düşünelim (büyük projelerde kullanılamayabilir). Cafe Bazel hangi kuralları kullanır?
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. Graphviz, yolu düzleştirilmiş bir liste yerine yönlendirilmiş dairesel bir grafik resmi olarak görmeye 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 Çıktı Biçimleri bölümüne bakın.
İstediğiniz sorguyu çalıştırarak başlayın ve aşırı araç bağımlılığını ortadan kaldırmak için --noimplicit_deps
işaretini ekleyin. Ardından, çıktı işaretini içeren sorguyu izleyin ve grafiğin metin sunumunu oluşturmak için grafiği graph.in
adlı dosyaya kaydedin.
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, yapı grafiğinin metin temsili olan graph.in
adında 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 şuna benzer bir şey 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ılavuz boyunca farklı sorgu işlevlerinin çıkışlarını görmek istediğinizde işinize yarayacaktır.
Tersine bağımlılıkları bulma
Bunun yerine, diğer hedeflerin hangi hedefleri 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" adı verilir. rdeps()
kullanımı, aşina olmadığınız bir kod tabanında dosya düzenlerken yararlı olabilir ve sizi ilgili kod tabanına bağımlı olan diğer dosyaları farkında olmadan bozmanızı önler.
Örneğin, cheese
bileşeninde bazı düzenlemeler yapmak istiyorsunuz. Cafe Bazel ile ilgili bir sorun oluşmasını önlemek 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ı.
Tüm "//..." projesi 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 döndürmesi, hem pizza hem de macAndCheese'in peyniri kullandığını gösterir. Sürpriz!
Etiketlere dayalı olarak 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, çoğu zaman 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ı ek açıklaması yeteneğine sahip olmayan C++ ve Python testlerinde testin rolüne ek açıklama ekleyebilir. Etiket ve boyut öğelerinin kullanılması, test paketlerini bir kod tabanının check-in politikasına göre derlerken 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 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
Cansu'nun ne sipariş etmek istediğini öğrenmek için bu sorguyu kullanın.
Cevap
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 ihtiyaç duyduğ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. Bu güncellenmiş BUILD
dosyasıyla yola çıkın:
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ına Smoothie
için yeni bir kural eklemek istiyorsunuz. Bu işlem, Smoothie
için oluşturulan Java dosyasını "src" dosyası olarak ve smoothie'nin her bir bileşeni 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, Şefin BUILD
dosyasına smoothie'yi bağımlılık olarak dahil etmek istersiniz.
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
öğesini yeniden oluşturun. Başarıyla oluşturulduysa tebrikler! "Kafe" için yeni bir bağımlılık eklediniz. 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 Kılavuzu'na bakın.
Şimdi de Smoothie
öğesinin eklendiği ve öncekiyle karşılaştırmak için yeni bağımlılık grafiğini 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
metriğine baktığınızda, Smoothie
adlı yerin diğer yemeklerle ortak bir bağımlılığı olmadığını, ancak Chef
için kullanılan bir başka hedef olduğunu görebilirsiniz.
somepath() ve allpaths()
Bir paketin neden başka bir pakete bağlı olduğunu sorgulamak isterseniz ne olur? Yanıt, ikisi arasında bir bağımlılık yolu göstermektir.
Şu iki işlev bağımlılık yollarını bulmanıza yardımcı olabilir: somepath()
ve allpaths()
. Başlangıç hedefi S ve varış noktası E verildiğinde S ile E arasındaki yolu somepath(S,E)
kullanarak bulun.
"Şef" ve "Peynir" hedefleri arasındaki ilişkilere bakarak bu iki işlev arasındaki farkları keşfedin. Bir hedeften diğerine gitmek için olası farklı yollar vardır:
- Şef → MacAndCheese → Peynir
- Şef → Pizza → Peynir
somepath()
size iki seçenekten tek bir yol sağlar, "allpaths()" ise olası tüm yolları sunar.
Ö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 yolunun ilk yolunu izler. Bunun yerine allpaths()
kullanırsanız şu avantajlardan yararlanırsını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 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
Restoranla ilgili ilk yorumu Cafe Bazel'in müşterilerinden biri yapmıştır. 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. Şunu kullanarak 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 önüne geçerseniz yorumu kimin yazdığını ve hangi yemeği tarif ettiğini bulmaya çalışın.
İpucu
Faydalı bilgiler için etiketleri ve bağımlılıkları kontrol edin.
Cevap
Bu yorumda Pizza ile ilgiliydi ve Emir'in yorumcu olduğuydu. 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ğinizden, Emir'in "BUILD" dosyasındaki hangi etikete sahip olduğunu bulmak için sorgu işlevini kullanarak 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 sorunu inceleyen kişi olduğunu belirtir.
Ö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ını inceleyin. 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.