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

รายงานปัญหา ดูแหล่งที่มา รุ่น Nightly · 8.0 7.4 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

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

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

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

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

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

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

รูปแบบ

รูปแบบ Python

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

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

สตริงเอกสาร

อธิบายไฟล์และฟังก์ชันโดยใช้ docstring ใช้ 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() ได้หากมีการปิดใช้โดยค่าเริ่มต้นและเปิดใช้ได้โดยการแก้ไขซอร์สเท่านั้น เช่น หากการใช้ print() ทั้งหมดได้รับการป้องกันโดย if DEBUG: โดยที่ DEBUG ได้รับการฮาร์ดโค้ดเป็น False โปรดคำนึงว่าข้อความเหล่านี้มีประโยชน์มากพอที่จะอธิบายผลกระทบต่อความอ่านง่ายหรือไม่

มาโคร

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

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

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

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

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

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

โดยทั่วไปแล้ว ยิ่งมาโครคล้ายกับกฎมากเท่าใด ก็ยิ่งดีเท่านั้น

ดูมาโครด้วย

กฎ

  • กฎ แง่มุม และแอตทริบิวต์ของกฎและแง่มุมควรใช้ชื่อแบบพิมพ์เล็ก ("snake case")
  • ชื่อกฎคือคำนามที่อธิบายถึงประเภทหลักของอาร์ติแฟกต์ที่กฎสร้างขึ้นจากมุมมองของข้อกำหนด (หรือผู้ใช้สำหรับกฎระดับล่าง) ซึ่งไม่จำเป็นต้องเป็นคำต่อท้ายไฟล์ เช่น กฎที่ผลิตอาร์ติแฟกต์ C++ สำหรับใช้เป็นส่วนขยาย Python อาจเรียกว่า 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
  • ส่งข้อมูลระหว่างกฎโดยใช้อินเทอร์เฟซ provider ที่กําหนดไว้อย่างดี ประกาศและจัดทำเอกสารเกี่ยวกับช่องผู้ให้บริการ
  • ออกแบบกฎโดยคำนึงถึงความยืดหยุ่น โปรดทราบว่ากฎอื่นๆ อาจต้องการโต้ตอบกับกฎของคุณ เข้าถึงผู้ให้บริการ และนําการดำเนินการที่คุณสร้างขึ้นมาใช้ซ้ำ
  • ปฏิบัติตามหลักเกณฑ์ด้านประสิทธิภาพในกฎ