คู่มือสไตล์ .bzl

รายงานปัญหา ดูแหล่งที่มา

หน้านี้ครอบคลุมหลักเกณฑ์พื้นฐานเกี่ยวกับ Starlark รวมทั้งข้อมูลเกี่ยวกับมาโครและกฎ

Starlark เป็นภาษาที่กําหนดวิธีสร้างซอฟต์แวร์ ดังนั้นจึงเป็นทั้งภาษาโปรแกรมและการกําหนดค่า

คุณจะใช้ Starlark เพื่อเขียนไฟล์ มาโคร และสร้างกฎ BUILD รายการ มาโครและกฎต่างๆ เป็นภาษาเมตาเป็นหลัก ซึ่งระบุวิธีเขียนไฟล์ BUILD ไฟล์ BUILD มีจุดประสงค์ให้เรียบง่ายและซ้ําซาก

ซอฟต์แวร์ทั้งหมดอ่านบ่อยกว่าเขียน โดยเฉพาะอย่างยิ่งสําหรับ Starlark เนื่องจากวิศวกรอ่านไฟล์ BUILD รายการเพื่อทําความเข้าใจทรัพยากร Dependency ของเป้าหมายและรายละเอียดของบิลด์ การอ่านนี้มักจะเกิดขึ้นในขณะที่กําลัง กําลังรีบ หรือในขณะเดียวกันก็ทํางานอื่นๆ ให้เสร็จได้ ดังนั้นความเรียบง่ายและการอ่านที่สําคัญมากจึงช่วยให้ผู้ใช้แยกวิเคราะห์และเข้าใจไฟล์ BUILD ได้อย่างรวดเร็ว

เมื่อผู้ใช้เปิดไฟล์ BUILD พวกเขาต้องการทราบรายการเป้าหมายในไฟล์อย่างรวดเร็ว หรือดูรายการแหล่งที่มาของไลบรารี C++ หรือนําทรัพยากร Dependency ออกจากไบนารีของ Java นั้น ทุกครั้งที่เพิ่มเลเยอร์นามธรรม คุณจะช่วยให้ผู้ใช้ทําสิ่งเหล่านี้ได้ยากขึ้น

เครื่องมือต่างๆ มากมายวิเคราะห์และอัปเดตไฟล์ BUILD รายการด้วย เครื่องมืออาจแก้ไขไฟล์ BUILD ไม่ได้หากใช้นามธรรม การทําให้ไฟล์ BUILD ไม่ซับซ้อนช่วยให้คุณใช้เครื่องมือได้ดีขึ้น เมื่อฐานของโค้ดขยายตัว ก็จะเกิดการเปลี่ยนแปลงมากขึ้นเรื่อยๆ ในไฟล์ BUILD หลายๆ ไฟล์เพื่ออัปเดตไลบรารีหรือล้างข้อมูล

คำแนะนำทั่วไป

มีรูปแบบ

สไตล์ Python

หากไม่แน่ใจ โปรดปฏิบัติตามคําแนะนํารูปแบบของ PEP 8 หากเป็นไปได้ โดยเฉพาะเรื่องการเว้นวรรค 4 ช่องแทนที่จะเป็น 2 ช่องเพื่อให้สอดคล้องกับแบบ Python

เนื่องจาก Starlark ไม่ใช่ Python รูปแบบ Python บางอย่างจึงไม่เกี่ยวข้อง ตัวอย่างเช่น PEP 8 แนะนําให้ใช้การเปรียบเทียบกับ Singleton จะดําเนินการด้วย is ซึ่งไม่ใช่โอเปอเรเตอร์ใน Starlark

Docs

เอกสารไฟล์และฟังก์ชันโดยใช้ docstrings ใช้ docstring ที่ด้านบนของไฟล์ .bzl แต่ละไฟล์ และใช้ docstring สําหรับฟังก์ชันสาธารณะแต่ละรายการ

กฎและแง่มุมของเอกสาร

เอกสารและแง่มุมต่างๆ รวมถึงแอตทริบิวต์ รวมถึงผู้ให้บริการและฟิลด์ควรบันทึกโดยใช้อาร์กิวเมนต์ doc

รูปแบบการตั้งชื่อ

  • ตัวแปรและชื่อฟังก์ชันใช้ตัวพิมพ์เล็กที่มีคําที่คั่นด้วยขีดล่าง ([a-z][a-z0-9_]*) เช่น cc_library
  • ค่าส่วนตัวระดับบนสุดจะเริ่มต้นด้วยขีดล่าง 1 ขีด 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() หากปิดใช้ไว้โดยค่าเริ่มต้นและเปิดใช้ได้โดยการแก้ไขแหล่งที่มาเท่านั้น เช่น หาก if DEBUG: ป้องกันการใช้ print() ทั้งหมดฮาร์ดโค้ดเป็น False โปรดทราบว่าข้อความเหล่านี้มีประโยชน์เพียงพอที่จะอธิบายผลกระทบต่อการอ่านได้หรือไม่

มาโคร

มาโครคือฟังก์ชันที่จะสร้างอินสแตนซ์ของกฎอย่างน้อย 1 กฎในระหว่างขั้นตอนการโหลด โดยทั่วไป หากเป็นไปได้ ให้ใช้กฎแทนมาโคร กราฟบิวด์ที่ผู้ใช้เห็นไม่เหมือนกับกราฟที่ Bazel ใช้ระหว่างบิลด์ มาโครจะขยายก่อนที่ Bazel จะทําการวิเคราะห์กราฟบิลด์

ด้วยเหตุนี้ เมื่อมีสิ่งใดผิดพลาด ผู้ใช้จะต้องทําความเข้าใจการนํามาโครของคุณไปใช้ในการแก้ปัญหาเกี่ยวกับบิวด์ นอกจากนี้ อาจตีความผลลัพธ์ bazel query ได้ยาก เนื่องจากเป้าหมายที่แสดงในผลลัพธ์มาจากการขยายมาโคร สุดท้ายแล้ว แง่มุมต่างๆ ไม่ได้รับรู้ถึงมาโคร การใช้เครื่องมือ จึงอาจขึ้นอยู่กับแง่มุมต่างๆ (IDE และอื่นๆ)

การใช้มาโครอย่างปลอดภัยมีไว้สําหรับการกําหนดเป้าหมายเพิ่มเติมที่จะอ้างอิงโดยตรงที่ไฟล์ Bazel CLI หรือในไฟล์ BUILD เท่านั้น ในกรณีดังกล่าว จะมีเพียงผู้ใช้ปลายทางเป้าหมายเหล่านั้นเท่านั้นที่จําเป็นต้องรู้เกี่ยวกับปัญหาเหล่านั้น และปัญหาบิลด์ที่มาโครต่างๆ นําไปใช้งานจะไม่ยากจนเกินไป

สําหรับมาโครที่กําหนดเป้าหมายที่สร้างขึ้น (รายละเอียดการใช้งานของมาโครที่ไม่ควรอ้างอิงที่ CLI หรือขึ้นอยู่กับเป้าหมายที่ไม่ได้สร้างขึ้นโดยมาโครนั้น) ให้ทําตามแนวทางปฏิบัติแนะนําต่อไปนี้

  • มาโครควรใช้อาร์กิวเมนต์ name และกําหนดเป้าหมายที่มีชื่อนั้น เป้าหมายนั้นจะกลายเป็นเป้าหมายหลักของมาโคร
  • เป้าหมายที่สร้างขึ้น ซึ่งเป็นเป้าหมายอื่นๆ ทั้งหมดที่มาโครกําหนดไว้ ควรทําดังนี้
    • ขึ้นต้นด้วย <name> หรือ _<name> เช่น การใช้ name = '%s_bar' % (name)
    • มีระดับการเข้าถึงที่จํากัด (//visibility:private) และ
    • มีแท็ก manual เพื่อหลีกเลี่ยงการขยายเป้าหมายไวลด์การ์ด (:all, ..., :* ฯลฯ)
  • ควรใช้ name เพื่อดึงชื่อเป้าหมายที่กําหนดโดยมาโครเท่านั้น ไม่ใช่ชื่ออื่นใด เช่น อย่าใช้ชื่อเพื่อรับทรัพยากร Dependency หรือไฟล์อินพุตที่ไม่ได้สร้างขึ้นโดยมาโคร
  • เป้าหมายทั้งหมดที่สร้างในมาโครควรจับคู่กับเป้าหมายหลักเพียงบางส่วน
  • ตั้งชื่อพารามิเตอร์ในมาโครให้สอดคล้องกัน หากส่งพารามิเตอร์เป็นค่าแอตทริบิวต์ไปยังเป้าหมายหลัก ให้คงชื่อเดิมไว้ หากพารามิเตอร์มาโครมีจุดประสงค์เดียวกับแอตทริบิวต์กฎทั่วไป เช่น deps ให้ระบุชื่อเหมือนกับแอตทริบิวต์ (ดูด้านล่าง)
  • เมื่อทําการเรียกมาโคร ให้ใช้เฉพาะอาร์กิวเมนต์คีย์เวิร์ดเท่านั้น การดําเนินการนี้สอดคล้องกับกฎและช่วยเพิ่มความสามารถในการอ่านได้อย่างมาก

วิศวกรมักจะเขียนมาโครเมื่อ Starlark API ของกฎที่เกี่ยวข้องไม่เพียงพอสําหรับ Use Case ที่เฉพาะเจาะจง ไม่ว่าจะกําหนดกฎภายใน Bazel ในโค้ดที่มาพร้อมเครื่องหรือใน Starlark ก็ตาม หากคุณกําลังประสบปัญหานี้ โปรดสอบถามผู้เขียนกฎว่าสามารถขยาย API เพื่อให้บรรลุเป้าหมายของคุณได้หรือไม่

หลักการทั่วไปคือ ยิ่งมีมาโครคล้ายกับกฎมากเท่าไร ก็ยิ่งทํางานได้ดีขึ้นเท่านั้น

ดูมาโครด้วย

กฎ

  • กฎ แง่มุม และแอตทริบิวต์ของแอตทริบิวต์ควรใช้ชื่อตัวพิมพ์เล็ก ("snake Case")
  • ชื่อกฎคือคํานามที่อธิบายประเภทของอาร์ติแฟกต์หลักที่กฎสร้างขึ้น จากมุมมองของทรัพยากร Dependency (หรือสําหรับกฎใบไม้ ผู้ใช้) ซึ่งไม่จําเป็นต้องเป็นคําต่อท้ายไฟล์ เช่น กฎที่ใช้สร้างอาร์ติแฟกต์ C++ ซึ่งใช้เป็นส่วนขยายของ Python อาจเรียกว่า py_extension สําหรับภาษาส่วนใหญ่ กฎทั่วไปมีดังนี้
    • *_library - หน่วยรวมหรือ "โมดูล"
    • *_binary - เป้าหมายที่ทําให้เกิดไฟล์ปฏิบัติการหรือหน่วยการทําให้ใช้งานได้
    • *_test - เป้าหมายทดสอบ ซึ่งรวมถึงการทดสอบหลายรายการ คาดว่าการทดสอบทั้งหมดในเป้าหมาย *_test จะมีรูปแบบต่างๆ กันในธีมเดียวกัน เช่น การทดสอบไลบรารีเดียว
    • *_import: เป้าหมายที่รวมอาร์ติแฟกต์ที่รวบรวมไว้ล่วงหน้า เช่น .jar หรือ .dll ที่ใช้ระหว่างการคอมไพล์
  • ใช้ชื่อและประเภทที่สอดคล้องกันสําหรับแอตทริบิวต์ แอตทริบิวต์ทั่วไปที่ใช้ได้มีดังนี้
    • srcs: label_list อนุญาตไฟล์: ไฟล์ต้นฉบับ ซึ่งโดยปกติแล้วจะเป็นมนุษย์
    • deps: label_list โดยปกติจะไม่อนุญาตไฟล์: การรวบรวมคลิป
    • data: label_list อนุญาตไฟล์: ไฟล์ข้อมูล เช่น ข้อมูลการทดสอบ
    • runtime_deps: label_list: ทรัพยากร Dependency ที่ไม่จําเป็นต้องรวบรวม
  • สําหรับแอตทริบิวต์ที่มีลักษณะการทํางานที่ไม่ชัดเจน (เช่น เทมเพลตสตริงที่มีการแทนที่พิเศษ หรือเครื่องมือที่เรียกใช้ตามข้อกําหนดเฉพาะ) ให้ใส่เอกสารโดยใช้อาร์กิวเมนต์คีย์เวิร์ด doc กับการประกาศแอตทริบิวต์ (attr.label_list() หรือที่คล้ายกัน)
  • ฟังก์ชันการใช้กฎควรเป็นฟังก์ชันส่วนตัวเกือบทั้งหมด (ตั้งชื่อด้วยเครื่องหมายขีดล่างนําหน้า) รูปแบบทั่วไปคือการระบุฟังก์ชันการใช้งานของ myrule โดยใช้ชื่อ _myrule_impl
  • ส่งข้อมูลระหว่างกฎโดยใช้อินเทอร์เฟซผู้ให้บริการที่กําหนดไว้อย่างชัดเจน ประกาศและช่องผู้ให้บริการเอกสาร
  • ออกแบบกฎโดยคํานึงถึงสิ่งต่อไปนี้ โปรดทราบว่ากฎอื่นๆ อาจต้องโต้ตอบกับกฎ เข้าถึงผู้ให้บริการ และนําการทํางานที่คุณสร้างมาใช้ซ้ํา
  • ปฏิบัติตามหลักเกณฑ์ด้านประสิทธิภาพในกฎ