इस ट्यूटोरियल में Baज़ल की मदद से, Java ऐप्लिकेशन बनाने की बुनियादी जानकारी दी गई है. आपको अपना फ़ाइल फ़ोल्डर सेट अप करना होगा और एक आसान Java प्रोजेक्ट बनाना होगा, जो
Baज़ल के मुख्य सिद्धांतों, जैसे कि टारगेट और BUILD
फ़ाइलों को दिखाता है.
पूरा होने का अनुमानित समय: 30 मिनट.
आप इन चीज़ों के बारे में जानेंगे
इस ट्यूटोरियल में आपको ये काम करने का तरीका पता चलेगा:
- कोई टारगेट बनाएं
- प्रोजेक्ट की डिपेंडेंसी को विज़ुअलाइज़ करना
- प्रोजेक्ट को कई टारगेट और पैकेज में बांटें
- सभी पैकेज में टारगेट विज़िबिलिटी को कंट्रोल करें
- लेबल के ज़रिए संदर्भ लक्ष्य
- टारगेट डिप्लॉय करना
वेब कंटेनर इंस्टॉल करने से पहले
Basel इंस्टॉल करें
ट्यूटोरियल के लिए तैयार होने के लिए, अगर आपने पहले से Basel को इंस्टॉल करें नहीं है, तो उसे इंस्टॉल करें.
JDK इंस्टॉल करें
Java JDK इंस्टॉल करें (पसंदीदा वर्शन 11 है, हालांकि 8 और 15 के बीच के वर्शन काम करते हैं).
JDK पर पॉइंट करने के लिए, JAVA_HOME एनवायरमेंट वैरिएबल को सेट करें.
Linux/macOS पर:
export JAVA_HOME="$(dirname $(dirname $(realpath $(which javac))))"
Windows पर:
- कंट्रोल पैनल खोलें.
- "सिस्टम और सुरक्षा" > "सिस्टम" > "बेहतर सिस्टम सेटिंग" > "बेहतर" टैब > "एनवायरमेंट वैरिएबल..." पर जाएं .
- "उपयोगकर्ता वैरिएबल" सूची (सबसे ऊपर मौजूद) में, "नया..." पर क्लिक करें.
- "वैरिएबल का नाम" फ़ील्ड में,
JAVA_HOME
डालें. - "डायरेक्ट्री ब्राउज़ करें..." पर क्लिक करें.
- JDK डायरेक्ट्री पर जाएं (जैसे,
C:\Program Files\Java\jdk1.8.0_152
). - सभी डायलॉग विंडो में "ठीक है" पर क्लिक करें.
सैंपल प्रोजेक्ट डाउनलोड करें
Baज़ल के GitHub रिपॉज़िटरी से सैंपल प्रोजेक्ट को वापस पाएं:
git clone https://github.com/bazelbuild/examples
इस ट्यूटोरियल के लिए सैंपल प्रोजेक्ट, examples/java-tutorial
डायरेक्ट्री में है और इसे इस तरह बनाया गया है:
java-tutorial
├── BUILD
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ ├── cmdline
│ │ ├── BUILD
│ │ └── Runner.java
│ ├── Greeting.java
│ └── ProjectRunner.java
└── WORKSPACE
बेज़ल के साथ बिल्ड
फ़ाइल फ़ोल्डर सेट अप करना
प्रोजेक्ट बनाने से पहले, आपको उसका फ़ाइल फ़ोल्डर सेट अप करना होगा. वर्कस्पेस एक डायरेक्ट्री होती है, जिसमें आपके प्रोजेक्ट की सोर्स फ़ाइलें और बेज़ल के बिल्ड आउटपुट मौजूद होते हैं. इसमें ऐसी फ़ाइलें भी शामिल होती हैं जिन्हें Basel ने खास के तौर पर पहचाना है:
यह
WORKSPACE
फ़ाइल, डायरेक्ट्री और उसके कॉन्टेंट की पहचान बेज़ल वर्कस्पेस के तौर पर करती है. साथ ही, यह प्रोजेक्ट की डायरेक्ट्री स्ट्रक्चर के रूट में रहती है,एक या एक से ज़्यादा
BUILD
फ़ाइलें, जो Basel को प्रोजेक्ट के अलग-अलग हिस्से बनाने का तरीका बताती हैं. (फ़ाइल फ़ोल्डर में मौजूद वह डायरेक्ट्री जिसमेंBUILD
फ़ाइल होती है, वह एक पैकेज होता है. इस ट्यूटोरियल में आपको बाद में पैकेज के बारे में जानकारी दी जाएगी.)
किसी डायरेक्ट्री को Baज़ल फ़ाइल फ़ोल्डर के तौर पर तय करने के लिए, उस डायरेक्ट्री में WORKSPACE
नाम की एक खाली फ़ाइल बनाएं.
जब Basel का प्रोजेक्ट बनाया गया हो, तब सभी इनपुट और डिपेंडेंसी एक ही फ़ाइल फ़ोल्डर में होनी चाहिए. अलग-अलग फ़ाइल फ़ोल्डर में मौजूद फ़ाइलें, एक-दूसरे से अलग होती हैं. हालांकि, अगर उन्हें लिंक नहीं किया जाता है, तो ये फ़ाइलें इस ट्यूटोरियल में शामिल नहीं हैं.
BUILD फ़ाइल को समझें
BUILD
फ़ाइल में Basel के लिए कई अलग-अलग तरह के निर्देश होते हैं.
सबसे ज़रूरी टाइप बिल्ड नियम है, जो बेज़ल को मनचाहा आउटपुट बनाने का तरीका बताता है. जैसे, एक्ज़ीक्यूटेबल बाइनरी या लाइब्रेरी. BUILD
फ़ाइल में बिल्ड नियम के हर इंस्टेंस को टारगेट कहा जाता है. यह सोर्स फ़ाइलों और डिपेंडेंसी के खास सेट के बारे में बताता है. कोई टारगेट दूसरे टारगेट
को भी पॉइंट कर सकता है.
java-tutorial/BUILD
फ़ाइल पर एक नज़र डालें:
java_binary(
name = "ProjectRunner",
srcs = glob(["src/main/java/com/example/*.java"]),
)
हमारे उदाहरण में, ProjectRunner
टारगेट, Basel के बिल्ट-इन
java_binary
नियम को इंस्टैंशिएट करता है. यह नियम, बेज़ल को .jar
फ़ाइल और एक रैपर शेल स्क्रिप्ट (दोनों का नाम टारगेट के नाम पर रखा गया है) बनाने के लिए कहता है.
टारगेट में मौजूद एट्रिब्यूट, इसकी निर्भरता और विकल्पों के बारे में साफ़ तौर पर बताते हैं.
name
एट्रिब्यूट ज़रूरी है, लेकिन कई एट्रिब्यूट ज़रूरी नहीं हैं. उदाहरण के लिए, ProjectRunner
नियम के टारगेट में name
, टारगेट का नाम है. srcs
उन सोर्स फ़ाइलों के बारे में बताता है जिनका इस्तेमाल Baze टारगेट बनाने के लिए करता है. main_class
, मुख्य तरीके वाली क्लास के बारे में बताता है. (आपने देखा होगा कि हमारे उदाहरण में, सोर्स फ़ाइलों को एक-एक करके दिखाने के बजाय, सोर्स फ़ाइलों के एक सेट को Baze में भेजने के लिए ग्लोब का इस्तेमाल किया गया है.
प्रोजेक्ट बनाएं
सैंपल प्रोजेक्ट बनाने के लिए, java-tutorial
डायरेक्ट्री पर जाएं और यह चलाकर देखें:
bazel build //:ProjectRunner
टारगेट लेबल में, //
वाला हिस्सा, फ़ाइल फ़ोल्डर के रूट के मुताबिक BUILD
फ़ाइल की जगह होता है (इस मामले में, रूट खुद) और BUILD
फ़ाइल में टारगेट का नाम ProjectRunner
है. (इस ट्यूटोरियल के आखिर में, आप टारगेट लेबल के बारे में ज़्यादा जानेंगे.)
Baज़ल, इस तरह के आउटपुट देता है:
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
बधाई हो, आपने अभी-अभी अपना पहला Bagel टारगेट बनाया है! Baज़र, बिल्ड
आउटपुट को फ़ाइल फ़ोल्डर के रूट में मौजूद bazel-bin
डायरेक्ट्री में सेव करता है. इसके कॉन्टेंट को ब्राउज़ करें और इसके आउटपुट के बारे में ज़्यादा जानकारी पाएं.
अब अपनी हाल ही में बनाई गई बाइनरी की जांच करें:
bazel-bin/ProjectRunner
डिपेंडेंसी ग्राफ़ देखें
Basel के लिए बिल्ड डिपेंडेंसी का इस्तेमाल, BUILD फ़ाइलों में साफ़ तौर पर करना ज़रूरी होता है. Baज़ल, प्रोजेक्ट का डिपेंडेंसी ग्राफ़ बनाने के लिए इन स्टेटमेंट का इस्तेमाल करता है. इससे इंक्रीमेंटल बिल्ड सही तरीके से चालू होता है.
सैंपल प्रोजेक्ट की डिपेंडेंसी को विज़ुअलाइज़ करने के लिए, Workspace के रूट पर इस कमांड को चलाकर, डिपेंडेंसी ग्राफ़ को टेक्स्ट के तौर पर दिखाया जा सकता है:
bazel query --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph
ऊपर दिया गया निर्देश, Basel को टारगेट //:ProjectRunner
(होस्ट और इंप्लिसिट डिपेंडेंसी को छोड़कर) के लिए सभी डिपेंडेंसी खोजने के लिए कहता है और आउटपुट को ग्राफ़ के तौर पर फ़ॉर्मैट करता है.
इसके बाद, टेक्स्ट को GraphViz में चिपकाएं.
जैसा कि आपको दिख रहा है, प्रोजेक्ट का एक ही टारगेट है, जो दो सोर्स फ़ाइलें बनाता है और इन पर किसी अन्य डिपेंडेंसी का इस्तेमाल नहीं किया जाता:
अपना फ़ाइल फ़ोल्डर सेट अप करने, अपना प्रोजेक्ट बनाने, और उसकी डिपेंडेंसी की जांच करने के बाद, कुछ मुश्किलें जोड़ी जा सकती हैं.
अपने Basel के बिल्ड को बेहतर बनाएं
छोटे प्रोजेक्ट के लिए सिर्फ़ एक टारगेट काफ़ी होता है. हालांकि, हो सकता है कि आप बड़े प्रोजेक्ट को कई टारगेट और पैकेज में बांटना चाहें, ताकि तेज़ी से इंक्रीमेंटल बिल्ड बनाने में मदद मिल सके. इसका मतलब है कि सिर्फ़ उन प्रोजेक्ट को दोबारा बनाना चाहिए जिनमें बदलाव हुआ है. साथ ही, प्रोजेक्ट के कई हिस्सों को एक साथ बनाकर तेज़ी से बिल्ड किया जा सकता है.
कई बिल्ड टारगेट तय करें
सैंपल प्रोजेक्ट के बिल्ड को दो टारगेट में बांटा जा सकता है. java-tutorial/BUILD
फ़ाइल के कॉन्टेंट को इनसे बदलें:
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"],
)
इस कॉन्फ़िगरेशन के साथ, Bagel पहले greeter
लाइब्रेरी बनाता है. इसके बाद, ProjectRunner
बाइनरी बनाता है. java_binary
में deps
एट्रिब्यूट से बेज़ल को पता चलता है कि
ProjectRunner
बाइनरी बनाने के लिए greeter
लाइब्रेरी ज़रूरी है.
प्रोजेक्ट के इस नए वर्शन को बनाने के लिए, यह कमांड चलाएं:
bazel build //:ProjectRunner
Baज़ल, इस तरह के आउटपुट देता है:
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
अब अपनी हाल ही में बनाई गई बाइनरी की जांच करें:
bazel-bin/ProjectRunner
अगर अब ProjectRunner.java
में बदलाव किया जाता है और प्रोजेक्ट को फिर से बनाया जाता है, तो Baze, सिर्फ़
उस फ़ाइल को फिर से कंपाइल करता है.
डिपेंडेंसी ग्राफ़ में देखने पर, पता चलता है कि ProjectRunner
उन इनपुट पर निर्भर है जो पहले थे. हालांकि, बिल्ड का स्ट्रक्चर अलग है:
अब आपने दो टारगेट के साथ प्रोजेक्ट बना लिया है. ProjectRunner
टारगेट, दो सोर्स फ़ाइलें बनाता है और एक अन्य टारगेट (:greeter
) पर निर्भर करता है. यह टारगेट एक अतिरिक्त सोर्स फ़ाइल बनाता है.
एक से ज़्यादा पैकेज का इस्तेमाल करें
अब प्रोजेक्ट को कई पैकेज में बांट लें. src/main/java/com/example/cmdline
डायरेक्ट्री को देखने पर, आपको पता चल जाएगा कि इसमें एक BUILD
फ़ाइल के साथ-साथ, कुछ सोर्स फ़ाइलें भी मौजूद हैं. इसलिए, Basel के लिए, फ़ाइल फ़ोल्डर में अब दो पैकेज शामिल हैं, //src/main/java/com/example/cmdline
और //
(क्योंकि फ़ाइल फ़ोल्डर के रूट में एक BUILD
फ़ाइल मौजूद है).
src/main/java/com/example/cmdline/BUILD
फ़ाइल पर एक नज़र डालें:
java_binary(
name = "runner",
srcs = ["Runner.java"],
main_class = "com.example.cmdline.Runner",
deps = ["//:greeter"],
)
runner
टारगेट, //
पैकेज में मौजूद greeter
टारगेट पर निर्भर करता है. इसलिए, टारगेट लेबल //:greeter
है - इसकी जानकारी बेज़ल, deps
एट्रिब्यूट के ज़रिए देते हैं.
डिपेंडेंसी ग्राफ़ पर एक नज़र डालें:
हालांकि, बिल्ड को सफल बनाने के लिए, आपको visibility
एट्रिब्यूट का इस्तेमाल करके, //BUILD
में मौजूद टारगेट को //src/main/java/com/example/cmdline/BUILD
में दिखने वाला runner
टारगेट साफ़ तौर पर देना होगा. ऐसा इसलिए होता है, क्योंकि डिफ़ॉल्ट रूप से टारगेट
सिर्फ़ उसी BUILD
फ़ाइल में मौजूद दूसरे टारगेट को दिखते हैं. (Bazz, टारगेट की मदद से विज़िबिलिटी का इस्तेमाल करता है. इससे पब्लिक एपीआई में ले जाने वाली लाइब्रेरी जैसी समस्याओं से बचा जा सकता है. जैसे, लागू करने की जानकारी वाली लाइब्रेरी.)
ऐसा करने के लिए, java-tutorial/BUILD
में greeter
टारगेट में visibility
एट्रिब्यूट जोड़ें, जैसा कि यहां दिखाया गया है:
java_library(
name = "greeter",
srcs = ["src/main/java/com/example/Greeting.java"],
visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
)
अब फ़ाइल फ़ोल्डर के रूट में यहां दिया गया कमांड चलाकर, नया पैकेज बनाया जा सकता है:
bazel build //src/main/java/com/example/cmdline:runner
Baज़ल, इस तरह के आउटपुट देता है:
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
अब अपनी हाल ही में बनाई गई बाइनरी की जांच करें:
./bazel-bin/src/main/java/com/example/cmdline/runner
अब आपने दो पैकेज बनाने के लिए, प्रोजेक्ट में बदलाव किया है. हर पैकेज में एक टारगेट है और यह उनके बीच की डिपेंडेंसी को समझता है.
टारगेट का रेफ़रंस देने के लिए लेबल का इस्तेमाल करना
BUILD
फ़ाइलों और कमांड लाइन में, Baze, टारगेट को रेफ़रंस देने के लिए टारगेट लेबल का इस्तेमाल करता है - उदाहरण के लिए, //:ProjectRunner
या
//src/main/java/com/example/cmdline:runner
. उनका सिंटैक्स इस तरह है:
//path/to/package:target-name
अगर टारगेट, किसी नियम का टारगेट है, तो path/to/package
उस डायरेक्ट्री का पाथ होता है जिसमें BUILD
फ़ाइल होती है. आपने BUILD
फ़ाइल में टारगेट को target-name
कहा है (name
एट्रिब्यूट). अगर टारगेट एक फ़ाइल टारगेट है, तो path/to/package
पैकेज के रूट का पाथ होता है. साथ ही, target-name
टारगेट फ़ाइल का नाम होता है, जिसमें इसका पूरा पाथ भी शामिल होता है.
रिपॉज़िटरी रूट पर टारगेट का रेफ़रंस देते समय, पैकेज पाथ खाली होता है.
बस //:target-name
का इस्तेमाल करें. एक ही BUILD
फ़ाइल में टारगेट का रेफ़रंस देते समय, //
फ़ाइल फ़ोल्डर के रूट आइडेंटिफ़ायर को स्किप किया जा सकता है और सिर्फ़ :target-name
का इस्तेमाल किया जा सकता है.
उदाहरण के लिए, java-tutorial/BUILD
फ़ाइल में मौजूद टारगेट के लिए, आपको पैकेज पाथ बताने की ज़रूरत नहीं है. इसकी वजह यह है कि फ़ाइल फ़ोल्डर रूट खुद एक पैकेज (//
) है. आपके दो टारगेट लेबल सिर्फ़ //:ProjectRunner
और //:greeter
थे.
हालांकि, //src/main/java/com/example/cmdline/BUILD
फ़ाइल में मौजूद टारगेट के लिए, आपको //src/main/java/com/example/cmdline
का पूरा पैकेज पाथ बताना था. साथ ही, आपका टारगेट लेबल //src/main/java/com/example/cmdline:runner
था.
डिप्लॉयमेंट के लिए Java टारगेट पैकेज करना
आइए, अब Java टारगेट को डिप्लॉय करने के लिए, बाइनरी बनाकर उसे सभी रनटाइम डिपेंडेंसी के साथ पैकेज करते हैं. इससे आप बाइनरी को अपने डेवलपमेंट एनवायरमेंट के बाहर चला सकते हैं.
जैसा कि आपको याद है, java_binary बिल्ड नियम .jar
और एक रैपर शेल स्क्रिप्ट बनाता है. इस निर्देश का इस्तेमाल करके, runner.jar
के कॉन्टेंट को देखें:
jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar
कॉन्टेंट हैं:
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
runner.jar
में Runner.class
शामिल है, लेकिन यह इस पर डिपेंडेंसी नहीं है
Greeting.class
. Basel की जनरेट की गई runner
स्क्रिप्ट, क्लासपाथ में greeter.jar
जोड़ती है. इसलिए, अगर उसे ऐसे ही छोड़ा जाता है, तो यह लोकल तौर पर चलेगा, लेकिन किसी दूसरी मशीन पर स्टैंडअलोन नहीं चलेगा. अच्छी बात यह है कि java_binary
नियम
की मदद से, अपने-आप में पूरी और डिप्लॉय की जा सकने वाली बाइनरी बनाई जा सकती है. इसे बनाने के लिए, टारगेट के नाम में
_deploy.jar
को जोड़ें:
bazel build //src/main/java/com/example/cmdline:runner_deploy.jar
Baज़ल, इस तरह के आउटपुट देता है:
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
आपने अभी-अभी runner_deploy.jar
बनाया है. इसे डेवलपमेंट एनवायरमेंट से अलग चलाया जा सकता है, क्योंकि इसमें ज़रूरी रनटाइम डिपेंडेंसी होती हैं. पहले वाले निर्देश का इस्तेमाल करके, इस स्टैंडअलोन JAR के कॉन्टेंट को देखें:
jar tf bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
कॉन्टेंट में सभी ज़रूरी क्लास के बारे में बताया गया है:
META-INF/
META-INF/MANIFEST.MF
build-data.properties
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
com/example/Greeting.class
इसके बारे में और पढ़ें
ज़्यादा जानकारी के लिए, यह देखें:
ट्रांज़िटिव Maven डिपेंडेंसी को मैनेज करने के नियमों के लिए rules_jvm_external का तरीका.
लोकल और रिमोट डेटा स्टोर करने की जगहों के साथ काम करने के बारे में ज़्यादा जानने के लिए, बाहरी डिपेंडेंसी.
बेज़ल के बारे में ज़्यादा जानने के लिए, अन्य नियम.
Basel के साथ C++ प्रोजेक्ट बनाना शुरू करने के लिए, C++ बिल्ड ट्यूटोरियल.
(Android ऐप्लिकेशन का ट्यूटोरियल और iOS ऐप्लिकेशन ट्यूटोरियल देखें).
बिल्डिंग बनाने के लिए शुभकामनाएं!