Bazel Eğitimi: Java Projesi Oluşturma

Bu eğiticide, Bazel ile Java uygulamaları oluşturma hakkındaki temel bilgiler verilmektedir. Çalışma alanınızı oluşturup hedefler ve BUILD dosyaları gibi temel Bazel kavramlarını gösteren basit bir Java projesi derleyeceksiniz.

Tahmini tamamlanma süresi: 30 dakika.

Neler öğreneceksiniz?

Bu eğiticide şunları öğreneceksiniz:

  • Hedef oluşturun
  • Projenin bağımlılıklarını görselleştirme
  • Projeyi birden çok hedefe ve pakete bölme
  • Paketler genelinde hedef görünürlüğünü kontrol etme
  • Hedeflere etiketler aracılığıyla referans verme
  • Hedef dağıtma

Başlamadan önce

Bazel'ı yükleme

Eğiticiye hazırlanmak için, henüz yüklemediyseniz öncelikle Bazel'i yükleyin.

JDK'yı yükleyin

  1. Java JDK'yı yükleyin (tercih edilen sürüm 11'dir, ancak 8 ile 15 arasındaki sürümler 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:

      1. Denetim Masası'nı açın.
      2. "Sistem ve Güvenlik" > "Sistem" > "Gelişmiş Sistem Ayarları" > "Gelişmiş" sekmesi > "Ortam Değişkenleri..." seçeneğine gidin. .
      3. "Kullanıcı değişkenleri" listesinin (en üstteki) altında "Yeni..." seçeneğini tıklayın.
      4. "Değişken adı" alanına JAVA_HOME yazın.
      5. "Dizine Göz At..." seçeneğini tıklayın.
      6. JDK dizinine gidin (örneğin, C:\Program Files\Java\jdk1.8.0_152).
      7. Tüm iletişim pencerelerinde "Tamam"ı tıklayın.

Örnek projeyi alma

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

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

Bu eğitim için örnek proje examples/java-tutorial dizinindedir 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
└── WORKSPACE

Bazel ile oluşturma

Çalışma alanını ayarlama

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

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

  • Bazel'a projenin farklı bölümlerini nasıl oluşturacağını bildiren bir veya daha fazla BUILD dosyası. (Çalışma alanında yer alan ve BUILD dosyası içeren bir dizin, bir pakettir. Bu eğiticinin ilerleyen bölümlerinde paketler hakkında bilgi edineceksiniz.)

Bir dizini Bazel çalışma alanı olarak tanımlamak için ilgili dizinde WORKSPACE adlı boş bir dosya oluşturun.

Bazel projeyi derlerken tüm girişler ve bağımlılıklar aynı çalışma alanında olmalıdır. Farklı çalışma alanlarında bulunan dosyalar, bağlanmadığı sürece birbirinden bağımsızdır. Bu, bu eğiticinin kapsamının dışındadır.

BUILD dosyasını anlama

Bir BUILD dosyası, Bazel için birkaç farklı türde talimat içeriyor. En önemli tür, Bazel'a yürütülebilir ikili programlar veya kitaplıklar gibi istenen çıkışları nasıl oluşturacağını bildiren oluşturma kuralıdır. BUILD dosyasındaki bir derleme kuralının her örneğine hedef adı verilir ve bu örneğin, belirli bir kaynak dosyaları ve bağımlılıklar grubuna işaret eder. Bir hedef, diğer hedefleri de gösterebilir.

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'ın yerleşik java_binary kuralını örneklendirir. Kural, Bazel'a bir .jar dosyası ve bir sarmalayıcı kabuk komut dosyası (her ikisi de hedeften sonra adlandırılmıştır) oluşturmasını 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'ın hedefi oluşturmak için kullandığı kaynak dosyaları ve main_class, ana yöntemi içeren sınıfı belirtir. (Örneğimizin, bir dizi kaynak dosyayı tek tek listelemek yerine Bazel'a iletmek için glob'u kullandığını fark etmiş olabilirsiniz.)

Projeyi oluşturma

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

bazel build //:ProjectRunner

Hedef etikette // bölümü, BUILD dosyasının çalışma alanının köküne göre konumudur (bu örnekte kökün kendisi). ProjectRunner, BUILD dosyasındaki hedef addır. (Bu eğiticinin sonunda hedef etiketler hakkında daha ayrıntılı bilgi edineceksiniz.)

Bazel, aşağıdakine benzer bir çıkış ü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 oluşturdunuz! Bazel, derleme çıktılarını çalışma alanının kök kısmındaki bazel-bin dizinine yerleştirir. Bazel'ın çıktı yapısı hakkında fikir edinmek için dosyanın 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 bildirilmesini gerektirir. Bazel bu ifadeleri projenin bağımlılık grafiğini oluşturmak için kullanır. Bu grafik, doğru artımlı derlemeler yapılmasını sağlar.

Örnek projenin bağımlılıklarını görselleştirmek için Workspace kökünde şu komutu çalıştırarak bağımlılık grafiğinin metin sunumunu oluşturabilirsiniz:

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

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

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

Gördüğünüz gibi projenin, hiçbir ek bağımlılığı olmayan iki kaynak dosya oluşturan tek bir hedefi var:

"ProjectRunner" hedefinin bağımlılık grafiği

Çalışma alanınızı oluşturduktan, projenizi oluşturduktan ve bağımlılıklarını inceledikten sonra, işleri biraz karmaşık hale getirebilirsiniz.

Bazel derlemenizi hassaslaştırın

Küçük projeler için tek bir hedef yeterli olsa da hızlı artımlı derlemelere olanak tanımak (yani yalnızca değiştirilenleri yeniden oluşturmak) ve aynı anda projenin birden fazla parçasını derleyerek derlemelerinizi hızlandırmak için büyük projeleri birden fazla hedefe ve pakete bölmek isteyebilirsiniz.

Birden çok derleme hedefi belirtin

Örnek proje yapısını iki hedefe bölebilirsiniz. java-tutorial/BUILD dosyasının içeriğini şununla 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ı oluşturur. java_binary öğesindeki deps özelliği, Bazel'a ProjectRunner ikili programını oluşturmak 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 çıkış ü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ştirir ve projeyi yeniden derlerseniz Bazel yalnızca bu dosyayı yeniden derler.

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

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

Artık projeyi iki hedefle oluşturdunuz. ProjectRunner hedefi, iki kaynak dosya oluşturur ve bir ek kaynak dosya oluşturan 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 göz atarsanız, bir BUILD dosyası ve bazı kaynak dosyalar da içerdiğini 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ğu için).

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 bağlıdır (dolayısıyla //:greeter hedef etiketi). Bazel, bunu deps özelliği aracılığıyla bilir. Bağımlılık grafiğine göz atın:

"Koşucu" hedefinin 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 bölgesindeki runner hedefini //BUILD bölgesindeki hedeflere açıkça belirtmeniz gerekir. Bunun nedeni, varsayılan olarak hedeflerin yalnızca aynı BUILD dosyasındaki diğer hedefler tarafından görülebilmesidir. (Bazel, uygulama ayrıntılarını içeren kitaplıklar ve herkese açık API'lere sızması gibi sorunları önlemek için hedef görünürlüğü kullanır.)

Bunu yapmak için visibility özelliğini aşağıda gösterildiği gibi java-tutorial/BUILD öğesindeki greeter hedefine ekleyin:

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

Artık ç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 çıkış ü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

Şimdi de projeyi, her biri bir hedef içeren iki paket halinde derlemek ve bunlar arasındaki bağımlılıkları anlamak için değiştirmiş olursunuz.

Hedeflere referans vermek için etiketleri kullanma

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

//path/to/package:target-name

Hedef bir kural hedefiyse path/to/package, BUILD dosyasını içeren dizinin yoludur. target-name ise BUILD dosyasında hedefi (name özelliği) adlandırdığınız yöntemdir. Hedef bir dosya hedefiyse path/to/package paket kök yolunun yoludur ve target-name hedef dosyanın tam yolu ile birlikte adıdır.

Depo kökündeki hedeflere referans verirken paket yolu boştur. Yalnızca //:target-name kullanmanız yeterlidir. 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, çalışma alanı kökünün kendisi bir paket (//) olduğundan ve iki hedef etiketiniz sadece //:ProjectRunner ve //:greeter olduğundan, java-tutorial/BUILD dosyasındaki hedefler için paket yolu belirtmeniz gerekmez.

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 hedefini paketleme

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

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

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

İçerik:

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 içeriyor ancak bağımlılığı Greeting.class içermiyor. Bazel'ın oluşturduğu runner komut dosyası, greeter.jar dosyasını sınıf yoluna ekler. Dolayısıyla bu şekilde bırakırsanız yerel olarak çalışır ancak başka bir makinede bağımsız olarak çalışmaz. Neyse ki java_binary kuralı bağımsız ve dağıtılabilir bir ikili program derlemenize olanak tanır. Oluşturmak için hedef adın sonuna _deploy.jar ekleyin:

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

Bazel, aşağıdakine benzer bir çıkış ü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 programını az önce oluşturdunuz. Önceki 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

İçerik, çalışması için gerekli tüm sınıfları içermelidir:

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:

Kolay gelsin!