Bazel Eğitimi: Java Projesi Oluşturma

Bu eğiticide, Bazel ile Java uygulamaları derlemenin temelleri açıklanmaktadır. Çalışma alanınızı ayarlayacak ve hedefler ve BUILD dosyaları gibi temel Bazel kavramlarını gösteren basit bir Java projesi derleyeceksiniz.

Tahmini tamamlama süresi: 30 dakikadır.

Neler öğreneceksiniz?

Bu eğitimde şunları öğreneceksiniz:

  • Hedef derleme
  • Projenin bağımlılıklarını görselleştirme
  • Projeyi birden fazla hedefe ve pakete bölme
  • Paketler genelinde hedef görünürlüğünü kontrol etme
  • Etiketler aracılığıyla hedeflere başvurma
  • Hedef dağıtma

Başlamadan önce

Bazel'i yükleme

Eğitime başlarken, yüklü değilse önce Bazel'i yükleyin.

JDK'yı yükleme

  1. Java JDK'yı yükleyin (tercih edilen sürüm 11'dir ancak 8 ila 15 arasındaki sürümler de desteklenir).

  2. JAVA_HOME ortam değişkenini JDK'yı işaret edecek şekilde ayarlayın.

    • Linux/macOS'te:

      export JAVA_HOME="$(dirname $(dirname $(realpath $(which javac))))"
      
    • Windows'da:

    • Denetim Masası'nı açın.

    • "Sistem ve Güvenlik" > "Sistem" > "Gelişmiş Sistem Ayarları" > "Gelişmiş" sekmesi > "Ortam Değişkenleri..." seçeneğine gidin. .

    • "Kullanıcı değişkenleri" listesinde (en üstteki) "Yeni..." seçeneğini tıklayın.

    • "Değişken adı" alanına JAVA_HOME girin.

    • "Dizine Göz At..." seçeneğini tıklayın.

    • JDK dizinine (örneğin, C:\Program Files\Java\jdk1.8.0_152) gidin.

    • Tüm iletişim pencerelerinde "Tamam"ı tıklayın.

Örnek projeyi alma

Örnek projeyi Bazel'in GitHub deposundan alın:

git clone https://github.com/bazelbuild/examples

Bu eğitimdeki örnek proje, examples/java-tutorial dizininde yer alır ve aşağıdaki gibi yapılandırılmıştır:

java-tutorial
├── BUILD
├── src
│   └── main
│       └── java
│           └── com
│               └── example
│                   ├── cmdline
│                   │   ├── BUILD
│                   │   └── Runner.java
│                   ├── Greeting.java
│                   └── ProjectRunner.java
└── MODULE.bazel

Bazel ile derleme

Çalışma alanını ayarlama

Proje derlemek için önce çalışma alanını ayarlamanız gerekir. Çalışma alanı, projenizin kaynak dosyalarını ve Bazel'in derleme çıktılarını içeren bir dizindir. Ayrıca Bazel'in özel olarak tanıdığı dosyaları da içerir:

  • Dizini ve içeriklerini Bazel çalışma alanı olarak tanımlayan ve projenin dizin yapısının kökünde bulunan MODULE.bazel dosyası,

  • Projenin farklı bölümlerinin nasıl derleneceğini Bazel'e bildiren bir veya daha fazla BUILD dosyası. (Çalışma alanında BUILD dosyası içeren bir dizin, paket olarak kabul edilir. Paketler hakkında daha fazla bilgiyi bu eğitimin ilerleyen bölümlerinde edineceksiniz.)

Bir dizini Bazel çalışma alanı olarak belirlemek için bu dizinde MODULE.bazel adlı boş bir dosya oluşturun.

Bazel projeyi derlediğinde tüm girişler ve bağımlılıklar aynı çalışma alanında olmalıdır. Farklı çalışma alanlarında bulunan dosyalar, bu eğitimin kapsamı dışında olan bağlantı oluşturma işlemi yapılmadığı sürece birbirinden bağımsızdır.

DERLEME dosyasını anlama

BUILD dosyası, Bazel için çeşitli talimat türleri içerir. En önemli tür, Bazel'e yürütülebilir ikili programlar veya kitaplıklar gibi istenen çıktıların nasıl derleneceğini söyleyen derleme kuralıdır. BUILD dosyasındaki her derleme kuralı örneği, hedef olarak adlandırılır ve belirli bir kaynak dosyalar ve bağımlılıklar kümesini işaret eder. Bir hedef, diğer hedefleri de işaret edebilir.

java-tutorial/BUILD dosyasına göz atın:

java_binary(
    name = "ProjectRunner",
    srcs = glob(["src/main/java/com/example/*.java"]),
)

Örneğimizde, ProjectRunner hedefi Bazel'in yerleşik java_binary kuralını örneklendirir. Kural, Bazel'e bir .jar dosyası ve bir sarmalayıcı kabuk komut dosyası (her ikisi de hedefle aynı ada sahip) derlemesini söyler.

Hedefteki özellikler, bağımlılıklarını ve seçeneklerini açıkça belirtir. name özelliği zorunlu olsa da çoğu isteğe bağlıdır. Örneğin, ProjectRunner kural hedefinde name, hedefin adıdır, srcs, Bazel'in hedefi derlemek için kullandığı kaynak dosyaları belirtir, main_class ise ana yöntemi içeren sınıfı belirtir. (Örneğimizde, kaynak dosyaları tek tek listelemek yerine Bazel'e aktarmak için glob kullanıldığını fark etmiş olabilirsiniz.)

Projeyi derleme

Örnek projenizi derlemek için java-tutorial dizinine gidin ve şu komutu çalıştırın:

bazel build //:ProjectRunner

Hedef etiketinde // kısmı, BUILD dosyasının çalışma alanının köküne göre konumu (bu durumda kök kendisidir), ProjectRunner ise BUILD dosyasındaki hedef adıdır. (Hedef etiketleri hakkında daha ayrıntılı bilgiyi bu eğitimin sonunda edineceksiniz.)

Bazel, aşağıdakine benzer bir çıktı üretir:

   INFO: Found 1 target...
   Target //:ProjectRunner up-to-date:
      bazel-bin/ProjectRunner.jar
      bazel-bin/ProjectRunner
   INFO: Elapsed time: 1.021s, Critical Path: 0.83s

Tebrikler, ilk Bazel hedefinizi derlediniz. Bazel, derleme çıkışlarını çalışma alanının kökündeki bazel-bin dizinine yerleştirir. Bazel'in çıkış yapısı hakkında fikir edinmek için içeriğine göz atın.

Şimdi yeni derlediğiniz ikili programı test edin:

bazel-bin/ProjectRunner

Bağımlılık grafiğini inceleme

Bazel, derleme bağımlılıklarının BUILD dosyalarında açıkça belirtilmesini gerektirir. Bazel, bu ifadeleri kullanarak projenin, doğru artımlı derlemeler yapılmasını sağlayan bağımlılık grafiğini oluşturur.

Örnek projenin bağımlılıklarını görselleştirmek için çalışma alanının kök dizininde şu komutu çalıştırarak bağımlılık grafiğinin metin gösterimini oluşturabilirsiniz:

bazel query  --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph

Yukarıdaki komut, Bazel'e //:ProjectRunner hedefinin tüm bağımlılıklarını (ana makine ve örtülü bağımlılıklar hariç) aramasını ve çıkışı grafik olarak biçimlendirmesini söyler.

Ardından metni GraphViz'e yapıştırın.

Projede ek bağımlılıklar olmadan iki kaynak dosyası derleyen tek bir hedef olduğunu göreceksiniz:

Hedef "ProjectRunner"ın bağımlılık grafiği

Çalışma alanınızı ayarlama, projenizi derleme ve bağımlılıklarını inceleme işlemlerinden sonra biraz karmaşıklık ekleyebilirsiniz.

Bazel derlemenizi ayrıntılandırma

Küçük projeler için tek bir hedef yeterli olsa da daha büyük projeleri birden fazla hedef ve pakete bölerek hızlı artımlı derlemeler (yani yalnızca değişenleri yeniden derleme) yapabilir ve bir projenin birden fazla bölümünü aynı anda derleyerek derleme işlemlerinizi hızlandırabilirsiniz.

Birden fazla derleme hedefi belirtme

Örnek proje derlemesini iki hedefe bölebilirsiniz. java-tutorial/BUILD dosyasının içeriğini aşağıdakiyle değiştirin:

java_binary(
    name = "ProjectRunner",
    srcs = ["src/main/java/com/example/ProjectRunner.java"],
    main_class = "com.example.ProjectRunner",
    deps = [":greeter"],
)

java_library(
    name = "greeter",
    srcs = ["src/main/java/com/example/Greeting.java"],
)

Bu yapılandırmada Bazel önce greeter kitaplığını, ardından ProjectRunner ikili programını derler. java_binary içindeki deps özelliği, Bazel'e ProjectRunner ikili programının derlenmesi için greeter kitaplığının gerekli olduğunu bildirir.

Projenin bu yeni sürümünü derlemek için aşağıdaki komutu çalıştırın:

bazel build //:ProjectRunner

Bazel, aşağıdakine benzer bir çıktı üretir:

INFO: Found 1 target...
Target //:ProjectRunner up-to-date:
  bazel-bin/ProjectRunner.jar
  bazel-bin/ProjectRunner
INFO: Elapsed time: 2.454s, Critical Path: 1.58s

Şimdi yeni derlediğiniz ikili programı test edin:

bazel-bin/ProjectRunner

Şimdi ProjectRunner.java dosyasını değiştirip projeyi yeniden derlerseniz Bazel yalnızca bu dosyayı yeniden derler.

Bağımlılık grafiğine baktığınızda ProjectRunner öğesinin, daha önce olduğu gibi aynı girişlere bağlı olduğunu ancak derlemenin yapısının farklı olduğunu görebilirsiniz:

Bağımlılık eklendikten sonra "ProjectRunner" hedefinin bağımlılık grafiği

Artık projeyi iki hedefle derlediniz. ProjectRunner hedefi bir kaynak dosyası derler ve ek kaynak dosyası derleyen bir başka hedefe (:greeter) bağlıdır.

Birden fazla paket kullanma

Şimdi projeyi birden fazla pakete bölelim. src/main/java/com/example/cmdline dizinine baktığınızda, bu dizinde BUILD dosyasının yanı sıra bazı kaynak dosyalarının da bulunduğunu görebilirsiniz. Bu nedenle, Bazel için çalışma alanı artık //src/main/java/com/example/cmdline ve // olmak üzere iki paket içeriyor (çalışma alanının kökünde BUILD dosyası olduğundan).

src/main/java/com/example/cmdline/BUILD dosyasına göz atın:

java_binary(
    name = "runner",
    srcs = ["Runner.java"],
    main_class = "com.example.cmdline.Runner",
    deps = ["//:greeter"],
)

runner hedefi, // paketindeki greeter hedefine (dolayısıyla //:greeter hedef etiketine) bağlıdır. Bazel bunu deps özelliği aracılığıyla bilir. Bağımlılık grafiğine göz atın:

Hedef "çalıştırıcının" bağımlılık grafiği

Ancak derlemenin başarılı olması için visibility özelliğini kullanarak //src/main/java/com/example/cmdline/BUILD içindeki runner hedefine //BUILD içindeki hedeflere açıkça görünürlük vermeniz gerekir. Bunun nedeni, varsayılan olarak hedeflerin yalnızca aynı BUILD dosyasındaki diğer hedeflere görünür olmasıdır. (Bazel, uygulama ayrıntılarını içeren kitaplıkların herkese açık API'lere sızması gibi sorunları önlemek için hedef görünürlüğünü kullanır.)

Bunu yapmak için visibility özelliğini java-tutorial/BUILD içindeki greeter hedefine aşağıdaki şekilde ekleyin:

java_library(
    name = "greeter",
    srcs = ["src/main/java/com/example/Greeting.java"],
    visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
)

Şimdi, çalışma alanının kök dizininde aşağıdaki komutu çalıştırarak yeni paketi derleyebilirsiniz:

bazel build //src/main/java/com/example/cmdline:runner

Bazel, aşağıdakine benzer bir çıktı üretir:

INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner up-to-date:
  bazel-bin/src/main/java/com/example/cmdline/runner.jar
  bazel-bin/src/main/java/com/example/cmdline/runner
  INFO: Elapsed time: 1.576s, Critical Path: 0.81s

Şimdi yeni derlediğiniz ikili programı test edin:

./bazel-bin/src/main/java/com/example/cmdline/runner

Artık projeyi, her biri bir hedef içeren iki paket olarak derleyecek şekilde değiştirdiniz ve aralarındaki bağımlılıkları anlıyorsunuz.

Hedeflere başvurmak için etiketleri kullanma

Bazel, BUILD dosyalarında ve komut satırında hedeflere referans vermek için hedef etiketlerini kullanır. Örneğin, //:ProjectRunner veya //src/main/java/com/example/cmdline:runner. Söz dizimleri aşağıdaki gibidir:

//path/to/package:target-name

Hedef bir kural hedefiyse path/to/package, BUILD dosyasını içeren dizinin yolu, target-name ise BUILD dosyasında hedefe verdiğiniz addır (name özelliği). Hedef bir dosya hedefiyse path/to/package, paketin kökünün yolu, target-name ise hedef dosyanın tam yolunu da içeren adıdır.

Depo kökündeki hedeflere referans verirken paket yolu boş olur. Bu durumda yalnızca //:target-name kullanın. Aynı BUILD dosyasındaki hedeflere referans verirken // çalışma alanı kök tanımlayıcısını atlayıp yalnızca :target-name kullanabilirsiniz.

Örneğin, java-tutorial/BUILD dosyasındaki hedefler için çalışma alanının kökü bir paket (//) ve iki hedef etiketiniz yalnızca //:ProjectRunner ve //:greeter olduğundan paket yolu belirtmeniz gerekmiyordu.

Ancak //src/main/java/com/example/cmdline/BUILD dosyasındaki hedefler için //src/main/java/com/example/cmdline öğesinin tam paket yolunu belirtmeniz gerekiyordu ve hedef etiketiniz //src/main/java/com/example/cmdline:runner idi.

Dağıtım için bir Java hedefi paketleme

Şimdi, tüm çalışma zamanı bağımlılıklarıyla ikili program derleyerek dağıtım için bir Java hedefi paketleyelim. Böylece ikili programı, geliştirme ortamınızın dışında çalıştırabilirsiniz.

Hatırlayacağınız gibi, java_binary derleme kuralı bir .jar ve bir sarmalayıcı kabuk komut dosyası oluşturur. Aşağıdaki komutu kullanarak runner.jar içeriğine göz atın:

jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar

İçerikler:

META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class

Gördüğünüz gibi runner.jar, Runner.class öğesini içeriyor ancak bağımlılığı olan Greeting.class öğesini içermiyor. Bazel'in oluşturduğu runner komut dosyası, sınıf yoluna greeter.jar eklediğinden bu şekilde bırakırsanız komut dosyası yerel olarak çalışır ancak başka bir makinede bağımsız olarak çalışmaz. Neyse ki java_binary kuralıyla, bağımsız ve dağıtılabilir bir ikili program derleyebilirsiniz. Bunu derlemek için hedef adına _deploy.jar ekleyin:

bazel build //src/main/java/com/example/cmdline:runner_deploy.jar

Bazel, aşağıdakine benzer bir çıktı üretir:

INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date:
  bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
INFO: Elapsed time: 1.700s, Critical Path: 0.23s

Gerekli çalışma zamanı bağımlılıklarını içerdiğinden geliştirme ortamınızdan bağımsız olarak çalıştırabileceğiniz runner_deploy.jar derlediniz. Daha önce kullandığınız komutu kullanarak bu bağımsız JAR'ın içeriğine göz atın:

jar tf bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar

İçerikler, aşağıdakileri çalıştırmak için gereken tüm sınıfları içerir:

META-INF/
META-INF/MANIFEST.MF
build-data.properties
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
com/example/Greeting.class

Daha fazla bilgi

Daha fazla bilgi için:

İyi derlemeler!