इस पेज पर, Starlark के लिए स्टाइल से जुड़े बुनियादी दिशा-निर्देश दिए गए हैं. इसमें मैक्रो और नियमों के बारे में भी जानकारी शामिल है.
Starlark एक ऐसी भाषा है जो यह तय करती है कि सॉफ़्टवेयर कैसे बनाया जाता है. इसलिए, यह प्रोग्रामिंग और कॉन्फ़िगरेशन, दोनों तरह की भाषा है.
BUILD
फ़ाइलें, मैक्रो, और बिल्ड के नियम लिखने के लिए, Starlark का इस्तेमाल किया जाएगा. मैक्रो और नियम, मेटा-लैंग्वेज होते हैं. ये बताते हैं कि BUILD
फ़ाइलें कैसे लिखी जाती हैं.
BUILD
फ़ाइलें, आसान और बार-बार दोहराई जाने वाली होनी चाहिए.
सॉफ़्टवेयर को लिखने से ज़्यादा बार पढ़ा जाता है. यह खास तौर पर Starlark के लिए सही है, क्योंकि इंजीनियर BUILD
फ़ाइलें पढ़कर, अपने टारगेट की डिपेंडेंसी और बिल्ड की जानकारी समझते हैं. अक्सर लोग इस जानकारी को सरसरी तौर पर, जल्दी में या किसी दूसरे काम के साथ-साथ पढ़ते हैं. इसलिए, BUILD
फ़ाइलों को आसान और पढ़ने में आसान बनाना बहुत ज़रूरी है, ताकि लोग उन्हें तुरंत पार्स और समझ सकें.
जब कोई उपयोगकर्ता BUILD
फ़ाइल खोलता है, तो वह तुरंत फ़ाइल में मौजूद टारगेट की सूची देखना चाहता है. इसके अलावा, वह C++ लाइब्रेरी के सोर्स की सूची देखना चाहता है या Java बाइनरी से किसी डिपेंडेंसी को हटाना चाहता है. हर बार ऐब्स्ट्रैक्शन की लेयर जोड़ने पर, उपयोगकर्ता के लिए ये काम करना मुश्किल हो जाता है.
BUILD
फ़ाइलों का विश्लेषण और उन्हें अपडेट करने के लिए, कई अलग-अलग टूल का इस्तेमाल किया जाता है. अगर आपकी BUILD
फ़ाइल में ऐब्स्ट्रैक्शन का इस्तेमाल किया गया है, तो हो सकता है कि टूल उसमें बदलाव न कर पाएं. BUILD
फ़ाइलों को आसान रखने से, आपको बेहतर टूलिंग मिल पाएगी. कोड बेस के बढ़ने पर, लाइब्रेरी को अपडेट करने या साफ़ करने के लिए, कई BUILD
फ़ाइलों में बदलाव करना पड़ता है.
सामान्य सलाह
- फ़ॉर्मेटर और लिंटर के तौर पर, Buildifier का इस्तेमाल करें.
- जांच के दिशा-निर्देशों का पालन करें.
शैली
Python स्टाइल
किसी भी तरह का संदेह होने पर, जहां भी हो सके वहां पीईपी 8 स्टाइल गाइड का पालन करें. खास तौर पर, इंडेंटेशन के लिए दो स्पेस के बजाय चार स्पेस का इस्तेमाल करें, ताकि Python के नियमों का पालन किया जा सके.
Starlark, Python नहीं है. इसलिए, Python स्टाइल के कुछ पहलू लागू नहीं होते. उदाहरण के लिए, PEP 8 के मुताबिक, सिंगलटन की तुलना is
से की जानी चाहिए. हालांकि, यह Starlark में ऑपरेटर नहीं है.
डॉकस्ट्रिंग
docstrings का इस्तेमाल करके, दस्तावेज़ की फ़ाइलें और फ़ंक्शन.
हर .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,
)
बूलियन वैल्यू
बूलियन वैल्यू के लिए, 1
और 0
के बजाय True
और False
वैल्यू का इस्तेमाल करें. जैसे, किसी नियम में बूलियन एट्रिब्यूट का इस्तेमाल करते समय.
सिर्फ़ डीबग करने के लिए प्रिंट का इस्तेमाल करना
प्रोडक्शन कोड में print()
फ़ंक्शन का इस्तेमाल न करें. इसका इस्तेमाल सिर्फ़ डीबग करने के लिए किया जाता है. साथ ही, यह आपकी .bzl
फ़ाइल के सभी प्रत्यक्ष और अप्रत्यक्ष उपयोगकर्ताओं को स्पैम करेगा. सिर्फ़ एक अपवाद है. अगर print()
डिफ़ॉल्ट रूप से बंद है और इसे सिर्फ़ सोर्स में बदलाव करके चालू किया जा सकता है, तो 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 API काफ़ी नहीं होता. इससे कोई फ़र्क़ नहीं पड़ता कि नियम को Bazel में नेटिव कोड में तय किया गया है या Starlark में. अगर आपको यह समस्या आ रही है, तो नियम बनाने वाले व्यक्ति से पूछें कि क्या वह आपके लक्ष्यों को पूरा करने के लिए, एपीआई को बढ़ा सकता है.
बुनियादी नियम यह है कि मैक्रो, नियमों से जितना ज़्यादा मिलता-जुलता होगा उतना ही बेहतर होगा.
मैक्रो भी देखें.
नियम
- नियमों, पहलुओं, और उनके एट्रिब्यूट के लिए, lower_case नाम ("स्नेक केस") का इस्तेमाल किया जाना चाहिए.
- नियम के नाम ऐसे संज्ञा शब्द होते हैं जो नियम से बनाए गए मुख्य आर्टफ़ैक्ट के बारे में बताते हैं. ये नाम, नियम की डिपेंडेंसी के हिसाब से तय किए जाते हैं. पत्तों वाले नियमों के लिए, ये नाम उपयोगकर्ता के हिसाब से तय किए जाते हैं. यह ज़रूरी नहीं है कि यह फ़ाइल का सफ़िक्स हो. उदाहरण के लिए, C++ आर्टफ़ैक्ट बनाने वाले नियम को
py_extension
कहा जा सकता है. इन आर्टफ़ैक्ट का इस्तेमाल Python एक्सटेंशन के तौर पर किया जाता है. ज़्यादातर भाषाओं के लिए, सामान्य नियमों में ये शामिल हैं:*_library
- एक कंपाइलेशन यूनिट या "मॉड्यूल".*_binary
- एक ऐसा टारगेट जो एक्ज़ीक्यूटेबल या डिप्लॉयमेंट यूनिट बनाता है.*_test
- एक टेस्ट टारगेट. इसमें एक से ज़्यादा टेस्ट शामिल हो सकते हैं. उम्मीद है कि*_test
टारगेट में किए गए सभी टेस्ट, एक ही थीम पर आधारित होंगे. उदाहरण के लिए, किसी एक लाइब्रेरी को टेस्ट करना.*_import
: एक ऐसा टारगेट जिसमें पहले से कंपाइल किया गया आर्टफ़ैक्ट शामिल हो. जैसे,.jar
या कंपाइलेशन के दौरान इस्तेमाल किया जाने वाला.dll
.
- एट्रिब्यूट के लिए एक जैसे नाम और टाइप इस्तेमाल करें. आम तौर पर लागू होने वाले कुछ एट्रिब्यूट ये हैं:
srcs
:label_list
, फ़ाइलों की अनुमति देता है: सोर्स फ़ाइलें, आम तौर पर इन्हें इंसान ने लिखा होता है.deps
:label_list
, आम तौर पर फ़ाइलों को अनुमति नहीं देता: कंपाइलेशन डिपेंडेंसी.data
:label_list
, फ़ाइलों की अनुमति देता है: डेटा फ़ाइलें, जैसे कि टेस्ट डेटा वगैरह.runtime_deps
:label_list
: रनटाइम डिपेंडेंसी, जिनकी कंपाइल करने के लिए ज़रूरत नहीं होती.
- ऐसे एट्रिब्यूट के लिए दस्तावेज़ उपलब्ध कराएं जिनके काम करने का तरीका साफ़ तौर पर समझ में नहीं आता. उदाहरण के लिए, खास सब्स्टिट्यूशन वाले स्ट्रिंग टेंप्लेट या खास ज़रूरी शर्तों के साथ इस्तेमाल किए जाने वाले टूल. इसके लिए, एट्रिब्यूट के एलान (
attr.label_list()
या इसी तरह का कोई अन्य) मेंdoc
कीवर्ड आर्ग्युमेंट का इस्तेमाल करें. - नियम लागू करने वाले फ़ंक्शन, ज़्यादातर मामलों में निजी फ़ंक्शन होने चाहिए. निजी फ़ंक्शन ऐसे फ़ंक्शन होते हैं जिनके नाम की शुरुआत अंडरस्कोर से होती है. आम तौर पर,
myrule
के लिए लागू करने वाले फ़ंक्शन को_myrule_impl
नाम दिया जाता है. - अच्छी तरह से तय किए गए provider इंटरफ़ेस का इस्तेमाल करके, अपने नियमों के बीच जानकारी पास करें. डेटा देने वाली कंपनी के फ़ील्ड के बारे में जानकारी दें और उनके दस्तावेज़ उपलब्ध कराएं.
- अपने नियम को इस तरह से डिज़ाइन करें कि उसे बढ़ाया जा सके. ध्यान रखें कि अन्य नियम, आपके नियम के साथ इंटरैक्ट कर सकते हैं. साथ ही, वे आपके प्रोवाइडर को ऐक्सेस कर सकते हैं और आपके बनाए गए कार्रवाइयों का फिर से इस्तेमाल कर सकते हैं.
- अपने नियमों में परफ़ॉर्मेंस के दिशा-निर्देशों का पालन करें.