.bzl स्टाइल गाइड

इस पेज पर Starlark की स्टाइल से जुड़े बुनियादी दिशा-निर्देश दिए गए हैं. साथ ही, इसमें मैक्रो और नियमों से जुड़ी जानकारी भी दी गई है.

Starlark एक ऐसी भाषा है जिससे यह तय होता है कि सॉफ़्टवेयर कैसे बनाया जाता है. इस भाषा में, यह एक प्रोग्रामिंग और कॉन्फ़िगरेशन भाषा, दोनों है.

BUILD फ़ाइलें, मैक्रो लिखने, और नियम बनाने के लिए Starlark का इस्तेमाल किया जाएगा. मैक्रो और नियम मुख्य रूप से मेटा-भाषाएं हैं - ये तय करते हैं कि BUILD फ़ाइलें कैसे लिखी जाएंगी. BUILD फ़ाइलों को आसान और बार-बार दिखाने के मकसद से बनाया गया है.

सभी सॉफ़्टवेयर को लिखे जाने की तुलना में ज़्यादा बार पढ़ा जाता है. यह खास तौर पर Starlark के लिए सही है. इंजीनियर, अपने टारगेट की डिपेंडेंसी और अपने बिल्ड की जानकारी को समझने के लिए, BUILD फ़ाइलों को पढ़ते हैं. यह रीडिंग अक्सर पास होने में, जल्दबाज़ी में या किसी दूसरे काम को पूरा करने के साथ-साथ होती है. इसलिए, इस्तेमाल करने वाले लोग BUILD फ़ाइलों को जल्दी से समझ सकें और पार्स कर सकें, इसलिए ज़रूरी है कि इस्तेमाल को आसान और पढ़ा जा सके.

जब कोई उपयोगकर्ता BUILD फ़ाइल खोलता है, तो वह फ़ाइल में मौजूद टारगेट की सूची के बारे में तुरंत जानना चाहता है या उस C++ लाइब्रेरी के सोर्स की सूची देखना चाहता है या फिर उस Java बाइनरी से निर्भरता को हटा देता है. हर बार ऐब्स्ट्रैक्शन की एक लेयर जोड़ने पर, उपयोगकर्ता के लिए ये टास्क करना मुश्किल हो जाता है.

कई अलग-अलग टूल की मदद से, BUILD फ़ाइलों का विश्लेषण किया जाता है और उन्हें अपडेट भी किया जाता है. अगर टूल आपकी BUILD फ़ाइल में ऐब्सट्रैक्टेशन का इस्तेमाल करता है, तो हो सकता है कि उसमें बदलाव न कर पाएं. अपनी BUILD फ़ाइलों को आसान बनाए रखने से, आपको बेहतर टूल मिल सकता है. कोड बेस बढ़ने के साथ-साथ, लाइब्रेरी को अपडेट करने या क्लीनअप करने के लिए, कई BUILD फ़ाइलों में बदलाव करने की प्रोसेस लगातार बढ़ती जा रही है.

सामान्य सलाह

स्टाइल

Python स्टाइल

किसी भी तरह का संदेह होने पर, जहां संभव हो वहां पीईपी 8 स्टाइल गाइड का पालन करें. खास तौर पर, Python कन्वेंशन को फ़ॉलो करने के लिए इंडेंटेशन के लिए दो के बजाय चार स्पेस का इस्तेमाल करें.

Starlark, Python नहीं है. इसलिए, Python स्टाइल के कुछ पहलू लागू नहीं होते. उदाहरण के लिए, पीईपी 8 सलाह देता है कि सिंगलटन की तुलना is से की जाए, जो Starlark में ऑपरेटर नहीं है.

डॉकस्ट्रिंग

docstrings का इस्तेमाल करके, फ़ाइलों और फ़ंक्शन का दस्तावेज़ बनाएं. हर .bzl फ़ाइल के ऊपर एक docstring और हर सार्वजनिक फ़ंक्शन के लिए docstring का इस्तेमाल करें.

दस्तावेज़ के नियम और पहलू

नियमों, पहलुओं, और उनके एट्रिब्यूट के साथ-साथ, सेवा देने वाली कंपनियों, और उनके फ़ील्ड की जानकारी देने के लिए, 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() फ़ंक्शन का इस्तेमाल न करें. इसका इस्तेमाल सिर्फ़ डीबग करने के लिए किया जाता है. इससे आपकी .bzl फ़ाइल के सभी सीधे तौर पर और किसी अन्य तरीके से नहीं जुड़े उपयोगकर्ताओं को स्पैम भेजा जाएगा. इसका अपवाद सिर्फ़ यह है कि आप ऐसा कोड सबमिट कर सकते हैं जो print() का इस्तेमाल तब करता हो, जब वह डिफ़ॉल्ट रूप से बंद हो और उसे सिर्फ़ सोर्स में बदलाव करके चालू किया जा सके. उदाहरण के लिए, अगर print() के सभी इस्तेमाल if DEBUG: से सुरक्षित हों, जहां DEBUG को False पर हार्डकोड किया जाता है. इस बात का ध्यान रखें कि क्या ये स्टेटमेंट पढ़ने लायक बनाने के हिसाब से काम के हैं.

मैक्रो

मैक्रो एक ऐसा फ़ंक्शन है जो लोड होने के दौरान एक या उससे ज़्यादा नियमों को इंस्टैंशिएट करता है. आम तौर पर, मैक्रो के बजाय जहां भी संभव हो, नियमों का इस्तेमाल करें. उपयोगकर्ता को दिखने वाला बिल्ड ग्राफ़, उस बिल्ड ग्राफ़ के जैसा नहीं होता, जिसे Bazel ने बिल्ड के दौरान इस्तेमाल किया था. Bzel के किसी बिल्ड ग्राफ़ का विश्लेषण करने से पहले, मैक्रो को बड़ा किया जाता है.

इस वजह से, अगर कोई गड़बड़ी होती है, तो उपयोगकर्ता को बिल्ड से जुड़ी समस्याओं को हल करने के लिए, आपके मैक्रो को लागू करने के तरीके को समझना होगा. इसके अलावा, bazel query के नतीजों को समझना मुश्किल हो सकता है, क्योंकि नतीजों में दिखाए गए टारगेट, मैक्रो एक्सपैंशन की मदद से मिलते हैं. आखिर में, पहलुओं को मैक्रो के बारे में जानकारी नहीं होती है. इसलिए, हो सकता है कि पहलुओं (आईडीई और अन्य) के आधार पर टूल करना विफल हो जाए.

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

जनरेट किए गए टारगेट तय करने वाले मैक्रो (मैक्रो के लागू करने की जानकारी, जिसे सीएलआई पर नहीं दिखाया जाना चाहिए या जो उस मैक्रो से इंस्टैंशिएट नहीं किए गए टारगेट पर निर्भर करता है) के लिए, इन सबसे सही तरीकों का पालन करें:

  • मैक्रो में, name आर्ग्युमेंट होना चाहिए. साथ ही, उस नाम का टारगेट तय करना चाहिए. वह टारगेट उस मैक्रो का मुख्य टारगेट बन जाता है.
  • किसी मैक्रो से तय किए गए अन्य सभी टारगेट जनरेट किए गए टारगेट में:
    • उनके नाम के आगे <name> या _<name> लगाएं. उदाहरण के लिए, name = '%s_bar' % (name) का इस्तेमाल करना.
    • सीमित लोगों को दिखाएं (//visibility:private) और
    • वाइल्डकार्ड टारगेट (:all, ..., :* वगैरह) में एक्सपैंशन से बचने के लिए, manual टैग का इस्तेमाल करें.
  • 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 नाम देना है.
  • पहले से तय कंपनी इंटरफ़ेस का इस्तेमाल करके, अपने नियमों के बीच जानकारी दें. दस्तावेज़ देने वाले फ़ील्ड का एलान करें और दस्तावेज़ उपलब्ध कराएं.
  • अपने नियम को समयसीमा को ध्यान में रखकर डिज़ाइन करें. इस बात का ध्यान रखें कि दूसरे नियम, आपके नियमों से इंटरैक्ट करना, सेवा देने वाली कंपनियों को ऐक्सेस करना, और आपकी बनाई गई कार्रवाइयों का फिर से इस्तेमाल कर सकते हैं.
  • अपने नियमों में दिए गए परफ़ॉर्मेंस के दिशा-निर्देशों का पालन करें.