Java और Bazel

किसी समस्या की शिकायत करें सोर्स देखें Nightly · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

इस पेज पर ऐसे संसाधन मौजूद हैं जिनसे आपको Java प्रोजेक्ट के साथ Bazel का इस्तेमाल करने में मदद मिलती है. इसमें, Bazel की मदद से Java प्रोजेक्ट बनाने के बारे में ट्यूटोरियल, बिल्ड नियम, और अन्य जानकारी का लिंक दिया गया है.

Bazel का इस्तेमाल करना

Java प्रोजेक्ट पर Bazel का इस्तेमाल करने के लिए, इन संसाधनों का इस्तेमाल करें:

Bazel पर माइग्रेट करना

अगर फ़िलहाल Maven की मदद से Java प्रोजेक्ट बनाए जा रहे हैं, तो Maven प्रोजेक्ट को Bazel की मदद से बनाने के लिए, माइग्रेशन गाइड में दिए गए निर्देशों का पालन करें:

Java के वर्शन

कॉन्फ़िगरेशन फ़्लैग के साथ सेट किए गए, Java के दो काम के वर्शन हैं:

  • डेटा स्टोर करने की जगह में मौजूद सोर्स फ़ाइलों का वर्शन
  • Java रनटाइम का वर्शन, जिसका इस्तेमाल कोड को लागू करने और उसकी जांच करने के लिए किया जाता है

अपनी रिपॉज़िटरी में सोर्स कोड के वर्शन को कॉन्फ़िगर करना

अतिरिक्त कॉन्फ़िगरेशन के बिना, Bazel यह मानता है कि रिपॉज़िटरी में मौजूद सभी Java सोर्स फ़ाइलें, एक ही Java वर्शन में लिखी गई हैं. रिपॉज़िटरी में सोर्स का वर्शन बताने के लिए, .bazelrc फ़ाइल में build --java_language_version={ver} जोड़ें. उदाहरण के लिए, {ver} 11 है. Bazel रिपॉज़िटरी के मालिकों को यह फ़्लैग सेट करना चाहिए, ताकि Bazel और उसके उपयोगकर्ता, सोर्स कोड के Java वर्शन नंबर का रेफ़रंस दे सकें. ज़्यादा जानकारी के लिए, Java भाषा के वर्शन का फ़्लैग देखें.

कोड को चलाने और उसकी जांच करने के लिए इस्तेमाल किए जाने वाले JVM को कॉन्फ़िगर करना

Bazel, कंपाइलेशन के लिए एक JDK और कोड को चलाने और उसकी जांच करने के लिए एक JVM का इस्तेमाल करता है.

डिफ़ॉल्ट रूप से, Bazel डाउनलोड किए गए JDK का इस्तेमाल करके कोड को कंपाइल करता है. साथ ही, यह लोकल मशीन पर इंस्टॉल किए गए JVM की मदद से कोड को चलाता है और उसकी जांच करता है. Bazel, JAVA_HOME या पाथ का इस्तेमाल करके JVM खोजता है.

इससे जनरेट हुई बाइनरी, सिस्टम लाइब्रेरी में स्थानीय तौर पर इंस्टॉल किए गए JVM के साथ काम करती हैं. इसका मतलब है कि बाइनरी इस बात पर निर्भर करती हैं कि मशीन पर क्या इंस्टॉल किया गया है.

प्रोग्राम को चलाने और टेस्ट करने के लिए इस्तेमाल किए जाने वाले JVM को कॉन्फ़िगर करने के लिए, --java_runtime_version फ़्लैग का इस्तेमाल करें. डिफ़ॉल्ट वैल्यू local_jdk है.

हर्मेटिक टेस्टिंग और कंपाइलेशन

हेर्मेटिक कंपाइल बनाने के लिए, कमांड लाइन फ़्लैग --java_runtime_version=remotejdk_11 का इस्तेमाल किया जा सकता है. कोड को किसी रिमोट रिपॉज़िटरी से डाउनलोड किए गए जेवीएम के लिए, कॉम्पाइल किया जाता है, चलाया जाता है, और उसका परीक्षण किया जाता है. ज़्यादा जानकारी के लिए, Java रनटाइम वर्शन फ़्लैग देखें.

Java में, बिल्ड टूल के कंपाइलेशन और एक्सीक्यूशन को कॉन्फ़िगर करना

टूल बनाने और उन्हें चलाने के लिए, JDK और JVM का एक दूसरा पेयर इस्तेमाल किया जाता है. इसका इस्तेमाल, बिल्ड करने की प्रोसेस में किया जाता है, लेकिन बिल्ड के नतीजों में नहीं. JDK और JVM को --tool_java_language_version और --tool_java_runtime_version का इस्तेमाल करके कंट्रोल किया जाता है. इनकी डिफ़ॉल्ट वैल्यू 11 और remotejdk_11 होती हैं.

स्थानीय तौर पर इंस्टॉल किए गए JDK का इस्तेमाल करके कंपाइल करना

Bazel, डिफ़ॉल्ट रूप से रिमोट JDK का इस्तेमाल करके कॉम्पाइल करता है, क्योंकि यह JDK के अंदरूनी हिस्सों को बदल रहा है. डिवाइस पर इंस्टॉल किए गए JDK का इस्तेमाल करने वाले कंपाइलेशन टूलचेन कॉन्फ़िगर किए जाते हैं. हालांकि, उनका इस्तेमाल नहीं किया जाता.

स्थानीय तौर पर इंस्टॉल किए गए JDK का इस्तेमाल करके, कॉम्पाइल करने के लिए, --extra_toolchains=@local_jdk//:all फ़्लैग का इस्तेमाल करें. ऐसा करने पर, स्थानीय JDK के लिए कॉम्पाइलेशन टूलचेन का इस्तेमाल किया जाएगा. हालांकि, ध्यान रखें कि यह किसी भी वेंडर के JDK पर काम नहीं कर सकता.

ज़्यादा जानकारी के लिए, Java टूलचेन कॉन्फ़िगर करना लेख पढ़ें.

सबसे सही तरीके

Bazel के इस्तेमाल के सबसे सही सामान्य तरीकों के अलावा, यहां Java प्रोजेक्ट के लिए सबसे सही तरीके बताए गए हैं.

डायरेक्ट्री का स्ट्रक्चर

Maven के स्टैंडर्ड डायरेक्ट्री लेआउट का इस्तेमाल करें (src/main/java में सोर्स, src/test/java में टेस्ट).

BUILD फ़ाइलें

BUILD फ़ाइलें बनाते समय इन दिशा-निर्देशों का पालन करें:

  • Java सोर्स वाली हर डायरेक्ट्री के लिए एक BUILD फ़ाइल का इस्तेमाल करें, क्योंकि इससे बाइल्ड की परफ़ॉर्मेंस बेहतर होती है.

  • हर BUILD फ़ाइल में एक java_library नियम होना चाहिए, जो इस तरह दिखता है:

    java_library(
        name = "directory-name",
        srcs = glob(["*.java"]),
        deps = [...],
    )
    
  • लाइब्रेरी का नाम, उस डायरेक्ट्री का नाम होना चाहिए जिसमें BUILD फ़ाइल मौजूद है. इससे लाइब्रेरी का लेबल छोटा हो जाता है. इसका मतलब है कि "//package:package" के बजाय "//package" का इस्तेमाल करें.

  • सोर्स, डायरेक्ट्री में मौजूद सभी Java फ़ाइलों के लिए, glob नॉन-रीकर्सिव होने चाहिए.

  • टेस्ट, src/test में मौजूद मैच करने वाली डायरेक्ट्री में होने चाहिए और इस लाइब्रेरी पर निर्भर होने चाहिए.

बेहतर Java बिल्ड के लिए नए नियम बनाना

ध्यान दें: नए नियम बनाने की सुविधा, बेहतर तरीके से बनाने और टेस्ट करने के लिए है. Bazel का इस्तेमाल शुरू करने के लिए, आपको इसकी ज़रूरत नहीं है.

Java प्रोजेक्ट बनाते समय, नीचे दिए गए मॉड्यूल, कॉन्फ़िगरेशन फ़्रैगमेंट, और प्रोवाइडर की मदद से, Bazel की सुविधाओं को बढ़ाया जा सकता है:

Java टूलचेन को कॉन्फ़िगर करना

Bazel, दो तरह के Java टूलचैन का इस्तेमाल करता है: - एक्सीक्यूशन, जिसका इस्तेमाल Java बाइनरी को चलाने और उनकी जांच करने के लिए किया जाता है. इसे --java_runtime_version फ़्लैग से कंट्रोल किया जाता है - कंपाइलेशन, जिसका इस्तेमाल Java सोर्स को कंपाइल करने के लिए किया जाता है. इसे --java_language_version फ़्लैग से कंट्रोल किया जाता है

अतिरिक्त प्रोग्राम चलाने के टूलचेन कॉन्फ़िगर करना

एक्सीक्यूशन टूलचेन, JVM होता है. यह स्थानीय या किसी रिपॉज़िटरी से हो सकता है. इसमें इसके वर्शन, ऑपरेटिंग सिस्टम, और सीपीयू आर्किटेक्चर के बारे में कुछ अतिरिक्त जानकारी होती है.

मॉड्यूल एक्सटेंशन में local_java_repository या remote_java_repository रेपो नियमों का इस्तेमाल करके, Java एक्सीक्यूशन टूलचेन जोड़े जा सकते हैं. नियम जोड़ने पर, एक फ़्लैग का इस्तेमाल करके JVM उपलब्ध हो जाता है. जब एक ही ऑपरेटिंग सिस्टम और सीपीयू आर्किटेक्चर के लिए कई परिभाषाएं दी जाती हैं, तो पहली परिभाषा का इस्तेमाल किया जाता है.

लोकल JVM के कॉन्फ़िगरेशन का उदाहरण:

load("@rules_java//toolchains:local_java_repository.bzl", "local_java_repository")

local_java_repository(
  name = "additionaljdk",          # Can be used with --java_runtime_version=additionaljdk, --java_runtime_version=11 or --java_runtime_version=additionaljdk_11
  version = 11,                    # Optional, if not set it is autodetected
  java_home = "/usr/lib/jdk-15/",  # Path to directory containing bin/java
)

रिमोट JVM के कॉन्फ़िगरेशन का उदाहरण:

load("@rules_java//toolchains:remote_java_repository.bzl", "remote_java_repository")

remote_java_repository(
  name = "openjdk_canary_linux_arm",
  prefix = "openjdk_canary", # Can be used with --java_runtime_version=openjdk_canary_11
  version = "11",            # or --java_runtime_version=11
  target_compatible_with = [ # Specifies constraints this JVM is compatible with
    "@platforms//cpu:arm",
    "@platforms//os:linux",
  ],
  urls = ...,               # Other parameters are from http_repository rule.
  sha256 = ...,
  strip_prefix = ...
)

अतिरिक्त कंपाइलेशन टूलचेन कॉन्फ़िगर करना

कंपाइलेशन टूलचेन में JDK और कई टूल होते हैं. Bazel, कंपाइलेशन के दौरान इनका इस्तेमाल करता है. साथ ही, ये टूल अन्य सुविधाएं भी देते हैं. जैसे: गड़बड़ी होने की संभावना, सख्त Java डिपेंडेंसी, हेडर कंपाइलेशन, Android डिसुगरिंग, कवरेज इंस्ट्रूमेंटेशन, और IDE के लिए genclass मैनेजमेंट.

JavaBuilder, Bazel के साथ बंडल किया गया एक टूल है. यह कंपाइलेशन को पूरा करता है और ऊपर बताई गई सुविधाएं देता है. असल कंपाइलेशन, JDK के इंटरनल कंपाइलर का इस्तेमाल करके किया जाता है. कंपाइल करने के लिए इस्तेमाल किए गए JDK की जानकारी, टूलचेन के java_runtime एट्रिब्यूट से मिलती है.

Bazel, JDK के कुछ इंटरनल को बदल देता है. JDK के 9 से ज़्यादा वर्शन के मामले में, java.compiler और jdk.compiler मॉड्यूल को JDK के फ़्लैग --patch_module का इस्तेमाल करके पैच किया जाता है. JDK वर्शन 8 के मामले में, -Xbootclasspath फ़्लैग का इस्तेमाल करके Java कंपाइलर को पैच किया जाता है.

VanillaJavaBuilder, JavaBuilder का दूसरा वर्शन है. इसमें JDK के इंटरनल कंपाइलर में कोई बदलाव नहीं किया जाता. साथ ही, इसमें कोई अतिरिक्त सुविधा भी नहीं होती. VanillaJavaBuilder का इस्तेमाल, पहले से मौजूद किसी भी टूलचैन से नहीं किया जाता.

JavaBuilder के अलावा, Bazel कंपाइलेशन के दौरान कई अन्य टूल का इस्तेमाल करता है.

ijar टूल, कॉल साइनैचर को छोड़कर बाकी सभी चीज़ों को हटाने के लिए, jar फ़ाइलों को प्रोसेस करता है. इस प्रोसेस के बाद बनने वाले कंटेनर को हेडर कंटेनर कहा जाता है. इनका इस्तेमाल, किसी फ़ंक्शन के मुख्य हिस्से में बदलाव होने पर, सिर्फ़ डाउनस्ट्रीम डिपेंडेंट को फिर से कंपाइल करके, कंपाइलेशन इंक्रीमेंटलिटी को बेहतर बनाने के लिए किया जाता है.

singlejar टूल, कई jar फ़ाइलों को एक ही फ़ाइल में पैक करता है.

genclass टूल, Java कंपाइलेशन के आउटपुट को पोस्ट-प्रोसेस करता है और एक ऐसा jar बनाता है जिसमें सिर्फ़ उन सोर्स की क्लास फ़ाइलें होती हैं जिन्हें एनोटेशन प्रोसेसर से जनरेट किया गया था.

JacocoRunner टूल, इंस्ट्रूमेंट की गई फ़ाइलों पर Jacoco चलाता है और नतीजों को LCOV फ़ॉर्मैट में दिखाता है.

TestRunner टूल, कंट्रोल किए गए एनवायरमेंट में JUnit 4 टेस्ट चलाता है.

BUILD फ़ाइल में default_java_toolchain मैक्रो जोड़कर और MODULE.bazel फ़ाइल में register_toolchains नियम जोड़कर या --extra_toolchains फ़्लैग का इस्तेमाल करके, कंपाइलेशन को फिर से कॉन्फ़िगर किया जा सकता है.

टूलचेन का इस्तेमाल सिर्फ़ तब किया जाता है, जब source_version एट्रिब्यूट की वैल्यू, --java_language_version फ़्लैग की बताई गई वैल्यू से मैच होती है.

टूलचेन कॉन्फ़िगरेशन का उदाहरण:

load(
  "@rules_java//toolchains:default_java_toolchain.bzl",
  "default_java_toolchain", "DEFAULT_TOOLCHAIN_CONFIGURATION", "BASE_JDK9_JVM_OPTS", "DEFAULT_JAVACOPTS"
)

default_java_toolchain(
  name = "repository_default_toolchain",
  configuration = DEFAULT_TOOLCHAIN_CONFIGURATION,        # One of predefined configurations
                                                          # Other parameters are from java_toolchain rule:
  java_runtime = "@rules_java//toolchains:remote_jdk11", # JDK to use for compilation and toolchain's tools execution
  jvm_opts = BASE_JDK9_JVM_OPTS + ["--enable_preview"],   # Additional JDK options
  javacopts = DEFAULT_JAVACOPTS + ["--enable_preview"],   # Additional javac options
  source_version = "9",
)

इसका इस्तेमाल --extra_toolchains=//:repository_default_toolchain_definition का इस्तेमाल करके किया जा सकता है या वर्कस्पेस में register_toolchains("//:repository_default_toolchain_definition") जोड़कर किया जा सकता है.

पहले से तय किए गए कॉन्फ़िगरेशन:

  • DEFAULT_TOOLCHAIN_CONFIGURATION: सभी सुविधाएं, JDK के 9 और उसके बाद के वर्शन के साथ काम करता है
  • VANILLA_TOOLCHAIN_CONFIGURATION: कोई अतिरिक्त सुविधा नहीं है. यह किसी भी वेंडर के JDK के साथ काम करता है.
  • PREBUILT_TOOLCHAIN_CONFIGURATION: डिफ़ॉल्ट सेटिंग जैसा ही, लेकिन सिर्फ़ पहले से बने टूल (ijar, singlejar) का इस्तेमाल करें
  • NONPREBUILT_TOOLCHAIN_CONFIGURATION: डिफ़ॉल्ट के तौर पर सेट की गई वैल्यू के जैसे ही, लेकिन सभी टूल सोर्स से बनाए गए हैं. यह अलग-अलग libc वाले ऑपरेटिंग सिस्टम पर काम का हो सकता है

JVM और Java कंपाइलर फ़्लैग कॉन्फ़िगर करना

JVM और javac फ़्लैग को फ़्लैग या default_java_toolchain एट्रिब्यूट की मदद से कॉन्फ़िगर किया जा सकता है.

काम के फ़्लैग ये हैं: --jvmopt, --host_jvmopt, --javacopt, और --host_javacopt.

default_java_toolchain एट्रिब्यूट के लिए, javacopts, jvm_opts, javabuilder_jvm_opts, और turbine_jvm_opts का इस्तेमाल किया जा सकता है.

पैकेज के हिसाब से Java कंपाइलर फ़्लैग का कॉन्फ़िगरेशन

default_java_toolchain के package_configuration एट्रिब्यूट का इस्तेमाल करके, चुनिंदा सोर्स फ़ाइलों के लिए अलग-अलग Java कंपाइलर फ़्लैग कॉन्फ़िगर किए जा सकते हैं. कृपया नीचे दिया गया उदाहरण देखें.

load("@rules_java//toolchains:default_java_toolchain.bzl", "default_java_toolchain")

# This is a convenience macro that inherits values from Bazel's default java_toolchain
default_java_toolchain(
    name = "toolchain",
    package_configuration = [
        ":error_prone",
    ],
    visibility = ["//visibility:public"],
)

# This associates a set of javac flags with a set of packages
java_package_configuration(
    name = "error_prone",
    javacopts = [
        "-Xep:MissingOverride:ERROR",
    ],
    packages = ["error_prone_packages"],
)

# This is a regular package_group, which is used to specify a set of packages to apply flags to
package_group(
    name = "error_prone_packages",
    packages = [
        "//foo/...",
        "-//foo/bar/...", # this is an exclusion
    ],
)

एक ही रिपॉज़िटरी में Java सोर्स कोड के कई वर्शन

Bazel, किसी बिल्ड में Java सोर्स के सिर्फ़ एक वर्शन को कंपाइल करने की सुविधा देता है. build. इसका मतलब है कि Java टेस्ट या ऐप्लिकेशन बनाते समय, सभी डिपेंडेंसी एक ही Java वर्शन के हिसाब से बनाई जाती हैं.

हालांकि, अलग-अलग फ़्लैग का इस्तेमाल करके अलग-अलग बिल्ड चलाए जा सकते हैं.

अलग-अलग फ़्लैग का इस्तेमाल आसान बनाने के लिए, किसी खास वर्शन के फ़्लैग के सेट को .bazelrc कॉन्फ़िगरेशन" के साथ ग्रुप किया जा सकता है:

build:java8 --java_language_version=8
build:java8 --java_runtime_version=local_jdk_8
build:java11 --java_language_version=11
build:java11 --java_runtime_version=remotejdk_11

इन कॉन्फ़िगरेशन का इस्तेमाल --config फ़्लैग के साथ किया जा सकता है. उदाहरण के लिए, bazel test --config=java11 //:java11_test.