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

किसी समस्या की शिकायत करें सोर्स देखें Nightly · 7.4 .

परिचय

क्या आपने पहले कभी Bazel का इस्तेमाल नहीं किया है? आप सही जगह पर हैं. Basel का इस्तेमाल करना आसान बनाने के लिए, First Build ट्यूटोरियल देखें. इस ट्यूटोरियल में, मुख्य शब्दों की परिभाषा दी गई है, क्योंकि इनका इस्तेमाल Bazel के संदर्भ में किया जाता है. साथ ही, इसमें आपको Bazel वर्कफ़्लो की बुनियादी जानकारी दी गई है. आपको जिन टूल की ज़रूरत है उनसे शुरू करके, आपको तीन प्रोजेक्ट बनाने और चलाने होंगे. इन प्रोजेक्ट की जटिलता बढ़ती जाएगी. साथ ही, आपको यह भी पता चलेगा कि ये प्रोजेक्ट कैसे और क्यों जटिल होते हैं.

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

पूरा होने में लगने वाला अनुमानित समय: 30 मिनट.

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

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

इसके बाद, अपने पसंदीदा कमांड-लाइन टूल में यह कमांड चलाकर, Bazel के GitHub रिपॉज़िटरी से सैंपल प्रोजेक्ट पाएं:

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

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

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

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

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

खास जानकारी: परिचय

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

शुरू करना

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

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

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

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

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

cpp-tutorial/stage1/main डायरेक्ट्री में मौजूद BUILD फ़ाइल पर एक नज़र डालें:

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

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

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

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

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

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

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

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

आपने अभी-अभी अपना पहला Basel टारगेट बनाया है. Baze, आउटपुट को bazel-bin डायरेक्ट्री में फ़ाइल फ़ोल्डर के रूट में रखती है.

अब अपने नए बाइनरी को टेस्ट करें, जो:

bazel-bin/main/hello-world

इससे "Hello world" मैसेज प्रिंट हो जाता है.

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

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

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

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

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

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

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

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

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 फ़ाइल की मदद से, Basel ने सबसे पहले hello-greet लाइब्रेरी (Baze के बिल्ट-इन cc_library नियम का इस्तेमाल करके) बनाई. इसके बाद, 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 एक अतिरिक्त इनपुट पर निर्भर करता है जिसे hello-greet कहते हैं:

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

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

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

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

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

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

यहां देखें कि अब दो सब-डायरेक्ट्री हैं और हर एक में एक 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 के बारे में ज़्यादा जानने के लिए, यहां कुछ और संसाधन दिए गए हैं:

मज़े से बनाएं!