इस ट्यूटोरियल में, Bazel की मदद से Java ऐप्लिकेशन बनाने की बुनियादी बातें बताई गई हैं. आपको अपना फ़ाइल फ़ोल्डर सेट अप करना होगा और एक आसान Java प्रोजेक्ट बनाना होगा,
बेज़ेल के मुख्य सिद्धांतों की जानकारी देता है, जैसे कि टारगेट और BUILD
फ़ाइलें.
पूरा होने का अनुमानित समय: 30 मिनट.
आपको क्या सीखने को मिलेगा
इस ट्यूटोरियल में, आपको ये काम करने का तरीका पता चलेगा:
- कोई टारगेट बनाएं
- प्रोजेक्ट की डिपेंडेंसी को विज़ुअलाइज़ करना
- प्रोजेक्ट को कई टारगेट और पैकेज में बांटना
- सभी पैकेज में टारगेट विज़िबिलिटी को कंट्रोल करें
- लेबल के ज़रिए संदर्भ लक्ष्य
- टारगेट डिप्लॉय करना
शुरू करने से पहले
Bazel इंस्टॉल करना
ट्यूटोरियल की तैयारी करने के लिए, पहले 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
Bazel की मदद से बिल्ड करना
फ़ाइल फ़ोल्डर सेट अप करना
प्रोजेक्ट बनाने से पहले, आपको उसका वर्कस्पेस सेट अप करना होगा. वर्कस्पेस एक ऐसी डायरेक्ट्री होती है जिसमें आपके प्रोजेक्ट की सोर्स फ़ाइलें और Bazel के बिल्ड आउटपुट मौजूद होते हैं. इसमें ऐसी फ़ाइलें भी शामिल होती हैं जिन्हें Bazel खास मानता है:
WORKSPACE
फ़ाइल, जो डायरेक्ट्री और उसके कॉन्टेंट की पहचान बेज़ल वर्कस्पेस और प्रोजेक्ट की डायरेक्ट्री स्ट्रक्चर के मूल में मौजूद है,एक या एक से ज़्यादा
BUILD
फ़ाइलें, जो BaZ को बताती हैं कि ब्राउज़र के अलग-अलग हिस्सों को कैसे बनाना है प्रोजेक्ट. (फ़ाइल फ़ोल्डर में मौजूद वह डायरेक्ट्री जिसमेंBUILD
फ़ाइल होती है वह पैकेज होती है. आपको इस ट्यूटोरियल में पैकेज के बारे में बाद में जानकारी मिलेगी.)
किसी डायरेक्ट्री को बेज़ल वर्कस्पेस के तौर पर दिखाने के लिए, नाम की एक खाली फ़ाइल बनाएं
WORKSPACE
उस डायरेक्ट्री में मौजूद हैं.
जब Bazel प्रोजेक्ट बनाता है, तो सभी इनपुट और डिपेंडेंसी एक ही वर्कस्पेस में होनी चाहिए. अलग-अलग फ़ाइल फ़ोल्डर में मौजूद फ़ाइलें, एक से अलग होती हैं जब तक कि कोई अन्य प्लैटफ़ॉर्म लिंक न किया गया हो. इस ट्यूटोरियल में इनके बारे में बताया गया है.
BUILD फ़ाइल को समझना
BUILD
फ़ाइल में, Bazel के लिए कई तरह के निर्देश होते हैं.
सबसे ज़रूरी टाइप बिल्ड रूल है, जो बेज़ल को बताता है कि
एक्ज़ीक्यूट किए जा सकने वाले बाइनरी या लाइब्रेरी जैसे आउटपुट के लिए इस्तेमाल कर सकते हैं. हर इंस्टेंस
BUILD
फ़ाइल में बिल्ड नियम को टारगेट कहा जाता है और
सोर्स फ़ाइलों और डिपेंडेंसी के खास सेट का इस्तेमाल किया जा सकता है. टारगेट, दूसरे टारगेट पर भी ले जा सकता है.
java-tutorial/BUILD
फ़ाइल को देखें:
java_binary(
name = "ProjectRunner",
srcs = glob(["src/main/java/com/example/*.java"]),
)
हमारे उदाहरण में, ProjectRunner
टारगेट, Bazel के पहले से मौजूद
java_binary
नियम को लागू करता है. यह नियम, Bazel को .jar
फ़ाइल और रैपर शेल स्क्रिप्ट बनाने के लिए कहता है. दोनों का नाम टारगेट के नाम पर रखा जाता है.
टारगेट में मौजूद एट्रिब्यूट, उसकी डिपेंडेंसी और विकल्पों के बारे में साफ़ तौर पर बताते हैं.
name
एट्रिब्यूट ज़रूरी है, लेकिन कई एट्रिब्यूट ज़रूरी नहीं हैं. उदाहरण के लिए, ProjectRunner
नियम टारगेट में, name
टारगेट का नाम है, srcs
उन सोर्स फ़ाइलों के बारे में बताता है जिनका इस्तेमाल Bazel, टारगेट बनाने के लिए करता है, और main_class
उस क्लास के बारे में बताता है जिसमें मुख्य तरीका शामिल है. (आपने देखा होगा कि हमारा उदाहरण
स्रोत फ़ाइलों के सेट को Basel में भेजने के लिए, glob का इस्तेमाल करता है
उन्हें एक-एक करके दिखाने के बजाय.)
प्रोजेक्ट बनाएं
सैंपल प्रोजेक्ट बनाने के लिए, java-tutorial
डायरेक्ट्री पर जाएं
और चलाएं:
bazel build //:ProjectRunner
टारगेट लेबल में, //
वाला हिस्सा, BUILD
फ़ाइल की जगह होता है
फ़ाइल फ़ोल्डर के रूट से मिलता-जुलता है (इस मामले में, रूट).
और BUILD
फ़ाइल में टारगेट का नाम ProjectRunner
है. (इस ट्यूटोरियल के आखिर में, आपको टारगेट लेबल के बारे में ज़्यादा जानकारी मिलेगी.)
Bazel से मिलता-जुलता आउटपुट मिलता है:
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
बधाई हो, आपने अपना पहला Bazel टारगेट बना लिया है! बेज़ल जगहें बिल्ड
bazel-bin
डायरेक्ट्री के आउटपुट के लिए, फ़ाइल फ़ोल्डर के रूट पर जाएं. ब्राउज़ करें
इसके कॉन्टेंट से बेज़ल के आउटपुट स्ट्रक्चर के बारे में आइडिया जान पाया.
अब अपनी हाल ही में बनाई गई बाइनरी की जांच करें:
bazel-bin/ProjectRunner
डिपेंडेंसी ग्राफ़ की समीक्षा करना
Basel के लिए बिल्ड डिपेंडेंसी का इस्तेमाल, BUILD फ़ाइलों में साफ़ तौर पर करना ज़रूरी होता है. Bazel, प्रोजेक्ट का डिपेंडेंसी ग्राफ़ बनाने के लिए उन स्टेटमेंट का इस्तेमाल करता है. इससे, सटीक इंक्रीमेंटल बिल्ड की सुविधा मिलती है.
सैंपल प्रोजेक्ट की डिपेंडेंसी को विज़ुअलाइज़ करने के लिए, वर्कस्पेस के रूट में यह कमांड चलाकर, डिपेंडेंसी ग्राफ़ का टेक्स्ट वर्शन जनरेट किया जा सकता है:
bazel query --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph
ऊपर दिया गया निर्देश, Bazel को टारगेट //:ProjectRunner
के लिए सभी डिपेंडेंसी ढूंढने के लिए कहता है. इसमें होस्ट और इनपुट डिपेंडेंसी शामिल नहीं हैं. साथ ही, यह निर्देश आउटपुट को ग्राफ़ के तौर पर फ़ॉर्मैट करने के लिए भी कहता है.
इसके बाद, टेक्स्ट को GraphViz में चिपकाएं.
जैसा कि आपको दिख रहा है, प्रोजेक्ट का एक ही टारगेट है, जो कोई अतिरिक्त निर्भरता नहीं:
अपना वर्कस्पेस सेट अप करने, प्रोजेक्ट बनाने, और उसकी डिपेंडेंसी की जांच करने के बाद, कुछ जटिलताएं जोड़ी जा सकती हैं.
Bazel के ज़रिए बने अपने बिल्ड को बेहतर बनाना
छोटे प्रोजेक्ट के लिए एक ही टारगेट काफ़ी होता है. हालांकि, हो सकता है कि कई टारगेट और पैकेज के लिए बड़े प्रोजेक्ट को बनाया गया है. इससे इन प्रोजेक्ट को तेज़ी से बढ़ाने में मदद मिलती है बिल्ड (इसका मतलब है कि जो बदलाव हुए हैं उन्हें फिर से बनाएं) और एक ही बार में प्रोजेक्ट के कई हिस्से तैयार करना.
कई बिल्ड टारगेट तय करें
सैंपल प्रोजेक्ट के बिल्ड को दो टारगेट में बांटा जा सकता है. 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"],
)
इस कॉन्फ़िगरेशन के साथ, Basel सबसे पहले greeter
लाइब्रेरी बनाता है,
ProjectRunner
बाइनरी. java_binary
में मौजूद deps
एट्रिब्यूट से Bazel को पता चलता है कि ProjectRunner
बाइनरी बनाने के लिए, greeter
लाइब्रेरी की ज़रूरत है.
प्रोजेक्ट के इस नए वर्शन को बनाने के लिए, यह कमांड चलाएं:
bazel build //:ProjectRunner
Bazel से मिलता-जुलता आउटपुट मिलता है:
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
में बदलाव किया जाता है और प्रोजेक्ट को फिर से बनाया जाता है, तो सिर्फ़ Basel का इस्तेमाल किया जाएगा
उस फ़ाइल को फिर से कंपाइल करता है.
डिपेंडेंसी ग्राफ़ को देखकर, यह पता चलता है कि ProjectRunner
पहले की तरह ही इनपुट पर निर्भर करता है. हालांकि, बिल्ड का स्ट्रक्चर अलग है:
अब आपने दो टारगेट के साथ प्रोजेक्ट बना लिया है. ProjectRunner
टारगेट, दो सोर्स फ़ाइलें बनाता है और एक अन्य टारगेट (:greeter
) पर निर्भर करता है, जो एक और सोर्स फ़ाइल बनाता है.
एक से ज़्यादा पैकेज इस्तेमाल करना
अब प्रोजेक्ट को कई पैकेज में बांटते हैं. src/main/java/com/example/cmdline
डायरेक्ट्री में एक BUILD
फ़ाइल के साथ-साथ कुछ सोर्स फ़ाइलें भी मौजूद हैं. इसलिए, Bazel के लिए, फ़ाइल फ़ोल्डर में अब दो पैकेज, //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
) - Bazel को यह जानकारी deps
एट्रिब्यूट से मिलती है.
डिपेंडेंसी ग्राफ़ पर एक नज़र डालें:
हालांकि, बिल्ड को सफल बनाने के लिए, आपको साफ़ तौर पर runner
टारगेट देना होगा
में टारगेट के लिए, //src/main/java/com/example/cmdline/BUILD
विज़िबिलिटी में
visibility
एट्रिब्यूट का इस्तेमाल करके //BUILD
. ऐसा डिफ़ॉल्ट टारगेट से होता है
केवल उसी BUILD
फ़ाइल में मौजूद अन्य लक्ष्यों को दिखाई देते हैं. (बेज़ल टारगेट का इस्तेमाल करता है
ताकि लागू करने की जानकारी वाली लाइब्रेरी जैसी समस्याओं को रोका जा सके
सार्वजनिक एपीआई में लीक हो रहा है.)
ऐसा करने के लिए, यहां visibility
एट्रिब्यूट को greeter
टारगेट में जोड़ें
java-tutorial/BUILD
, जैसा कि नीचे दिखाया गया है:
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
Bazel से मिलता-जुलता आउटपुट मिलता है:
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
फ़ाइल मौजूद है. साथ ही, target-name
वह नाम है जिसे आपने BUILD
फ़ाइल में टारगेट (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
Bazel से मिलता-जुलता आउटपुट मिलता है:
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
इसके बारे में और पढ़ें
ज़्यादा जानकारी के लिए, यह देखें:
इसके लिए rules_jvm_external ये नियम, ट्रांज़िटिव Maven डिपेंडेंसी मैनेज करने के लिए बनाए गए हैं.
बाहरी डिपेंडेंसी के साथ काम करने के बारे में ज़्यादा जानने के लिए डेटा स्टोर करने की जगहों को स्थानीय और रिमोट तौर पर स्टोर कर सकता है.
Bazel के बारे में ज़्यादा जानने के लिए, अन्य नियम.
Bazel की मदद से C++ प्रोजेक्ट बनाने के लिए, C++ बिल्ड ट्यूटोरियल.
Android ऐप्लिकेशन ट्यूटोरियल और iOS ऐप्लिकेशन ट्यूटोरियल, ताकि Bazel की मदद से Android और iOS के लिए मोबाइल ऐप्लिकेशन बनाए जा सकें.
बिल्डिंग बनाने के लिए शुभकामनाएं!