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

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

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

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

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

จะมีการอ่านซอฟต์แวร์ทั้งหมดบ่อยกว่าการเขียน โดยเฉพาะอย่างยิ่งสำหรับ Starlark ขณะที่วิศวกรอ่านไฟล์ BUILD เพื่อทำความเข้าใจทรัพยากร Dependency ของเป้าหมายและรายละเอียดของบิลด์ การอ่านค่านี้มักจะผ่านเวลา เร่งรีบ หรือควบคู่กันไปเพื่อให้ทำงานอื่นๆ ได้สำเร็จ ดังนั้น ความเรียบง่ายและความสามารถในการอ่านจึงเป็นสิ่งสำคัญอย่างยิ่งเพื่อให้ผู้ใช้สามารถแยกวิเคราะห์และทำความเข้าใจไฟล์ 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 เพื่อรับชื่อเป้าหมายที่มาโครกำหนดเท่านั้น ไม่ใช่สำหรับอย่างอื่น เช่น อย่าใช้ชื่อเพื่อดึงทรัพยากร Dependency หรือไฟล์อินพุตที่ไม่ได้สร้างขึ้นโดยมาโครเอง
  • เป้าหมายทั้งหมดที่สร้างในมาโครควรเชื่อมต่อกับเป้าหมายหลักในทางใดทางหนึ่ง
  • ตั้งชื่อพารามิเตอร์ในมาโครให้สอดคล้องกัน หากมีการส่งพารามิเตอร์เป็นค่าแอตทริบิวต์ไปยังเป้าหมายหลัก ให้ใช้ชื่อเดิมต่อไป หากพารามิเตอร์มาโครมีวัตถุประสงค์เดียวกับแอตทริบิวต์กฎทั่วไป เช่น deps ให้ตั้งชื่อตามแอตทริบิวต์ (ดูด้านล่าง)
  • เมื่อเรียกใช้มาโคร ให้ใช้เฉพาะอาร์กิวเมนต์คีย์เวิร์ด วิธีการนี้สอดคล้องกับกฎต่างๆ และช่วยให้อ่านได้ง่ายขึ้นมาก

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

ตามหลักการทั่วไป ยิ่งมาโครมีลักษณะคล้ายกฎมากเท่าใดก็ยิ่งดีเท่านั้น

ดูมาโครเพิ่มเติม

กฎ

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