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

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

หน้านี้ครอบคลุมหลักเกณฑ์ด้านรูปแบบพื้นฐานสำหรับ 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 แนะนำว่าการเปรียบเทียบกับ Singleton ควรทำด้วย is ซึ่งไม่ใช่โอเปอเรเตอร์ใน Starlark

Docstring

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

กฎและลักษณะของเอกสาร

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

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

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

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

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