इस पेज पर, Starlark के लिए स्टाइल से जुड़े बुनियादी दिशा-निर्देश दिए गए हैं. साथ ही, इसमें मैक्रो और नियमों के बारे में भी जानकारी शामिल है.
Starlark एक ऐसी भाषा है जिससे यह तय किया जाता है कि सॉफ़्टवेयर कैसे बनाया जाता है. इसलिए, यह प्रोग्रामिंग और कॉन्फ़िगरेशन, दोनों तरह की भाषा है.
BUILD फ़ाइलें, मैक्रो, और बिल्ड के नियम लिखने के लिए, Starlark का इस्तेमाल किया जाता है. मैक्रो और नियम, मेटा-लैंग्वेज होते हैं. इनसे यह तय किया जाता है कि BUILD फ़ाइलें कैसे लिखी जाती हैं.
BUILD फ़ाइलें, आसान और बार-बार इस्तेमाल की जाने वाली होनी चाहिए.
सॉफ़्टवेयर को लिखने के मुकाबले ज़्यादा बार पढ़ा जाता है. खास तौर पर, Starlark के लिए यह बात सही है, क्योंकि इंजीनियर अपने टारगेट की डिपेंडेंसी और बिल्ड की जानकारी समझने के लिए, BUILD फ़ाइलें पढ़ते हैं. इन्हें अक्सर जल्दबाज़ी में, किसी अन्य काम के साथ-साथ, या कभी-कभी ही पढ़ा जाता है. इसलिए,
ये फ़ाइलें आसान और आसानी से पढ़ी जा सकने वाली होनी चाहिए, ताकि उपयोगकर्ता इन्हें तुरंत पार्स और
समझ सकें.BUILD
जब कोई उपयोगकर्ता BUILD फ़ाइल खोलता है, तो वह तुरंत यह जानना चाहता है कि फ़ाइल में टारगेट की सूची कौनसी है. इसके अलावा, वह C++ लाइब्रेरी के सोर्स की सूची देखना चाहता है या Java बाइनरी से डिपेंडेंसी हटाना चाहता है. हर बार ऐब्स्ट्रैक्शन की एक लेयर जोड़ने पर, उपयोगकर्ता के लिए ये काम करना मुश्किल हो जाता है.
BUILD फ़ाइलों का विश्लेषण और अपडेट, कई अलग-अलग टूल से भी किया जाता है. अगर आपकी BUILD फ़ाइल में ऐब्स्ट्रैक्शन का इस्तेमाल किया गया है, तो हो सकता है कि टूल उसमें बदलाव न कर पाएं. BUILD फ़ाइलों को आसान रखने से, आपको बेहतर टूलिंग मिल पाएगी. कोड बेस बढ़ने पर, किसी लाइब्रेरी को अपडेट करने या साफ़-सफ़ाई करने के लिए, कई BUILD फ़ाइलों में बदलाव करना ज़्यादा से ज़्यादा ज़रूरी हो जाता है.
सामान्य सलाह
- फ़ॉर्मेटर और लिंटर के तौर पर, Buildifier का इस्तेमाल करें.
- टेस्टिंग के दिशा-निर्देशों का पालन करें.
शैली
Python की शैली
किसी भी तरह का संदेह होने पर, जहां तक हो सके PEP 8 स्टाइल गाइड का पालन करें. खास तौर पर, Python के कन्वेंशन के मुताबिक इंडेंटेशन के लिए दो के बजाय चार स्पेस का इस्तेमाल करें.
Starlark,
Python नहीं है.
इसलिए, Python की शैली के कुछ पहलू लागू नहीं होते. उदाहरण के लिए, PEP 8 में सलाह दी जाती है कि सिंगलटन की तुलना is से की जाए. हालांकि, Starlark में यह ऑपरेटर नहीं है.
डॉकस्ट्रिंग
डॉकस्ट्रिंग का इस्तेमाल करके, फ़ाइलों और फ़ंक्शन के बारे में जानकारी दें.
हर .bzl फ़ाइल के सबसे ऊपर, डॉकस्ट्रिंग का इस्तेमाल करें. साथ ही, हर सार्वजनिक फ़ंक्शन के लिए भी डॉकस्ट्रिंग का इस्तेमाल करें.
नियमों और आसपेक्ट के बारे में जानकारी देना
नियमों और आसपेक्ट के साथ-साथ, उनके एट्रिब्यूट, प्रोवाइडर, और उनके फ़ील्ड के बारे में जानकारी देने के लिए, doc आर्ग्युमेंट का इस्तेमाल किया जाना चाहिए.
नेमिंग कन्वेंशन
- वैरिएबल और फ़ंक्शन के नामों के लिए, लोअरकेस का इस्तेमाल किया जाता है. साथ ही, शब्दों को अंडरस्कोर (
[a-z][a-z0-9_]*) से अलग किया जाता है. जैसे,cc_library. - टॉप-लेवल की निजी वैल्यू, एक अंडरस्कोर से शुरू होती हैं. Bazel यह पक्का करता है कि निजी वैल्यू का इस्तेमाल, अन्य फ़ाइलों से न किया जा सके. लोकल वैरिएबल के लिए, अंडरस्कोर प्रीफ़िक्स का इस्तेमाल नहीं किया जाना चाहिए.
लाइन की लंबाई
BUILD फ़ाइलों की तरह, लाइन की लंबाई की कोई तय सीमा नहीं होती, क्योंकि लेबल लंबे हो सकते हैं.
जहां तक हो सके, हर लाइन में ज़्यादा से ज़्यादा 79 वर्णों का इस्तेमाल करें. इसके लिए, Python की
स्टाइल गाइड, PEP 8 का पालन करें. इस दिशा-निर्देश को सख्ती से लागू नहीं किया जाना चाहिए: एडिटर को 80 से ज़्यादा कॉलम दिखाने चाहिए. साथ ही, ऑटोमेटेड बदलावों से अक्सर लंबी लाइनें बन जाती हैं. इसके अलावा, लोगों को उन लाइनों को अलग-अलग करने में समय नहीं लगाना चाहिए जिन्हें आसानी से पढ़ा जा सकता है.
कीवर्ड आर्ग्युमेंट
कीवर्ड आर्ग्युमेंट में, बराबर के निशान के आस-पास स्पेस का इस्तेमाल करना बेहतर होता है:
def fct(name, srcs):
filtered_srcs = my_filter(source = srcs)
native.cc_library(
name = name,
srcs = filtered_srcs,
testonly = True,
)
बूलियन वैल्यू
बूलियन वैल्यू के लिए, True और False वैल्यू का इस्तेमाल करना बेहतर होता है. जैसे, किसी नियम में बूलियन एट्रिब्यूट का इस्तेमाल करते समय. इसके लिए, 1 और 0 वैल्यू का इस्तेमाल न करें.
सिर्फ़ डीबग करने के लिए, print का इस्तेमाल करना
प्रोडक्शन कोड में, print() फ़ंक्शन का इस्तेमाल न करें. इसका इस्तेमाल सिर्फ़ डीबग करने के लिए किया जाता है. साथ ही, इससे आपकी .bzl फ़ाइल के सभी डायरेक्ट और इनडायरेक्ट उपयोगकर्ताओं को स्पैम मिलेगा. सिर्फ़ एक अपवाद यह है कि अगर डिफ़ॉल्ट रूप से print() का इस्तेमाल करने वाला कोड बंद है और सोर्स में बदलाव करके ही इसे चालू किया जा सकता है, तो ऐसा कोड सबमिट किया जा सकता है. उदाहरण के लिए, अगर print() के सभी इस्तेमाल, if DEBUG: से सुरक्षित हैं, जहां DEBUG को False पर हार्डकोड किया गया है. इस बात का ध्यान रखें कि ये स्टेटमेंट, पढ़ने में आसानी पर पड़ने वाले असर को सही ठहराने के लिए काफ़ी काम के हैं या नहीं.
मैक्रो
मैक्रो एक ऐसा फ़ंक्शन है जो लोड होने के दौरान, एक या एक से ज़्यादा नियमों को इंस्टैंशिएट करता है. आम तौर पर, मैक्रो के बजाय नियमों का इस्तेमाल करें. उपयोगकर्ता को दिखने वाला बिल्ड ग्राफ़, Bazel के बिल्ड के दौरान इस्तेमाल किए जाने वाले बिल्ड ग्राफ़ से अलग होता है. Bazel के बिल्ड ग्राफ़ का विश्लेषण करने से पहले, मैक्रो को एक्सपैंड किया जाता है.
इस वजह से, कोई गड़बड़ी होने पर, उपयोगकर्ता को बिल्ड की समस्याओं को हल करने के लिए, आपके मैक्रो के लागू करने के तरीके को समझना होगा. इसके अलावा, bazel
query नतीजों को समझना मुश्किल हो सकता है, क्योंकि नतीजों में दिखाए गए टारगेट
मैक्रो के एक्सपैंशन से मिलते हैं. आखिर में, आसपेक्ट को मैक्रो के बारे में पता नहीं होता. इसलिए, आसपेक्ट पर निर्भर रहने वाले टूल (आईडीई वगैरह) काम नहीं कर सकते.
मैक्रो का सुरक्षित इस्तेमाल, Bazel CLI या BUILD फ़ाइलों में सीधे तौर पर रेफ़रंस किए जाने वाले अतिरिक्त टारगेट तय करने के लिए किया जाता है. ऐसे में, उन टारगेट के असली उपयोगकर्ताओं को ही उनके बारे में जानने की ज़रूरत होती है. साथ ही, मैक्रो की वजह से होने वाली बिल्ड की समस्याएं, उनके इस्तेमाल से कभी दूर नहीं होतीं.
जनरेट किए गए टारगेट तय करने वाले मैक्रो के लिए, ये सबसे सही तरीके अपनाएं. मैक्रो के लागू करने के तरीके की जानकारी, जिसे सीएलआई पर रेफ़र नहीं किया जाना चाहिए या उन टारगेट पर निर्भर नहीं होना चाहिए जिन्हें उस मैक्रो से इंस्टैंशिएट नहीं किया गया है:
- किसी मैक्रो में
nameआर्ग्युमेंट होना चाहिए. साथ ही, उस नाम से एक टारगेट तय किया जाना चाहिए. वह टारगेट, उस मैक्रो का मुख्य टारगेट बन जाता है. - जनरेट किए गए टारगेट, यानी किसी मैक्रो से तय किए गए अन्य सभी टारगेट के नाम में:
<name>या_<name>प्रीफ़िक्स होना चाहिए. उदाहरण के लिए,name = '%s_bar' % (name)का इस्तेमाल करना.- विज़िबिलिटी सीमित होनी चाहिए (
//visibility:private). - वाइल्डकार्ड टारगेट (
:all,...,:*वगैरह) में एक्सपैंशन से बचने के लिए,manualटैग होना चाहिए.
nameका इस्तेमाल, सिर्फ़ मैक्रो से तय किए गए टारगेट के नाम पाने के लिए किया जाना चाहिए. इसका इस्तेमाल किसी अन्य काम के लिए नहीं किया जाना चाहिए. उदाहरण के लिए, मैक्रो से जनरेट न होने वाली डिपेंडेंसी या इनपुट फ़ाइल पाने के लिए, नाम का इस्तेमाल न करें.- मैक्रो में बनाए गए सभी टारगेट, मुख्य टारगेट से किसी न किसी तरह जुड़े होने चाहिए.
- कन्वेंशन के मुताबिक, मैक्रो तय करते समय,
nameपहला आर्ग्युमेंट होना चाहिए. - मैक्रो में पैरामीटर के नाम एक जैसे रखें. अगर किसी पैरामीटर को मुख्य टारगेट की एट्रिब्यूट वैल्यू के तौर पर पास किया जाता है, तो उसका नाम वही रखें. अगर कोई मैक्रो पैरामीटर, सामान्य नियम एट्रिब्यूट के तौर पर काम करता है, तो उसका नाम एट्रिब्यूट के नाम जैसा ही रखें. जैसे,
deps(नीचे देखें). - मैक्रो को कॉल करते समय, सिर्फ़ कीवर्ड आर्ग्युमेंट का इस्तेमाल करें. यह नियमों के मुताबिक है. साथ ही, इससे पढ़ने में आसानी होती है.
इंजीनियर अक्सर मैक्रो तब लिखते हैं, जब काम के नियमों का Starlark एपीआई, उनके खास इस्तेमाल के लिए काफ़ी नहीं होता. भले ही, नियम को Bazel में नेटिव कोड में तय किया गया हो या Starlark में. अगर आपको यह समस्या आ रही है, तो नियम के लेखक से पूछें कि क्या वे आपके लक्ष्यों को पूरा करने के लिए, एपीआई को बढ़ा सकते हैं.
आम तौर पर, मैक्रो नियमों से जितने मिलते-जुलते होंगे, उतना ही बेहतर होगा.
नियम
- नियमों, आसपेक्ट, और उनके एट्रिब्यूट के नामों के लिए, लोअरकेस ("स्नेक केस") का इस्तेमाल किया जाना चाहिए.
- नियमों के नाम ऐसे संज्ञा शब्द होते हैं जो नियम से बनने वाले मुख्य तरह के आर्टफ़ैक्ट के बारे में बताते हैं. इन्हें डिपेंडेंसी के नज़रिए से (या लीफ़ नियमों के लिए, उपयोगकर्ता के नज़रिए से) तय किया जाता है. यह ज़रूरी नहीं है कि यह फ़ाइल का सफ़िक्स हो. उदाहरण के लिए, Python एक्सटेंशन के तौर पर इस्तेमाल किए जाने वाले C++ आर्टफ़ैक्ट बनाने वाले नियम को
py_extensionकहा जा सकता है. ज़्यादातर भाषाओं के लिए, सामान्य नियमों में ये शामिल हैं:*_library- एक कंपाइलेशन यूनिट या "मॉड्यूल".*_binary- एक ऐसा टारगेट जो एक्ज़ीक्यूटेबल या डिप्लॉयमेंट यूनिट बनाता है.*_test- एक टेस्ट टारगेट. इसमें एक से ज़्यादा टेस्ट शामिल हो सकते हैं.*_testटारगेट में सभी टेस्ट, एक ही थीम पर आधारित होने चाहिए. उदाहरण के लिए, किसी एक लाइब्रेरी की जांच करना.*_import: एक ऐसा टारगेट जो पहले से कंपाइल किए गए आर्टफ़ैक्ट को एनकैप्सुलेट करता है. जैसे,.jarया.dll, जिसका इस्तेमाल कंपाइलेशन के दौरान किया जाता है.
- एट्रिब्यूट के लिए एक जैसे नाम और टाइप का इस्तेमाल करें. आम तौर पर लागू होने वाले कुछ एट्रिब्यूट में ये शामिल हैं:
srcs:label_list. इसमें ये फ़ाइलें शामिल हो सकती हैं: सोर्स फ़ाइलें, आम तौर पर लोगों ने लिखी होती हैं.deps:label_list. इसमें आम तौर पर ये फ़ाइलें शामिल नहीं होतीं: कंपाइलेशन डिपेंडेंसी.data:label_list. इसमें ये फ़ाइलें शामिल हो सकती हैं: डेटा फ़ाइलें, जैसे कि टेस्ट डेटा वगैरह.runtime_deps:label_list. इसमें रनटाइम डिपेंडेंसी शामिल होती हैं, जिनकी ज़रूरत कंपाइलेशन के लिए नहीं होती.
- ऐसे एट्रिब्यूट जिनके व्यवहार के बारे में साफ़ तौर पर पता नहीं चलता. उदाहरण के लिए, खास तौर पर सब्स्टिट्यूशन वाले स्ट्रिंग टेंप्लेट या खास ज़रूरतों के साथ लागू किए जाने वाले टूल के लिए,
docकीवर्ड आर्ग्युमेंट का इस्तेमाल करके दस्तावेज़ उपलब्ध कराएं. इसके लिए, एट्रिब्यूट के एलान (attr.label_list()या इसी तरह के किसी अन्य एलान) का इस्तेमाल करें. - नियम को लागू करने वाले फ़ंक्शन, लगभग हमेशा निजी फ़ंक्शन होने चाहिए. इनके नाम की शुरुआत में अंडरस्कोर होना चाहिए. आम तौर पर,
myruleको लागू करने वाले फ़ंक्शन का नाम_myrule_implरखा जाता है. - अच्छी तरह से तय किए गए प्रोवाइडर इंटरफ़ेस का इस्तेमाल करके, अपने नियमों के बीच जानकारी पास करें. प्रोवाइडर फ़ील्ड का एलान करें और उनके बारे में जानकारी दें.
- अपने नियम को इस तरह डिज़ाइन करें कि उसे बढ़ाया जा सके. ध्यान रखें कि अन्य नियम, आपके नियम के साथ इंटरैक्ट कर सकते हैं, आपके प्रोवाइडर को ऐक्सेस कर सकते हैं, और आपके बनाए गए ऐक्शन का फिर से इस्तेमाल कर सकते हैं.
- अपने नियमों में, परफ़ॉर्मेंस के दिशा-निर्देशों का पालन करें.