Bazel ट्यूटोरियल: C++ प्रोजेक्ट बनाएं

शुरुआती जानकारी

क्या आपने Bazel का इस्तेमाल पहले कभी नहीं किया? आप सही जगह पर हैं. Bazel का इस्तेमाल करने के आसान तरीके के बारे में जानने के लिए, 'फ़र्स्ट बिल्ड' ट्यूटोरियल देखें. इस ट्यूटोरियल में मुख्य शब्दों के बारे में बताया गया है, क्योंकि इनका इस्तेमाल Bazel के कॉन्टेक्स्ट में किया जाता है. इसमें आपको Bazel वर्कफ़्लो की बुनियादी जानकारी भी मिलती है. अपनी ज़रूरत के टूल से शुरुआत करके, आपको तीन प्रोजेक्ट बनाने और चलाने की सुविधा मिलेगी. इनकी मदद से, यह जाना जा सकता है कि ये प्रोजेक्ट कैसे और क्यों जटिल होते हैं.

Bazel एक बिल्ड सिस्टम है, जो कई भाषाओं में वीडियो के बिल्ड के साथ काम करता है. इस ट्यूटोरियल में C++ प्रोजेक्ट का इस्तेमाल उदाहरण के तौर पर किया गया है. साथ ही, इसमें ज़्यादातर भाषाओं में लागू होने वाले सामान्य दिशा-निर्देश और फ़्लो भी दिए गए हैं.

पूरा होने का अनुमानित समय: 30 मिनट.

ज़रूरी शर्तें

अगर आपने पहले से ऐसा नहीं किया है, तो Bzel इंस्टॉल करके शुरू करें. यह ट्यूटोरियल, सोर्स कंट्रोल करने के लिए Git का इस्तेमाल करता है, इसलिए सबसे अच्छे नतीजों के लिए Git इंस्टॉल करें.

इसके बाद, Bazel के GitHub डेटा स्टोर करने की जगह से सैंपल प्रोजेक्ट को फिर से पाएं. इसके लिए, अपनी पसंद के कमांड-लाइन टूल में दिए गए निर्देशों का पालन करें:

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

इस ट्यूटोरियल का सैंपल प्रोजेक्ट, examples/cpp-tutorial डायरेक्ट्री में है.

यहां देखें कि इसे कैसे बनाया गया है:

examples
└── cpp-tutorial
    ├──stage1
    │  ├── main
    │  │   ├── BUILD
    │  │   └── hello-world.cc
    │  └── WORKSPACE
    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE
    └──stage3
       ├── main
       │   ├── BUILD
       │   ├── hello-world.cc
       │   ├── hello-greet.cc
       │   └── hello-greet.h
       ├── lib
       │   ├── BUILD
       │   ├── hello-time.cc
       │   └── hello-time.h
       └── WORKSPACE

फ़ाइलों के तीन सेट हैं. हर सेट, इस ट्यूटोरियल में एक चरण को दिखाता है. पहले चरण में, आपको एक पैकेज के लिए एक टारगेट बनाना होगा. दूसरे चरण में, आपको एक ही पैकेज से बाइनरी और लाइब्रेरी, दोनों बनाने होंगे. तीसरे और आखिरी चरण में, कई पैकेज वाला प्रोजेक्ट बनाया जाएगा और उसे कई टारगेट के साथ बनाया जाएगा.

खास जानकारी: शुरुआती जानकारी

Bazel (और Git) को इंस्टॉल करके और इस ट्यूटोरियल के लिए डेटा स्टोर करने की जगह को क्लोन करके, आपने Bazel के साथ अपने पहले बिल्ड की बुनियाद तैयार कर दी है. कुछ शर्तें तय करने और अपना फ़ाइल फ़ोल्डर सेट अप करने के लिए, अगले सेक्शन पर जाएं.

रिपोर्ट का इस्तेमाल करना

फ़ाइल फ़ोल्डर सेट अप करना

प्रोजेक्ट बनाने से पहले, आपको उसका फ़ाइल फ़ोल्डर सेट अप करना होगा. वर्कस्पेस ऐसी डायरेक्ट्री है जिसमें आपके प्रोजेक्ट की सोर्स फ़ाइलें और Bazel के बिल्ड आउटपुट होते हैं. इसमें ये महत्वपूर्ण फ़ाइलें भी शामिल होती हैं:

  • WORKSPACE file , जो डायरेक्ट्री और इसके कॉन्टेंट की पहचान Bazel Workspace के तौर पर करता है. यह प्रोजेक्ट के डायरेक्ट्री स्ट्रक्चर के रूट में भी मौजूद होता है.
  • एक या एक से ज़्यादा BUILD files , जो Bazel को बताते हैं कि प्रोजेक्ट के अलग-अलग हिस्से कैसे बनाने हैं. फ़ाइल फ़ोल्डर में, BUILD फ़ाइल वाली डायरेक्ट्री एक पैकेज होती है. (इस ट्यूटोरियल में बाद में पैकेज के बारे में ज़्यादा जानकारी दी गई है.)

आने वाले प्रोजेक्ट में, किसी डायरेक्ट्री को Bazel फ़ाइल फ़ोल्डर के तौर पर सेट करने के लिए, उस डायरेक्ट्री में WORKSPACE नाम की खाली फ़ाइल बनाएं. इस ट्यूटोरियल में, हर चरण में एक WORKSPACE फ़ाइल पहले से मौजूद है.

ध्यान दें: जब Bazel प्रोजेक्ट बनाता है, तब सभी इनपुट एक ही फ़ाइल फ़ोल्डर में होने चाहिए. अलग-अलग फ़ाइल फ़ोल्डर में मौजूद फ़ाइलें एक-दूसरे से अलग होती हैं, जब तक कि उन्हें लिंक न किया गया हो. फ़ाइल फ़ोल्डर के नियमों के बारे में ज़्यादा जानकारी इस गाइड में मिल सकती है.

BUILD फ़ाइल को समझना

BUILD फ़ाइल में, Bazel के लिए अलग-अलग तरह के निर्देश दिए गए हैं. हर BUILD फ़ाइल में, निर्देशों के सेट के तौर पर कम से कम एक नियम होना ज़रूरी है. इससे, Bazel को मनमुताबिक आउटपुट बनाने का तरीका पता चलता है, जैसे कि एक्ज़ीक्यूटेबल बाइनरी या लाइब्रेरी. BUILD फ़ाइल में बिल्ड नियम के हर इंस्टेंस को टारगेट कहा जाता है. यह सोर्स फ़ाइलों के खास सेट और डिपेंडेंसी के बारे में बताता है. टारगेट किसी दूसरे टारगेट की ओर भी इशारा कर सकता है.

cpp-tutorial/stage1/main डायरेक्ट्री में, BUILD फ़ाइल को देखें:

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)

हमारे उदाहरण में, hello-world टारगेट, Bazel में पहले से मौजूद cc_binary rule को इंस्टैंशिएट करता है. यह नियम, Bazel को hello-world.cc सोर्स फ़ाइल से, बिना किसी डिपेंडेंसी के अपने-आप पूरा एक्ज़ीक्यूटेबल बाइनरी बनाने के लिए कहता है.

खास जानकारी: शुरू करना

अब आपको कुछ अहम शब्दों के बारे में पता है. साथ ही, आपको यह भी पता है कि इस प्रोजेक्ट और Bazel के संदर्भ में इनका क्या मतलब है. अगले सेक्शन में, आपको प्रोजेक्ट का पहला चरण बनाकर उसकी जांच करनी होगी.

पहला चरण: एक टारगेट, एक पैकेज

अब प्रोजेक्ट का पहला हिस्सा बनाया जा सकता है. विज़ुअल रेफ़रंस के लिए, प्रोजेक्ट के पहले चरण वाले सेक्शन का स्ट्रक्चर इस तरह है:

examples
└── cpp-tutorial
    └──stage1
       ├── main
       │   ├── BUILD
       │   └── hello-world.cc
       └── WORKSPACE

cpp-tutorial/stage1 डायरेक्ट्री पर जाने के लिए, यह तरीका चलाएं:

cd cpp-tutorial/stage1

इसके बाद, चलाएं:

bazel build //main:hello-world

टारगेट लेबल में, //main: वाला हिस्सा फ़ाइल फ़ोल्डर के रूट के सापेक्ष BUILD फ़ाइल की लोकेशन होता है और BUILD फ़ाइल में hello-world, टारगेट का नाम होता है.

Bazel कुछ ऐसा बनाता है:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.267s, Critical Path: 0.25s

आपने अभी-अभी अपना पहला Bazel टारगेट बनाया है. Bazel, आउटपुट को bazel-binवर्कस्पेस डायरेक्ट्री में बनाता है.

अब अपनी हाल ही में बनी बाइनरी की जांच करें, जो:

bazel-bin/main/hello-world

इसकी वजह से, प्रिंट किया गया “Hello world” मैसेज दिखेगा.

यहां पहले चरण का डिपेंडेंसी ग्राफ़ दिया गया है:

हैलो-वर्ल्ड के लिए डिपेंडेंसी ग्राफ़, एक सोर्स फ़ाइल के साथ एक टारगेट दिखाता है.

खास जानकारी: पहला चरण

पहला बिल्ड पूरा कर लेने के बाद, आपको पता चल जाता है कि बिल्ड कैसे बनाया जाएगा. अगले चरण में, एक और टारगेट जोड़कर इसे और मुश्किल बनाया जा सकता है.

दूसरा चरण: एक से ज़्यादा बिल्ड टारगेट

छोटे प्रोजेक्ट के लिए एक ही टारगेट काफ़ी होता है. हालांकि, हो सकता है कि आप बड़े प्रोजेक्ट को कई टारगेट और पैकेज में बांटना चाहें. यह तेज़ी से इन्क्रीमेंटल बिल्ड बनाने की अनुमति देता है. इसका मतलब है कि Bazel सिर्फ़ उन बदलावों को फिर से बनाता है जिनमें बदलाव किए गए हैं. साथ ही, यह प्रोजेक्ट के कई हिस्सों को एक साथ बनाने की प्रोसेस को तेज़ करता है. ट्यूटोरियल के इस चरण में टारगेट जोड़ा जाता है और अगले चरण में पैकेज जोड़ा जाता है.

यह वही डायरेक्ट्री है जिसके साथ दूसरे चरण में काम किया जा रहा है:

    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE

नीचे cpp-tutorial/stage2/main डायरेक्ट्री में BUILD फ़ाइल देखें:

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
    ],
)

इस BUILD फ़ाइल की मदद से, Bazel पहले hello-greet लाइब्रेरी बनाता है. यह लाइब्रेरी, Bazel के बिल्ट-इन cc_library rule का इस्तेमाल करके, उसके बाद hello-world बाइनरी बनाती है. hello-world के टारगेट में मौजूद deps एट्रिब्यूट से, Bazel को पता चलता है कि hello-world बाइनरी बनाने के लिए, hello-greet लाइब्रेरी की ज़रूरत है.

प्रोजेक्ट का यह नया वर्शन बनाने से पहले, आपको डायरेक्ट्री बदलनी होंगी. इसके लिए, cpp-tutorial/stage2 डायरेक्ट्री पर स्विच करना होगा:

cd ../stage2

अब आप नीचे दिए गए जाने-पहचाने निर्देश का इस्तेमाल करके नई बाइनरी बना सकते हैं:

bazel build //main:hello-world

एक बार फिर से, Bazel कुछ ऐसा वीडियो बनाता है:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.399s, Critical Path: 0.30s

अब अपने अभी बनी बाइनरी की जांच की जा सकती है, जिससे एक और “Hello world” मिलता है:

bazel-bin/main/hello-world

अगर अब आप hello-greet.cc में बदलाव करते हैं और प्रोजेक्ट को फिर से बनाते हैं, तो Bazel सिर्फ़ उस फ़ाइल को दोबारा इकट्ठा करता है.

डिपेंडेंसी ग्राफ़ देखने पर, आप देख सकते हैं कि हैलो-वर्ल्ड पहले की तरह ही इनपुट पर निर्भर करता है. हालांकि, बिल्ड का स्ट्रक्चर अलग है:

`नमस्ते-वर्ल्ड` के लिए डिपेंडेंसी ग्राफ़, फ़ाइल में बदलाव के बाद स्ट्रक्चर में हुए बदलावों को दिखाता है.

खास जानकारी: दूसरा चरण

अब आपने दो टारगेट के साथ प्रोजेक्ट बना लिया है. hello-world टारगेट, एक सोर्स फ़ाइल बनाता है और एक अन्य टारगेट (//main:hello-greet) पर निर्भर करता है, जो दो अतिरिक्त सोर्स फ़ाइलें बनाता है. अगले सेक्शन में, इसे एक कदम आगे ले जाएं और एक और पैकेज जोड़ें.

तीसरा चरण: एक से ज़्यादा पैकेज

इस अगले चरण में, Android घड़ी के विजेट की एक और लेयर जोड़ी जाती है और कई पैकेज वाला प्रोजेक्ट बनाया जाता है. cpp-tutorial/stage3 डायरेक्ट्री के स्ट्रक्चर और कॉन्टेंट को नीचे देखें:

└──stage3
   ├── main
   │   ├── BUILD
   │   ├── hello-world.cc
   │   ├── hello-greet.cc
   │   └── hello-greet.h
   ├── lib
   │   ├── BUILD
   │   ├── hello-time.cc
   │   └── hello-time.h
   └── WORKSPACE

अब दो सब-डायरेक्ट्री हैं और हर एक में BUILD फ़ाइल है. इसलिए, Bazel के लिए, अब फ़ाइल फ़ोल्डर में दो पैकेज हैं: lib और main.

lib/BUILD फ़ाइल पर एक नज़र डालें:

cc_library(
    name = "hello-time",
    srcs = ["hello-time.cc"],
    hdrs = ["hello-time.h"],
    visibility = ["//main:__pkg__"],
)

और main/BUILD फ़ाइल में:

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
        "//lib:hello-time",
    ],
)

मुख्य पैकेज में मौजूद hello-world का टारगेट, lib पैकेज (इसलिए टारगेट लेबल //lib:hello-time) में दिए गए hello-time टारगेट पर निर्भर करता है. Bazel deps एट्रिब्यूट से यह जानकारी लेता है. इसे डिपेंडेंसी ग्राफ़ में देखा जा सकता है:

`hello-world` के लिए डिपेंडेंसी ग्राफ़ दिखाता है कि कैसे मुख्य पैकेज में टारगेट, `lib` पैकेज में मौजूद टारगेट पर निर्भर करता है.

बिल्ड को सफल बनाने के लिए, आपको lib/BUILD में //lib:hello-time टारगेट को, 'किसको दिखे' एट्रिब्यूट का इस्तेमाल करके, main/BUILD में मौजूद टारगेट को साफ़ तौर पर दिखाना है. ऐसा इसलिए होता है, क्योंकि डिफ़ॉल्ट टारगेट सिर्फ़ एक ही BUILD फ़ाइल में मौजूद अन्य टारगेट को दिखते हैं. Bazel, टारगेट की गई विज़िबिलिटी का इस्तेमाल इसलिए करता है, ताकि लाइब्रेरी जैसी समस्याओं को रोका जा सके. इन समस्याओं में, लागू करने की जानकारी सार्वजनिक एपीआई में लीक होने से जुड़ी जानकारी शामिल होती है.

अब प्रोजेक्ट का यह फ़ाइनल वर्शन बनाएं. यह चलाकर cpp-tutorial/stage3 डायरेक्ट्री पर स्विच करें:

cd  ../stage3

एक बार फिर से, नीचे दिए गए निर्देश को चलाएं:

bazel build //main:hello-world

Bazel कुछ ऐसा बनाता है:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 0.167s, Critical Path: 0.00s

अब आखिरी Hello world मैसेज के लिए, इस ट्यूटोरियल की आखिरी बाइनरी की जांच करें:

bazel-bin/main/hello-world

खास जानकारी: तीसरा चरण

अब आपने इस प्रोजेक्ट को तीन टारगेट के साथ दो पैकेज के तौर पर बनाया है और इनके बीच की निर्भरता को समझते हैं. इससे आपको Bazel के साथ आगे बढ़ने और आने वाले समय के प्रोजेक्ट बनाने में मदद मिलती है. अगले सेक्शन में, बैजल सफ़र को जारी रखने का तरीका जानें.

अगले चरण

आपने Bazel के साथ अपना पहला बेसिक बिल्ड पूरा कर लिया है, लेकिन यह तो बस शुरुआत है. Bazel के साथ सीखते रहने के लिए यहां कुछ और संसाधन दिए गए हैं:

इमारत बनाने के लिए शुभकामनाएं!