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) को इंस्टॉल करके और इस ट्यूटोरियल के लिए रिपॉज़िटरी को क्लोन करके, आपने Bzel के साथ अपने पहले बिल्ड की बुनियाद तैयार कर ली है. कुछ शर्तों के बारे में बताने और अपना फ़ाइल फ़ोल्डर सेट अप करने के लिए, अगले सेक्शन पर जाएं.

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

वर्कस्पेस सेट अप करना

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

  • WORKSPACE file , जो डायरेक्ट्री और उसके कॉन्टेंट की पहचान, Bazel फ़ाइल फ़ोल्डर के तौर पर करती है. साथ ही, यह प्रोजेक्ट की डायरेक्ट्री स्ट्रक्चर के रूट में रहती है.
  • एक या एक से ज़्यादा BUILD files , जो बैजल को प्रोजेक्ट के अलग-अलग हिस्से बनाने का तरीका बताते हैं. फ़ाइल फ़ोल्डर में मौजूद जिस डायरेक्ट्री में 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 फ़ाइल की जगह है और hello-world BUILD फ़ाइल में टारगेट का नाम है.

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” मैसेज दिखता है.

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

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

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

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

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

हालांकि, छोटे प्रोजेक्ट के लिए एक टारगेट काफ़ी होता है, लेकिन हो सकता है कि आप बड़े प्रोजेक्ट को कई टारगेट और पैकेज में बांटना चाहें. इसकी मदद से, तेज़ी से इंक्रीमेंटल बिल्ड मिलते हैं – इसका मतलब है कि 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

एक बार फिर, बेज़ेल ने कुछ ऐसा बनाया:

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, hello-greet नाम के एक और इनपुट पर निर्भर है:

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

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

अब आपने दो टारगेट के साथ प्रोजेक्ट बना लिया है. 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 पैकेज में मौजूदhello-time के टारगेट पर निर्भर करता है. इसलिए, टारगेट लेबल //lib: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 के साथ अपना पहला बेसिक बिल्ड पूरा कर लिया है, लेकिन यह अभी शुरुआत ही है. Bazel के साथ सीखना जारी रखने के लिए, यहां कुछ और संसाधन दिए गए हैं:

बिल्डिंग मुबारक!